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

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

(Adding dynamic classifiers) Added getmetadatavalues() function, which will not be part of dbclass because it cannot be implemented efficiently by gdbmclass.

File size: 7.4 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 file extension string
92text_t sqlitedbclass::getfileextension ()
93{
94 return ".db";
95}
96
97
98// returns true on success
99bool sqlitedbclass::getkeydata (const text_t& key, text_t &data)
100{
101 text_t sql_cmd = "SELECT value FROM data WHERE key='" + key + "'";
102 vector<text_tmap> sql_results;
103 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
104 {
105 return false;
106 }
107
108 text_tmap sql_result = sql_results[0];
109 data = sql_result["value"];
110 return true;
111}
112
113
114// returns array of keys
115text_tarray sqlitedbclass::getkeys ()
116{
117 text_tarray keys;
118
119 // Get all the entries in the "key" column of the table
120 text_t sql_cmd = "SELECT key FROM data";
121 vector<text_tmap> sql_results;
122 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
123 {
124 return keys;
125 }
126
127 // Iterate through the keys and add them to the array to be returned
128 vector<text_tmap>::iterator sql_results_iterator = sql_results.begin();
129 while (sql_results_iterator != sql_results.end())
130 {
131 text_tmap sql_result = (*sql_results_iterator);
132 keys.push_back(sql_result["key"]);
133 sql_results_iterator++;
134 }
135
136 return keys;
137}
138
139
140text_tarray sqlitedbclass::getmetadatavalues (const text_t &metadata_element_name)
141{
142 text_tarray metadata_values;
143
144 // Get all the entries in the "value" column of the "document_metadata" table
145 text_t sql_cmd = "SELECT value FROM document_metadata WHERE element='" + metadata_element_name + "'";
146 vector<text_tmap> sql_results;
147 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
148 {
149 return metadata_values;
150 }
151
152 // Iterate through the values and add them to the array to be returned
153 vector<text_tmap>::iterator sql_results_iterator = sql_results.begin();
154 while (sql_results_iterator != sql_results.end())
155 {
156 text_tmap sql_result = (*sql_results_iterator);
157 metadata_values.push_back(sql_result["value"]);
158 sql_results_iterator++;
159 }
160
161 return metadata_values;
162}
163
164
165// returns true on success
166bool sqlitedbclass::setkeydata (const text_t &key, const text_t &data)
167{
168 // We need to do either an INSERT or UPDATE depending on whether the key already exists
169 if (!exists(key))
170 {
171 text_t sql_cmd = "INSERT INTO data (key, value) VALUES ('" + key + "', '" + data + "')";
172 return sqlexec(sql_cmd);
173 }
174 else
175 {
176 text_t sql_cmd = "UPDATE data SET value='" + data + "' WHERE key='" + key + "'";
177 return sqlexec(sql_cmd);
178 }
179}
180
181
182// ----------------------------------------------------------------------------------------
183// SQLITE-ONLY FUNCTIONS
184// ----------------------------------------------------------------------------------------
185
186// sqlexec simply executes the given sql statement - it doesn't obtain a
187// result set - returns true if the sql statement was executed successfully
188bool sqlitedbclass::sqlexec(const text_t &sql_cmd)
189{
190 if (sqlitefile == NULL) return false;
191
192 char *sql_cmd_cstr = sql_cmd.getcstr();
193
194 int rv = 0;
195 int tries = 0;
196 while ((rv = sqlite3_exec(sqlitefile, sql_cmd_cstr, NULL, NULL, NULL)) == SQLITE_BUSY)
197 {
198 sleep(1000);
199 tries++;
200 if (tries > SQLITE_MAX_RETRIES)
201 {
202 outconvertclass text_t2ascii;
203 (*logout) << text_t2ascii << "max_retries exceeded for sql query: " << sql_cmd << "\n";
204 break;
205 }
206 }
207
208 delete[] sql_cmd_cstr;
209
210 if (rv == SQLITE_OK) return true;
211
212 // sqlite3_exec failed - return false
213 outconvertclass text_t2ascii;
214 (*logout) << text_t2ascii << "Error executing sql statement: " << sql_cmd << "\n";
215 return false;
216}
217
218
219// callback functions for sqlgetarray
220static int sqlgetarray_callback(void *res, int numcols, char **vals, char **columnnames)
221{
222 vector<text_tmap> *result = (vector<text_tmap>*) res;
223 text_tmap row;
224
225 for (int i = 0; i < numcols; i++)
226 {
227 row[columnnames[i]] = "";
228 // vals[i] will be NULL if set to a NULL db value
229 if (vals[i])
230 {
231 row[columnnames[i]] = vals[i];
232 }
233 }
234
235 result->push_back(row);
236 return 0;
237}
238
239
240// sqlgetarray executes sql and returns the result set in sql_results
241bool sqlitedbclass::sqlgetarray(const text_t &sql_cmd, vector<text_tmap> &sql_results)
242{
243 if (sqlitefile == NULL) return false;
244
245 char *sql_cmd_cstr = sql_cmd.getcstr();
246 sql_results.erase(sql_results.begin(), sql_results.end());
247
248 int rv = 0;
249 int tries = 0;
250 while ((rv = sqlite3_exec(sqlitefile, sql_cmd_cstr, sqlgetarray_callback, &sql_results, NULL)) == SQLITE_BUSY)
251 {
252 sleep(1000);
253 tries++;
254 if (tries > SQLITE_MAX_RETRIES)
255 {
256 outconvertclass text_t2ascii;
257 (*logout) << text_t2ascii << "max_retries exceeded for sql query: " << sql_cmd << "\n";
258 break;
259 }
260 }
261
262 delete[] sql_cmd_cstr;
263
264 if (rv == SQLITE_OK) return true;
265
266 // sqlite3_exec failed - return empty result set
267 outconvertclass text_t2ascii;
268 (*logout) << text_t2ascii << "Error executing sql statement: " << sql_cmd << "\n";
269 return false;
270}
271
272
273// returns true if exists
274bool sqlitedbclass::sqltableexists(const text_t &table_name)
275{
276 text_t sql_cmd = "SELECT * FROM sqlite_master WHERE tbl_name='" + table_name + "'";
277 vector<text_tmap> sql_results;
278 if (!sqlgetarray(sql_cmd, sql_results) || sql_results.size() == 0)
279 {
280 return false;
281 }
282
283 return true;
284}
285
286
287// sleep for the given number of milliseconds
288void sleep(int m)
289{
290#ifdef __WIN32__
291 Sleep(m);
292#else
293 usleep(m);
294#endif
295}
Note: See TracBrowser for help on using the repository browser.