chiark / gitweb /
where-vessels: expand report area to fill space available
[ypp-sc-tools.main.git] / yarrg / rssql.c
1 /*
2  * Route searcher - database helper functions
3  */
4 /*
5  *  This is part of the YARRG website, a tool for assisting
6  *  players of Yohoho Puzzle Pirates.
7  * 
8  *  Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
9  *
10  *  This program is free software: you can redistribute it and/or modify
11  *  it under the terms of the GNU Affero General Public License as
12  *  published by the Free Software Foundation, either version 3 of the
13  *  License, or (at your option) any later version.
14  *  
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Affero General Public License for more details.
19  *  
20  *  You should have received a copy of the GNU Affero General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *  
23  *  Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
24  *  are used without permission.  This program is not endorsed or
25  *  sponsored by Three Rings.
26  */
27
28 #include "rscommon.h"
29
30 sqlite3 *db;
31 sqlite3_stmt *ss_ipair;
32
33 int islandtablesz;
34
35 DEBUG_DEFINE_DEBUGF(sql);
36 DEBUG_DEFINE_SOME_DEBUGF(sql,debug2f);
37
38 static int busy_handler(void *u, int previous) {
39   debugf("[[DB BUSY %d]]",previous);
40   sysassert(! usleep(5000) );
41   return 1;
42 }
43
44 void setup_sql(const char *database) {
45   sqlite3_stmt *sst;
46   
47   SQL_MUST( sqlite3_open(database, &db) );
48   SQL_MUST( sqlite3_busy_handler(db, busy_handler, 0) );
49
50   sst= sql_prepare("BEGIN","(begin)");
51   assert( !SQL_STEP(sst) );
52   sqlite3_finalize(sst);
53
54   islandtablesz= 1 + sql_single_int("SELECT max(islandid) FROM islands");
55   debugf("SQL islandtablesz=%d\n",islandtablesz);
56 }
57
58 int sql_single_int(const char *stmt) {
59   sqlite3_stmt *sst;
60   sst= sql_prepare(stmt,"(single int)");
61   assert( SQL_STEP(sst) );
62   int rv= sqlite3_column_int(sst,0);
63   sqlite3_finalize(sst);
64   return rv;
65 }
66
67 void sql_fatal(const char *stmt_what, int sqr, const char *act_what) {
68   fatal("SQL call failed, stmt %s code %d: %s: %s",
69         stmt_what, sqr, sqlite3_errmsg(db), act_what);
70 }
71
72 void sql_bind(sqlite3_stmt *ss, int index, int value,
73               const char *ss_what, const char *val_what) {
74   debug2f("SQL BIND %s #%d = %d = %s\n", ss_what, index, value, val_what);
75   int sqr= sqlite3_bind_int(ss, index, value);
76   if (sqr) sql_fatal(ss_what, sqr,
77                      masprintf("bind #%d (%s)", index, val_what));
78 }
79   
80 sqlite3_stmt *sql_prepare(const char *stmt, const char *what) {
81   sqlite3_stmt *ssr;
82   debugf("SQL PREPARE %s [[\n%s\n]]\n", what, stmt);
83   SQL_MUST( sqlite3_prepare(db, stmt, -1, &ssr, 0) );
84   return ssr;
85 }
86
87 int sql_step_distinct(sqlite3_stmt *ssh, const char *ssh_string,
88                       const char *file, int line,
89                       int *cols, int ncols, int nkeycols) {
90   for (;;) {
91     if (!sql_step(ssh, ssh_string, file, line)) return 0;
92
93     int i;
94     for (i=0; i<ncols; i++) {
95       int v= sqlite3_column_int(ssh, i);
96       if (v == cols[i]) continue;
97       
98       assert(i<nkeycols);
99       cols[i++]= v;
100       for ( ; i<ncols; i++)
101         cols[i]= sqlite3_column_int(ssh, i);
102       return 1;
103     }
104   }
105 }
106
107 int sql_step(sqlite3_stmt *ssh, const char *ssh_string,
108              const char *file, int line) {
109   for (;;) {
110     int sqr;
111     sqr= sqlite3_step((ssh));
112     switch (sqr) {
113     case SQLITE_DONE:
114       debug2f("SQL %s DONE\n",ssh_string);
115       return 0;
116     case SQLITE_ROW:
117       if (DEBUGP(sql2)) {
118         int i;
119         fprintf(debug,"SQL %s R",ssh_string);
120         for (i=0; i<sqlite3_column_count(ssh); i++) {
121           fputc('\t',debug);
122           const char *txt= (const char*)sqlite3_column_text(ssh,i);
123           fputs(txt ? txt : "<null>", debug);
124         }
125         fputs("\n",debug);
126       }
127       return 1;
128     default: fatal("SQL step failed at %s:%d: code %d: %s: %s",
129                    file, line, sqr, sqlite3_errmsg(db), ssh_string);
130     }
131   }
132 }