chiark / gitweb /
ccc79be3609a42fb0c6197839980f2641a7fcdef
[ypp-sc-tools.db-test.git] / pctb / db-idempotent-populate
1 #!/usr/bin/perl -w
2 #
3 # usage: ./db-idempotent-populate <Oceanname>
4 #  creates or updates OCEAN-Oceanname.db
5 #  from master-master.txt
6
7 # This is part of ypp-sc-tools, a set of third-party tools for assisting
8 # players of Yohoho Puzzle Pirates.
9 #
10 # Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
11 #
12 # This program is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation, either version 3 of the License, or
15 # (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 #
25 # Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
26 # are used without permission.  This program is not endorsed or
27 # sponsored by Three Rings.
28
29 use strict (qw(vars));
30
31 use DBI;
32
33 use Commods;
34
35 @ARGV==1 or die;
36 my ($oceanname) = @ARGV;
37
38 my $dbfn= "OCEAN-$oceanname.db";
39
40 our $dbh;
41
42 sub dbdoall ($) {
43     foreach my $cmd (split /\;/, $_[0]) {
44         $dbh->do("$cmd;") if $cmd =~ m/\S/;
45     }
46 }
47
48 #---------- setup ----------
49
50 parse_masters_ocean($oceanname);
51 our $ocean= $oceans{$oceanname};
52
53 $dbh= DBI->connect("dbi:SQLite:$dbfn",'','',
54                    { AutoCommit=>0,
55                      RaiseError=>1, ShowErrorStatement=>1,
56                      unicode=>1 })
57     or die "$dbfn $DBI::errstr ?";
58
59 #---------- schema ----------
60
61 foreach my $bs (qw(buy sell)) {
62     dbdoall(<<END)
63  CREATE TABLE IF NOT EXISTS $bs (
64         commodid        INTEGER                 NOT NULL,
65         islandid        INTEGER                 NOT NULL,
66         stallid         INTEGER                 NOT NULL,
67         price           INTEGER                 NOT NULL,
68         qty             INTEGER                 NOT NULL,
69         PRIMARY KEY (commodid, islandid, stallid)
70  );
71  CREATE INDEX IF NOT EXISTS ${bs}_by_island ON $bs (commodid, islandid, price);
72  CREATE INDEX IF NOT EXISTS ${bs}_by_price  ON $bs (commodid, price, islandid);
73 END
74     ;
75 }
76
77 dbdoall(<<END)
78  CREATE TABLE IF NOT EXISTS commods (
79         commodid        INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
80         commodname      TEXT    UNIQUE          NOT NULL,
81         unitmass        INTEGER,
82         unitvolume      INTEGER
83  );
84  CREATE TABLE IF NOT EXISTS islands (
85         islandid        INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
86         islandname      TEXT    UNIQUE          NOT NULL,
87         archipelago     TEXT                    NOT NULL
88  );
89  CREATE TABLE IF NOT EXISTS stalls (
90         stallid         INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
91         islandid        INTEGER                 NOT NULL,
92         stallname       TEXT                    NOT NULL,
93         UNIQUE (islandid, stallname)
94  );
95  CREATE TABLE IF NOT EXISTS uploads (
96         islandid        INTEGER PRIMARY KEY     NOT NULL,
97         age             INTEGER                 NOT NULL,
98         clientspec      TEXT                    NOT NULL,
99         serverspec      TEXT                    NOT NULL
100  );
101  CREATE TABLE IF NOT EXISTS dists (
102         aiid            INTEGER                 NOT NULL,
103         biid            INTEGER                 NOT NULL,
104         dist            INTEGER                 NOT NULL,
105         PRIMARY KEY (aiid, biid)
106  );
107 END
108     ;
109
110 $dbh->commit;
111
112 #---------- commodity list ----------
113
114 {
115     my $sth= $dbh->prepare(<<'END')
116  INSERT OR IGNORE INTO commods (commodname) VALUES (?);
117 END
118     ;
119     foreach my $commod (sort keys %commods) {
120         $sth->execute($commod);
121     }
122     $dbh->commit;
123 }
124
125 #---------- island list ----------
126
127 {
128     my $sth= $dbh->prepare(<<'END')
129  INSERT OR IGNORE INTO islands (islandname, archipelago) VALUES (?, ?);
130 END
131     ;
132     foreach my $archname (sort keys %$ocean) {
133         my $arch= $ocean->{$archname};
134         foreach my $islandname (sort keys %$arch) {
135             $sth->execute($islandname, $archname);
136         }
137     }
138     $dbh->commit;
139 }
140
141 #---------- routes ----------
142
143 {
144     foreach my $islandname (sort keys %{ $route_mysteries{$oceanname} }) {
145         warn "$route_mysteries{$oceanname}{$islandname} routes".
146             " for unknown island $islandname\n";
147     }
148
149     dbdoall(<<END)
150  CREATE TEMPORARY TABLE newdists (
151         aiid            INTEGER                 NOT NULL,
152         biid            INTEGER                 NOT NULL,
153         dist            INTEGER                 NOT NULL
154  );
155  INSERT INTO newdists SELECT (aiid,biid,dist) FROM dists;
156  INSERT INTO newdists SELECT (biid,aiid,dist) FROM dists;
157  INSERT INTO newdists SELECT (islandid,islandid,0) FROM islands;
158 END
159     ;
160
161     my $sth= $dbh->prepare(<<'END')
162  INSERT INTO newdists VALUES
163         ((SELECT islandid FROM islands WHERE islandname == ?),
164          (SELECT islandid FROM islands WHERE islandname == ?),
165          ?);
166 END
167     ;
168     my $allroutes= $routes{$oceanname};
169     foreach my $an (keys %$allroutes) {
170         my $routes= $allroutes->{$an};
171         foreach my $bn (keys %$routes) {
172             $sth->execute($an, $bn, $routes->{$bn});
173         }
174     }
175
176     my $stmt_updatemain= $dbh->prepare(<<'END')
177  UPDATE dists SET dist = (
178         SELECT min(dist) FROM newdists
179         WHERE dists.aiid == newdists.aiid
180           AND dists.biid == newdists.biid
181           AND NOT dists.dist <= newdists.dist
182  );
183 END
184
185     my $stmt_removeredund= $dbh->prepare(<<'END')
186  DELETE FROM newdists
187         WHERE dist > (
188                 SELECT dists.dist
189                 WHERE dists.aiid == newdists.aiid
190                   AND dists.aiid == newdists.aiid
191  );
192 END
193     ;
194
195     my $stmt_gennew= $dbh->prepare(<<'END')
196  INSERT INTO newdists (
197         SELECT src.aiid, dst.biid, min(src.dist + dst.dist)
198         FROM dists AS src, dists AS dst ON src.biid == dst.aiid
199         GROUP BY src.aiid, dst.biid
200  );
201 END
202     ;
203     
204     for (;;) {
205         $ar= $dbh->selectall_arrayref("select ia.islandname, ib.islandname,newdists.dist from newdists, islands as ia on newdists.aiid = ia.islandid, islands as ib on newdists.biid = ib.islandid;");
206         print Dumper($ar);
207
208         my $affected= $stmt_updatemain->execute();
209         last unless $affected;
210
211         $stmt_
212         
213 }
214
215 #use Data::Dumper;
216 #print Dumper(\%routes);
217
218 __DATA__