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 (®istering);
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 (®istering);
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