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 22288 : int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
37 : {
38 22288 : const char *pszInput = context->pszNext;
39 :
40 22288 : *ppNode = NULL;
41 :
42 : /* -------------------------------------------------------------------- */
43 : /* Do we have a start symbol to return? */
44 : /* -------------------------------------------------------------------- */
45 22288 : if( context->nStartToken != 0 )
46 : {
47 1884 : int nRet = context->nStartToken;
48 1884 : context->nStartToken = 0;
49 1884 : return nRet;
50 : }
51 :
52 : /* -------------------------------------------------------------------- */
53 : /* Skip white space. */
54 : /* -------------------------------------------------------------------- */
55 49668 : while( *pszInput == ' ' || *pszInput == '\t'
56 : || *pszInput == 10 || *pszInput == 13 )
57 8860 : pszInput++;
58 :
59 20404 : if( *pszInput == '\0' )
60 : {
61 1792 : context->pszNext = pszInput;
62 1792 : return EOF;
63 : }
64 :
65 : /* -------------------------------------------------------------------- */
66 : /* Handle string constants. */
67 : /* -------------------------------------------------------------------- */
68 18612 : if( *pszInput == '"' || *pszInput == '\'' )
69 : {
70 : char *token;
71 : int i_token;
72 :
73 726 : pszInput++;
74 :
75 726 : token = (char *) CPLMalloc(strlen(pszInput)+1);
76 726 : i_token = 0;
77 :
78 5780 : while( *pszInput != '\0' )
79 : {
80 5052 : if( *pszInput == '\\' && pszInput[1] == '"' )
81 0 : pszInput++;
82 5052 : else if( *pszInput == '\\' && pszInput[1] == '\'' )
83 0 : pszInput++;
84 5052 : else if( *pszInput == '\'' && pszInput[1] == '\'' )
85 0 : pszInput++;
86 5052 : else if( *pszInput == '"' )
87 : {
88 60 : pszInput++;
89 60 : break;
90 : }
91 4992 : else if( *pszInput == '\'' )
92 : {
93 664 : pszInput++;
94 664 : break;
95 : }
96 :
97 4328 : token[i_token++] = *(pszInput++);
98 : }
99 726 : token[i_token] = '\0';
100 :
101 726 : *ppNode = new swq_expr_node( token );
102 726 : CPLFree( token );
103 :
104 726 : context->pszNext = pszInput;
105 :
106 726 : return SWQT_STRING;
107 : }
108 :
109 : /* -------------------------------------------------------------------- */
110 : /* Handle numbers. */
111 : /* -------------------------------------------------------------------- */
112 17886 : else if( *pszInput >= '0' && *pszInput <= '9' )
113 : {
114 1910 : CPLString osToken;
115 1910 : const char *pszNext = pszInput + 1;
116 :
117 1910 : osToken += *pszInput;
118 :
119 : // collect non-decimal part of number
120 4762 : while( *pszNext >= '0' && *pszNext <= '9' )
121 942 : osToken += *(pszNext++);
122 :
123 : // collect decimal places.
124 1910 : if( *pszNext == '.' )
125 : {
126 578 : osToken += *(pszNext++);
127 1270 : while( *pszNext >= '0' && *pszNext <= '9' )
128 114 : osToken += *(pszNext++);
129 : }
130 :
131 : // collect exponent
132 1910 : if( *pszNext == 'e' || *pszNext == 'E' )
133 : {
134 2 : osToken += *(pszNext++);
135 2 : if( *pszNext == '-' || *pszNext == '+' )
136 2 : osToken += *(pszNext++);
137 6 : while( *pszNext >= '0' && *pszNext <= '9' )
138 2 : osToken += *(pszNext++);
139 : }
140 :
141 1910 : context->pszNext = pszNext;
142 :
143 1910 : if( strstr(osToken,".")
144 : || strstr(osToken,"e")
145 : || strstr(osToken,"E") )
146 : {
147 580 : *ppNode = new swq_expr_node( CPLAtof(osToken) );
148 : }
149 : else
150 : {
151 1330 : *ppNode = new swq_expr_node( atoi(osToken) );
152 : }
153 :
154 1910 : return SWQT_NUMBER;
155 : }
156 :
157 : /* -------------------------------------------------------------------- */
158 : /* Handle alpha-numerics. */
159 : /* -------------------------------------------------------------------- */
160 15976 : else if( isalnum( *pszInput ) )
161 : {
162 8746 : int nReturn = SWQT_IDENTIFIER;
163 8746 : CPLString osToken;
164 8746 : const char *pszNext = pszInput + 1;
165 :
166 8746 : osToken += *pszInput;
167 :
168 : // collect text characters
169 49468 : while( isalnum( *pszNext ) || *pszNext == '_'
170 : || ((unsigned char) *pszNext) > 127 )
171 31976 : osToken += *(pszNext++);
172 :
173 8746 : context->pszNext = pszNext;
174 :
175 8746 : if( EQUAL(osToken,"IN") )
176 96 : nReturn = SWQT_IN;
177 8650 : else if( EQUAL(osToken,"LIKE") )
178 22 : nReturn = SWQT_LIKE;
179 8628 : else if( EQUAL(osToken,"ILIKE") )
180 2 : nReturn = SWQT_LIKE;
181 8626 : else if( EQUAL(osToken,"ESCAPE") )
182 4 : nReturn = SWQT_ESCAPE;
183 8622 : else if( EQUAL(osToken,"NULL") )
184 28 : nReturn = SWQT_NULL;
185 8594 : else if( EQUAL(osToken,"IS") )
186 26 : nReturn = SWQT_IS;
187 8568 : else if( EQUAL(osToken,"NOT") )
188 30 : nReturn = SWQT_NOT;
189 8538 : else if( EQUAL(osToken,"AND") )
190 548 : nReturn = SWQT_AND;
191 7990 : else if( EQUAL(osToken,"OR") )
192 12 : nReturn = SWQT_OR;
193 7978 : else if( EQUAL(osToken,"BETWEEN") )
194 68 : nReturn = SWQT_BETWEEN;
195 7910 : else if( EQUAL(osToken,"SELECT") )
196 886 : nReturn = SWQT_SELECT;
197 7024 : else if( EQUAL(osToken,"LEFT") )
198 50 : nReturn = SWQT_LEFT;
199 6974 : else if( EQUAL(osToken,"JOIN") )
200 52 : nReturn = SWQT_JOIN;
201 6922 : else if( EQUAL(osToken,"WHERE") )
202 402 : nReturn = SWQT_WHERE;
203 6520 : else if( EQUAL(osToken,"ON") )
204 48 : nReturn = SWQT_ON;
205 6472 : else if( EQUAL(osToken,"ORDER") )
206 52 : nReturn = SWQT_ORDER;
207 6420 : else if( EQUAL(osToken,"BY") )
208 52 : nReturn = SWQT_BY;
209 6368 : else if( EQUAL(osToken,"FROM") )
210 816 : nReturn = SWQT_FROM;
211 5552 : else if( EQUAL(osToken,"AS") )
212 106 : nReturn = SWQT_AS;
213 5446 : else if( EQUAL(osToken,"ASC") )
214 22 : nReturn = SWQT_ASC;
215 5424 : else if( EQUAL(osToken,"DESC") )
216 18 : nReturn = SWQT_DESC;
217 5406 : else if( EQUAL(osToken,"DISTINCT") )
218 62 : nReturn = SWQT_DISTINCT;
219 5344 : else if( EQUAL(osToken,"CAST") )
220 86 : nReturn = SWQT_CAST;
221 : else
222 : {
223 5258 : *ppNode = new swq_expr_node( osToken );
224 5258 : nReturn = SWQT_IDENTIFIER;
225 : }
226 :
227 8746 : return nReturn;
228 : }
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Handle special tokens. */
232 : /* -------------------------------------------------------------------- */
233 : else
234 : {
235 7230 : context->pszNext = pszInput+1;
236 7230 : return *pszInput;
237 : }
238 : }
239 :
240 : /************************************************************************/
241 : /* swq_select_summarize() */
242 : /************************************************************************/
243 :
244 : const char *
245 524 : swq_select_summarize( swq_select *select_info,
246 : int dest_column, const char *value )
247 :
248 : {
249 524 : swq_col_def *def = select_info->column_defs + dest_column;
250 : swq_summary *summary;
251 :
252 : /* -------------------------------------------------------------------- */
253 : /* Do various checking. */
254 : /* -------------------------------------------------------------------- */
255 524 : if( select_info->query_mode == SWQM_RECORDSET )
256 0 : return "swq_select_summarize() called on non-summary query.";
257 :
258 524 : if( dest_column < 0 || dest_column >= select_info->result_columns )
259 0 : return "dest_column out of range in swq_select_summarize().";
260 :
261 524 : if( def->col_func == SWQCF_NONE && !def->distinct_flag )
262 0 : return NULL;
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Create the summary information if this is the first row */
266 : /* being processed. */
267 : /* -------------------------------------------------------------------- */
268 524 : if( select_info->column_summary == NULL && value != NULL )
269 : {
270 : int i;
271 :
272 : select_info->column_summary = (swq_summary *)
273 42 : CPLMalloc(sizeof(swq_summary) * select_info->result_columns);
274 : memset( select_info->column_summary, 0,
275 42 : sizeof(swq_summary) * select_info->result_columns );
276 :
277 100 : for( i = 0; i < select_info->result_columns; i++ )
278 : {
279 58 : select_info->column_summary[i].min = 1e20;
280 58 : select_info->column_summary[i].max = -1e20;
281 : }
282 : }
283 :
284 524 : if( select_info->column_summary == NULL )
285 16 : return NULL;
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* If distinct processing is on, process that now. */
289 : /* -------------------------------------------------------------------- */
290 508 : summary = select_info->column_summary + dest_column;
291 :
292 508 : if( def->distinct_flag )
293 : {
294 : int i;
295 :
296 : /* This should be implemented with a much more complicated
297 : data structure to achieve any sort of efficiency. */
298 1608 : for( i = 0; i < summary->count; i++ )
299 : {
300 1472 : if( value == NULL )
301 : {
302 186 : if (summary->distinct_list[i] == NULL)
303 12 : break;
304 : }
305 2572 : else if( summary->distinct_list[i] != NULL &&
306 1286 : strcmp(value,summary->distinct_list[i]) == 0 )
307 250 : break;
308 : }
309 :
310 398 : if( i == summary->count )
311 : {
312 136 : char **old_list = summary->distinct_list;
313 :
314 : summary->distinct_list = (char **)
315 136 : CPLMalloc(sizeof(char *) * (summary->count+1));
316 : memcpy( summary->distinct_list, old_list,
317 136 : sizeof(char *) * summary->count );
318 272 : summary->distinct_list[(summary->count)++] =
319 136 : (value != NULL) ? CPLStrdup( value ) : NULL;
320 :
321 136 : CPLFree(old_list);
322 : }
323 : }
324 :
325 : /* -------------------------------------------------------------------- */
326 : /* Process various options. */
327 : /* -------------------------------------------------------------------- */
328 :
329 508 : switch( def->col_func )
330 : {
331 : case SWQCF_MIN:
332 20 : if( value != NULL && value[0] != '\0' )
333 : {
334 20 : double df_val = CPLAtof(value);
335 20 : if( df_val < summary->min )
336 6 : summary->min = df_val;
337 : }
338 20 : break;
339 : case SWQCF_MAX:
340 34 : if( value != NULL && value[0] != '\0' )
341 : {
342 34 : double df_val = CPLAtof(value);
343 34 : if( df_val > summary->max )
344 14 : summary->max = df_val;
345 : }
346 34 : break;
347 : case SWQCF_AVG:
348 : case SWQCF_SUM:
349 0 : if( value != NULL && value[0] != '\0' )
350 : {
351 0 : summary->count++;
352 0 : summary->sum += CPLAtof(value);
353 : }
354 0 : break;
355 :
356 : case SWQCF_COUNT:
357 80 : if( value != NULL && !def->distinct_flag )
358 56 : summary->count++;
359 80 : break;
360 :
361 : case SWQCF_NONE:
362 374 : break;
363 :
364 : case SWQCF_CUSTOM:
365 0 : return "swq_select_summarize() called on custom field function.";
366 :
367 : default:
368 0 : return "swq_select_summarize() - unexpected col_func";
369 : }
370 :
371 508 : return NULL;
372 : }
373 : /************************************************************************/
374 : /* sort comparison functions. */
375 : /************************************************************************/
376 :
377 104 : static int FORCE_CDECL swq_compare_int( const void *item1, const void *item2 )
378 : {
379 : int v1, v2;
380 :
381 104 : const char* pszStr1 = *((const char **) item1);
382 104 : const char* pszStr2 = *((const char **) item2);
383 104 : if (pszStr1 == NULL)
384 0 : return (pszStr2 == NULL) ? 0 : -1;
385 104 : else if (pszStr2 == NULL)
386 20 : return 1;
387 :
388 84 : v1 = atoi(pszStr1);
389 84 : v2 = atoi(pszStr2);
390 :
391 84 : if( v1 < v2 )
392 32 : return -1;
393 52 : else if( v1 == v2 )
394 0 : return 0;
395 : else
396 52 : return 1;
397 : }
398 :
399 50 : static int FORCE_CDECL swq_compare_real( const void *item1, const void *item2 )
400 : {
401 : double v1, v2;
402 :
403 50 : const char* pszStr1 = *((const char **) item1);
404 50 : const char* pszStr2 = *((const char **) item2);
405 50 : if (pszStr1 == NULL)
406 0 : return (pszStr2 == NULL) ? 0 : -1;
407 50 : else if (pszStr2 == NULL)
408 4 : return 1;
409 :
410 46 : v1 = CPLAtof(pszStr1);
411 46 : v2 = CPLAtof(pszStr2);
412 :
413 46 : if( v1 < v2 )
414 18 : return -1;
415 28 : else if( v1 == v2 )
416 0 : return 0;
417 : else
418 28 : return 1;
419 : }
420 :
421 28 : static int FORCE_CDECL swq_compare_string( const void *item1, const void *item2 )
422 : {
423 28 : const char* pszStr1 = *((const char **) item1);
424 28 : const char* pszStr2 = *((const char **) item2);
425 28 : if (pszStr1 == NULL)
426 0 : return (pszStr2 == NULL) ? 0 : -1;
427 28 : else if (pszStr2 == NULL)
428 4 : return 1;
429 :
430 24 : return strcmp( pszStr1, pszStr2 );
431 : }
432 :
433 : /************************************************************************/
434 : /* swq_select_finish_summarize() */
435 : /* */
436 : /* Call to complete summarize work. Does stuff like ordering */
437 : /* the distinct list for instance. */
438 : /************************************************************************/
439 :
440 54 : const char *swq_select_finish_summarize( swq_select *select_info )
441 :
442 : {
443 : int (FORCE_CDECL *compare_func)(const void *, const void*);
444 54 : int count = 0;
445 54 : char **distinct_list = NULL;
446 :
447 54 : if( select_info->query_mode != SWQM_DISTINCT_LIST
448 : || select_info->order_specs == 0 )
449 32 : return NULL;
450 :
451 22 : if( select_info->order_specs > 1 )
452 0 : return "Can't ORDER BY a DISTINCT list by more than one key.";
453 :
454 44 : if( select_info->order_defs[0].field_index !=
455 22 : select_info->column_defs[0].field_index )
456 0 : return "Only selected DISTINCT field can be used for ORDER BY.";
457 :
458 22 : if( select_info->column_summary == NULL )
459 0 : return NULL;
460 :
461 22 : if( select_info->column_defs[0].field_type == SWQ_INTEGER )
462 8 : compare_func = swq_compare_int;
463 14 : else if( select_info->column_defs[0].field_type == SWQ_FLOAT )
464 8 : compare_func = swq_compare_real;
465 : else
466 6 : compare_func = swq_compare_string;
467 :
468 22 : distinct_list = select_info->column_summary[0].distinct_list;
469 22 : count = select_info->column_summary[0].count;
470 :
471 22 : qsort( distinct_list, count, sizeof(char *), compare_func );
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* Do we want the list ascending in stead of descending? */
475 : /* -------------------------------------------------------------------- */
476 22 : if( !select_info->order_defs[0].ascending_flag )
477 : {
478 : char *saved;
479 : int i;
480 :
481 42 : for( i = 0; i < count/2; i++ )
482 : {
483 30 : saved = distinct_list[i];
484 30 : distinct_list[i] = distinct_list[count-i-1];
485 30 : distinct_list[count-i-1] = saved;
486 : }
487 : }
488 :
489 22 : return NULL;
490 : }
491 :
492 : /************************************************************************/
493 : /* swq_select_free() */
494 : /************************************************************************/
495 :
496 0 : void swq_select_free( swq_select *select_info )
497 :
498 : {
499 0 : delete select_info;
500 0 : }
501 :
502 : /************************************************************************/
503 : /* swq_identify_field() */
504 : /************************************************************************/
505 :
506 5788 : int swq_identify_field( const char *token, swq_field_list *field_list,
507 : swq_field_type *this_type, int *table_id )
508 :
509 : {
510 : int i;
511 : char table_name[128];
512 5788 : const char *field_token = token;
513 : int tables_enabled;
514 :
515 10008 : if( field_list->table_count > 0 && field_list->table_ids != NULL )
516 4220 : tables_enabled = TRUE;
517 : else
518 1568 : tables_enabled = FALSE;
519 :
520 : /* -------------------------------------------------------------------- */
521 : /* Parse out table name if present, and table support enabled. */
522 : /* -------------------------------------------------------------------- */
523 5788 : table_name[0] = '\0';
524 5788 : if( tables_enabled && strchr(token, '.') != NULL )
525 : {
526 194 : int dot_offset = (int)(strchr(token,'.') - token);
527 :
528 194 : if( dot_offset < (int) sizeof(table_name) )
529 : {
530 194 : strncpy( table_name, token, dot_offset );
531 194 : table_name[dot_offset] = '\0';
532 194 : field_token = token + dot_offset + 1;
533 : }
534 : }
535 :
536 : /* -------------------------------------------------------------------- */
537 : /* Search for matching field. */
538 : /* -------------------------------------------------------------------- */
539 19484 : for( i = 0; i < field_list->count; i++ )
540 : {
541 18602 : int t_id = 0;
542 :
543 18602 : if( !EQUAL( field_list->names[i], field_token ) )
544 13628 : continue;
545 :
546 : /* Do the table specifications match? */
547 4974 : if( tables_enabled )
548 : {
549 3896 : t_id = field_list->table_ids[i];
550 4152 : if( table_name[0] != '\0'
551 256 : && !EQUAL(table_name,field_list->table_defs[t_id].table_alias))
552 68 : continue;
553 :
554 : // if( t_id != 0 && table_name[0] == '\0' )
555 : // continue;
556 : }
557 :
558 : /* We have a match, return various information */
559 4906 : if( this_type != NULL )
560 : {
561 4782 : if( field_list->types != NULL )
562 4782 : *this_type = field_list->types[i];
563 : else
564 0 : *this_type = SWQ_OTHER;
565 : }
566 :
567 4906 : if( table_id != NULL )
568 4906 : *table_id = t_id;
569 :
570 4906 : if( field_list->ids == NULL )
571 1078 : return i;
572 : else
573 3828 : return field_list->ids[i];
574 : }
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* No match, return failure. */
578 : /* -------------------------------------------------------------------- */
579 882 : if( this_type != NULL )
580 876 : *this_type = SWQ_OTHER;
581 :
582 882 : if( table_id != NULL )
583 882 : *table_id = 0;
584 :
585 882 : return -1;
586 : }
587 :
588 : /************************************************************************/
589 : /* swq_expr_compile() */
590 : /************************************************************************/
591 :
592 982 : CPLErr swq_expr_compile( const char *where_clause,
593 : int field_count,
594 : char **field_names,
595 : swq_field_type *field_types,
596 : swq_expr_node **expr_out )
597 :
598 : {
599 : swq_field_list field_list;
600 :
601 982 : field_list.count = field_count;
602 982 : field_list.names = field_names;
603 982 : field_list.types = field_types;
604 982 : field_list.table_ids = NULL;
605 982 : field_list.ids = NULL;
606 :
607 982 : field_list.table_count = 0;
608 982 : field_list.table_defs = NULL;
609 :
610 982 : return swq_expr_compile2( where_clause, &field_list, expr_out );
611 : }
612 :
613 :
614 : /************************************************************************/
615 : /* swq_expr_compile2() */
616 : /************************************************************************/
617 :
618 982 : CPLErr swq_expr_compile2( const char *where_clause,
619 : swq_field_list *field_list,
620 : swq_expr_node **expr_out )
621 :
622 : {
623 :
624 982 : swq_parse_context context;
625 :
626 982 : context.pszInput = where_clause;
627 982 : context.pszNext = where_clause;
628 982 : context.nStartToken = SWQT_LOGICAL_START;
629 :
630 982 : if( swqparse( &context ) == 0
631 : && context.poRoot->Check( field_list ) != SWQ_ERROR )
632 : {
633 982 : *expr_out = context.poRoot;
634 :
635 982 : return CE_None;
636 : }
637 : else
638 : {
639 0 : delete context.poRoot;
640 0 : *expr_out = NULL;
641 0 : return CE_Failure;
642 : }
643 : }
644 :
645 : /************************************************************************/
646 : /* swq_is_reserved_keyword() */
647 : /************************************************************************/
648 :
649 : static const char* apszSQLReservedKeywords[] = {
650 : "OR",
651 : "AND",
652 : "NOT",
653 : "LIKE",
654 : "IS",
655 : "NULL",
656 : "IN",
657 : "BETWEEN",
658 : "CAST",
659 : "DISTINCT",
660 : "ESCAPE",
661 : "SELECT",
662 : "LEFT",
663 : "JOIN",
664 : "WHERE",
665 : "ON",
666 : "ORDER",
667 : "BY",
668 : "FROM",
669 : "AS",
670 : "ASC",
671 : "DESC"
672 : };
673 :
674 346 : int swq_is_reserved_keyword(const char* pszStr)
675 : {
676 7958 : for(int i = 0; i < (int)(sizeof(apszSQLReservedKeywords)/sizeof(char*)); i++)
677 : {
678 7612 : if (EQUAL(pszStr, apszSQLReservedKeywords[i]))
679 0 : return TRUE;
680 : }
681 346 : return FALSE;
682 : }
|