1 : /******************************************************************************
2 : *
3 : * Component: OGDI Driver Support Library
4 : * Purpose: Generic SQL WHERE Expression Implementation.
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (C) 2001 Information Interoperability Institute (3i)
9 : *
10 : * Permission to use, copy, modify and distribute this software and
11 : * its documentation for any purpose and without fee is hereby granted,
12 : * provided that the above copyright notice appear in all copies, that
13 : * both the copyright notice and this permission notice appear in
14 : * supporting documentation, and that the name of 3i not be used
15 : * in advertising or publicity pertaining to distribution of the software
16 : * without specific, written prior permission. 3i makes no
17 : * representations about the suitability of this software for any purpose.
18 : * It is provided "as is" without express or implied warranty.
19 : ****************************************************************************/
20 :
21 : #include <ctype.h>
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_multiproc.h"
25 : #include "swq.h"
26 : #include "swq_parser.hpp"
27 :
28 : #define YYSTYPE swq_expr_node*
29 :
30 : /************************************************************************/
31 : /* swqlex() */
32 : /* */
33 : /* Read back a token from the input. */
34 : /************************************************************************/
35 :
36 14738 : int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
37 : {
38 14738 : const char *pszInput = context->pszNext;
39 :
40 14738 : *ppNode = NULL;
41 :
42 : /* -------------------------------------------------------------------- */
43 : /* Do we have a start symbol to return? */
44 : /* -------------------------------------------------------------------- */
45 14738 : if( context->nStartToken != 0 )
46 : {
47 1463 : int nRet = context->nStartToken;
48 1463 : context->nStartToken = 0;
49 1463 : return nRet;
50 : }
51 :
52 : /* -------------------------------------------------------------------- */
53 : /* Skip white space. */
54 : /* -------------------------------------------------------------------- */
55 32826 : while( *pszInput == ' ' || *pszInput == '\t'
56 : || *pszInput == 10 || *pszInput == 13 )
57 6276 : pszInput++;
58 :
59 13275 : if( *pszInput == '\0' )
60 : {
61 1394 : context->pszNext = pszInput;
62 1394 : return EOF;
63 : }
64 :
65 : /* -------------------------------------------------------------------- */
66 : /* Handle string constants. */
67 : /* -------------------------------------------------------------------- */
68 11881 : if( *pszInput == '"' || *pszInput == '\'' )
69 : {
70 : char *token;
71 : int i_token;
72 498 : char chQuote = *pszInput;
73 498 : int bFoundEndQuote = FALSE;
74 :
75 498 : pszInput++;
76 :
77 498 : token = (char *) CPLMalloc(strlen(pszInput)+1);
78 498 : i_token = 0;
79 :
80 4171 : while( *pszInput != '\0' )
81 : {
82 3671 : if( *pszInput == '\\' && pszInput[1] == '"' )
83 0 : pszInput++;
84 3671 : else if( *pszInput == '\\' && pszInput[1] == '\'' )
85 0 : pszInput++;
86 3671 : else if( *pszInput == '\'' && pszInput[1] == '\'' )
87 0 : pszInput++;
88 3671 : else if( *pszInput == chQuote )
89 : {
90 496 : pszInput++;
91 496 : bFoundEndQuote = TRUE;
92 496 : break;
93 : }
94 :
95 3175 : token[i_token++] = *(pszInput++);
96 : }
97 498 : token[i_token] = '\0';
98 :
99 498 : if( !bFoundEndQuote )
100 : {
101 : CPLError(CE_Failure, CPLE_AppDefined,
102 2 : "Did not find end-of-string character");
103 2 : CPLFree( token );
104 2 : return 0;
105 : }
106 :
107 496 : *ppNode = new swq_expr_node( token );
108 496 : CPLFree( token );
109 :
110 496 : context->pszNext = pszInput;
111 :
112 496 : return SWQT_STRING;
113 : }
114 :
115 : /* -------------------------------------------------------------------- */
116 : /* Handle numbers. */
117 : /* -------------------------------------------------------------------- */
118 11383 : else if( *pszInput >= '0' && *pszInput <= '9' )
119 : {
120 1551 : CPLString osToken;
121 1551 : const char *pszNext = pszInput + 1;
122 :
123 1551 : osToken += *pszInput;
124 :
125 : // collect non-decimal part of number
126 3841 : while( *pszNext >= '0' && *pszNext <= '9' )
127 739 : osToken += *(pszNext++);
128 :
129 : // collect decimal places.
130 1551 : if( *pszNext == '.' )
131 : {
132 333 : osToken += *(pszNext++);
133 1294 : while( *pszNext >= '0' && *pszNext <= '9' )
134 628 : osToken += *(pszNext++);
135 : }
136 :
137 : // collect exponent
138 1551 : if( *pszNext == 'e' || *pszNext == 'E' )
139 : {
140 1 : osToken += *(pszNext++);
141 1 : if( *pszNext == '-' || *pszNext == '+' )
142 1 : osToken += *(pszNext++);
143 3 : while( *pszNext >= '0' && *pszNext <= '9' )
144 1 : osToken += *(pszNext++);
145 : }
146 :
147 1551 : context->pszNext = pszNext;
148 :
149 1551 : if( strstr(osToken,".")
150 : || strstr(osToken,"e")
151 : || strstr(osToken,"E") )
152 : {
153 334 : *ppNode = new swq_expr_node( CPLAtof(osToken) );
154 : }
155 : else
156 : {
157 1217 : *ppNode = new swq_expr_node( atoi(osToken) );
158 : }
159 :
160 1551 : return SWQT_NUMBER;
161 : }
162 :
163 : /* -------------------------------------------------------------------- */
164 : /* Handle alpha-numerics. */
165 : /* -------------------------------------------------------------------- */
166 9832 : else if( isalnum( *pszInput ) )
167 : {
168 5390 : int nReturn = SWQT_IDENTIFIER;
169 5390 : CPLString osToken;
170 5390 : const char *pszNext = pszInput + 1;
171 :
172 5390 : osToken += *pszInput;
173 :
174 : // collect text characters
175 31579 : while( isalnum( *pszNext ) || *pszNext == '_'
176 : || ((unsigned char) *pszNext) > 127 )
177 20799 : osToken += *(pszNext++);
178 :
179 5390 : context->pszNext = pszNext;
180 :
181 5390 : if( EQUAL(osToken,"IN") )
182 48 : nReturn = SWQT_IN;
183 5342 : else if( EQUAL(osToken,"LIKE") )
184 12 : nReturn = SWQT_LIKE;
185 5330 : else if( EQUAL(osToken,"ILIKE") )
186 1 : nReturn = SWQT_LIKE;
187 5329 : else if( EQUAL(osToken,"ESCAPE") )
188 2 : nReturn = SWQT_ESCAPE;
189 5327 : else if( EQUAL(osToken,"NULL") )
190 35 : nReturn = SWQT_NULL;
191 5292 : else if( EQUAL(osToken,"IS") )
192 24 : nReturn = SWQT_IS;
193 5268 : else if( EQUAL(osToken,"NOT") )
194 22 : nReturn = SWQT_NOT;
195 5246 : else if( EQUAL(osToken,"AND") )
196 301 : nReturn = SWQT_AND;
197 4945 : else if( EQUAL(osToken,"OR") )
198 23 : nReturn = SWQT_OR;
199 4922 : else if( EQUAL(osToken,"BETWEEN") )
200 34 : nReturn = SWQT_BETWEEN;
201 4888 : else if( EQUAL(osToken,"SELECT") )
202 590 : nReturn = SWQT_SELECT;
203 4298 : else if( EQUAL(osToken,"LEFT") )
204 25 : nReturn = SWQT_LEFT;
205 4273 : else if( EQUAL(osToken,"JOIN") )
206 26 : nReturn = SWQT_JOIN;
207 4247 : else if( EQUAL(osToken,"WHERE") )
208 319 : nReturn = SWQT_WHERE;
209 3928 : else if( EQUAL(osToken,"ON") )
210 24 : nReturn = SWQT_ON;
211 3904 : else if( EQUAL(osToken,"ORDER") )
212 27 : nReturn = SWQT_ORDER;
213 3877 : else if( EQUAL(osToken,"BY") )
214 27 : nReturn = SWQT_BY;
215 3850 : else if( EQUAL(osToken,"FROM") )
216 553 : nReturn = SWQT_FROM;
217 3297 : else if( EQUAL(osToken,"AS") )
218 63 : nReturn = SWQT_AS;
219 3234 : else if( EQUAL(osToken,"ASC") )
220 11 : nReturn = SWQT_ASC;
221 3223 : else if( EQUAL(osToken,"DESC") )
222 9 : nReturn = SWQT_DESC;
223 3214 : else if( EQUAL(osToken,"DISTINCT") )
224 31 : nReturn = SWQT_DISTINCT;
225 3183 : else if( EQUAL(osToken,"CAST") )
226 53 : nReturn = SWQT_CAST;
227 3130 : else if( EQUAL(osToken,"UNION") )
228 7 : nReturn = SWQT_UNION;
229 3123 : else if( EQUAL(osToken,"ALL") )
230 6 : nReturn = SWQT_ALL;
231 : else
232 : {
233 3117 : *ppNode = new swq_expr_node( osToken );
234 3117 : nReturn = SWQT_IDENTIFIER;
235 : }
236 :
237 5390 : return nReturn;
238 : }
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* Handle special tokens. */
242 : /* -------------------------------------------------------------------- */
243 : else
244 : {
245 4442 : context->pszNext = pszInput+1;
246 4442 : return *pszInput;
247 : }
248 : }
249 :
250 : /************************************************************************/
251 : /* swq_select_summarize() */
252 : /************************************************************************/
253 :
254 : const char *
255 262 : swq_select_summarize( swq_select *select_info,
256 : int dest_column, const char *value )
257 :
258 : {
259 262 : swq_col_def *def = select_info->column_defs + dest_column;
260 : swq_summary *summary;
261 :
262 : /* -------------------------------------------------------------------- */
263 : /* Do various checking. */
264 : /* -------------------------------------------------------------------- */
265 262 : if( select_info->query_mode == SWQM_RECORDSET )
266 0 : return "swq_select_summarize() called on non-summary query.";
267 :
268 262 : if( dest_column < 0 || dest_column >= select_info->result_columns )
269 0 : return "dest_column out of range in swq_select_summarize().";
270 :
271 262 : if( def->col_func == SWQCF_NONE && !def->distinct_flag )
272 0 : return NULL;
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* Create the summary information if this is the first row */
276 : /* being processed. */
277 : /* -------------------------------------------------------------------- */
278 262 : if( select_info->column_summary == NULL && value != NULL )
279 : {
280 : int i;
281 :
282 : select_info->column_summary = (swq_summary *)
283 21 : CPLMalloc(sizeof(swq_summary) * select_info->result_columns);
284 : memset( select_info->column_summary, 0,
285 21 : sizeof(swq_summary) * select_info->result_columns );
286 :
287 50 : for( i = 0; i < select_info->result_columns; i++ )
288 : {
289 29 : select_info->column_summary[i].min = 1e20;
290 29 : select_info->column_summary[i].max = -1e20;
291 : }
292 : }
293 :
294 262 : if( select_info->column_summary == NULL )
295 8 : return NULL;
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* If distinct processing is on, process that now. */
299 : /* -------------------------------------------------------------------- */
300 254 : summary = select_info->column_summary + dest_column;
301 :
302 254 : if( def->distinct_flag )
303 : {
304 : int i;
305 :
306 : /* This should be implemented with a much more complicated
307 : data structure to achieve any sort of efficiency. */
308 804 : for( i = 0; i < summary->count; i++ )
309 : {
310 736 : if( value == NULL )
311 : {
312 93 : if (summary->distinct_list[i] == NULL)
313 6 : break;
314 : }
315 1286 : else if( summary->distinct_list[i] != NULL &&
316 643 : strcmp(value,summary->distinct_list[i]) == 0 )
317 125 : break;
318 : }
319 :
320 199 : if( i == summary->count )
321 : {
322 68 : char **old_list = summary->distinct_list;
323 :
324 : summary->distinct_list = (char **)
325 68 : CPLMalloc(sizeof(char *) * (summary->count+1));
326 : memcpy( summary->distinct_list, old_list,
327 68 : sizeof(char *) * summary->count );
328 136 : summary->distinct_list[(summary->count)++] =
329 68 : (value != NULL) ? CPLStrdup( value ) : NULL;
330 :
331 68 : CPLFree(old_list);
332 : }
333 : }
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Process various options. */
337 : /* -------------------------------------------------------------------- */
338 :
339 254 : switch( def->col_func )
340 : {
341 : case SWQCF_MIN:
342 10 : if( value != NULL && value[0] != '\0' )
343 : {
344 10 : double df_val = CPLAtof(value);
345 10 : if( df_val < summary->min )
346 3 : summary->min = df_val;
347 : }
348 10 : break;
349 : case SWQCF_MAX:
350 17 : if( value != NULL && value[0] != '\0' )
351 : {
352 17 : double df_val = CPLAtof(value);
353 17 : if( df_val > summary->max )
354 7 : summary->max = df_val;
355 : }
356 17 : break;
357 : case SWQCF_AVG:
358 : case SWQCF_SUM:
359 0 : if( value != NULL && value[0] != '\0' )
360 : {
361 0 : summary->count++;
362 0 : summary->sum += CPLAtof(value);
363 : }
364 0 : break;
365 :
366 : case SWQCF_COUNT:
367 40 : if( value != NULL && !def->distinct_flag )
368 28 : summary->count++;
369 40 : break;
370 :
371 : case SWQCF_NONE:
372 187 : break;
373 :
374 : case SWQCF_CUSTOM:
375 0 : return "swq_select_summarize() called on custom field function.";
376 :
377 : default:
378 0 : return "swq_select_summarize() - unexpected col_func";
379 : }
380 :
381 254 : return NULL;
382 : }
383 : /************************************************************************/
384 : /* sort comparison functions. */
385 : /************************************************************************/
386 :
387 52 : static int FORCE_CDECL swq_compare_int( const void *item1, const void *item2 )
388 : {
389 : int v1, v2;
390 :
391 52 : const char* pszStr1 = *((const char **) item1);
392 52 : const char* pszStr2 = *((const char **) item2);
393 52 : if (pszStr1 == NULL)
394 0 : return (pszStr2 == NULL) ? 0 : -1;
395 52 : else if (pszStr2 == NULL)
396 10 : return 1;
397 :
398 42 : v1 = atoi(pszStr1);
399 42 : v2 = atoi(pszStr2);
400 :
401 42 : if( v1 < v2 )
402 16 : return -1;
403 26 : else if( v1 == v2 )
404 0 : return 0;
405 : else
406 26 : return 1;
407 : }
408 :
409 25 : static int FORCE_CDECL swq_compare_real( const void *item1, const void *item2 )
410 : {
411 : double v1, v2;
412 :
413 25 : const char* pszStr1 = *((const char **) item1);
414 25 : const char* pszStr2 = *((const char **) item2);
415 25 : if (pszStr1 == NULL)
416 0 : return (pszStr2 == NULL) ? 0 : -1;
417 25 : else if (pszStr2 == NULL)
418 2 : return 1;
419 :
420 23 : v1 = CPLAtof(pszStr1);
421 23 : v2 = CPLAtof(pszStr2);
422 :
423 23 : if( v1 < v2 )
424 9 : return -1;
425 14 : else if( v1 == v2 )
426 0 : return 0;
427 : else
428 14 : return 1;
429 : }
430 :
431 14 : static int FORCE_CDECL swq_compare_string( const void *item1, const void *item2 )
432 : {
433 14 : const char* pszStr1 = *((const char **) item1);
434 14 : const char* pszStr2 = *((const char **) item2);
435 14 : if (pszStr1 == NULL)
436 0 : return (pszStr2 == NULL) ? 0 : -1;
437 14 : else if (pszStr2 == NULL)
438 2 : return 1;
439 :
440 12 : return strcmp( pszStr1, pszStr2 );
441 : }
442 :
443 : /************************************************************************/
444 : /* swq_select_finish_summarize() */
445 : /* */
446 : /* Call to complete summarize work. Does stuff like ordering */
447 : /* the distinct list for instance. */
448 : /************************************************************************/
449 :
450 27 : const char *swq_select_finish_summarize( swq_select *select_info )
451 :
452 : {
453 : int (FORCE_CDECL *compare_func)(const void *, const void*);
454 27 : int count = 0;
455 27 : char **distinct_list = NULL;
456 :
457 27 : if( select_info->query_mode != SWQM_DISTINCT_LIST
458 : || select_info->order_specs == 0 )
459 16 : return NULL;
460 :
461 11 : if( select_info->order_specs > 1 )
462 0 : return "Can't ORDER BY a DISTINCT list by more than one key.";
463 :
464 22 : if( select_info->order_defs[0].field_index !=
465 11 : select_info->column_defs[0].field_index )
466 0 : return "Only selected DISTINCT field can be used for ORDER BY.";
467 :
468 11 : if( select_info->column_summary == NULL )
469 0 : return NULL;
470 :
471 11 : if( select_info->column_defs[0].field_type == SWQ_INTEGER )
472 4 : compare_func = swq_compare_int;
473 7 : else if( select_info->column_defs[0].field_type == SWQ_FLOAT )
474 4 : compare_func = swq_compare_real;
475 : else
476 3 : compare_func = swq_compare_string;
477 :
478 11 : distinct_list = select_info->column_summary[0].distinct_list;
479 11 : count = select_info->column_summary[0].count;
480 :
481 11 : qsort( distinct_list, count, sizeof(char *), compare_func );
482 :
483 : /* -------------------------------------------------------------------- */
484 : /* Do we want the list ascending in stead of descending? */
485 : /* -------------------------------------------------------------------- */
486 11 : if( !select_info->order_defs[0].ascending_flag )
487 : {
488 : char *saved;
489 : int i;
490 :
491 21 : for( i = 0; i < count/2; i++ )
492 : {
493 15 : saved = distinct_list[i];
494 15 : distinct_list[i] = distinct_list[count-i-1];
495 15 : distinct_list[count-i-1] = saved;
496 : }
497 : }
498 :
499 11 : return NULL;
500 : }
501 :
502 : /************************************************************************/
503 : /* swq_select_free() */
504 : /************************************************************************/
505 :
506 0 : void swq_select_free( swq_select *select_info )
507 :
508 : {
509 0 : delete select_info;
510 0 : }
511 :
512 : /************************************************************************/
513 : /* swq_identify_field() */
514 : /************************************************************************/
515 : static
516 : int swq_identify_field_internal( const char *field_token, const char* table_name,
517 : swq_field_list *field_list,
518 : swq_field_type *this_type, int *table_id, int tables_enabled );
519 :
520 4262 : int swq_identify_field( const char *token, swq_field_list *field_list,
521 : swq_field_type *this_type, int *table_id )
522 :
523 : {
524 4262 : CPLString osTableName;
525 4262 : const char *field_token = token;
526 : int tables_enabled;
527 :
528 7334 : if( field_list->table_count > 0 && field_list->table_ids != NULL )
529 3072 : tables_enabled = TRUE;
530 : else
531 1190 : tables_enabled = FALSE;
532 :
533 : /* -------------------------------------------------------------------- */
534 : /* Parse out table name if present, and table support enabled. */
535 : /* -------------------------------------------------------------------- */
536 4262 : if( tables_enabled && strchr(token, '.') != NULL )
537 : {
538 97 : int dot_offset = (int)(strchr(token,'.') - token);
539 :
540 97 : osTableName = token;
541 97 : osTableName.resize(dot_offset);
542 97 : field_token = token + dot_offset + 1;
543 :
544 : #ifdef notdef
545 : /* We try to detect if a.b is the a.b field */
546 : /* of the main table, or the b field of the a table */
547 : /* If both exists, report an error. */
548 : /* This works, but I'm not sure this is a good idea to */
549 : /* enable that. It is a sign that our SQL grammar is somewhat */
550 : /* ambiguous */
551 :
552 : swq_field_type eTypeWithTablesEnabled;
553 : int nTableIdWithTablesEnabled;
554 : int nRetWithTablesEnabled = swq_identify_field_internal(
555 : field_token, osTableName.c_str(), field_list,
556 : &eTypeWithTablesEnabled, &nTableIdWithTablesEnabled, TRUE);
557 :
558 : swq_field_type eTypeWithTablesDisabled;
559 : int nTableIdWithTablesDisabled;
560 : int nRetWithTablesDisabled = swq_identify_field_internal(
561 : token, "", field_list,
562 : &eTypeWithTablesDisabled, &nTableIdWithTablesDisabled, FALSE);
563 :
564 : if( nRetWithTablesEnabled >= 0 && nRetWithTablesDisabled >= 0 )
565 : {
566 : CPLError(CE_Failure, CPLE_AppDefined,
567 : "Ambiguous situation. Both %s exists as a field in "
568 : "main table and %s exists as a field in %s table",
569 : token, osTableName.c_str(), field_token);
570 : return -1;
571 : }
572 : else if( nRetWithTablesEnabled >= 0 )
573 : {
574 : if( this_type != NULL ) *this_type = eTypeWithTablesEnabled;
575 : if( table_id != NULL ) *table_id = nTableIdWithTablesEnabled;
576 : return nRetWithTablesEnabled;
577 : }
578 : else if( nRetWithTablesDisabled >= 0 )
579 : {
580 : if( this_type != NULL ) *this_type = eTypeWithTablesDisabled;
581 : if( table_id != NULL ) *table_id = nTableIdWithTablesDisabled;
582 : return nRetWithTablesDisabled;
583 : }
584 : else
585 : {
586 : return -1;
587 : }
588 : #endif
589 : }
590 :
591 : return swq_identify_field_internal(field_token, osTableName.c_str(), field_list,
592 4262 : this_type, table_id, tables_enabled);
593 : }
594 :
595 :
596 4262 : int swq_identify_field_internal( const char *field_token, const char* table_name,
597 : swq_field_list *field_list,
598 : swq_field_type *this_type, int *table_id, int tables_enabled )
599 :
600 : {
601 : int i;
602 : /* -------------------------------------------------------------------- */
603 : /* Search for matching field. */
604 : /* -------------------------------------------------------------------- */
605 22174 : for( i = 0; i < field_list->count; i++ )
606 : {
607 21621 : int t_id = 0;
608 :
609 21621 : if( !EQUAL( field_list->names[i], field_token ) )
610 17878 : continue;
611 :
612 : /* Do the table specifications match? */
613 3743 : if( tables_enabled )
614 : {
615 2882 : t_id = field_list->table_ids[i];
616 3010 : if( table_name[0] != '\0'
617 128 : && !EQUAL(table_name,field_list->table_defs[t_id].table_alias))
618 34 : continue;
619 :
620 : // if( t_id != 0 && table_name[0] == '\0' )
621 : // continue;
622 : }
623 :
624 : /* We have a match, return various information */
625 3709 : if( this_type != NULL )
626 : {
627 3646 : if( field_list->types != NULL )
628 3646 : *this_type = field_list->types[i];
629 : else
630 0 : *this_type = SWQ_OTHER;
631 : }
632 :
633 3709 : if( table_id != NULL )
634 3709 : *table_id = t_id;
635 :
636 3709 : if( field_list->ids == NULL )
637 861 : return i;
638 : else
639 2848 : return field_list->ids[i];
640 : }
641 :
642 : /* -------------------------------------------------------------------- */
643 : /* No match, return failure. */
644 : /* -------------------------------------------------------------------- */
645 553 : if( this_type != NULL )
646 550 : *this_type = SWQ_OTHER;
647 :
648 553 : if( table_id != NULL )
649 553 : *table_id = 0;
650 :
651 553 : return -1;
652 : }
653 :
654 : /************************************************************************/
655 : /* swq_expr_compile() */
656 : /************************************************************************/
657 :
658 849 : CPLErr swq_expr_compile( const char *where_clause,
659 : int field_count,
660 : char **field_names,
661 : swq_field_type *field_types,
662 : swq_expr_node **expr_out )
663 :
664 : {
665 : swq_field_list field_list;
666 :
667 849 : field_list.count = field_count;
668 849 : field_list.names = field_names;
669 849 : field_list.types = field_types;
670 849 : field_list.table_ids = NULL;
671 849 : field_list.ids = NULL;
672 :
673 849 : field_list.table_count = 0;
674 849 : field_list.table_defs = NULL;
675 :
676 849 : return swq_expr_compile2( where_clause, &field_list, expr_out );
677 : }
678 :
679 :
680 : /************************************************************************/
681 : /* swq_expr_compile2() */
682 : /************************************************************************/
683 :
684 849 : CPLErr swq_expr_compile2( const char *where_clause,
685 : swq_field_list *field_list,
686 : swq_expr_node **expr_out )
687 :
688 : {
689 :
690 849 : swq_parse_context context;
691 :
692 849 : context.pszInput = where_clause;
693 849 : context.pszNext = where_clause;
694 849 : context.nStartToken = SWQT_LOGICAL_START;
695 :
696 849 : if( swqparse( &context ) == 0
697 : && context.poRoot->Check( field_list ) != SWQ_ERROR )
698 : {
699 849 : *expr_out = context.poRoot;
700 :
701 849 : return CE_None;
702 : }
703 : else
704 : {
705 0 : delete context.poRoot;
706 0 : *expr_out = NULL;
707 0 : return CE_Failure;
708 : }
709 : }
710 :
711 : /************************************************************************/
712 : /* swq_is_reserved_keyword() */
713 : /************************************************************************/
714 :
715 : static const char* apszSQLReservedKeywords[] = {
716 : "OR",
717 : "AND",
718 : "NOT",
719 : "LIKE",
720 : "IS",
721 : "NULL",
722 : "IN",
723 : "BETWEEN",
724 : "CAST",
725 : "DISTINCT",
726 : "ESCAPE",
727 : "SELECT",
728 : "LEFT",
729 : "JOIN",
730 : "WHERE",
731 : "ON",
732 : "ORDER",
733 : "BY",
734 : "FROM",
735 : "AS",
736 : "ASC",
737 : "DESC",
738 : "UNION",
739 : "ALL"
740 : };
741 :
742 404 : int swq_is_reserved_keyword(const char* pszStr)
743 : {
744 10052 : for(int i = 0; i < (int)(sizeof(apszSQLReservedKeywords)/sizeof(char*)); i++)
745 : {
746 9656 : if (EQUAL(pszStr, apszSQLReservedKeywords[i]))
747 8 : return TRUE;
748 : }
749 396 : return FALSE;
750 : }
|