source: gsdl/trunk/lib/sqlitedbclass.cpp@ 15655

Last change on this file since 15655 was 15655, checked in by mdewsnip, 16 years ago

(Adding new DB support) Created default implementations of getinfo() and setinfo() in dbclass so they don't necessarily be re-implemented for every subclass.

File size: 6.5 KB
Line 
1/**********************************************************************
2 *
3 * sqlitedbclass.cpp --
4 * Copyright (C) 2008 DL Consulting Ltd
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (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 General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "sqlitedbclass.h"
27#include "unitool.h"
28
29
30#define SQLITE_MAX_RETRIES 8
31
32
33sqlitedbclass::~sqlitedbclass()
34{
35 closedatabase();
36}
37
38
39// returns true if opened
40bool sqlitedbclass::opendatabase (const text_t &filename, int mode, int num_retrys,
41#ifdef __WIN32__
42 bool need_filelock
43#else
44 bool
45#endif
46 )
47{
48 // Check if we've already got the database open
49 if (sqlitefile != NULL)
50 {
51 if (openfile == filename) return true;
52 else closedatabase();
53 }
54
55 char *filename_cstr = filename.getcstr();
56 sqlite3_open(filename_cstr, &sqlitefile);
57 delete[] filename_cstr;
58
59 if (sqlitefile == NULL)
60 {
61 (*logout) << "ERROR: sqlitedbclass::opendatabase() failed on: " << filename << "\n";
62 return false;
63 }
64
65 if ((mode == DB_WRITER || mode == DB_WRITER_CREATE) && !sqltableexists("data"))
66 {
67 sqlexec("CREATE TABLE data (key TEXT, value TEXT, PRIMARY KEY(key))");
68 }
69
70 return true;
71}
72
73
74void sqlitedbclass::closedatabase ()
75{
76 if (sqlitefile == NULL) return;
77
78 sqlite3_close(sqlitefile);
79 sqlitefile = NULL;
80 openfile.clear();
81}
82
83
84void sqlitedbclass::deletekey (const text_t &key)
85{
86 text_t sql_cmd = "DELETE FROM data WHERE key='" + key + "'";
87 sqlexec(sql_cmd);
88}
89
90
91// returns true on success
92bool sqlitedbclass::getkeydata (const text_t& key, text_t &data)
93{
94 text_t sql_cmd = "SELECT value FROM data WHERE key='" + key + "'";
95 vector<text_tmap> sql_results;
96 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
97 {
98 return false;
99 }
100
101 text_tmap sql_result = sql_results[0];
102 data = sql_result["value"];
103 return true;
104}
105
106
107// returns array of keys
108text_tarray sqlitedbclass::getkeys ()
109{
110 text_tarray keys;
111
112 // Get all the entries in the "key" column of the table
113 text_t sql_cmd = "SELECT key FROM data";
114 vector<text_tmap> sql_results;
115 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
116 {
117 return keys;
118 }
119
120 // Iterate through the keys and add them to the array to be returned
121 vector<text_tmap>::iterator sql_results_iterator = sql_results.begin();
122 while (sql_results_iterator != sql_results.end())
123 {
124 text_tmap sql_result = (*sql_results_iterator);
125 keys.push_back(sql_result["key"]);
126 sql_results_iterator++;
127 }
128
129 return keys;
130}
131
132
133// returns true on success
134bool sqlitedbclass::setkeydata (const text_t &key, const text_t &data)
135{
136 // We need to do either an INSERT or UPDATE depending on whether the key already exists
137 if (!exists(key))
138 {
139 text_t sql_cmd = "INSERT INTO data (key, value) VALUES ('" + key + "', '" + data + "')";
140 return sqlexec(sql_cmd);
141 }
142 else
143 {
144 text_t sql_cmd = "UPDATE data SET value='" + data + "' WHERE key='" + key + "'";
145 return sqlexec(sql_cmd);
146 }
147}
148
149
150// ----------------------------------------------------------------------------------------
151// SQLITE-ONLY FUNCTIONS
152// ----------------------------------------------------------------------------------------
153
154// sqlexec simply executes the given sql statement - it doesn't obtain a
155// result set - returns true if the sql statement was executed successfully
156bool sqlitedbclass::sqlexec(const text_t &sql_cmd)
157{
158 if (sqlitefile == NULL) return false;
159
160 char *sql_cmd_cstr = sql_cmd.getcstr();
161
162 int rv = 0;
163 int tries = 0;
164 while ((rv = sqlite3_exec(sqlitefile, sql_cmd_cstr, NULL, NULL, NULL)) == SQLITE_BUSY)
165 {
166 sleep(1000);
167 tries++;
168 if (tries > SQLITE_MAX_RETRIES)
169 {
170 outconvertclass text_t2ascii;
171 (*logout) << text_t2ascii << "max_retries exceeded for sql query: " << sql_cmd << "\n";
172 break;
173 }
174 }
175
176 delete[] sql_cmd_cstr;
177
178 if (rv == SQLITE_OK) return true;
179
180 // sqlite3_exec failed - return false
181 outconvertclass text_t2ascii;
182 (*logout) << text_t2ascii << "Error executing sql statement: " << sql_cmd << "\n";
183 return false;
184}
185
186
187// callback functions for sqlgetarray
188static int sqlgetarray_callback(void *res, int numcols, char **vals, char **columnnames)
189{
190 vector<text_tmap> *result = (vector<text_tmap>*) res;
191 text_tmap row;
192
193 for (int i = 0; i < numcols; i++)
194 {
195 row[columnnames[i]] = "";
196 // vals[i] will be NULL if set to a NULL db value
197 if (vals[i])
198 {
199 row[columnnames[i]] = vals[i];
200 }
201 }
202
203 result->push_back(row);
204 return 0;
205}
206
207
208// sqlgetarray executes sql and returns the result set in sql_results
209bool sqlitedbclass::sqlgetarray(const text_t &sql_cmd, vector<text_tmap> &sql_results)
210{
211 if (sqlitefile == NULL) return false;
212
213 char *sql_cmd_cstr = sql_cmd.getcstr();
214 sql_results.erase(sql_results.begin(), sql_results.end());
215
216 int rv = 0;
217 int tries = 0;
218 while ((rv = sqlite3_exec(sqlitefile, sql_cmd_cstr, sqlgetarray_callback, &sql_results, NULL)) == SQLITE_BUSY)
219 {
220 sleep(1000);
221 tries++;
222 if (tries > SQLITE_MAX_RETRIES)
223 {
224 outconvertclass text_t2ascii;
225 (*logout) << text_t2ascii << "max_retries exceeded for sql query: " << sql_cmd << "\n";
226 break;
227 }
228 }
229
230 delete[] sql_cmd_cstr;
231
232 if (rv == SQLITE_OK) return true;
233
234 // sqlite3_exec failed - return empty result set
235 outconvertclass text_t2ascii;
236 (*logout) << text_t2ascii << "Error executing sql statement: " << sql_cmd << "\n";
237 return false;
238}
239
240
241// returns true if exists
242bool sqlitedbclass::sqltableexists(const text_t &table_name)
243{
244 text_t sql_cmd = "SELECT * FROM sqlite_master WHERE tbl_name='" + table_name + "'";
245 vector<text_tmap> sql_results;
246 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
247 {
248 return false;
249 }
250
251 return true;
252}
253
254
255// sleep for the given number of milliseconds
256void sleep(int m)
257{
258#ifdef __WIN32__
259 Sleep(m);
260#else
261 usleep(m);
262#endif
263}
Note: See TracBrowser for help on using the repository browser.