1 /*
2 * Copyright (C) 2001 - 2002 Carlos Perelló Marín <carlos@gnome-db.org>
3 * Copyright (C) 2001 - 2002 Rodrigo Moya <rodrigo@gnome-db.org>
4 * Copyright (C) 2001 - 2012 Vivien Malerba <malerba@gnome-db.org>
5 * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo@src.gnome.org>
6 * Copyright (C) 2010 David King <davidk@openismus.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <glib/gi18n-lib.h>
25 #include "gda-sqlite-util.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include "gda-sqlite.h"
29 #include <libgda/gda-connection-private.h>
30 #undef GDA_DISABLE_DEPRECATED
31 #include <libgda/sql-parser/gda-statement-struct-util.h>
32 #include "gda-sqlite-recordset.h"
33
34 #include <libgda/sqlite/keywords_hash.h>
35 #include "keywords_hash.c" /* this one is dynamically generated */
36
37 static guint
nocase_str_hash(gconstpointer v)38 nocase_str_hash (gconstpointer v)
39 {
40 guint ret;
41 gchar *up = g_ascii_strup ((gchar *) v, -1);
42 ret = g_str_hash ((gconstpointer) up);
43 g_free (up);
44 return ret;
45 }
46
47 static gboolean
nocase_str_equal(gconstpointer v1,gconstpointer v2)48 nocase_str_equal (gconstpointer v1, gconstpointer v2)
49 {
50 return g_ascii_strcasecmp ((gchar *) v1, (gchar *) v2) == 0 ? TRUE : FALSE;
51 }
52
53 void
_gda_sqlite_compute_types_hash(SqliteConnectionData * cdata)54 _gda_sqlite_compute_types_hash (SqliteConnectionData *cdata)
55 {
56 if (!cdata->types_hash) {
57 gint i;
58 GType type, *array;
59 GHashTable *hash;
60 cdata->types_hash = g_hash_table_new (nocase_str_hash, nocase_str_equal);
61 hash = cdata->types_hash;
62 #define NB_DECLARED_G_TYPES 14
63 cdata->types_array = g_new (GType, NB_DECLARED_G_TYPES);
64 array = cdata->types_array;
65
66 type = G_TYPE_INT;
67 i = 0;
68 array [i] = type;
69 g_hash_table_insert (hash, "integer", array + i);
70 g_hash_table_insert (hash, "int", array + i);
71
72 type = G_TYPE_UINT;
73 i++;
74 array [i] = type;
75 g_hash_table_insert (hash, "unsigned integer", array + i);
76 g_hash_table_insert (hash, "unsigned int", array + i);
77 g_hash_table_insert (hash, "uint", array + i);
78
79 type = G_TYPE_BOOLEAN;
80 i++;
81 array [i] = type;
82 g_hash_table_insert (hash, "boolean", array + i);
83
84 type = G_TYPE_DATE;
85 i++;
86 array [i] = type;
87 g_hash_table_insert (hash, "date", array + i);
88
89 type = GDA_TYPE_TIME;
90 i++;
91 array [i] = type;
92 g_hash_table_insert (hash, "time", array + i);
93
94 type = GDA_TYPE_TIMESTAMP;
95 i++;
96 array [i] = type;
97 g_hash_table_insert (hash, "timestamp", array + i);
98
99 type = G_TYPE_DOUBLE;
100 i++;
101 array [i] = type;
102 g_hash_table_insert (hash, "real", array + i);
103
104 type = G_TYPE_STRING;
105 i++;
106 array [i] = type;
107 g_hash_table_insert (hash, "text", array + i);
108 g_hash_table_insert (hash, "string", array + i);
109 g_hash_table_insert (hash, "varchar", array + i);
110
111 type = GDA_TYPE_BINARY;
112 i++;
113 array [i] = type;
114 g_hash_table_insert (hash, "binary", array + i);
115
116 type = GDA_TYPE_BLOB;
117 i++;
118 array [i] = type;
119 g_hash_table_insert (hash, "blob", array + i);
120
121 type = G_TYPE_INT64;
122 i++;
123 array [i] = type;
124 g_hash_table_insert (hash, "int64", array + i);
125
126 type = G_TYPE_UINT64;
127 i++;
128 array [i] = type;
129 g_hash_table_insert (hash, "uint64", array + i);
130
131 type = GDA_TYPE_SHORT;
132 i++;
133 array [i] = type;
134 g_hash_table_insert (hash, "short", array + i);
135
136 type = GDA_TYPE_USHORT;
137 i++;
138 array [i] = type;
139 g_hash_table_insert (hash, "ushort", array + i);
140 g_hash_table_insert (hash, "unsigned short", array + i);
141 g_assert (i < NB_DECLARED_G_TYPES);
142 }
143 }
144
145 GType
_gda_sqlite_compute_g_type(int sqlite_type)146 _gda_sqlite_compute_g_type (int sqlite_type)
147 {
148 switch (sqlite_type) {
149 case SQLITE_INTEGER:
150 return G_TYPE_INT;
151 case SQLITE_FLOAT:
152 return G_TYPE_DOUBLE;
153 case 0:
154 case SQLITE_TEXT:
155 return G_TYPE_STRING;
156 case SQLITE_BLOB:
157 return GDA_TYPE_BLOB;
158 case SQLITE_NULL:
159 return GDA_TYPE_NULL;
160 default:
161 g_warning ("Unknown SQLite internal data type %d", sqlite_type);
162 return G_TYPE_STRING;
163 }
164 }
165
166
167
168 #ifdef GDA_DEBUG
169 void
_gda_sqlite_test_keywords(void)170 _gda_sqlite_test_keywords (void)
171 {
172 test_keywords();
173 }
174 #endif
175
176 GdaSqlReservedKeywordsFunc
_gda_sqlite_get_reserved_keyword_func(void)177 _gda_sqlite_get_reserved_keyword_func (void)
178 {
179 return is_keyword;
180 }
181
182 static gchar *
identifier_add_quotes(const gchar * str)183 identifier_add_quotes (const gchar *str)
184 {
185 gchar *retval, *rptr;
186 const gchar *sptr;
187 gint len;
188
189 if (!str)
190 return NULL;
191
192 len = strlen (str);
193 retval = g_new (gchar, 2*len + 3);
194 *retval = '"';
195 for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) {
196 if (*sptr == '"') {
197 *rptr = '"';
198 rptr++;
199 *rptr = *sptr;
200 }
201 else
202 *rptr = *sptr;
203 }
204 *rptr = '"';
205 rptr++;
206 *rptr = 0;
207 return retval;
208 }
209
210 static gboolean
_sql_identifier_needs_quotes(const gchar * str)211 _sql_identifier_needs_quotes (const gchar *str)
212 {
213 const gchar *ptr;
214
215 g_return_val_if_fail (str, FALSE);
216 for (ptr = str; *ptr; ptr++) {
217 /* quote if 1st char is a number */
218 if ((*ptr <= '9') && (*ptr >= '0')) {
219 if (ptr == str)
220 return TRUE;
221 continue;
222 }
223 if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
224 ((*ptr >= 'a') && (*ptr <= 'z')))
225 continue;
226
227 if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
228 return TRUE;
229 }
230 return FALSE;
231 }
232
233 /* Returns: @str */
234 static gchar *
sqlite_remove_quotes(gchar * str)235 sqlite_remove_quotes (gchar *str)
236 {
237 glong total;
238 gchar *ptr;
239 glong offset = 0;
240 char delim;
241
242 if (!str)
243 return NULL;
244 delim = *str;
245 if ((delim != '[') && (delim != '"') && (delim != '\'') && (delim != '`'))
246 return str;
247
248 total = strlen (str);
249 if ((str[total-1] == delim) || ((delim == '[') && (str[total-1] == ']'))) {
250 /* string is correctly terminated */
251 memmove (str, str+1, total-2);
252 total -=2;
253 }
254 else {
255 /* string is _not_ correctly terminated */
256 memmove (str, str+1, total-1);
257 total -=1;
258 }
259 str[total] = 0;
260
261 if ((delim == '"') || (delim == '\'')) {
262 ptr = (gchar *) str;
263 while (offset < total) {
264 /* we accept the "''" as a synonym of "\'" */
265 if (*ptr == delim) {
266 if (*(ptr+1) == delim) {
267 memmove (ptr+1, ptr+2, total - offset);
268 offset += 2;
269 }
270 else {
271 *str = 0;
272 return str;
273 }
274 }
275 else if (*ptr == '"') {
276 if (*(ptr+1) == '"') {
277 memmove (ptr+1, ptr+2, total - offset);
278 offset += 2;
279 }
280 else {
281 *str = 0;
282 return str;
283 }
284 }
285 else if (*ptr == '\\') {
286 if (*(ptr+1) == '\\') {
287 memmove (ptr+1, ptr+2, total - offset);
288 offset += 2;
289 }
290 else {
291 if (*(ptr+1) == delim) {
292 *ptr = delim;
293 memmove (ptr+1, ptr+2, total - offset);
294 offset += 2;
295 }
296 else {
297 *str = 0;
298 return str;
299 }
300 }
301 }
302 else
303 offset ++;
304
305 ptr++;
306 }
307 }
308
309 return str;
310 }
311
312 gchar *
_gda_sqlite_identifier_quote(G_GNUC_UNUSED GdaServerProvider * provider,GdaConnection * cnc,const gchar * id,gboolean for_meta_store,gboolean force_quotes)313 _gda_sqlite_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc,
314 const gchar *id,
315 gboolean for_meta_store, gboolean force_quotes)
316 {
317 GdaSqlReservedKeywordsFunc kwfunc;
318 kwfunc = _gda_sqlite_get_reserved_keyword_func ();
319
320 if (for_meta_store) {
321 gchar *tmp, *ptr;
322 tmp = sqlite_remove_quotes (g_strdup (id));
323 if (kwfunc (tmp)) {
324 ptr = gda_sql_identifier_force_quotes (tmp);
325 g_free (tmp);
326 return ptr;
327 }
328 else {
329 /* if only alphanum => don't quote */
330 for (ptr = tmp; *ptr; ptr++) {
331 if ((*ptr >= 'A') && (*ptr <= 'Z'))
332 *ptr += 'a' - 'A';
333 if (((*ptr >= 'a') && (*ptr <= 'z')) ||
334 ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
335 (*ptr >= '_'))
336 continue;
337 else {
338 ptr = gda_sql_identifier_force_quotes (tmp);
339 g_free (tmp);
340 return ptr;
341 }
342 }
343 return tmp;
344 }
345 }
346 else {
347 if (*id == '"') {
348 /* there are already some quotes */
349 return g_strdup (id);
350 }
351 else if ((*id == '[') || (*id == '`')) {
352 /* there are already some quotes */
353 gchar *tmp, *ptr;
354 tmp = sqlite_remove_quotes (g_strdup (id));
355 ptr = gda_sql_identifier_force_quotes (tmp);
356 g_free (tmp);
357 return ptr;
358 }
359 if (kwfunc (id) || _sql_identifier_needs_quotes (id) || force_quotes)
360 return identifier_add_quotes (id);
361
362 /* nothing to do */
363 return g_strdup (id);
364 }
365 }
366
367 gboolean
_gda_sqlite_check_transaction_started(GdaConnection * cnc,gboolean * out_started,GError ** error)368 _gda_sqlite_check_transaction_started (GdaConnection *cnc, gboolean *out_started, GError **error)
369 {
370 GdaTransactionStatus *trans;
371
372 trans = gda_connection_get_transaction_status (cnc);
373 if (!trans) {
374 if (!gda_connection_begin_transaction (cnc, NULL,
375 GDA_TRANSACTION_ISOLATION_UNKNOWN, error))
376 return FALSE;
377 else
378 *out_started = TRUE;
379 }
380 return TRUE;
381 }
382