1 /*
2  * Copyright (C) 2008 - 2011 Murray Cumming <murrayc@murrayc.com>
3  * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org>
4  * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
5  * Copyright (C) 2010 David King <davidk@openismus.com>
6  * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
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 <string.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <glib/gi18n-lib.h>
29 #include <libgda/sql-parser/gda-sql-parser.h>
30 #include <libgda/sql-parser/gda-sql-parser-private.h>
31 #include <libgda/gda-debug-macros.h>
32 #include <libgda/sql-parser/gda-statement-struct-util.h>
33 #include <libgda/sql-parser/token_types.h>
34 #include <libgda/gda-lockable.h>
35 
36 /*
37  * Main static functions
38  */
39 static void gda_sql_parser_class_init (GdaSqlParserClass *klass);
40 static void gda_sql_parser_init (GdaSqlParser *stmt);
41 static void gda_sql_parser_dispose (GObject *object);
42 static void gda_sql_parser_finalize (GObject *object);
43 
44 static void gda_sql_parser_set_property (GObject *object,
45 					guint param_id,
46 					const GValue *value,
47 					GParamSpec *pspec);
48 static void gda_sql_parser_get_property (GObject *object,
49 					guint param_id,
50 					GValue *value,
51 					GParamSpec *pspec);
52 
53 /* GdaLockable interface */
54 static void                 gda_sql_parser_lockable_init (GdaLockableIface *iface);
55 static void                 gda_sql_parser_lock      (GdaLockable *lockable);
56 static gboolean             gda_sql_parser_trylock   (GdaLockable *lockable);
57 static void                 gda_sql_parser_unlock    (GdaLockable *lockable);
58 
59 /* get a pointer to the parents to be able to call their destructor */
60 static GObjectClass  *parent_class = NULL;
61 
62 static void gda_sql_parser_reset (GdaSqlParser *parser);
63 static GValue *tokenizer_get_next_token (GdaSqlParser *parser);
64 
65 static void push_tokenizer_context (GdaSqlParser *parser);
66 static void pop_tokenizer_context (GdaSqlParser *parser);
67 static gint fetch_forward (GdaSqlParser *parser, gint *out_nb_pushed, ...);
68 static void merge_tokenizer_contexts (GdaSqlParser *parser, gint n_contexts);
69 
70 /*
71  * The interface to the LEMON-generated parser
72  */
73 void *priv_gda_sql_delimiterAlloc (void*(*)(size_t));
74 void priv_gda_sql_delimiterFree (void*, void(*)(void*));
75 void priv_gda_sql_delimiterTrace (void*, char *);
76 void priv_gda_sql_delimiter (void*, int, GValue *, GdaSqlParserIface *);
77 
78 void *priv_gda_sql_parserAlloc (void*(*)(size_t));
79 void priv_gda_sql_parserFree (void*, void(*)(void*));
80 void priv_gda_sql_parserTrace (void*, char *);
81 void priv_gda_sql_parser (void*, int, GValue *, GdaSqlParserIface *);
82 
83 
84 /* signals */
85 enum
86 {
87 	CHANGED,
88 	LAST_SIGNAL
89 };
90 
91 /* properties */
92 enum
93 {
94 	PROP_0,
95 	PROP_FLAVOUR,
96 	PROP_MODE,
97 	PROP_LINE_ERROR,
98 	PROP_COL_ERROR
99 #ifdef GDA_DEBUG
100 	,PROP_DEBUG
101 #endif
102 };
103 
104 /* module error */
gda_sql_parser_error_quark(void)105 GQuark gda_sql_parser_error_quark (void)
106 {
107 	static GQuark quark;
108 	if (!quark)
109 		quark = g_quark_from_static_string ("gda_sql_parser_error");
110 	return quark;
111 }
112 
113 
114 GType
gda_sql_parser_get_type(void)115 gda_sql_parser_get_type (void)
116 {
117 	static GType type = 0;
118 
119 	if (G_UNLIKELY (type == 0)) {
120 		static GMutex registering;
121 		static const GTypeInfo info = {
122 			sizeof (GdaSqlParserClass),
123 			(GBaseInitFunc) NULL,
124 			(GBaseFinalizeFunc) NULL,
125 			(GClassInitFunc) gda_sql_parser_class_init,
126 			NULL,
127 			NULL,
128 			sizeof (GdaSqlParser),
129 			0,
130 			(GInstanceInitFunc) gda_sql_parser_init,
131 			0
132 		};
133 
134 		static GInterfaceInfo lockable_info = {
135                         (GInterfaceInitFunc) gda_sql_parser_lockable_init,
136 			NULL,
137                         NULL
138                 };
139 
140 		g_mutex_lock (&registering);
141 		if (type == 0) {
142 			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqlParser", &info, 0);
143 			g_type_add_interface_static (type, GDA_TYPE_LOCKABLE, &lockable_info);
144 		}
145 		g_mutex_unlock (&registering);
146 	}
147 	return type;
148 }
149 
150 static void
gda_sql_parser_class_init(GdaSqlParserClass * klass)151 gda_sql_parser_class_init (GdaSqlParserClass * klass)
152 {
153 	GObjectClass   *object_class = G_OBJECT_CLASS (klass);
154 	parent_class = g_type_class_peek_parent (klass);
155 
156 	object_class->dispose = gda_sql_parser_dispose;
157 	object_class->finalize = gda_sql_parser_finalize;
158 
159 	/* Properties */
160 	object_class->set_property = gda_sql_parser_set_property;
161 	object_class->get_property = gda_sql_parser_get_property;
162 	g_object_class_install_property (object_class, PROP_FLAVOUR,
163 					 g_param_spec_int ("tokenizer-flavour", NULL, NULL,
164 							   GDA_SQL_PARSER_FLAVOUR_STANDARD,
165 							   GDA_SQL_PARSER_FLAVOUR_POSTGRESQL,
166 							   GDA_SQL_PARSER_FLAVOUR_STANDARD,
167 							   G_PARAM_WRITABLE | G_PARAM_READABLE));
168 	g_object_class_install_property (object_class, PROP_MODE,
169 					 g_param_spec_int ("mode", NULL, NULL,
170 							   GDA_SQL_PARSER_MODE_PARSE,
171 							   GDA_SQL_PARSER_MODE_DELIMIT,
172 							   GDA_SQL_PARSER_MODE_PARSE,
173 							   G_PARAM_WRITABLE | G_PARAM_READABLE));
174 	g_object_class_install_property (object_class, PROP_LINE_ERROR,
175 					 g_param_spec_int ("line-error", NULL, NULL,
176 							   0, G_MAXINT, 0,
177 							   G_PARAM_READABLE));
178 	g_object_class_install_property (object_class, PROP_COL_ERROR,
179 					 g_param_spec_int ("column-error", NULL, NULL,
180 							   0, G_MAXINT, 0,
181 							   G_PARAM_READABLE));
182 #ifdef GDA_DEBUG
183 	g_object_class_install_property (object_class, PROP_DEBUG,
184 					 g_param_spec_boolean ("debug", NULL, NULL,
185 							       FALSE,
186 							       G_PARAM_WRITABLE));
187 #endif
188 }
189 
190 static void
gda_sql_parser_lockable_init(GdaLockableIface * iface)191 gda_sql_parser_lockable_init (GdaLockableIface *iface)
192 {
193 	iface->i_lock = gda_sql_parser_lock;
194 	iface->i_trylock = gda_sql_parser_trylock;
195 	iface->i_unlock = gda_sql_parser_unlock;
196 }
197 
198 static void
gda_sql_parser_reset(GdaSqlParser * parser)199 gda_sql_parser_reset (GdaSqlParser *parser)
200 {
201 	g_free (parser->priv->sql);
202 	parser->priv->sql = NULL;
203 	g_array_free (parser->priv->passed_tokens, TRUE);
204 	parser->priv->passed_tokens = g_array_new (FALSE, FALSE, sizeof (gint));
205 
206 	g_free (parser->priv->error_msg);
207 	parser->priv->error_msg = NULL;
208 	parser->priv->error_line = 0;
209 	parser->priv->error_col = 0;
210 	parser->priv->error_pos = 0;
211 
212 	if (parser->priv->parsed_statements) {
213 		g_slist_foreach (parser->priv->parsed_statements, (GFunc) gda_sql_statement_free, NULL);
214 		g_slist_free (parser->priv->parsed_statements);
215 		parser->priv->parsed_statements = NULL;
216 	}
217 
218 	if (parser->priv->pushed_contexts) {
219 		g_slist_foreach (parser->priv->pushed_contexts, (GFunc) g_free, NULL);
220 		g_slist_free (parser->priv->pushed_contexts);
221 		parser->priv->pushed_contexts = NULL;
222 	}
223 
224 	parser->priv->context->next_token_start = NULL;
225 	parser->priv->context->in_param_spec = FALSE;
226 	parser->priv->context->block_level = 0;
227 	parser->priv->context->last_token_start = NULL;
228 }
229 
230 static void
gda_sql_parser_init(GdaSqlParser * parser)231 gda_sql_parser_init (GdaSqlParser *parser)
232 {
233 	GdaSqlParserClass *klass;
234 
235 	klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser);
236 
237 	parser->priv = g_new0 (GdaSqlParserPrivate, 1);
238 	parser->priv->mutex = gda_mutex_new ();
239 	parser->priv->flavour = GDA_SQL_PARSER_FLAVOUR_STANDARD;
240 	if (klass->delim_alloc)
241 		parser->priv->lemon_delimiter = klass->delim_alloc ((void*(*)(size_t)) g_malloc);
242 	else
243 		parser->priv->lemon_delimiter = priv_gda_sql_delimiterAlloc ((void*(*)(size_t)) g_malloc);
244 	if (klass->parser_alloc)
245 		parser->priv->lemon_parser = klass->parser_alloc ((void*(*)(size_t)) g_malloc);
246 	else
247 		parser->priv->lemon_parser = priv_gda_sql_parserAlloc ((void*(*)(size_t)) g_malloc);
248 	parser->priv->mode = GDA_SQL_PARSER_MODE_PARSE;
249 	parser->priv->flavour = GDA_SQL_PARSER_FLAVOUR_STANDARD;
250 
251 	parser->priv->sql = NULL;
252 	parser->priv->passed_tokens = g_array_new (FALSE, FALSE, sizeof (gint));
253 
254 	parser->priv->context = g_new0 (TokenizerContext, 1);
255 	parser->priv->context->delimiter = ';';
256 	parser->priv->context->in_param_spec = FALSE;
257 	parser->priv->context->block_level = 0;
258 	parser->priv->context->next_token_start = NULL;
259 	parser->priv->context->last_token_start = NULL;
260 
261 	parser->priv->error_msg = NULL;
262 	parser->priv->error_line = 0;
263 	parser->priv->error_col = 0;
264 	parser->priv->error_pos = 0;
265 }
266 
267 /**
268  * gda_sql_parser_new:
269  *
270  * Creates a new #GdaSqlParser object
271  *
272  * Returns: the new object
273  */
274 GdaSqlParser*
gda_sql_parser_new(void)275 gda_sql_parser_new (void)
276 {
277 	GObject *obj;
278 
279 	obj = g_object_new (GDA_TYPE_SQL_PARSER, NULL);
280 	return GDA_SQL_PARSER (obj);
281 }
282 
283 static void
gda_sql_parser_dispose(GObject * object)284 gda_sql_parser_dispose (GObject *object)
285 {
286 	GdaSqlParser *parser;
287 
288 	g_return_if_fail (object != NULL);
289 	g_return_if_fail (GDA_IS_SQL_PARSER (object));
290 
291 	parser = GDA_SQL_PARSER (object);
292 	if (parser->priv) {
293 	}
294 
295 	/* parent class */
296 	parent_class->dispose (object);
297 }
298 
299 static void
gda_sql_parser_finalize(GObject * object)300 gda_sql_parser_finalize (GObject *object)
301 {
302 	GdaSqlParser *parser;
303 
304 	g_return_if_fail (object != NULL);
305 	g_return_if_fail (GDA_IS_SQL_PARSER (object));
306 
307 	parser = GDA_SQL_PARSER (object);
308 	if (parser->priv) {
309 		GdaSqlParserClass *klass;
310 
311 		klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser);
312 		gda_sql_parser_reset (parser);
313 		g_free (parser->priv->context);
314 
315 		if (klass->delim_alloc) {
316 			g_assert (klass->delim_free);
317 			klass->delim_free (parser->priv->lemon_delimiter, g_free);
318 		}
319 		else
320 			priv_gda_sql_delimiterFree (parser->priv->lemon_delimiter, g_free);
321 		if (klass->parser_alloc) {
322 			g_assert (klass->parser_free);
323 			klass->parser_free (parser->priv->lemon_parser, g_free);
324 		}
325 		else
326 			priv_gda_sql_parserFree (parser->priv->lemon_parser, g_free);
327 
328 		g_array_free (parser->priv->passed_tokens, TRUE);
329 
330 		gda_mutex_free (parser->priv->mutex);
331 		g_free (parser->priv);
332 		parser->priv = NULL;
333 	}
334 
335 	/* parent class */
336 	parent_class->finalize (object);
337 }
338 
339 
340 static void
gda_sql_parser_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)341 gda_sql_parser_set_property (GObject *object,
342 			     guint param_id,
343 			     const GValue *value,
344 			     GParamSpec *pspec)
345 {
346 	GdaSqlParser *parser;
347 
348 	parser = GDA_SQL_PARSER (object);
349 	if (parser->priv) {
350 		gda_mutex_lock (parser->priv->mutex);
351 		switch (param_id) {
352 		case PROP_FLAVOUR:
353 			parser->priv->flavour = g_value_get_int (value);
354 			break;
355 		case PROP_MODE:
356 			parser->priv->mode = g_value_get_int (value);
357 			break;
358 #ifdef GDA_DEBUG
359 		case PROP_DEBUG: {
360 			gboolean debug = g_value_get_boolean (value);
361 			GdaSqlParserClass *klass;
362 
363 			klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser);
364 			if (klass->delim_alloc) {
365 				g_assert (klass->delim_trace);
366 				klass->delim_trace ((parser->priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) && debug ?
367 						    stdout : NULL, ".......DELIMITER DEBUG:");
368 			}
369 			else
370 				priv_gda_sql_delimiterTrace ((parser->priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) && debug ?
371 							stdout : NULL, ".......DELIMITER DEBUG:");
372 			if (klass->parser_alloc) {
373 				g_assert (klass->parser_trace);
374 				klass->parser_trace ((parser->priv->mode == GDA_SQL_PARSER_MODE_PARSE) && debug ?
375 						     stdout : NULL, ".......PARSE DEBUG:");
376 			}
377 			else
378 				priv_gda_sql_parserTrace ((parser->priv->mode == GDA_SQL_PARSER_MODE_PARSE) && debug ?
379 						     stdout : NULL, ".......PARSE DEBUG:");
380 			break;
381 		}
382 #endif
383 		default:
384 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
385 			break;
386 		}
387 		gda_mutex_unlock (parser->priv->mutex);
388 	}
389 }
390 
391 static void
gda_sql_parser_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)392 gda_sql_parser_get_property (GObject *object,
393 			     guint param_id,
394 			     GValue *value,
395 			     GParamSpec *pspec)
396 {
397 	GdaSqlParser *parser;
398 	parser = GDA_SQL_PARSER (object);
399 
400 	if (parser->priv) {
401 		switch (param_id) {
402 		case PROP_FLAVOUR:
403 			g_value_set_int (value, parser->priv->flavour);
404 			break;
405 		case PROP_MODE:
406 			g_value_set_int (value, parser->priv->mode);
407 			break;
408 		case PROP_LINE_ERROR:
409 			g_value_set_int (value, parser->priv->error_line);
410 			break;
411 		case PROP_COL_ERROR:
412 			g_value_set_int (value, parser->priv->error_col);
413 			break;
414 		default:
415 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
416 			break;
417 		}
418 	}
419 }
420 
421 /**
422  * gda_sql_parser_parse_string:
423  * @parser: a #GdaSqlParser object
424  * @sql: the SQL string to parse
425  * @remain: (out) (allow-none): location to store a pointer to remaining part of @sql in case @sql has multiple statement, or %NULL
426  * @error: location to store error, or %NULL
427  *
428  * Parses @sql and creates a #GdaStatement statement from the first SQL statement contained in @sql: if @sql
429  * contains more than one statement, then the remaining part of the string is not parsed at all, and @remain (if
430  * not %NULL) will point at the first non parsed character.
431  *
432  * To include variables in the @sql string, see the
433  * <link linkend="GdaSqlParser.description">GdaSqlParser's object description</link>.
434  *
435  * Returns: (transfer full) (allow-none): a new #GdaStatement object, or %NULL if an error occurred
436  */
437 GdaStatement *
gda_sql_parser_parse_string(GdaSqlParser * parser,const gchar * sql,const gchar ** remain,GError ** error)438 gda_sql_parser_parse_string (GdaSqlParser *parser, const gchar *sql, const gchar **remain, GError **error)
439 {
440 	GdaStatement *stmt = NULL;
441 	GValue *value;
442 	GdaSqlParserIface piface;
443 	gint ntokens = 0;
444 	GdaSqlParserMode parse_mode;
445 	GdaSqlParserClass *klass;
446 	void (*_delimit) (void*, int, GValue *, GdaSqlParserIface *) = priv_gda_sql_delimiter;
447 	void (*_parse) (void*, int, GValue *, GdaSqlParserIface *) = priv_gda_sql_parser;
448 	gint *delim_trans = delim_tokens;
449 	gint *parser_trans= parser_tokens;
450 
451 	g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL);
452 	g_return_val_if_fail (parser->priv, NULL);
453 
454 	if (!sql)
455 		return NULL;
456 
457 	gda_mutex_lock (parser->priv->mutex);
458 
459 	if (remain)
460 		*remain = NULL;
461 
462 	klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser);
463 	if (klass->delim_alloc) {
464 		g_assert (klass->delim_parse);
465 		_delimit = klass->delim_parse;
466 		g_assert (klass->delim_tokens_trans);
467 		delim_trans = klass->delim_tokens_trans;
468 	}
469 	if (klass->parser_alloc) {
470 		g_assert (klass->parser_parse);
471 		_parse = klass->parser_parse;
472 		g_assert (klass->parser_tokens_trans);
473 		parser_trans = klass->parser_tokens_trans;
474 	}
475 
476 	/* re-init parser */
477 	gda_sql_parser_reset (parser);
478 	parser->priv->sql = g_strdup (sql);
479 	parser->priv->context->next_token_start = parser->priv->sql;
480 
481 	parse_mode = parser->priv->mode; /* save current mode */
482 	/*g_print ("\t\t===== %s MODE =====\n",
483 	  parse_mode == GDA_SQL_PARSER_MODE_PARSE ? "PARSE" : "DELIMIT");*/
484 	piface.parser = parser;
485 	piface.parsed_statement = NULL;
486 
487 	for (value = tokenizer_get_next_token (parser);
488 	     parser->priv->context->token_type != L_ILLEGAL;
489 	     value = tokenizer_get_next_token (parser)) {
490 		switch (parser->priv->context->token_type) {
491 		case L_SQLCOMMENT:
492 			gda_value_free (value);
493 			value = NULL;
494 			break;
495 		case L_SPACE:
496 			if (parser->priv->context->in_param_spec ||
497 			    (parser->priv->mode == GDA_SQL_PARSER_MODE_PARSE)) {
498 				/* ignore space */
499 				gda_value_free (value);
500 				value = NULL;
501 				break;
502 			}
503 		default:
504 			if (parser->priv->mode == GDA_SQL_PARSER_MODE_DELIMIT) {
505 				if ((parser->priv->context->token_type == L_BEGIN) &&
506 				    (parser->priv->passed_tokens->len != 0) &&
507 				    !g_ascii_strcasecmp (g_value_get_string (value), "BEGIN")) {
508 					/* a BEGIN command increments the block level only if it's not the
509 					 * first word of statement */
510 					parser->priv->context->block_level ++;
511 				}
512 				if (parser->priv->context->token_type == L_LOOP) {
513 					parser->priv->context->block_level ++;
514 				}
515 				else if ((parser->priv->context->token_type == L_END) &&
516 					 (parser->priv->passed_tokens->len != 0)) {
517 					/* a END command decrements the block level only if it's not the
518 					 * first word of statement */
519 					parser->priv->context->block_level --;
520 					if (parser->priv->context->block_level == 0)
521 						parser->priv->context->ignore_semi = FALSE;
522 				}
523 				else if (parser->priv->context->token_type == L_ENDLOOP) {
524 					parser->priv->context->block_level --;
525 				}
526 				else if (parser->priv->context->token_type == L_DECLARE)
527 					parser->priv->context->ignore_semi = TRUE;
528 				else if ((parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_ORACLE) &&
529 					 ((parser->priv->context->token_type == L_AS) ||
530 					  (parser->priv->context->token_type == L_IS))) {
531 					/* examine tokens history to see if we have somewhere a CREATE FUNCTION or
532 					 * CREATE PROCEDURE */
533 					gint i;
534 					for (i = parser->priv->passed_tokens->len - 1; i >= 0; i --) {
535 						gint ttype;
536 						ttype = g_array_index (parser->priv->passed_tokens, gint, i);
537 						if (ttype == L_CREATE)
538 							break;
539 					}
540 					if (i >= 0)
541 						parser->priv->context->ignore_semi = TRUE;
542 				}
543 				else if ((parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_MYSQL) &&
544 					 (parser->priv->context->token_type == L_DELIMITER)) {
545 					GValue *v;
546 					push_tokenizer_context (parser);
547 					v = tokenizer_get_next_token (parser);
548 					if (parser->priv->context->token_type == L_SPACE) {
549 						push_tokenizer_context (parser);
550 						g_value_reset (v);
551 						g_free (v);
552 						v = tokenizer_get_next_token (parser);
553 						pop_tokenizer_context (parser);
554 					}
555 					pop_tokenizer_context (parser);
556 					if (v) {
557 						if (G_VALUE_TYPE (v) == G_TYPE_STRING) {
558 							const gchar *str;
559 							str = g_value_get_string (v);
560 							if (str)
561 								parser->priv->context->delimiter = *str;
562 						}
563 						else
564 							TO_IMPLEMENT;
565 						g_value_reset (v);
566 						g_free (v);
567 					}
568 				}
569 			}
570 
571 			/* send found tokens until end of buffer */
572 			g_array_append_val (parser->priv->passed_tokens, parser->priv->context->token_type);
573 
574 			switch (parser->priv->mode) {
575 			case GDA_SQL_PARSER_MODE_PARSE:
576 				/*g_print ("TRANS %d => %d\n", parser->priv->context->token_type,
577 				  parser_trans [parser->priv->context->token_type]);*/
578 				_parse (parser->priv->lemon_parser,
579 					parser_trans [parser->priv->context->token_type], value, &piface);
580 				value = NULL;
581 				break;
582 			case GDA_SQL_PARSER_MODE_DELIMIT:
583 				_delimit (parser->priv->lemon_delimiter,
584 					  delim_trans [parser->priv->context->token_type], value, &piface);
585 				value = NULL;
586 				break;
587 			default:
588 				TO_IMPLEMENT;
589 			}
590 
591 			ntokens++;
592 			break;
593 		}
594 		if ((parser->priv->context->token_type == L_END_OF_FILE) || (parser->priv->context->token_type == L_SEMI)) {
595 			/* end of statement */
596 			break;
597 		}
598 		if (parser->priv->error_pos != 0)
599 			break;
600 	}
601 	if (parser->priv->context->token_type == L_ILLEGAL) {
602 		if (value)
603 			gda_value_free (value);
604 		gda_sql_parser_set_syntax_error (parser);
605 	}
606 
607 	/* send the EOF token to the LEMON parser */
608 	switch (parser->priv->mode) {
609 	case GDA_SQL_PARSER_MODE_PARSE:
610 		_parse (parser->priv->lemon_parser, 0, NULL, &piface);
611 		break;
612 	case GDA_SQL_PARSER_MODE_DELIMIT:
613 		_delimit (parser->priv->lemon_delimiter, 0, NULL, &piface);
614 		break;
615 	default:
616 		TO_IMPLEMENT;
617 	}
618 	if (remain) {
619 		if (* parser->priv->context->next_token_start) {
620 			gint i = parser->priv->context->next_token_start - parser->priv->sql;
621 			*remain = sql + i;
622 			while (**remain == ' ' || **remain == '\n') {
623 				*remain = sql + (++i);
624 			}
625 		}
626 	}
627 
628 	if (piface.parsed_statement) {
629 		gchar hold;
630 
631 		hold = *parser->priv->context->next_token_start;
632 		*parser->priv->context->next_token_start = 0;
633 		piface.parsed_statement->sql = g_strdup (parser->priv->sql);
634 		*parser->priv->context->next_token_start = hold;
635 
636 		stmt = g_object_new (GDA_TYPE_STATEMENT,
637 				     "structure", piface.parsed_statement, NULL);
638 		gda_sql_statement_free (piface.parsed_statement);
639 	}
640 	else {
641 		if (parser->priv->mode == GDA_SQL_PARSER_MODE_PARSE) {
642 			/* try to create a statement using the delimiter mode */
643 			parser->priv->mode = GDA_SQL_PARSER_MODE_DELIMIT;
644 			stmt = gda_sql_parser_parse_string (parser, sql, remain, error);
645 		}
646 		else if (error) {
647 			if ((ntokens <= 1) && (parser->priv->context->token_type != L_ILLEGAL))
648 				g_set_error (error, GDA_SQL_PARSER_ERROR, GDA_SQL_PARSER_EMPTY_SQL_ERROR,
649 					 "%s", _("SQL code does not contain any statement"));
650 			else
651 				g_set_error (error, GDA_SQL_PARSER_ERROR, parser->priv->error_type,
652 					 "%s", parser->priv->error_msg);
653 		}
654 	}
655 
656 	parser->priv->mode = parse_mode;
657 
658 	gda_mutex_unlock (parser->priv->mutex);
659 
660 	return stmt;
661 }
662 
663 /**
664  * gda_sql_parser_parse_string_as_batch:
665  * @parser: a #GdaSqlParser object
666  * @sql: the SQL string to parse
667  * @remain: (out) (allow-none): location to store a pointer to remaining part of @sql in case an error occurred while parsing @sql, or %NULL
668  * @error: location to store error, or %NULL
669  *
670  * Parse @sql and creates a #GdaBatch object which contains all the #GdaStatement objects created while parsing (one object
671  * per SQL statement). Empty statements (composed of spaces only) do not appear in the resulting object.
672  *
673  * @sql is parsed and #GdaStatement objects are created as long as no error is found in @sql. If an error is found
674  * at some point, then the parsing stops and @remain may contain a non %NULL pointer, @error may be set, and %NULL
675  * is returned.
676  *
677  * if @sql is %NULL, then the returned #GdaBatch object will contain no statement.
678  *
679  * To include variables in the @sql string, see the
680  * <link linkend="GdaSqlParser.description">GdaSqlParser's object description</link>.
681  *
682  * Returns: (transfer full) (allow-none): a new #GdaBatch object, or %NULL if an error occurred
683  */
684 GdaBatch *
gda_sql_parser_parse_string_as_batch(GdaSqlParser * parser,const gchar * sql,const gchar ** remain,GError ** error)685 gda_sql_parser_parse_string_as_batch (GdaSqlParser *parser, const gchar *sql, const gchar **remain,
686 				      GError **error)
687 {
688 	GdaBatch *batch;
689 	GdaStatement *stmt;
690 	const gchar *int_sql;
691 	gboolean allok = TRUE;
692 	gint n_stmt = 0;
693 	gint n_empty = 0;
694 
695 	g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL);
696 	g_return_val_if_fail (parser->priv, NULL);
697 
698 	if (remain)
699 		*remain = NULL;
700 
701 	batch = gda_batch_new ();
702 	if (!sql)
703 		return batch;
704 
705 	gda_mutex_lock (parser->priv->mutex);
706 
707 	int_sql = sql;
708 	while (int_sql && allok) {
709 		GError *lerror = NULL;
710 		const gchar *int_remain = NULL;
711 
712 		stmt = gda_sql_parser_parse_string (parser, int_sql, &int_remain, &lerror);
713 		if (stmt) {
714 			if (gda_statement_is_useless (stmt))
715 				n_empty++;
716 			else {
717 				gda_batch_add_statement (batch, stmt);
718 				n_stmt++;
719 			}
720 			g_object_unref (stmt);
721 		}
722 		else if (lerror && (lerror->domain == GDA_SQL_PARSER_ERROR) &&
723 			 (lerror->code == GDA_SQL_PARSER_EMPTY_SQL_ERROR))
724 			n_empty++;
725 		else {
726 			if (int_remain)
727 				allok = FALSE;
728 			if (lerror) {
729 				g_propagate_error (error, lerror);
730 				lerror = NULL;
731 			}
732 		}
733 		if (lerror)
734 			g_error_free (lerror);
735 		int_sql = int_remain;
736 	}
737 
738 	if ((n_stmt == 0) && (n_empty != 0))
739 		g_set_error (error, GDA_SQL_PARSER_ERROR, GDA_SQL_PARSER_EMPTY_SQL_ERROR,
740 			      "%s", _("SQL code does not contain any statement"));
741 
742 	if (!allok || (n_stmt == 0)) {
743 		if (remain)
744 			*remain = int_sql;
745 		g_object_unref (batch);
746 		batch = NULL;
747 	}
748 
749 	gda_mutex_unlock (parser->priv->mutex);
750 
751 	return batch;
752 }
753 
754 /**
755  * gda_sql_parser_parse_file_as_batch:
756  * @parser: a #GdaSqlParser object
757  * @filename: name of the file to parse
758  * @error: location to store error, or %NULL
759  *
760  * Parse @filename's contents and creates a #GdaBatch object which contains all the
761  *  #GdaStatement objects created while parsing (one object per SQL statement).
762  *
763  * @filename's contents are parsed and #GdaStatement objects are created as long as no error is found. If an error is found
764  * at some point, then the parsing stops, @error may be set and %NULL is returned
765  *
766  * if @sql is %NULL, then the returned #GdaBatch object will contain no statement.
767  *
768  * Returns: (transfer full) (allow-none): a new #GdaBatch object, or %NULL if an error occurred
769  */
770 GdaBatch *
gda_sql_parser_parse_file_as_batch(GdaSqlParser * parser,const gchar * filename,GError ** error)771 gda_sql_parser_parse_file_as_batch (GdaSqlParser *parser, const gchar *filename, GError **error)
772 {
773 	gchar *contents;
774 
775 	g_return_val_if_fail (GDA_IS_SQL_PARSER (parser), NULL);
776 	g_return_val_if_fail (parser->priv, NULL);
777 	g_return_val_if_fail (filename, NULL);
778 
779 	if (!g_file_get_contents (filename, &contents, NULL, error))
780 		return NULL;
781 	else {
782 		GdaBatch *batch;
783 		batch = gda_sql_parser_parse_string_as_batch (parser, contents, NULL, error);
784 		g_free (contents);
785 		return batch;
786 	}
787 }
788 
789 
790 /*
791  *
792  * Private API
793  *
794  */
795 static gint
get_position(GdaSqlParser * parser)796 get_position (GdaSqlParser *parser)
797 {
798 	gint total;
799 	gchar *z = parser->priv->sql;
800 	gint i, l, c;
801 
802 	total = parser->priv->context->last_token_start - parser->priv->sql;
803 	for (i = 0, l = 0, c = 0; i < total; i++) {
804 		if (z[i] == '\n') {
805 			l++;
806 			c = 0;
807 		}
808 		else
809 			c++;
810 	}
811 	parser->priv->error_line = l + 1;
812 	parser->priv->error_col = c + 1;
813 
814 	return total + 1;
815 }
816 
817 void
gda_sql_parser_set_syntax_error(GdaSqlParser * parser)818 gda_sql_parser_set_syntax_error (GdaSqlParser *parser)
819 {
820 	if (!parser->priv->error_msg) {
821 		parser->priv->error_type = GDA_SQL_PARSER_SYNTAX_ERROR;
822 		parser->priv->error_pos = get_position (parser);
823 		parser->priv->error_msg = g_strdup_printf (_("Syntax error at line %d, column %d"),
824 							   parser->priv->error_line, parser->priv->error_col);
825 		/*g_print ("@syntax error at line %d, col %d\n",
826 		  parser->priv->error_line, parser->priv->error_col);*/
827 	}
828 }
829 
830 void
gda_sql_parser_set_overflow_error(GdaSqlParser * parser)831 gda_sql_parser_set_overflow_error (GdaSqlParser *parser)
832 {
833 	if (!parser->priv->error_msg) {
834 		parser->priv->error_type = GDA_SQL_PARSER_OVERFLOW_ERROR;
835 		parser->priv->error_pos = get_position (parser);
836 		parser->priv->error_msg = g_strdup_printf (_("Overflow error at line %d, column %d"),
837 							   parser->priv->error_line, parser->priv->error_col);
838 		/*g_print ("@overflow error at line %d, col %d\n",
839 		  parser->priv->error_line, parser->priv->error_col);*/
840 	}
841 }
842 
843 
844 
845 /*
846  *
847  * Tokenizer
848  *
849  */
850 /*
851 ** If X is a character that can be used in an identifier then
852 ** IdChar(X) will be true.  Otherwise it is false.
853 **
854 ** For ASCII, any character with the high-order bit set is
855 ** allowed in an identifier.  For 7-bit characters,
856 ** sqlite3IsIdChar[X] must be 1.
857 */
858 static const char AsciiIdChar[] = {
859      /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
860 	0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 2x */
861 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 3x */
862 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 4x */
863 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 5x */
864 	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 6x */
865 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 7x */
866 };
867 #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20]))
868 
869 static const unsigned char UpperToLower[] = {
870       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
871      18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
872      36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
873      54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
874     104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
875     122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
876     108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
877     126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
878     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
879     162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
880     180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
881     198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
882     216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
883     234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
884     252,253,254,255
885 };
886 
887 static gboolean
str_caseequal(gconstpointer v1,gconstpointer v2)888 str_caseequal (gconstpointer v1, gconstpointer v2)
889 {
890 	const gchar *string1 = v1;
891 	const gchar *string2 = v2;
892 
893 	return strcasecmp (string1, string2) == 0;
894 }
895 
896 static guint
str_casehash(gconstpointer v)897 str_casehash (gconstpointer v)
898 {
899 	/* 31 bit hash function */
900 	const signed char *p = v;
901 	guint32 h = UpperToLower[*p];
902 
903 	if (h)
904 		for (p += 1; *p != '\0'; p++)
905 			h = (h << 5) - h + UpperToLower[*p];
906 
907 	return h;
908 }
909 
910 static gint
keywordCode(GdaSqlParser * parser,gchar * str,gint len)911 keywordCode (GdaSqlParser *parser, gchar *str, gint len)
912 {
913 	static GMutex mutex;
914 	static GHashTable *keywords = NULL;
915 	gint type;
916 	gchar oldc;
917 
918 	g_mutex_lock (&mutex);
919 	if (!keywords) {
920 		/* if keyword begins with a number, it is the GdaSqlParserFlavour to which it only applies:
921 		* for example "4start" would refer to the START keyword for PostgreSQL only */
922 		keywords = g_hash_table_new (str_casehash, str_caseequal);
923 		g_hash_table_insert (keywords, "all", GINT_TO_POINTER (L_ALL));
924 		g_hash_table_insert (keywords, "and", GINT_TO_POINTER (L_AND));
925 		g_hash_table_insert (keywords, "as", GINT_TO_POINTER (L_AS));
926 		g_hash_table_insert (keywords, "asc", GINT_TO_POINTER (L_ASC));
927 		g_hash_table_insert (keywords, "3batch", GINT_TO_POINTER (L_BATCH));
928 		g_hash_table_insert (keywords, "begin", GINT_TO_POINTER (L_BEGIN));
929 		g_hash_table_insert (keywords, "between", GINT_TO_POINTER (L_BETWEEN));
930 		g_hash_table_insert (keywords, "by", GINT_TO_POINTER (L_BY));
931 		g_hash_table_insert (keywords, "case", GINT_TO_POINTER (L_CASE));
932 		g_hash_table_insert (keywords, "cast", GINT_TO_POINTER (L_CAST));
933 		g_hash_table_insert (keywords, "comment", GINT_TO_POINTER (L_COMMENT));
934 		g_hash_table_insert (keywords, "commit", GINT_TO_POINTER (L_COMMIT));
935 		g_hash_table_insert (keywords, "committed", GINT_TO_POINTER (L_COMMITTED));
936 		g_hash_table_insert (keywords, "create", GINT_TO_POINTER (L_CREATE));
937 		g_hash_table_insert (keywords, "cross", GINT_TO_POINTER (L_CROSS));
938 		g_hash_table_insert (keywords, "declare", GINT_TO_POINTER (L_DECLARE));
939 		g_hash_table_insert (keywords, "delete", GINT_TO_POINTER (L_DELETE));
940 		g_hash_table_insert (keywords, "deferred", GINT_TO_POINTER (L_DEFERRED));
941 		g_hash_table_insert (keywords, "delimiter", GINT_TO_POINTER (L_DELIMITER));
942 		g_hash_table_insert (keywords, "desc", GINT_TO_POINTER (L_DESC));
943 		g_hash_table_insert (keywords, "distinct", GINT_TO_POINTER (L_DISTINCT));
944 		g_hash_table_insert (keywords, "else", GINT_TO_POINTER (L_ELSE));
945 		g_hash_table_insert (keywords, "end", GINT_TO_POINTER (L_END));
946 		g_hash_table_insert (keywords, "except", GINT_TO_POINTER (L_EXCEPT));
947 		g_hash_table_insert (keywords, "exclusive", GINT_TO_POINTER (L_EXCLUSIVE));
948 		g_hash_table_insert (keywords, "3force", GINT_TO_POINTER (L_FORCE));
949 		g_hash_table_insert (keywords, "from", GINT_TO_POINTER (L_FROM));
950 		g_hash_table_insert (keywords, "full", GINT_TO_POINTER (L_FULL));
951 		g_hash_table_insert (keywords, "group", GINT_TO_POINTER (L_GROUP));
952 		g_hash_table_insert (keywords, "having", GINT_TO_POINTER (L_HAVING));
953 		g_hash_table_insert (keywords, "ilike", GINT_TO_POINTER (L_ILIKE));
954 		g_hash_table_insert (keywords, "immediate", GINT_TO_POINTER (L_IMMEDIATE));
955 		g_hash_table_insert (keywords, "in", GINT_TO_POINTER (L_IN));
956 		g_hash_table_insert (keywords, "inner", GINT_TO_POINTER (L_INNER));
957 		g_hash_table_insert (keywords, "insert", GINT_TO_POINTER (L_INSERT));
958 		g_hash_table_insert (keywords, "intersect", GINT_TO_POINTER (L_INTERSECT));
959 		g_hash_table_insert (keywords, "into", GINT_TO_POINTER (L_INTO));
960 		g_hash_table_insert (keywords, "is", GINT_TO_POINTER (L_IS));
961 		g_hash_table_insert (keywords, "isolation", GINT_TO_POINTER (L_ISOLATION));
962 		g_hash_table_insert (keywords, "join", GINT_TO_POINTER (L_JOIN));
963 		g_hash_table_insert (keywords, "left", GINT_TO_POINTER (L_LEFT));
964 		g_hash_table_insert (keywords, "level", GINT_TO_POINTER (L_LEVEL));
965 		g_hash_table_insert (keywords, "like", GINT_TO_POINTER (L_LIKE));
966 		g_hash_table_insert (keywords, "limit", GINT_TO_POINTER (L_LIMIT));
967 		g_hash_table_insert (keywords, "loop", GINT_TO_POINTER (L_LOOP));
968 		g_hash_table_insert (keywords, "natural", GINT_TO_POINTER (L_NATURAL));
969 		g_hash_table_insert (keywords, "not", GINT_TO_POINTER (L_NOT));
970 		g_hash_table_insert (keywords, "3nowait", GINT_TO_POINTER (L_NOWAIT));
971 		g_hash_table_insert (keywords, "null", GINT_TO_POINTER (L_NULL));
972 		g_hash_table_insert (keywords, "offset", GINT_TO_POINTER (L_OFFSET));
973 		g_hash_table_insert (keywords, "on", GINT_TO_POINTER (L_ON));
974 		g_hash_table_insert (keywords, "only", GINT_TO_POINTER (L_ONLY));
975 		g_hash_table_insert (keywords, "or", GINT_TO_POINTER (L_OR));
976 		g_hash_table_insert (keywords, "order", GINT_TO_POINTER (L_ORDER));
977 		g_hash_table_insert (keywords, "outer", GINT_TO_POINTER (L_OUTER));
978 		g_hash_table_insert (keywords, "right", GINT_TO_POINTER (L_RIGHT));
979 		g_hash_table_insert (keywords, "read", GINT_TO_POINTER (L_READ));
980 		g_hash_table_insert (keywords, "release", GINT_TO_POINTER (L_RELEASE));
981 		g_hash_table_insert (keywords, "repeatable", GINT_TO_POINTER (L_REPEATABLE));
982 		g_hash_table_insert (keywords, "rollback", GINT_TO_POINTER (L_ROLLBACK));
983 		g_hash_table_insert (keywords, "savepoint", GINT_TO_POINTER (L_SAVEPOINT));
984 		g_hash_table_insert (keywords, "select", GINT_TO_POINTER (L_SELECT));
985 		g_hash_table_insert (keywords, "serializable", GINT_TO_POINTER (L_SERIALIZABLE));
986 		g_hash_table_insert (keywords, "set", GINT_TO_POINTER (L_SET));
987 		g_hash_table_insert (keywords, "similar", GINT_TO_POINTER (L_SIMILAR));
988 		g_hash_table_insert (keywords, "start", GINT_TO_POINTER (L_BEGIN));
989 		g_hash_table_insert (keywords, "then", GINT_TO_POINTER (L_THEN));
990 		g_hash_table_insert (keywords, "to", GINT_TO_POINTER (L_TO));
991 		g_hash_table_insert (keywords, "transaction", GINT_TO_POINTER (L_TRANSACTION));
992 		g_hash_table_insert (keywords, "uncommitted", GINT_TO_POINTER (L_UNCOMMITTED));
993 		g_hash_table_insert (keywords, "union", GINT_TO_POINTER (L_UNION));
994 		g_hash_table_insert (keywords, "update", GINT_TO_POINTER (L_UPDATE));
995 		g_hash_table_insert (keywords, "using", GINT_TO_POINTER (L_USING));
996 		g_hash_table_insert (keywords, "values", GINT_TO_POINTER (L_VALUES));
997 		g_hash_table_insert (keywords, "3wait", GINT_TO_POINTER (L_WAIT));
998 		g_hash_table_insert (keywords, "when", GINT_TO_POINTER (L_WHEN));
999 		g_hash_table_insert (keywords, "where", GINT_TO_POINTER (L_WHERE));
1000 		g_hash_table_insert (keywords, "work", GINT_TO_POINTER (L_TRANSACTION));
1001 		g_hash_table_insert (keywords, "write", GINT_TO_POINTER (L_WRITE));
1002 	}
1003 	g_mutex_unlock (&mutex);
1004 
1005 	oldc = str[len];
1006 	str[len] = 0;
1007 	type = GPOINTER_TO_INT (g_hash_table_lookup (keywords, str));
1008 	if (type == 0) {
1009 		/* try prepending the current flavour */
1010 		gchar *tmp;
1011 		tmp = g_strdup_printf ("%d%s", parser->priv->flavour, str);
1012 		type = GPOINTER_TO_INT (g_hash_table_lookup (keywords, tmp));
1013 		g_free (tmp);
1014 		if (type == 0) {
1015 			if (parser->priv->mode == GDA_SQL_PARSER_MODE_PARSE)
1016 				type = L_ID;
1017 			else
1018 				type = L_RAWSTRING;
1019 		}
1020 	}
1021 	/*g_print ("Looking for /%s/ -> %d\n", str, type);*/
1022 	str[len] = oldc;
1023 
1024 	return type;
1025 }
1026 
1027 static GValue *
token_as_string(gchar * ptr,gint len)1028 token_as_string (gchar *ptr, gint len)
1029 {
1030 	gchar *end, oldc;
1031 	GValue *retval;
1032 
1033 	end = ptr + len;
1034 	oldc = *end;
1035 	*end = 0;
1036 
1037 	retval = g_new0 (GValue, 1);
1038 	g_value_init (retval, G_TYPE_STRING);
1039 	g_value_set_string (retval, ptr);
1040 
1041 	*end = oldc;
1042 
1043 	return retval;
1044 }
1045 
1046 static gboolean
1047 handle_composed_2_keywords (GdaSqlParser *parser, GValue *retval, gint second, gint replacer);
1048 
1049 /*
1050  *
1051  * Returns: the token Id, or:
1052  *   L_ILLEGAL if an error occurred
1053  *   L_END_OF_FILE if nothing more to analyze
1054  */
1055 static GValue *
getToken(GdaSqlParser * parser)1056 getToken (GdaSqlParser *parser)
1057 {
1058 	int i, c;
1059 	gchar *z = parser->priv->context->next_token_start;
1060 	GValue *retval = NULL;
1061 	gint consumed_chars = 1;
1062 
1063 	/* init to capture non treaded cases */
1064 	parser->priv->context->token_type = G_MININT;
1065 
1066 	if (!*z) {
1067 		parser->priv->context->token_type = L_END_OF_FILE;
1068 		consumed_chars = 0;
1069 		goto tok_end;
1070 	}
1071 
1072 #ifdef GDA_DEBUG_NO
1073 	gchar debug_hold = 0;
1074 	gboolean debugcut = FALSE;
1075 	if (strlen (z) > 50) {
1076 		debugcut = TRUE;
1077 		debug_hold = z[50];
1078 		z[50] = 0;
1079 	}
1080 
1081 	g_print ("TOK for `%s` (delim='%c') is: ", z, parser->priv->context->delimiter);
1082 	if (debugcut)
1083 		z[50] = debug_hold;
1084 #endif
1085 
1086 	if (*z == parser->priv->context->delimiter) {
1087 		if (!parser->priv->context->ignore_semi && (parser->priv->context->block_level == 0))
1088 			parser->priv->context->token_type = L_SEMI;
1089 		else
1090 			parser->priv->context->token_type = L_RAWSTRING;
1091 		consumed_chars = 1;
1092 		retval = token_as_string (parser->priv->context->next_token_start, 1);
1093 		goto tok_end;
1094 	}
1095 
1096 	switch (*z) {
1097 	case ' ': case '\t': case '\n': case '\f': case '\r': {
1098 		for (i=1; isspace (z[i]); i++){}
1099 		if ((z[i] == '/') && (z[i+1] == '*')) {
1100 			parser->priv->context->token_type = L_LSBRACKET;
1101 			consumed_chars = i + 2;
1102 			parser->priv->context->in_param_spec = TRUE;
1103 		}
1104 		else {
1105 			parser->priv->context->token_type = L_SPACE;
1106 			consumed_chars = i;
1107 		}
1108 		break;
1109 	}
1110 	case '-':
1111 		if ( z[1]=='-' ){
1112 			for (i=2;  (c=z[i])!=0 && c!='\n'; i++){}
1113 			parser->priv->context->token_type = L_SQLCOMMENT;
1114 			consumed_chars = i;
1115 		}
1116 		else {
1117 			parser->priv->context->token_type = L_MINUS;
1118 			consumed_chars = 1;
1119 		}
1120 		break;
1121 
1122 	case '(':
1123 		parser->priv->context->token_type = L_LP;
1124 		consumed_chars = 1;
1125 		break;
1126 	case ')':
1127 		parser->priv->context->token_type = L_RP;
1128 		consumed_chars = 1;
1129 		break;
1130 	case '+':
1131 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1132 			parser->priv->context->token_type = L_PLUS;
1133 			consumed_chars = 1;
1134 		}
1135 		break;
1136 	case '*':
1137 		if (z[1] == '/') {
1138 			parser->priv->context->token_type = L_RSBRACKET;
1139 			consumed_chars = 2;
1140 			parser->priv->context->in_param_spec = FALSE;
1141 		}
1142 		else {
1143 			parser->priv->context->token_type = L_STAR;
1144 			consumed_chars = 1;
1145 		}
1146 		break;
1147 	case '%':
1148 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1149 			parser->priv->context->token_type = L_REM;
1150 			consumed_chars = 1;
1151 		}
1152 		break;
1153 	case '/':
1154 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1155 			if (z[1] != '*' || z[2] == 0) {
1156 				parser->priv->context->token_type = L_SLASH;
1157 				consumed_chars = 1;
1158 			}
1159 		}
1160 		else if (z[1] == '*') {
1161 			/* delimit mode */
1162 			parser->priv->context->token_type = L_LSBRACKET;
1163 			consumed_chars = 2;
1164 			parser->priv->context->in_param_spec = TRUE;
1165 		}
1166 		break;
1167 	case '=':
1168 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1169 			parser->priv->context->token_type = L_EQ;
1170 			consumed_chars = 1 + (z[1] == '=');
1171 		}
1172 		break;
1173 	case '<':
1174 		if ((c = z[1]) == '=') {
1175 			parser->priv->context->token_type = L_LEQ;
1176 			consumed_chars = 2;
1177 		}
1178 		else if (c == '>') {
1179 			parser->priv->context->token_type = L_DIFF;
1180 			consumed_chars = 2;
1181 		}
1182 		else if (c== '<') {
1183 			parser->priv->context->token_type = L_LSHIFT;
1184 			consumed_chars = 2;
1185 		}
1186 		else {
1187 			parser->priv->context->token_type = L_LT;
1188 			consumed_chars = 1;
1189 		}
1190 		break;
1191 	case '>':
1192 		if ((c = z[1]) == '=') {
1193 			parser->priv->context->token_type = L_GEQ;
1194 			consumed_chars = 2;
1195 		}
1196 		else if (c == '>') {
1197 			parser->priv->context->token_type = L_RSHIFT;
1198 			consumed_chars = 2;
1199 		}
1200 		else {
1201 			parser->priv->context->token_type = L_GT;
1202 			consumed_chars = 1;
1203 		}
1204 		break;
1205 	case '!':
1206 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1207 			if ((c = z[1]) == '=') {
1208 				parser->priv->context->token_type = L_DIFF;
1209 				consumed_chars = 2;
1210 			}
1211 			else if (c == '~') {
1212 				if (z[2] == '*') {
1213 					parser->priv->context->token_type = L_NOT_REGEXP_CI;
1214 					consumed_chars = 3;
1215 				}
1216 				else {
1217 					parser->priv->context->token_type = L_NOT_REGEXP;
1218 					consumed_chars = 2;
1219 				}
1220 			}
1221 		}
1222 		break;
1223 	case '|':
1224 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1225 			if (z[1] != '|') {
1226 				parser->priv->context->token_type = L_BITOR;
1227 				consumed_chars = 1;
1228 			} else {
1229 				parser->priv->context->token_type = L_CONCAT;
1230 				consumed_chars = 2;
1231 			}
1232 		}
1233 		else {
1234 			parser->priv->context->token_type = L_RAWSTRING;
1235 			consumed_chars = 1;
1236 		}
1237 		break;
1238 	case ',':
1239 		parser->priv->context->token_type = L_COMMA;
1240 		consumed_chars = 1;
1241 		break;
1242 	case '&':
1243 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1244 			parser->priv->context->token_type = L_BITAND;
1245 			consumed_chars = 1;
1246 		}
1247 		break;
1248 	case '~':
1249 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1250 			if (z[1] == '*') {
1251 				parser->priv->context->token_type = L_REGEXP_CI;
1252 				consumed_chars = 2;
1253 			}
1254 			else {
1255 				if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_POSTGRESQL)
1256 					parser->priv->context->token_type = L_REGEXP;
1257 				else
1258 					parser->priv->context->token_type = L_BITNOT;
1259 				consumed_chars = 1;
1260 			}
1261 		}
1262 		break;
1263 	case '\'':
1264 	case '"': {
1265 		char delim = z[0];
1266 		for (i = 1; (c = z[i]) != 0; i++) {
1267 			if (c == delim) {
1268 				if (z[i+1] == delim)
1269 					i++;
1270 				else
1271 					break;
1272 			}
1273 			else if (c == '\\')
1274 				i++;
1275 		}
1276 		if (c) {
1277 			if (delim == '"')
1278 				parser->priv->context->token_type = L_TEXTUAL;
1279 			else
1280 				parser->priv->context->token_type = L_STRING;
1281 			consumed_chars = i+1;
1282 		}
1283 		else {
1284 			parser->priv->context->token_type = L_ILLEGAL;
1285 			consumed_chars = 0;
1286 		}
1287 		break;
1288 	}
1289 	case '.':
1290 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1291 			if (! isdigit (z[1])) {
1292 				parser->priv->context->token_type = L_DOT;
1293 				consumed_chars = 1;
1294 				break;
1295 			}
1296 			/* If the next character is a digit, this is a floating point
1297 			** number that begins with ".".  Fall thru into the next case */
1298 		}
1299 	case '0': case '1': case '2': case '3': case '4':
1300 	case '5': case '6': case '7': case '8': case '9': {
1301 		parser->priv->context->token_type = L_INTEGER;
1302 		if ((z[0] == '0') && ((z[1] == 'x') || (z[1] == 'X')) && (z[2] != 0)) {
1303 			/* hexadecimal */
1304 			for (i=2; isxdigit (z[i]); i++){}
1305 		}
1306 		else {
1307 			for (i=0; isdigit (z[i]); i++){}
1308 			if (z[i] == '.') {
1309 				i++;
1310 				while (isdigit (z[i])) {i++;}
1311 				parser->priv->context->token_type = L_FLOAT;
1312 			}
1313 			if ((z[i]=='e' || z[i]=='E') &&
1314 			    (isdigit (z[i+1]) ||
1315 			     ((z[i+1]=='+' || z[i+1]=='-') && isdigit (z[i+2])))) {
1316 				i += 2;
1317 				while (isdigit (z[i])) {i++;}
1318 				parser->priv->context->token_type = L_FLOAT;
1319 			}
1320 		}
1321 		if (parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) {
1322 			while (IdChar (z[i])) {
1323 				parser->priv->context->token_type = L_ILLEGAL;
1324 				i++;
1325 			}
1326 		}
1327 		else {
1328 			while (IdChar (z[i])) {
1329 				parser->priv->context->token_type = L_RAWSTRING;
1330 				i++;
1331 			}
1332 		}
1333 		consumed_chars = i;
1334 		break;
1335 	}
1336 	case '?':
1337 		if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) {
1338 			for(i=1; isdigit(z[i]); i++){}
1339 			parser->priv->context->token_type = L_SIMPLEPARAM;
1340 			retval = token_as_string (parser->priv->context->next_token_start + 1, i - 1);
1341 			consumed_chars = i;
1342 		}
1343 		break;
1344 	case '#': {
1345 		if (z[1] == '#') {
1346 			/* parameter */
1347 			for (i=2; (z[i]) &&
1348 				     (IdChar (z[i]) || (z[i] == '+') || (z[i] == '-') || (z[i] == '.') || (z[i] == ':') ||
1349 				      (z[i] == '|') || (z[i] == '@') || (z[i] == '?')) &&
1350 				     (z[i] != '/') && (z[i] != parser->priv->context->delimiter)
1351 				     /*(!isspace (z[i])) && (z[i] != '/') &&
1352 				       (z[i] != parser->priv->context->delimiter)*/; i++) {}
1353 			if (i > 2) {
1354 				parser->priv->context->token_type = L_SIMPLEPARAM;
1355 				retval = token_as_string (parser->priv->context->next_token_start + 2, i - 2);
1356 			}
1357 			else
1358 				parser->priv->context->token_type = L_UNSPECVAL;
1359 			consumed_chars = i;
1360 		}
1361 		else {
1362 			if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_MYSQL) {
1363 				/* comment */
1364 				for (i=1;  (c=z[i])!=0 && c!='\n'; i++){}
1365 				parser->priv->context->token_type = L_SQLCOMMENT;
1366 				consumed_chars = i;
1367 			}
1368 			else
1369 				parser->priv->context->token_type = L_ILLEGAL;
1370 		}
1371 		break;
1372 	}
1373 	case '$':
1374 		if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_POSTGRESQL) {
1375 			for(i=1; isalnum(z[i]) || (z[i] == '_'); i++){}
1376 			if (z[i] == '$') {
1377 				/* this is the start of the PostgreSQL's Dollar-Quoted strings */
1378 				gchar *tag_start = z;
1379 				gint tag_len = i+1;
1380 
1381 				/* no matching tag found => error */
1382 				parser->priv->context->token_type = L_ILLEGAL;
1383 
1384 				i++;
1385 				while (z[i]) {
1386 					/* go to the next '$' */
1387 					gint j;
1388 					for (; z[i] && (z[i] != '$'); i++);
1389 					for (j = 0; j < tag_len; j++, i++) {
1390 						if (z[i] != tag_start[j])
1391 							break; /* for */
1392 					}
1393 					if (j == tag_len) {
1394 						/* tags matched */
1395 						parser->priv->context->token_type = L_STRING;
1396 						consumed_chars = i;
1397 
1398 						retval = token_as_string (parser->priv->context->next_token_start, consumed_chars);
1399 						/* remove comments from returned string */
1400 						gchar *tmp, *ptr;
1401 						tmp = (gchar*) g_value_get_string (retval);
1402 						for (ptr = tmp; *ptr; ptr++) {
1403 							if (((ptr == tmp) || (*(ptr-1) == '\n')) && (*ptr == '-') && (ptr[1] == '-')) {
1404 								/* we have a comment */
1405 								gchar *ptr2;
1406 								for (ptr2 = ptr + 2; ptr2 && (*ptr2 != '\n'); ptr2++) {};
1407 								memmove (ptr, ptr2, sizeof (char) * (strlen (ptr2) + 1));
1408 							}
1409 						}
1410 
1411 						break; /* while */
1412 					}
1413 					i++;
1414 				}
1415 			}
1416 		}
1417 		else if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) {
1418 			for(i=1; isalnum(z[i]); i++){}
1419 			parser->priv->context->token_type = L_SIMPLEPARAM;
1420 			retval = token_as_string (parser->priv->context->next_token_start + 1, i - 1);
1421 			consumed_chars = i;
1422 		}
1423 		break;
1424 	case '@':
1425 	case ':':
1426 		if (z[1] == ':') {
1427 			parser->priv->context->token_type = L_PGCAST;
1428 			consumed_chars = 2;
1429 		}
1430 		else if (parser->priv->flavour == GDA_SQL_PARSER_FLAVOUR_SQLITE) {
1431 			for(i=1; isalnum(z[i]) || (z[i] == '_'); i++){}
1432 			parser->priv->context->token_type = L_SIMPLEPARAM;
1433 			retval = token_as_string (parser->priv->context->next_token_start + 1, i - 1);
1434 			consumed_chars = i;
1435 		}
1436 		break;
1437 #ifndef SQLITE_OMIT_BLOB_LITERAL
1438 	case 'x': case 'X': {
1439 		if (  (c=z[1])=='\'' || c=='"' ){
1440 			int delim = c;
1441 			parser->priv->context->token_type = L_BLOB;
1442 			for (i=2;  (c=z[i])!=0; i++){
1443 				if ( c==delim ){
1444 					if ( i%2 ) parser->priv->context->token_type = L_ILLEGAL;
1445 					break;
1446 				}
1447 				if ( !isxdigit (c) ){
1448 					parser->priv->context->token_type = L_ILLEGAL;
1449 					consumed_chars = i;
1450 					break;
1451 				}
1452 			}
1453 			if ( c ) i++;
1454 			consumed_chars = i;
1455 		}
1456 		break;
1457 	}
1458 #endif
1459 	default:
1460 		break;
1461 	}
1462 
1463 	if (parser->priv->context->token_type == G_MININT) {
1464 		/* now treat non treated cases */
1465 		if ((parser->priv->mode != GDA_SQL_PARSER_MODE_DELIMIT) && (! parser->priv->context->in_param_spec)) {
1466 			if (IdChar (*z)) {
1467 				for (i=1; IdChar (z[i]); i++){}
1468 				parser->priv->context->token_type = keywordCode (parser, (char*)z, i);
1469 				consumed_chars = i;
1470 			}
1471 		}
1472 		else {
1473 			if ((! parser->priv->context->in_param_spec) && IdChar (*z)) {
1474 				gint ttype;
1475 
1476 				for (i=1; IdChar (z[i]); i++){}
1477 				ttype = keywordCode (parser, (char*)z, i);
1478 				if (ttype != L_RAWSTRING) {
1479 					parser->priv->context->token_type = ttype;
1480 					consumed_chars = i;
1481 				}
1482 			}
1483 
1484 			if (parser->priv->context->token_type == G_MININT) {
1485 				if (!strncmp (parser->priv->context->next_token_start, "name:", 5)) {
1486 					parser->priv->context->next_token_start += 5;
1487 					retval = getToken (parser);
1488 					parser->priv->context->token_type = L_PNAME;
1489 					consumed_chars = 0;
1490 				}
1491 				else if (!strncmp (parser->priv->context->next_token_start, "type:", 5)) {
1492 					parser->priv->context->next_token_start += 5;
1493 					retval = getToken (parser);
1494 					parser->priv->context->token_type = L_PTYPE;
1495 					consumed_chars = 0;
1496 				}
1497 				else if (!strncmp (parser->priv->context->next_token_start, "descr:", 6)) {
1498 					parser->priv->context->next_token_start += 6;
1499 					retval = getToken (parser);
1500 					parser->priv->context->token_type = L_PDESCR;
1501 					consumed_chars = 0;
1502 				}
1503 				else if (!strncmp (parser->priv->context->next_token_start, "nullok:", 7)) {
1504 					parser->priv->context->next_token_start += 7;
1505 					retval = getToken (parser);
1506 					parser->priv->context->token_type = L_PNULLOK;
1507 					consumed_chars = 0;
1508 				}
1509 				else {
1510 					for (i=1; z[i] && (! isspace (z[i])) &&
1511 						     (z[i] != parser->priv->context->delimiter) && (z[i] != '*') &&
1512 						     (z[i] != '\'') && (z[i] != '"') && (z[i] != '#'); i++){}
1513 					parser->priv->context->token_type = L_RAWSTRING;
1514 					consumed_chars = i;
1515 				}
1516 			}
1517 		}
1518 	}
1519 
1520 	/* fallback for the token type */
1521 	if (parser->priv->context->token_type == G_MININT)
1522 		parser->priv->context->token_type = L_ILLEGAL;
1523 
1524 	if (!retval)
1525 		retval = token_as_string (parser->priv->context->next_token_start, consumed_chars);
1526  tok_end:
1527 	parser->priv->context->last_token_start = parser->priv->context->next_token_start;
1528 	parser->priv->context->next_token_start += consumed_chars;
1529 
1530 	if (parser->priv->context->token_type == L_END)
1531 		handle_composed_2_keywords (parser, retval, L_LOOP, L_ENDLOOP);
1532 	else if (parser->priv->context->token_type == L_IS)
1533 		handle_composed_2_keywords (parser, retval, L_NULL, L_ISNULL);
1534 	else if (parser->priv->context->token_type == L_NOT) {
1535 		handle_composed_2_keywords (parser, retval, L_NULL, L_NOTNULL) ||
1536 			handle_composed_2_keywords (parser, retval, L_LIKE, L_NOTLIKE) ||
1537 			handle_composed_2_keywords (parser, retval, L_ILIKE, L_NOTILIKE);
1538 	}
1539 	else if (parser->priv->context->token_type == L_SIMILAR)
1540 		handle_composed_2_keywords (parser, retval, L_TO, L_SIMILAR);
1541 
1542 #ifdef GDA_DEBUG_NO
1543 	if (retval) {
1544 		gchar *str = gda_sql_value_stringify (retval);
1545 		g_print ("%d (%s)\n", parser->priv->context->token_type, str);
1546 		g_free (str);
1547 	}
1548 	else if (parser->priv->context->token_type == L_END_OF_FILE)
1549 		g_print ("%d (END OF FILE)\n", parser->priv->context->token_type);
1550 	else
1551 		g_print ("%d\n", parser->priv->context->token_type);
1552 #endif
1553 	return retval;
1554 }
1555 
1556 static gboolean
handle_composed_2_keywords(GdaSqlParser * parser,GValue * retval,gint second,gint replacer)1557 handle_composed_2_keywords (GdaSqlParser *parser, GValue *retval, gint second, gint replacer)
1558 {
1559 	gint npushed, nmatched;
1560 	GValue *v = NULL;
1561 	gboolean match;
1562 	nmatched = fetch_forward (parser, &npushed, second, &v, 0);
1563 	match = (nmatched == 1);
1564 	if (match) {
1565 		gchar *newstr;
1566 		merge_tokenizer_contexts (parser, npushed);
1567 		parser->priv->context->token_type = replacer;
1568 
1569 		newstr = g_strdup_printf ("%s %s", g_value_get_string (retval), g_value_get_string (v));
1570 		g_value_reset (retval);
1571 		g_value_take_string (retval, newstr);
1572 	}
1573 	if (v) {
1574 		g_value_reset (v);
1575 		g_free (v);
1576 	}
1577 	return match;
1578 }
1579 
1580 static GValue *
tokenizer_get_next_token(GdaSqlParser * parser)1581 tokenizer_get_next_token (GdaSqlParser *parser)
1582 {
1583 	return getToken (parser);
1584 }
1585 
1586 static void
push_tokenizer_context(GdaSqlParser * parser)1587 push_tokenizer_context (GdaSqlParser *parser)
1588 {
1589 	TokenizerContext *nc;
1590 
1591 	nc = g_new (TokenizerContext, 1);
1592 	*nc = *parser->priv->context;
1593 	parser->priv->pushed_contexts = g_slist_prepend (parser->priv->pushed_contexts, parser->priv->context);
1594 	parser->priv->context = nc;
1595 #ifdef GDA_DEBUG_NO
1596 	g_print ("Push context\n");
1597 #endif
1598 }
1599 
1600 static void
pop_tokenizer_context(GdaSqlParser * parser)1601 pop_tokenizer_context (GdaSqlParser *parser)
1602 {
1603 	g_return_if_fail (parser->priv->pushed_contexts);
1604 	g_free (parser->priv->context);
1605 	parser->priv->context = (TokenizerContext*) parser->priv->pushed_contexts->data;
1606 	parser->priv->pushed_contexts = g_slist_remove (parser->priv->pushed_contexts, parser->priv->context);
1607 #ifdef GDA_DEBUG_NO
1608 	g_print ("Pop context\n");
1609 #endif
1610 }
1611 
1612 /*
1613  * Looks forward which tokens are available next, and returns the number of tokens corresponding to
1614  * expected token(s)
1615  *
1616  * extra arguments are a list of (gint expected_type, GValue **value) followed by 0
1617  */
1618 static gint
fetch_forward(GdaSqlParser * parser,gint * out_nb_pushed,...)1619 fetch_forward (GdaSqlParser *parser, gint *out_nb_pushed, ...)
1620 {
1621 	gint nmatched = 0;
1622 	gint npushed = 0;
1623 	va_list ap;
1624 
1625 	gint exp_type;
1626 	va_start (ap, out_nb_pushed);
1627 	exp_type = va_arg (ap, gint);
1628 	while (exp_type != 0) {
1629 		GValue **holder;
1630 		GValue *v1;
1631 		gint ttype;
1632 
1633 		holder = va_arg (ap, GValue **);
1634 		if (holder)
1635 			*holder = NULL;
1636 
1637 		push_tokenizer_context (parser); npushed++;
1638 		v1 = getToken (parser);
1639 		ttype = parser->priv->context->token_type;
1640 		if (ttype == L_SPACE) {
1641 			GValue *v2;
1642 			push_tokenizer_context (parser); npushed++;
1643 			v2 = getToken (parser);
1644 			ttype = parser->priv->context->token_type;
1645 			g_value_reset (v1);
1646 			g_free (v1);
1647 			v1 = v2;
1648 		}
1649 		if (ttype != exp_type) {
1650 			if (v1) {
1651 				g_value_reset (v1);
1652 				g_free (v1);
1653 			}
1654 
1655 			/* not what was expected => pop all the contexts */
1656 			for (; npushed > nmatched ; npushed--)
1657 				pop_tokenizer_context (parser);
1658 			break; /* while */
1659 		}
1660 		else {
1661 			if (holder)
1662 				*holder = v1;
1663 			else {
1664 				g_value_reset (v1);
1665 				g_free (v1);
1666 			}
1667 			nmatched ++;
1668 		}
1669 		exp_type = va_arg (ap, gint);
1670 	}
1671 	va_end (ap);
1672 
1673 	if (out_nb_pushed)
1674 		*out_nb_pushed = npushed;
1675 	return nmatched;
1676 }
1677 
1678 /* merge the @n_contexts into the current context */
1679 static void
merge_tokenizer_contexts(GdaSqlParser * parser,gint n_contexts)1680 merge_tokenizer_contexts (GdaSqlParser *parser, gint n_contexts)
1681 {
1682 	TokenizerContext *c;
1683 	gint i;
1684 	g_return_if_fail (n_contexts > 0);
1685 
1686 	c = g_slist_nth_data (parser->priv->pushed_contexts, n_contexts - 1);
1687 	g_return_if_fail (c);
1688 
1689 	parser->priv->context->token_type = c->token_type;
1690 	parser->priv->context->last_token_start = c->last_token_start;
1691 	parser->priv->context->delimiter = c->delimiter;
1692 	for (i = 0; i < n_contexts; i++) {
1693 		g_free (parser->priv->pushed_contexts->data);
1694 		parser->priv->pushed_contexts = g_slist_remove (parser->priv->pushed_contexts,
1695 								parser->priv->pushed_contexts->data);
1696 	}
1697 }
1698 
1699 static void
gda_sql_parser_lock(GdaLockable * lockable)1700 gda_sql_parser_lock (GdaLockable *lockable)
1701 {
1702 	GdaSqlParser *parser = (GdaSqlParser *) lockable;
1703 	g_return_if_fail (parser->priv);
1704 
1705 	gda_mutex_lock (parser->priv->mutex);
1706 }
1707 
1708 static gboolean
gda_sql_parser_trylock(GdaLockable * lockable)1709 gda_sql_parser_trylock (GdaLockable *lockable)
1710 {
1711 	GdaSqlParser *parser = (GdaSqlParser *) lockable;
1712 	g_return_val_if_fail (parser->priv, FALSE);
1713 
1714 	return gda_mutex_trylock (parser->priv->mutex);
1715 }
1716 
1717 static void
gda_sql_parser_unlock(GdaLockable * lockable)1718 gda_sql_parser_unlock (GdaLockable *lockable)
1719 {
1720 	GdaSqlParser *parser = (GdaSqlParser *) lockable;
1721 	g_return_if_fail (parser->priv);
1722 
1723 	gda_mutex_unlock (parser->priv->mutex);
1724 }
1725