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