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 <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 : #include <ctype.h>
25 :
26 : #include "cpl_conv.h"
27 : #include "cpl_multiproc.h"
28 : #include "swq.h"
29 :
30 : #ifndef SWQ_MALLOC
31 : #define SWQ_MALLOC(x) malloc(x)
32 : #define SWQ_FREE(x) free(x)
33 : #endif
34 :
35 : #ifdef _MSC_VER
36 : # define FORCE_CDECL __cdecl
37 : #else
38 : # define FORCE_CDECL
39 : #endif
40 :
41 : #ifndef TRUE
42 : # define TRUE 1
43 : #endif
44 :
45 : #ifndef FALSE
46 : # define FALSE 0
47 : #endif
48 :
49 : #if defined(_WIN32) && !defined(_WIN32_WCE)
50 : # define strcasecmp stricmp
51 : #elif defined(_WIN32_WCE)
52 : # define strcasecmp _stricmp
53 : #endif
54 :
55 :
56 : #define SWQ_OP_IS_LOGICAL(op) ((op) == SWQ_OR || (op) == SWQ_AND || (op) == SWQ_NOT)
57 : #define SWQ_OP_IS_POSTUNARY(op) ((op) == SWQ_ISNULL || (op) == SWQ_ISNOTNULL)
58 :
59 : /************************************************************************/
60 : /* swq_free() */
61 : /************************************************************************/
62 :
63 8 : void swq_free( void *pMemory )
64 :
65 : {
66 8 : SWQ_FREE( pMemory );
67 8 : }
68 :
69 : /************************************************************************/
70 : /* swq_malloc() */
71 : /************************************************************************/
72 :
73 128 : void *swq_malloc( int nSize )
74 :
75 : {
76 128 : return SWQ_MALLOC(nSize);
77 : }
78 :
79 : /************************************************************************/
80 : /* swq_realloc() */
81 : /************************************************************************/
82 :
83 104 : void *swq_realloc( void *old_mem, int old_size, int new_size )
84 :
85 : {
86 : void *new_mem;
87 :
88 104 : new_mem = swq_malloc( new_size );
89 :
90 104 : if( old_mem != NULL )
91 : {
92 43 : memcpy( new_mem, old_mem, old_size < new_size ? old_size : new_size);
93 43 : SWQ_FREE( old_mem );
94 : }
95 104 : if (old_size <= new_size )
96 104 : memset( ((char *) new_mem) + old_size, 0, new_size - old_size );
97 :
98 104 : return new_mem;
99 : }
100 :
101 : /************************************************************************/
102 : /* swq_get_errbuf() */
103 : /************************************************************************/
104 :
105 : #define SWQ_SIZEOF_ERRBUF 1024
106 :
107 : #define SNPRINTF_ERR1(x) do { char* pszErrBuf = swq_get_errbuf(); snprintf( pszErrBuf, SWQ_SIZEOF_ERRBUF, x); pszErrBuf[SWQ_SIZEOF_ERRBUF-1] = '\0'; } while(0)
108 : #define SNPRINTF_ERR2(x,y) do { char* pszErrBuf = swq_get_errbuf(); snprintf( pszErrBuf, SWQ_SIZEOF_ERRBUF, x, y); pszErrBuf[SWQ_SIZEOF_ERRBUF-1] = '\0'; } while(0)
109 : #define SNPRINTF_ERR3(x,y,z) do { char* pszErrBuf = swq_get_errbuf(); snprintf( pszErrBuf, SWQ_SIZEOF_ERRBUF, x, y, z); pszErrBuf[SWQ_SIZEOF_ERRBUF-1] = '\0'; } while(0)
110 :
111 2 : char *swq_get_errbuf()
112 :
113 : {
114 2 : char *pszStaticResult = (char *) CPLGetTLS( CTLS_SWQ_ERRBUF );
115 2 : if( pszStaticResult == NULL )
116 : {
117 1 : pszStaticResult = (char *) CPLMalloc(SWQ_SIZEOF_ERRBUF);
118 1 : CPLSetTLS( CTLS_SWQ_ERRBUF, pszStaticResult, TRUE );
119 : }
120 :
121 2 : return pszStaticResult;
122 : }
123 :
124 : /************************************************************************/
125 : /* swq_isalphanum() */
126 : /* */
127 : /* Is the passed character in the set of things that could */
128 : /* occur in an alphanumeric token, or a number? */
129 : /************************************************************************/
130 :
131 5302 : static int swq_isalphanum( char c )
132 :
133 : {
134 5302 : if( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
135 : || (c >= '0' && c <= '9') || c == '.' || c == '+' || c == '-'
136 : || c == '_' || c == '*' || ((unsigned char) c) > 127 )
137 4263 : return TRUE;
138 : else
139 1039 : return FALSE;
140 : }
141 :
142 : /************************************************************************/
143 : /* swq_token() */
144 : /************************************************************************/
145 :
146 1279 : static char *swq_token( const char *expression, char **next, int *is_literal )
147 :
148 : {
149 : char *token;
150 : int i_token;
151 :
152 1279 : if( is_literal != NULL )
153 522 : *is_literal = 0;
154 :
155 5910 : while( *expression == ' ' || *expression == '\t'
156 2558 : || *expression == 10 || *expression == 13 )
157 794 : expression++;
158 :
159 1279 : if( *expression == '\0' )
160 : {
161 198 : *next = (char *) expression;
162 198 : return NULL;
163 : }
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Handle string constants. */
167 : /* -------------------------------------------------------------------- */
168 1123 : if( *expression == '"' || *expression == '\'' )
169 : {
170 42 : expression++;
171 :
172 42 : token = (char *) SWQ_MALLOC(strlen(expression)+1);
173 42 : i_token = 0;
174 :
175 299 : while( *expression != '\0' )
176 : {
177 257 : if( *expression == '\\' && expression[1] == '"' )
178 0 : expression++;
179 257 : else if( *expression == '\\' && expression[1] == '\'' )
180 0 : expression++;
181 257 : else if( *expression == '\'' && expression[1] == '\'' )
182 0 : expression++;
183 257 : else if( *expression == '"' )
184 : {
185 19 : expression++;
186 19 : break;
187 : }
188 238 : else if( *expression == '\'' )
189 : {
190 23 : expression++;
191 23 : break;
192 : }
193 :
194 215 : token[i_token++] = *(expression++);
195 : }
196 42 : token[i_token] = '\0';
197 :
198 42 : if( is_literal != NULL )
199 12 : *is_literal = 1;
200 : }
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Handle alpha-numerics. */
204 : /* -------------------------------------------------------------------- */
205 1039 : else if( swq_isalphanum( *expression ) )
206 : {
207 786 : token = (char *) SWQ_MALLOC(strlen(expression)+1);
208 786 : i_token = 0;
209 :
210 5049 : while( swq_isalphanum( *expression ) )
211 : {
212 3477 : token[i_token++] = *(expression++);
213 : }
214 :
215 786 : token[i_token] = '\0';
216 : }
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Handle special tokens. */
220 : /* -------------------------------------------------------------------- */
221 : else
222 : {
223 253 : token = (char *) SWQ_MALLOC(3);
224 253 : token[0] = *expression;
225 253 : token[1] = '\0';
226 253 : expression++;
227 :
228 : /* special logic to group stuff like '>=' into one token. */
229 :
230 826 : if( (*token == '<' || *token == '>' || *token == '=' || *token == '!')
231 573 : && (*expression == '<' || *expression == '>' || *expression == '='))
232 : {
233 0 : token[1] = *expression;
234 0 : token[2] = '\0';
235 0 : expression++;
236 : }
237 : }
238 :
239 1081 : *next = (char *) expression;
240 :
241 1081 : return token;
242 : }
243 :
244 : /************************************************************************/
245 : /* swq_strdup() */
246 : /************************************************************************/
247 :
248 421 : static char *swq_strdup( const char *input )
249 :
250 : {
251 : char *result;
252 :
253 421 : result = (char *) SWQ_MALLOC(strlen(input)+1);
254 421 : strcpy( result, input );
255 :
256 421 : return result;
257 : }
258 :
259 : /************************************************************************/
260 : /* ==================================================================== */
261 : /* WHERE clause parsing */
262 : /* ==================================================================== */
263 : /************************************************************************/
264 :
265 : /************************************************************************/
266 : /* swq_test_like() */
267 : /* */
268 : /* Does input match pattern? */
269 : /************************************************************************/
270 :
271 90 : int swq_test_like( const char *input, const char *pattern )
272 :
273 : {
274 90 : if( input == NULL || pattern == NULL )
275 0 : return 0;
276 :
277 221 : while( *input != '\0' )
278 : {
279 129 : if( *pattern == '\0' )
280 0 : return 0;
281 :
282 129 : else if( *pattern == '_' )
283 : {
284 0 : input++;
285 0 : pattern++;
286 : }
287 129 : else if( *pattern == '%' )
288 : {
289 : int eat;
290 :
291 12 : if( pattern[1] == '\0' )
292 2 : return 1;
293 :
294 : /* try eating varying amounts of the input till we get a positive*/
295 87 : for( eat = 0; input[eat] != '\0'; eat++ )
296 : {
297 78 : if( swq_test_like(input+eat,pattern+1) )
298 1 : return 1;
299 : }
300 :
301 9 : return 0;
302 : }
303 : else
304 : {
305 117 : if( tolower(*pattern) != tolower(*input) )
306 76 : return 0;
307 : else
308 : {
309 41 : input++;
310 41 : pattern++;
311 : }
312 : }
313 : }
314 :
315 2 : if( *pattern != '\0' && strcmp(pattern,"%") != 0 )
316 1 : return 0;
317 : else
318 1 : return 1;
319 : }
320 :
321 : /************************************************************************/
322 : /* swq_identify_op() */
323 : /************************************************************************/
324 :
325 191 : static swq_op swq_identify_op( char **tokens, int *tokens_consumed )
326 :
327 : {
328 191 : const char *token = tokens[*tokens_consumed];
329 :
330 191 : if( strcasecmp(token,"OR") == 0 )
331 0 : return SWQ_OR;
332 :
333 191 : if( strcasecmp(token,"AND") == 0 )
334 21 : return SWQ_AND;
335 :
336 170 : if( strcasecmp(token,"NOT") == 0 )
337 : {
338 0 : if( tokens[*tokens_consumed+1] != NULL
339 0 : && (strcasecmp(tokens[*tokens_consumed+1],"LIKE") == 0
340 0 : || strcasecmp(tokens[*tokens_consumed+1],"ILIKE") == 0) )
341 : {
342 0 : *tokens_consumed += 1;
343 0 : return SWQ_NOTLIKE;
344 : }
345 0 : else if( tokens[*tokens_consumed+1] != NULL
346 0 : && strcasecmp(tokens[*tokens_consumed+1],"IN") == 0 )
347 : {
348 0 : *tokens_consumed += 1;
349 0 : return SWQ_NOTIN;
350 : }
351 : else
352 0 : return SWQ_NOT;
353 : }
354 :
355 170 : if( strcasecmp(token,"<=") == 0 )
356 0 : return SWQ_LE;
357 :
358 170 : if( strcasecmp(token,">=") == 0 )
359 0 : return SWQ_GE;
360 :
361 170 : if( strcasecmp(token,"=") == 0 )
362 97 : return SWQ_EQ;
363 :
364 73 : if( strcasecmp(token,"!=") == 0 )
365 0 : return SWQ_NE;
366 :
367 73 : if( strcasecmp(token,"<>") == 0 )
368 0 : return SWQ_NE;
369 :
370 73 : if( strcasecmp(token,"<") == 0 )
371 31 : return SWQ_LT;
372 :
373 42 : if( strcasecmp(token,">") == 0 )
374 31 : return SWQ_GT;
375 :
376 11 : if( strcasecmp(token,"LIKE") == 0 )
377 2 : return SWQ_LIKE;
378 :
379 9 : if( strcasecmp(token,"ILIKE") == 0 )
380 2 : return SWQ_LIKE;
381 :
382 7 : if( strcasecmp(token,"IN") == 0 )
383 7 : return SWQ_IN;
384 :
385 0 : if( strcasecmp(token,"IS") == 0 )
386 : {
387 0 : if( tokens[*tokens_consumed+1] == NULL )
388 0 : return SWQ_UNKNOWN;
389 0 : else if( strcasecmp(tokens[*tokens_consumed+1],"NULL") == 0 )
390 : {
391 0 : *tokens_consumed += 1;
392 0 : return SWQ_ISNULL;
393 : }
394 0 : else if( strcasecmp(tokens[*tokens_consumed+1],"NOT") == 0
395 0 : && tokens[*tokens_consumed+2] != NULL
396 0 : && strcasecmp(tokens[*tokens_consumed+2],"NULL") == 0 )
397 : {
398 0 : *tokens_consumed += 2;
399 0 : return SWQ_ISNOTNULL;
400 : }
401 : else
402 0 : return SWQ_UNKNOWN;
403 : }
404 :
405 0 : return SWQ_UNKNOWN;
406 : }
407 :
408 : /************************************************************************/
409 : /* swq_identify_field() */
410 : /************************************************************************/
411 :
412 342 : static int swq_identify_field( const char *token, swq_field_list *field_list,
413 : swq_field_type *this_type, int *table_id )
414 :
415 : {
416 : int i;
417 : char table_name[128];
418 342 : const char *field_token = token;
419 : int tables_enabled;
420 :
421 538 : if( field_list->table_count > 0 && field_list->table_ids != NULL )
422 196 : tables_enabled = TRUE;
423 : else
424 146 : tables_enabled = FALSE;
425 :
426 : /* -------------------------------------------------------------------- */
427 : /* Parse out table name if present, and table support enabled. */
428 : /* -------------------------------------------------------------------- */
429 342 : table_name[0] = '\0';
430 342 : if( tables_enabled && strchr(token, '.') != NULL )
431 : {
432 59 : int dot_offset = (int)(strchr(token,'.') - token);
433 :
434 59 : if( dot_offset < sizeof(table_name) )
435 : {
436 59 : strncpy( table_name, token, dot_offset );
437 59 : table_name[dot_offset] = '\0';
438 59 : field_token = token + dot_offset + 1;
439 : }
440 : }
441 :
442 : /* -------------------------------------------------------------------- */
443 : /* Search for matching field. */
444 : /* -------------------------------------------------------------------- */
445 852 : for( i = 0; i < field_list->count; i++ )
446 : {
447 851 : int t_id = 0;
448 :
449 851 : if( strcasecmp( field_list->names[i], field_token ) != 0 )
450 493 : continue;
451 :
452 : /* Do the table specifications match? */
453 358 : if( tables_enabled )
454 : {
455 212 : t_id = field_list->table_ids[i];
456 288 : if( table_name[0] != '\0'
457 : && strcasecmp(table_name,
458 76 : field_list->table_defs[t_id].table_alias) != 0 )
459 17 : continue;
460 :
461 : #ifdef notdef
462 : if( t_id != 0 && table_name[0] == '\0' )
463 : continue;
464 : #endif
465 : }
466 :
467 : /* We have a match, return various information */
468 341 : if( this_type != NULL )
469 : {
470 304 : if( field_list->types != NULL )
471 304 : *this_type = field_list->types[i];
472 : else
473 0 : *this_type = SWQ_OTHER;
474 : }
475 :
476 341 : if( table_id != NULL )
477 341 : *table_id = t_id;
478 :
479 341 : if( field_list->ids == NULL )
480 146 : return i;
481 : else
482 195 : return field_list->ids[i];
483 : }
484 :
485 : /* -------------------------------------------------------------------- */
486 : /* No match, return failure. */
487 : /* -------------------------------------------------------------------- */
488 1 : if( this_type != NULL )
489 1 : *this_type = SWQ_OTHER;
490 :
491 1 : if( table_id != NULL )
492 1 : *table_id = 0;
493 :
494 1 : return -1;
495 : }
496 :
497 : /************************************************************************/
498 : /* swq_parse_in_list() */
499 : /* */
500 : /* Parse the argument list to the IN predicate. Might be used */
501 : /* something like: */
502 : /* */
503 : /* WHERE color IN ('Red', 'Green', 'Blue') */
504 : /************************************************************************/
505 :
506 7 : static char *swq_parse_in_list( char **tokens, int *tokens_consumed )
507 :
508 : {
509 7 : int i, text_off = 2;
510 : char *result;
511 :
512 14 : if( tokens[*tokens_consumed] == NULL
513 7 : || strcasecmp(tokens[*tokens_consumed],"(") != 0 )
514 : {
515 0 : SNPRINTF_ERR1("IN argument doesn't start with '('." );
516 0 : return NULL;
517 : }
518 :
519 7 : *tokens_consumed += 1;
520 :
521 : /* Establish length of all tokens plus separators. */
522 :
523 63 : for( i = *tokens_consumed;
524 56 : tokens[i] != NULL && strcasecmp(tokens[i],")") != 0;
525 21 : i++ )
526 : {
527 21 : text_off += strlen(tokens[i]) + 1;
528 : }
529 :
530 7 : result = (char *) SWQ_MALLOC(text_off);
531 :
532 : /* Actually capture all the arguments. */
533 :
534 7 : text_off = 0;
535 49 : while( tokens[*tokens_consumed] != NULL
536 21 : && strcasecmp(tokens[*tokens_consumed],")") != 0 )
537 : {
538 14 : strcpy( result + text_off, tokens[*tokens_consumed] );
539 14 : text_off += strlen(tokens[*tokens_consumed]) + 1;
540 :
541 14 : *tokens_consumed += 1;
542 :
543 35 : if( strcasecmp(tokens[*tokens_consumed],",") != 0
544 21 : && strcasecmp(tokens[*tokens_consumed],")") != 0 )
545 : {
546 0 : SNPRINTF_ERR1("Contents of IN predicate missing comma or closing bracket." );
547 0 : SWQ_FREE( result );
548 0 : return NULL;
549 : }
550 14 : else if( strcasecmp(tokens[*tokens_consumed],",") == 0 )
551 7 : *tokens_consumed += 1;
552 : }
553 :
554 : /* add final extra terminating zero char */
555 7 : result[text_off] = '\0';
556 :
557 7 : if( tokens[*tokens_consumed] == NULL )
558 : {
559 0 : SNPRINTF_ERR1("Contents of IN predicate missing closing bracket." );
560 0 : SWQ_FREE( result );
561 0 : return NULL;
562 : }
563 :
564 7 : *tokens_consumed += 1;
565 :
566 7 : return result;
567 : }
568 :
569 :
570 : /************************************************************************/
571 : /* swq_subexpr_compile() */
572 : /************************************************************************/
573 :
574 : static const char *
575 170 : swq_subexpr_compile( char **tokens, swq_field_list *field_list,
576 : swq_expr **expr_out, int *tokens_consumed )
577 :
578 : {
579 : swq_expr *op;
580 : const char *error;
581 170 : int op_code = 0;
582 :
583 170 : *tokens_consumed = 0;
584 170 : *expr_out = NULL;
585 :
586 170 : if( tokens[0] == NULL || tokens[1] == NULL )
587 : {
588 0 : SNPRINTF_ERR1("Not enough tokens to complete expression." );
589 0 : return swq_get_errbuf();
590 : }
591 :
592 170 : op = (swq_field_op *) SWQ_MALLOC(sizeof(swq_field_op));
593 170 : memset( op, 0, sizeof(swq_field_op) );
594 170 : op->field_index = -1;
595 :
596 170 : if( strcmp(tokens[0],"(") == 0 )
597 : {
598 0 : int sub_consumed = 0;
599 :
600 0 : error = swq_subexpr_compile( tokens + 1, field_list,
601 0 : (swq_expr **) &(op->first_sub_expr),
602 : &sub_consumed );
603 0 : if( error != NULL )
604 : {
605 0 : swq_expr_free( op );
606 0 : return error;
607 : }
608 :
609 0 : if( strcmp(tokens[sub_consumed+1],")") != 0 )
610 : {
611 0 : swq_expr_free( op );
612 0 : SNPRINTF_ERR1("Unclosed brackets, or incomplete expression.");
613 0 : return swq_get_errbuf();
614 : }
615 :
616 0 : *tokens_consumed += sub_consumed + 2;
617 :
618 : /* If we are at the end of the tokens, we should return our subnode */
619 0 : if( tokens[*tokens_consumed] == NULL
620 0 : || strcmp(tokens[*tokens_consumed],")") == 0 )
621 : {
622 0 : *expr_out = (swq_expr *) op->first_sub_expr;
623 0 : op->first_sub_expr = NULL;
624 0 : swq_expr_free( op );
625 0 : return NULL;
626 : }
627 : }
628 170 : else if( strcasecmp(tokens[0],"NOT") == 0 )
629 : {
630 : /* do nothing, the NOT will be collected as the operation */
631 : }
632 : else
633 : {
634 170 : op->field_index =
635 170 : swq_identify_field( tokens[*tokens_consumed], field_list,
636 : &(op->field_type),
637 : &(op->table_index) );
638 :
639 170 : if( op->field_index < 0 )
640 : {
641 0 : swq_expr_free( op );
642 0 : SNPRINTF_ERR2( "Failed to identify field:%s", tokens[*tokens_consumed] );
643 0 : return swq_get_errbuf();
644 : }
645 :
646 170 : (*tokens_consumed)++;
647 : }
648 :
649 : /*
650 : ** Identify the operation.
651 : */
652 170 : if( tokens[*tokens_consumed] == NULL || tokens[*tokens_consumed+1] == NULL)
653 : {
654 0 : swq_expr_free( op );
655 0 : SNPRINTF_ERR1( "Not enough tokens to complete expression." );
656 0 : return swq_get_errbuf();
657 : }
658 :
659 170 : op->operation = swq_identify_op( tokens, tokens_consumed );
660 170 : if( op->operation == SWQ_UNKNOWN )
661 : {
662 0 : swq_expr_free( op );
663 0 : SNPRINTF_ERR2( "Failed to identify operation:%s", tokens[*tokens_consumed] );
664 0 : return swq_get_errbuf();
665 : }
666 :
667 170 : if( SWQ_OP_IS_LOGICAL( op->operation )
668 : && op->first_sub_expr == NULL
669 0 : && op->operation != SWQ_NOT )
670 : {
671 0 : swq_expr_free( op );
672 0 : SNPRINTF_ERR1( "Used logical operation with non-logical operand.");
673 0 : return swq_get_errbuf();
674 : }
675 :
676 417 : if( op->field_index != -1 && op->field_type == SWQ_STRING
677 209 : && (op->operation != SWQ_EQ && op->operation != SWQ_NE
678 14 : && op->operation != SWQ_GT && op->operation != SWQ_LT
679 12 : && op->operation != SWQ_GE && op->operation != SWQ_LE
680 10 : && op->operation != SWQ_LIKE && op->operation != SWQ_NOTLIKE
681 2 : && op->operation != SWQ_IN && op->operation != SWQ_NOTIN
682 0 : && op->operation != SWQ_ISNULL && op->operation != SWQ_ISNOTNULL ))
683 : {
684 : /* NOTE: the use of names[] here is wrong. We should be looking
685 : up the field that matches op->field_index and op->table_index */
686 :
687 0 : SNPRINTF_ERR3(
688 : "Attempt to use STRING field `%s' with numeric comparison `%s'.",
689 : field_list->names[op->field_index], tokens[*tokens_consumed] );
690 0 : swq_expr_free( op );
691 0 : return swq_get_errbuf();
692 : }
693 :
694 170 : (*tokens_consumed)++;
695 :
696 : /*
697 : ** Collect the second operand as a subexpression.
698 : */
699 :
700 170 : if( SWQ_OP_IS_POSTUNARY(op->operation) )
701 : {
702 : /* we don't need another argument. */
703 : }
704 :
705 170 : else if( tokens[*tokens_consumed] == NULL )
706 : {
707 0 : SNPRINTF_ERR1( "Not enough tokens to complete expression." );
708 0 : swq_expr_free( op );
709 0 : return swq_get_errbuf();
710 : }
711 :
712 170 : else if( SWQ_OP_IS_LOGICAL( op->operation ) )
713 : {
714 0 : int sub_consumed = 0;
715 :
716 0 : error = swq_subexpr_compile( tokens + *tokens_consumed, field_list,
717 0 : (swq_expr **) &(op->second_sub_expr),
718 : &sub_consumed );
719 0 : if( error != NULL )
720 : {
721 0 : swq_expr_free( op );
722 0 : return error;
723 : }
724 :
725 0 : *tokens_consumed += sub_consumed;
726 : }
727 :
728 : /* The IN predicate has a complex argument syntax. */
729 177 : else if( op->operation == SWQ_IN || op->operation == SWQ_NOTIN )
730 : {
731 7 : op->string_value = swq_parse_in_list( tokens, tokens_consumed );
732 7 : if( op->string_value == NULL )
733 : {
734 0 : swq_expr_free( op );
735 0 : return swq_get_errbuf();
736 : }
737 : }
738 :
739 : /*
740 : ** Otherwise collect it as a literal value.
741 : */
742 : else
743 : {
744 163 : op->string_value = swq_strdup(tokens[*tokens_consumed]);
745 163 : op->int_value = atoi(op->string_value);
746 163 : op->float_value = atof(op->string_value);
747 :
748 1058 : if( op->field_index != -1
749 433 : && (op->field_type == SWQ_INTEGER || op->field_type == SWQ_FLOAT)
750 125 : && op->string_value[0] != '-'
751 250 : && op->string_value[0] != '+'
752 250 : && op->string_value[0] != '.'
753 375 : && (op->string_value[0] < '0' || op->string_value[0] > '9') )
754 : {
755 : /* NOTE: the use of names[] here is wrong. We should be looking
756 : up the field that matches op->field_index and op->table_index */
757 :
758 0 : SNPRINTF_ERR3(
759 : "Attempt to compare numeric field `%s' to non-numeric"
760 : " value `%s' is illegal.",
761 : field_list->names[op->field_index], op->string_value );
762 0 : swq_expr_free( op );
763 0 : return swq_get_errbuf();
764 : }
765 :
766 163 : (*tokens_consumed)++;
767 : }
768 :
769 170 : *expr_out = op;
770 :
771 : /* Transform stuff like A NOT LIKE X into NOT (A LIKE X) */
772 510 : if( op->operation == SWQ_NOTLIKE
773 170 : || op->operation == SWQ_ISNOTNULL
774 340 : || op->operation == SWQ_NOTIN )
775 : {
776 0 : if( op->operation == SWQ_NOTLIKE )
777 0 : op->operation = SWQ_LIKE;
778 0 : else if( op->operation == SWQ_NOTIN )
779 0 : op->operation = SWQ_IN;
780 0 : else if( op->operation == SWQ_ISNOTNULL )
781 0 : op->operation = SWQ_ISNULL;
782 :
783 0 : op = (swq_field_op *) SWQ_MALLOC(sizeof(swq_field_op));
784 0 : memset( op, 0, sizeof(swq_field_op) );
785 0 : op->field_index = -1;
786 0 : op->second_sub_expr = (struct swq_node_s *) *expr_out;
787 0 : op->operation = SWQ_NOT;
788 :
789 0 : *expr_out = op;
790 : }
791 :
792 170 : op = NULL;
793 :
794 : /*
795 : ** Are we part of an unparantized logical expression chain? If so,
796 : ** grab the remainder of the expression at "this level" and add to the
797 : ** local tree.
798 : */
799 170 : op_code = SWQ_UNKNOWN;
800 170 : if( tokens[*tokens_consumed] != NULL )
801 21 : op_code = swq_identify_op( tokens, tokens_consumed );
802 :
803 170 : if( SWQ_OP_IS_LOGICAL(op_code) )
804 : {
805 21 : swq_expr *remainder = NULL;
806 : swq_expr *parent;
807 : int sub_consumed;
808 :
809 21 : error = swq_subexpr_compile( tokens + *tokens_consumed + 1, field_list,
810 : &remainder, &sub_consumed );
811 21 : if( error != NULL )
812 : {
813 0 : swq_expr_free( *expr_out );
814 0 : *expr_out = NULL;
815 0 : return error;
816 : }
817 :
818 21 : parent = (swq_field_op *) SWQ_MALLOC(sizeof(swq_field_op));
819 21 : memset( parent, 0, sizeof(swq_field_op) );
820 21 : parent->field_index = -1;
821 :
822 21 : parent->first_sub_expr = (struct swq_node_s *) *expr_out;
823 21 : parent->second_sub_expr = (struct swq_node_s *) remainder;
824 21 : parent->operation = op_code;
825 :
826 21 : *expr_out = parent;
827 :
828 21 : *tokens_consumed += sub_consumed + 1;
829 : }
830 :
831 170 : return NULL;
832 : }
833 :
834 : /************************************************************************/
835 : /* swq_expr_compile() */
836 : /************************************************************************/
837 :
838 126 : const char *swq_expr_compile( const char *where_clause,
839 : int field_count,
840 : char **field_names,
841 : swq_field_type *field_types,
842 : swq_expr **expr_out )
843 :
844 : {
845 : swq_field_list field_list;
846 :
847 126 : field_list.count = field_count;
848 126 : field_list.names = field_names;
849 126 : field_list.types = field_types;
850 126 : field_list.table_ids = NULL;
851 126 : field_list.ids = NULL;
852 :
853 126 : field_list.table_count = 0;
854 126 : field_list.table_defs = NULL;
855 :
856 126 : return swq_expr_compile2( where_clause, &field_list, expr_out );
857 : }
858 :
859 :
860 : /************************************************************************/
861 : /* swq_expr_compile2() */
862 : /************************************************************************/
863 :
864 149 : const char *swq_expr_compile2( const char *where_clause,
865 : swq_field_list *field_list,
866 : swq_expr **expr_out )
867 :
868 : {
869 : #define TOKEN_BLOCK_SIZE 1024
870 : char **token_list, *rest_of_expr;
871 149 : int token_count = 0;
872 : int tokens_consumed, i, token_list_size;
873 : const char *error;
874 :
875 : /*
876 : ** Collect token array.
877 : */
878 149 : token_list = (char **)SWQ_MALLOC(sizeof(char *) * TOKEN_BLOCK_SIZE);
879 149 : token_list_size = TOKEN_BLOCK_SIZE;
880 149 : rest_of_expr = (char *) where_clause;
881 1565 : while( (token_list[token_count] =
882 708 : swq_token(rest_of_expr,&rest_of_expr,NULL)) != NULL )
883 : {
884 559 : token_count++;
885 559 : if (token_count == token_list_size)
886 : {
887 0 : token_list = (char **)swq_realloc(token_list,
888 0 : sizeof(char *) * token_list_size,
889 : sizeof(char *) * (token_list_size + TOKEN_BLOCK_SIZE));
890 0 : token_list_size += TOKEN_BLOCK_SIZE;
891 : }
892 : }
893 :
894 : /*
895 : ** Parse the expression.
896 : */
897 149 : *expr_out = NULL;
898 149 : error =
899 149 : swq_subexpr_compile( token_list, field_list, expr_out,
900 : &tokens_consumed );
901 :
902 708 : for( i = 0; i < token_count; i++ )
903 559 : SWQ_FREE( token_list[i] );
904 :
905 149 : SWQ_FREE(token_list);
906 :
907 149 : if( error != NULL )
908 0 : return error;
909 :
910 149 : if( tokens_consumed < token_count )
911 : {
912 0 : swq_expr_free( *expr_out );
913 0 : *expr_out = NULL;
914 0 : SNPRINTF_ERR2( "Syntax error, %d extra tokens",
915 : token_count - tokens_consumed );
916 0 : return swq_get_errbuf();
917 : }
918 :
919 149 : return NULL;
920 : }
921 :
922 : /************************************************************************/
923 : /* swq_expr_free() */
924 : /************************************************************************/
925 :
926 191 : void swq_expr_free( swq_expr *expr )
927 :
928 : {
929 191 : if( expr == NULL )
930 0 : return;
931 :
932 191 : if( expr->first_sub_expr != NULL )
933 21 : swq_expr_free( (swq_expr *) expr->first_sub_expr );
934 191 : if( expr->second_sub_expr != NULL )
935 21 : swq_expr_free( (swq_expr *) expr->second_sub_expr );
936 :
937 191 : if( expr->string_value != NULL )
938 170 : SWQ_FREE( expr->string_value );
939 :
940 191 : SWQ_FREE( expr );
941 : }
942 :
943 : /************************************************************************/
944 : /* swq_expr_evaluate() */
945 : /************************************************************************/
946 :
947 1075 : int swq_expr_evaluate( swq_expr *expr, swq_op_evaluator fn_evaluator,
948 : void *record_handle )
949 :
950 : {
951 1075 : if( expr->operation == SWQ_OR )
952 : {
953 0 : return swq_expr_evaluate( (swq_expr *) expr->first_sub_expr,
954 : fn_evaluator,
955 : record_handle)
956 0 : || swq_expr_evaluate( (swq_expr *) expr->second_sub_expr,
957 : fn_evaluator,
958 0 : record_handle);
959 : }
960 1075 : else if( expr->operation == SWQ_AND )
961 : {
962 67 : return swq_expr_evaluate( (swq_expr *) expr->first_sub_expr,
963 : fn_evaluator,
964 : record_handle)
965 43 : && swq_expr_evaluate( (swq_expr *) expr->second_sub_expr,
966 : fn_evaluator,
967 24 : record_handle);
968 : }
969 1032 : else if( expr->operation == SWQ_NOT )
970 : {
971 0 : return !swq_expr_evaluate( (swq_expr *) expr->second_sub_expr,
972 : fn_evaluator,
973 : record_handle);
974 : }
975 : else
976 : {
977 1032 : return fn_evaluator( expr, record_handle );
978 : }
979 : }
980 :
981 : /************************************************************************/
982 : /* swq_expr_dump() */
983 : /************************************************************************/
984 :
985 0 : void swq_expr_dump( swq_expr *expr, FILE * fp, int depth )
986 :
987 : {
988 : char spaces[60];
989 : int i;
990 0 : const char *op_name = "unknown";
991 :
992 0 : for( i = 0; i < depth*2 && i < sizeof(spaces); i++ )
993 0 : spaces[i] = ' ';
994 0 : spaces[i] = '\0';
995 :
996 : /*
997 : ** first term.
998 : */
999 0 : if( expr->first_sub_expr != NULL )
1000 0 : swq_expr_dump( (swq_expr *) expr->first_sub_expr, fp, depth + 1 );
1001 : else
1002 0 : fprintf( fp, "%s Field %d\n", spaces, expr->field_index );
1003 :
1004 : /*
1005 : ** Operation.
1006 : */
1007 0 : if( expr->operation == SWQ_OR )
1008 0 : op_name = "OR";
1009 0 : if( expr->operation == SWQ_AND )
1010 0 : op_name = "AND";
1011 0 : if( expr->operation == SWQ_NOT)
1012 0 : op_name = "NOT";
1013 0 : if( expr->operation == SWQ_GT )
1014 0 : op_name = ">";
1015 0 : if( expr->operation == SWQ_LT )
1016 0 : op_name = "<";
1017 0 : if( expr->operation == SWQ_EQ )
1018 0 : op_name = "=";
1019 0 : if( expr->operation == SWQ_NE )
1020 0 : op_name = "!=";
1021 0 : if( expr->operation == SWQ_GE )
1022 0 : op_name = ">=";
1023 0 : if( expr->operation == SWQ_LE )
1024 0 : op_name = "<=";
1025 0 : if( expr->operation == SWQ_LIKE )
1026 0 : op_name = "LIKE";
1027 0 : if( expr->operation == SWQ_ISNULL )
1028 0 : op_name = "IS NULL";
1029 0 : if( expr->operation == SWQ_IN )
1030 0 : op_name = "IN";
1031 :
1032 0 : fprintf( fp, "%s%s\n", spaces, op_name );
1033 :
1034 : /*
1035 : ** Second term.
1036 : */
1037 0 : if( expr->second_sub_expr != NULL )
1038 0 : swq_expr_dump( (swq_expr *) expr->second_sub_expr, fp, depth + 1 );
1039 0 : else if( expr->operation == SWQ_IN || expr->operation == SWQ_NOTIN )
1040 : {
1041 : const char *src;
1042 :
1043 0 : fprintf( fp, "%s (\"%s\"", spaces, expr->string_value );
1044 0 : src = expr->string_value + strlen(expr->string_value) + 1;
1045 0 : while( *src != '\0' )
1046 : {
1047 0 : fprintf( fp, ",\"%s\"", src );
1048 0 : src += strlen(src) + 1;
1049 : }
1050 :
1051 0 : fprintf( fp, ")\n" );
1052 : }
1053 0 : else if( expr->string_value != NULL )
1054 0 : fprintf( fp, "%s %s\n", spaces, expr->string_value );
1055 0 : }
1056 :
1057 : /************************************************************************/
1058 : /* ==================================================================== */
1059 : /* SELECT statement parsing */
1060 : /* ==================================================================== */
1061 : /************************************************************************/
1062 :
1063 : /*
1064 : Supported SQL Syntax:
1065 :
1066 : SELECT <field-list> FROM <table_def>
1067 : [LEFT JOIN <table_def>
1068 : ON [<table_ref>.]<key_field> = [<table_ref>.].<key_field>]*
1069 : [WHERE <where-expr>]
1070 : [ORDER BY <sort specification list>]
1071 :
1072 : <field-list> ::= <column-spec> [ { , <column-spec> }... ]
1073 :
1074 : <column-spec> ::= <field-spec> [ <as clause> ]
1075 : | CAST ( <field-spec> AS <data type> ) [ <as clause> ]
1076 :
1077 : <field-spec> ::= [DISTINCT] <field_ref>
1078 : | <field_func> ( [DISTINCT] <field-ref> )
1079 : | Count(*)
1080 :
1081 : <as clause> ::= [ AS ] <column_name>
1082 :
1083 : <data type> ::= character [ ( field_length ) ]
1084 : | float [ ( field_length ) ]
1085 : | numeric [ ( field_length [, field_precision ] ) ]
1086 : | integer [ ( field_length ) ]
1087 : | date [ ( field_length ) ]
1088 : | time [ ( field_length ) ]
1089 : | timestamp [ ( field_length ) ]
1090 :
1091 : <field-func> ::= AVG | MAX | MIN | SUM | COUNT
1092 :
1093 : <field_ref> ::= [<table_ref>.]field_name
1094 :
1095 : <sort specification list> ::=
1096 : <sort specification> [ { <comma> <sort specification> }... ]
1097 :
1098 : <sort specification> ::= <sort key> [ <ordering specification> ]
1099 :
1100 : <sort key> ::= <field_ref>
1101 :
1102 : <ordering specification> ::= ASC | DESC
1103 :
1104 : <table_def> ::= ['<datasource name>'.]table_name [table_alias]
1105 :
1106 : <table_ref> ::= table_name | table_alias
1107 : */
1108 :
1109 : static int swq_parse_table_def( swq_select *select_info,
1110 : int *is_literal,
1111 : char **token, char **input );
1112 :
1113 : static int swq_parse_typename( swq_col_def *col_def,
1114 : int *is_literal,
1115 : char **token, char **input );
1116 :
1117 : /************************************************************************/
1118 : /* swq_select_preparse() */
1119 : /************************************************************************/
1120 :
1121 50 : const char *swq_select_preparse( const char *select_statement,
1122 : swq_select **select_info_ret )
1123 :
1124 : {
1125 : swq_select *select_info;
1126 : char *token;
1127 : char *input;
1128 : int is_literal;
1129 : int type_cast;
1130 : swq_col_def *swq_cols;
1131 :
1132 : #define MAX_COLUMNS 250
1133 :
1134 50 : *select_info_ret = NULL;
1135 :
1136 50 : if (select_statement == NULL || select_statement[0] == '\0')
1137 : {
1138 1 : SNPRINTF_ERR1( "Empty SQL request string" );
1139 1 : return swq_get_errbuf();
1140 : }
1141 :
1142 : /* -------------------------------------------------------------------- */
1143 : /* Get first token. Ensure it is SELECT. */
1144 : /* -------------------------------------------------------------------- */
1145 49 : token = swq_token( select_statement, &input, NULL );
1146 49 : if( strcasecmp(token,"select") != 0 )
1147 : {
1148 0 : SWQ_FREE( token );
1149 0 : SNPRINTF_ERR1( "Missing keyword SELECT" );
1150 0 : return swq_get_errbuf();
1151 : }
1152 49 : SWQ_FREE( token );
1153 :
1154 : /* -------------------------------------------------------------------- */
1155 : /* allocate selection structure. */
1156 : /* -------------------------------------------------------------------- */
1157 49 : select_info = (swq_select *) SWQ_MALLOC(sizeof(swq_select));
1158 49 : memset( select_info, 0, sizeof(swq_select) );
1159 :
1160 49 : select_info->raw_select = swq_strdup( select_statement );
1161 :
1162 : /* -------------------------------------------------------------------- */
1163 : /* Allocate a big field list. */
1164 : /* -------------------------------------------------------------------- */
1165 49 : swq_cols = (swq_col_def *) SWQ_MALLOC(sizeof(swq_col_def) * MAX_COLUMNS);
1166 49 : memset( swq_cols, 0, sizeof(swq_col_def) * MAX_COLUMNS );
1167 :
1168 49 : select_info->column_defs = swq_cols;
1169 :
1170 : /* -------------------------------------------------------------------- */
1171 : /* Collect the field list, terminated by FROM keyword. */
1172 : /* -------------------------------------------------------------------- */
1173 49 : token = swq_token( input, &input, &is_literal );
1174 394 : while( token != NULL
1175 345 : && (is_literal || strcasecmp(token,"FROM") != 0) )
1176 : {
1177 : char *next_token;
1178 : int next_is_literal;
1179 :
1180 66 : if( select_info->result_columns == MAX_COLUMNS )
1181 : {
1182 0 : SWQ_FREE( token );
1183 0 : swq_select_free( select_info );
1184 0 : SNPRINTF_ERR2(
1185 : "More than MAX_COLUMNS (%d) columns in SELECT statement.",
1186 : MAX_COLUMNS );
1187 0 : return swq_get_errbuf();
1188 : }
1189 :
1190 : /* Ensure that we have a comma before fields other than the first. */
1191 :
1192 66 : if( select_info->result_columns > 0 )
1193 : {
1194 17 : if( strcasecmp(token,",") != 0 )
1195 : {
1196 0 : SNPRINTF_ERR2(
1197 : "Missing comma after column %s in SELECT statement.",
1198 : swq_cols[select_info->result_columns-1].field_name );
1199 0 : SWQ_FREE( token );
1200 0 : swq_select_free( select_info );
1201 0 : return swq_get_errbuf();
1202 : }
1203 :
1204 17 : SWQ_FREE( token );
1205 17 : token = swq_token( input, &input, &is_literal );
1206 : }
1207 :
1208 : /* set up some default values. */
1209 66 : swq_cols[select_info->result_columns].field_precision = -1;
1210 66 : swq_cols[select_info->result_columns].target_type = SWQ_OTHER;
1211 66 : select_info->result_columns++;
1212 :
1213 66 : next_token = swq_token( input, &input, &next_is_literal );
1214 :
1215 : /* Detect the type cast. */
1216 66 : type_cast = 0;
1217 134 : if (token != NULL && next_token != NULL &&strcasecmp(token,"CAST") == 0
1218 68 : && strcasecmp(next_token,"(") == 0)
1219 : {
1220 2 : type_cast = 1;
1221 2 : SWQ_FREE( token );
1222 2 : SWQ_FREE( next_token );
1223 2 : token = swq_token( input, &input, &is_literal );
1224 2 : next_token = swq_token( input, &input, &next_is_literal );
1225 : }
1226 :
1227 : /*
1228 : ** Handle function operators.
1229 : */
1230 135 : if( !is_literal && !next_is_literal && next_token != NULL
1231 66 : && strcasecmp(next_token,"(") == 0 )
1232 : {
1233 3 : SWQ_FREE( next_token );
1234 :
1235 3 : swq_cols[select_info->result_columns-1].col_func_name = token;
1236 :
1237 3 : token = swq_token( input, &input, &is_literal );
1238 :
1239 6 : if( token != NULL && !is_literal
1240 3 : && strcasecmp(token,"DISTINCT") == 0 )
1241 : {
1242 0 : swq_cols[select_info->result_columns-1].distinct_flag = 1;
1243 :
1244 0 : SWQ_FREE( token );
1245 0 : token = swq_token( input, &input, &is_literal );
1246 : }
1247 :
1248 3 : swq_cols[select_info->result_columns-1].field_name = token;
1249 :
1250 3 : token = swq_token( input, &input, &is_literal );
1251 :
1252 3 : if( token == NULL || strcasecmp(token,")") != 0 )
1253 : {
1254 0 : if( token != NULL )
1255 0 : SWQ_FREE( token );
1256 0 : swq_select_free( select_info );
1257 0 : return "Missing closing bracket in field function.";
1258 : }
1259 :
1260 3 : SWQ_FREE( token );
1261 3 : token = swq_token( input, &input, &is_literal );
1262 : }
1263 :
1264 : /*
1265 : ** Handle simple field.
1266 : */
1267 : else
1268 : {
1269 126 : if( token != NULL && !is_literal
1270 63 : && strcasecmp(token,"DISTINCT") == 0 )
1271 : {
1272 8 : swq_cols[select_info->result_columns-1].distinct_flag = 1;
1273 :
1274 8 : SWQ_FREE( token );
1275 8 : token = next_token;
1276 8 : is_literal = next_is_literal;
1277 :
1278 8 : next_token = swq_token( input, &input, &next_is_literal );
1279 : }
1280 :
1281 63 : swq_cols[select_info->result_columns-1].field_name = token;
1282 63 : token = next_token;
1283 63 : is_literal = next_is_literal;
1284 : }
1285 :
1286 : /* handle the type cast*/
1287 66 : if (type_cast && token != NULL)
1288 : {
1289 2 : if (strcasecmp(token,"AS") != 0)
1290 : {
1291 0 : SWQ_FREE( token );
1292 0 : swq_select_free( select_info );
1293 0 : return "Missing 'AS' keyword in the type cast in SELECT statement.";
1294 : }
1295 :
1296 2 : SWQ_FREE( token );
1297 2 : token = swq_token( input, &input, &is_literal );
1298 :
1299 : /* processing the typename */
1300 2 : if( swq_parse_typename( &swq_cols[select_info->result_columns-1], &is_literal, &token, &input) != 0 )
1301 : {
1302 0 : swq_select_free( select_info );
1303 0 : return swq_get_errbuf();
1304 : }
1305 :
1306 2 : if (token != NULL && strcasecmp(token,")") != 0)
1307 : {
1308 0 : if( token != NULL )
1309 0 : SWQ_FREE( token );
1310 0 : swq_select_free( select_info );
1311 0 : return "Missing closing bracket after the type cast in SELECT statement.";
1312 : }
1313 :
1314 2 : SWQ_FREE( token );
1315 2 : token = swq_token( input, &input, &is_literal );
1316 :
1317 2 : type_cast = 0;
1318 : }
1319 :
1320 : /* Handle the field alias */
1321 66 : if( token != NULL && strcasecmp(token,",") != 0 && strcasecmp(token,"from") != 0)
1322 : {
1323 : /* Skip field alias keyword. */
1324 0 : if (strcasecmp(token,"AS") == 0)
1325 : {
1326 0 : SWQ_FREE( token );
1327 0 : token = swq_token( input, &input, &is_literal );
1328 0 : if (token == NULL)
1329 : {
1330 0 : swq_select_free( select_info );
1331 0 : return "Unexpected terminator after the type cast in SELECT statement.";
1332 : }
1333 : }
1334 0 : swq_cols[select_info->result_columns-1].field_alias = token;
1335 0 : token = swq_token( input, &input, &is_literal );
1336 : }
1337 : }
1338 :
1339 : /* make a columns_def list that is just the right size. */
1340 49 : select_info->column_defs = (swq_col_def *)
1341 : SWQ_MALLOC(sizeof(swq_col_def) * select_info->result_columns);
1342 49 : memcpy( select_info->column_defs, swq_cols,
1343 : sizeof(swq_col_def) * select_info->result_columns );
1344 49 : SWQ_FREE( swq_cols );
1345 :
1346 : /* -------------------------------------------------------------------- */
1347 : /* Collect the table name from the FROM clause. */
1348 : /* -------------------------------------------------------------------- */
1349 49 : if( token == NULL || strcasecmp(token,"FROM") != 0 )
1350 : {
1351 0 : SNPRINTF_ERR1( "Missing FROM clause in SELECT statement." );
1352 0 : swq_select_free( select_info );
1353 0 : return swq_get_errbuf();
1354 : }
1355 :
1356 49 : SWQ_FREE( token );
1357 49 : token = swq_token( input, &input, &is_literal );
1358 :
1359 49 : if( token == NULL )
1360 : {
1361 0 : SNPRINTF_ERR1( "Missing table name in FROM clause." );
1362 0 : swq_select_free( select_info );
1363 0 : return swq_get_errbuf();
1364 : }
1365 :
1366 49 : if( swq_parse_table_def( select_info, &is_literal, &token, &input) != 0 )
1367 : {
1368 0 : swq_select_free( select_info );
1369 0 : return swq_get_errbuf();
1370 : }
1371 :
1372 : /* -------------------------------------------------------------------- */
1373 : /* Do we have a LEFT JOIN (or just JOIN) clause? */
1374 : /* -------------------------------------------------------------------- */
1375 184 : while( token != NULL
1376 62 : && (strcasecmp(token,"LEFT") == 0
1377 73 : || strcasecmp(token,"JOIN") == 0) )
1378 : {
1379 : swq_join_def *join_info;
1380 :
1381 13 : if( strcasecmp(token,"LEFT") == 0 )
1382 : {
1383 13 : SWQ_FREE( token );
1384 13 : token = swq_token( input, &input, &is_literal );
1385 :
1386 13 : if( token == NULL || strcasecmp(token,"JOIN") != 0 )
1387 : {
1388 0 : SNPRINTF_ERR1( "Missing JOIN keyword after LEFT." );
1389 0 : swq_select_free( select_info );
1390 0 : return swq_get_errbuf();
1391 : }
1392 : }
1393 :
1394 13 : SWQ_FREE( token );
1395 13 : token = swq_token( input, &input, &is_literal );
1396 :
1397 : /* Create join definition structure */
1398 39 : select_info->join_defs = (swq_join_def *)
1399 13 : swq_realloc( select_info->join_defs,
1400 13 : sizeof(swq_join_def) * (select_info->join_count),
1401 : sizeof(swq_join_def) * (select_info->join_count+1) );
1402 :
1403 13 : join_info = select_info->join_defs + select_info->join_count++;
1404 :
1405 : /* Parse out target table */
1406 13 : join_info->secondary_table =
1407 13 : swq_parse_table_def( select_info, &is_literal, &token, &input);
1408 :
1409 13 : if( join_info->secondary_table < 0 )
1410 : {
1411 0 : swq_select_free( select_info );
1412 0 : return swq_get_errbuf();
1413 : }
1414 :
1415 : /* Check for ON keyword */
1416 13 : if( token == NULL )
1417 0 : token = swq_token( input, &input, &is_literal );
1418 :
1419 13 : if( token == NULL || strcasecmp(token,"ON") != 0 )
1420 : {
1421 0 : swq_select_free( select_info );
1422 0 : SNPRINTF_ERR1( "Corrupt JOIN clause, expecting ON keyword." );
1423 0 : return swq_get_errbuf();
1424 : }
1425 :
1426 13 : SWQ_FREE( token );
1427 :
1428 13 : join_info->primary_field_name =
1429 13 : swq_token( input, &input, &is_literal );
1430 :
1431 13 : token = swq_token( input, &input, &is_literal );
1432 13 : if( token == NULL || strcasecmp(token,"=") != 0 )
1433 : {
1434 0 : swq_select_free( select_info );
1435 0 : SNPRINTF_ERR1( "Corrupt JOIN clause, expecting '=' condition.");
1436 0 : return swq_get_errbuf();
1437 : }
1438 :
1439 13 : SWQ_FREE( token );
1440 :
1441 13 : join_info->op = SWQ_EQ;
1442 :
1443 13 : join_info->secondary_field_name =
1444 13 : swq_token( input, &input, &is_literal );
1445 :
1446 13 : if( join_info->secondary_field_name == NULL )
1447 : {
1448 0 : swq_select_free( select_info );
1449 0 : SNPRINTF_ERR1( "Corrupt JOIN clause, missing secondary field.");
1450 0 : return swq_get_errbuf();
1451 : }
1452 :
1453 13 : token = swq_token( input, &input, &is_literal );
1454 : }
1455 :
1456 : /* -------------------------------------------------------------------- */
1457 : /* Do we have a WHERE clause? */
1458 : /* -------------------------------------------------------------------- */
1459 49 : if( token != NULL && strcasecmp(token,"WHERE") == 0 )
1460 : {
1461 23 : const char *where_base = input;
1462 :
1463 69 : while( *where_base == ' ' )
1464 23 : where_base++;
1465 :
1466 23 : SWQ_FREE( token );
1467 :
1468 23 : token = swq_token( input, &input, &is_literal );
1469 131 : while( token != NULL )
1470 : {
1471 89 : if( strcasecmp(token,"ORDER") == 0 && !is_literal )
1472 : {
1473 4 : break;
1474 : }
1475 :
1476 85 : if( token != NULL )
1477 : {
1478 85 : SWQ_FREE( token );
1479 :
1480 85 : token = swq_token( input, &input, &is_literal );
1481 : }
1482 : }
1483 :
1484 23 : select_info->whole_where_clause = swq_strdup(where_base);
1485 :
1486 23 : if( input != NULL )
1487 : {
1488 23 : if( token != NULL )
1489 4 : select_info->whole_where_clause[input - where_base - strlen(token)] = '\0';
1490 : else
1491 19 : select_info->whole_where_clause[input - where_base] = '\0';
1492 : }
1493 : }
1494 :
1495 : /* -------------------------------------------------------------------- */
1496 : /* Parse ORDER BY clause. */
1497 : /* -------------------------------------------------------------------- */
1498 49 : if( token != NULL && strcasecmp(token,"ORDER") == 0 )
1499 : {
1500 11 : SWQ_FREE( token );
1501 :
1502 11 : token = swq_token( input, &input, &is_literal );
1503 :
1504 11 : if( token == NULL || strcasecmp(token,"BY") != 0 )
1505 : {
1506 0 : if( token != NULL )
1507 0 : SWQ_FREE( token );
1508 :
1509 0 : SNPRINTF_ERR1( "ORDER BY clause missing BY keyword." );
1510 0 : swq_select_free( select_info );
1511 0 : return swq_get_errbuf();
1512 : }
1513 :
1514 11 : SWQ_FREE( token );
1515 11 : token = swq_token( input, &input, &is_literal );
1516 44 : while( token != NULL
1517 22 : && (select_info->order_specs == 0
1518 11 : || strcasecmp(token,",") == 0) )
1519 : {
1520 11 : swq_order_def *old_defs = select_info->order_defs;
1521 : swq_order_def *def;
1522 :
1523 11 : if( select_info->order_specs != 0 )
1524 : {
1525 0 : SWQ_FREE( token );
1526 0 : token = swq_token( input, &input, &is_literal );
1527 : }
1528 :
1529 11 : select_info->order_defs = (swq_order_def *)
1530 : SWQ_MALLOC(sizeof(swq_order_def)*(select_info->order_specs+1));
1531 :
1532 11 : if( old_defs != NULL )
1533 : {
1534 0 : memcpy( select_info->order_defs, old_defs,
1535 : sizeof(swq_order_def)*select_info->order_specs );
1536 0 : SWQ_FREE( old_defs );
1537 : }
1538 :
1539 11 : def = select_info->order_defs + select_info->order_specs;
1540 11 : def->field_name = token;
1541 11 : def->field_index = 0;
1542 11 : def->ascending_flag = 1;
1543 :
1544 11 : token = swq_token( input, &input, &is_literal );
1545 14 : if( token != NULL && strcasecmp(token,"DESC") == 0 )
1546 : {
1547 3 : SWQ_FREE( token );
1548 3 : token = swq_token( input, &input, &is_literal );
1549 :
1550 3 : def->ascending_flag = 0;
1551 : }
1552 8 : else if( token != NULL && strcasecmp(token,"ASC") == 0 )
1553 : {
1554 5 : SWQ_FREE( token );
1555 5 : token = swq_token( input, &input, &is_literal );
1556 : }
1557 :
1558 11 : select_info->order_specs++;
1559 : }
1560 : }
1561 :
1562 : /* -------------------------------------------------------------------- */
1563 : /* If we have anything left it indicates an error! */
1564 : /* -------------------------------------------------------------------- */
1565 49 : if( token != NULL )
1566 : {
1567 :
1568 0 : SNPRINTF_ERR2(
1569 : "Failed to parse SELECT statement, extra input at %s token.",
1570 : token );
1571 :
1572 0 : SWQ_FREE( token );
1573 0 : swq_select_free( select_info );
1574 0 : return swq_get_errbuf();
1575 : }
1576 :
1577 49 : *select_info_ret = select_info;
1578 :
1579 49 : return NULL;
1580 : }
1581 :
1582 : /************************************************************************/
1583 : /* swq_parse_typename() */
1584 : /************************************************************************/
1585 :
1586 2 : static int swq_parse_typename( swq_col_def *col_def,
1587 : int *is_literal,
1588 : char **token, char **input )
1589 :
1590 : {
1591 : int parse_length;
1592 : int parse_precision;
1593 :
1594 2 : if( *token == NULL )
1595 0 : *token = swq_token( *input, input, is_literal );
1596 :
1597 2 : if( *token == NULL )
1598 : {
1599 0 : SNPRINTF_ERR1( "Corrupt type name, insufficient tokens." );
1600 0 : return -1;
1601 : }
1602 :
1603 : /* -------------------------------------------------------------------- */
1604 : /* Check for the SQL92 typenames */
1605 : /* -------------------------------------------------------------------- */
1606 2 : parse_length = 0;
1607 2 : parse_precision = 0;
1608 2 : if( strcasecmp(*token,"character") == 0 )
1609 : {
1610 1 : col_def->target_type = SWQ_STRING;
1611 1 : col_def->field_length = 1;
1612 1 : parse_length = 1;
1613 : }
1614 1 : else if( strcasecmp(*token,"integer") == 0 )
1615 : {
1616 0 : col_def->target_type = SWQ_INTEGER;
1617 0 : parse_length = 1;
1618 : }
1619 1 : else if( strcasecmp(*token,"float") == 0 )
1620 : {
1621 0 : col_def->target_type = SWQ_FLOAT;
1622 0 : parse_length = 1;
1623 : }
1624 1 : else if( strcasecmp(*token,"numeric") == 0 )
1625 : {
1626 1 : col_def->target_type = SWQ_FLOAT;
1627 1 : parse_length = 1;
1628 1 : parse_precision = 1;
1629 : }
1630 0 : else if( strcasecmp(*token,"timestamp") == 0 )
1631 : {
1632 0 : col_def->target_type = SWQ_TIMESTAMP;
1633 0 : parse_length = 1;
1634 : }
1635 0 : else if( strcasecmp(*token,"date") == 0 )
1636 : {
1637 0 : col_def->target_type = SWQ_DATE;
1638 0 : parse_length = 1;
1639 : }
1640 0 : else if( strcasecmp(*token,"time") == 0 )
1641 : {
1642 0 : col_def->target_type = SWQ_TIME;
1643 0 : parse_length = 1;
1644 : }
1645 : else
1646 : {
1647 0 : SNPRINTF_ERR2( "Unrecognized typename %s.", *token );
1648 0 : SWQ_FREE( *token );
1649 0 : *token = NULL;
1650 0 : return -1;
1651 : }
1652 :
1653 2 : SWQ_FREE( *token );
1654 2 : *token = swq_token( *input, input, is_literal );
1655 :
1656 : /* -------------------------------------------------------------------- */
1657 : /* Check for the field length and precision */
1658 : /* -------------------------------------------------------------------- */
1659 2 : if (parse_length && *token != NULL && strcasecmp(*token,"(") == 0)
1660 : {
1661 2 : SWQ_FREE( *token );
1662 2 : *token = swq_token( *input, input, is_literal );
1663 :
1664 2 : if (*token != NULL)
1665 : {
1666 2 : col_def->field_length = atoi( *token );
1667 2 : SWQ_FREE( *token );
1668 2 : *token = swq_token( *input, input, is_literal );
1669 : }
1670 :
1671 2 : if (parse_precision && *token != NULL && strcasecmp(*token,",") == 0)
1672 : {
1673 1 : SWQ_FREE( *token );
1674 1 : *token = swq_token( *input, input, is_literal );
1675 1 : if (*token != NULL)
1676 : {
1677 1 : col_def->field_precision = atoi( *token );
1678 1 : SWQ_FREE( *token );
1679 1 : *token = swq_token( *input, input, is_literal );
1680 : }
1681 : }
1682 :
1683 2 : if (*token == NULL || strcasecmp(*token,")") != 0)
1684 : {
1685 0 : if (*token != NULL)
1686 : {
1687 0 : SWQ_FREE( *token );
1688 0 : *token = NULL;
1689 : }
1690 0 : SNPRINTF_ERR1( "Missing closing bracket in the field length specifier." );
1691 0 : return -1;
1692 : }
1693 :
1694 2 : SWQ_FREE( *token );
1695 2 : *token = swq_token( *input, input, is_literal );
1696 : }
1697 2 : return 0;
1698 : }
1699 :
1700 : /************************************************************************/
1701 : /* swq_parse_table_def() */
1702 : /* */
1703 : /* Supported table definition forms: */
1704 : /* */
1705 : /* <table_def> :== table_name */
1706 : /* | 'data_source'.table_name */
1707 : /* | table_name table_alias */
1708 : /* | 'data_source'.table_name table_alias */
1709 : /************************************************************************/
1710 :
1711 62 : static int swq_parse_table_def( swq_select *select_info,
1712 : int *is_literal,
1713 : char **token, char **input )
1714 :
1715 : {
1716 : int i;
1717 62 : char *datasource = NULL;
1718 62 : char *table = NULL;
1719 62 : char *alias = NULL;
1720 :
1721 62 : if( *token == NULL )
1722 0 : *token = swq_token( *input, input, is_literal );
1723 :
1724 62 : if( *token == NULL )
1725 : {
1726 0 : SNPRINTF_ERR1( "Corrupt table definition, insufficient tokens." );
1727 0 : return -1;
1728 : }
1729 :
1730 : /* -------------------------------------------------------------------- */
1731 : /* Do we have a datasource literal? */
1732 : /* -------------------------------------------------------------------- */
1733 62 : if( *token != NULL && *is_literal )
1734 : {
1735 5 : datasource = *token;
1736 5 : *token = swq_token( *input, input, is_literal );
1737 :
1738 5 : if( *token == NULL )
1739 : {
1740 0 : *token = datasource;
1741 0 : datasource = NULL;
1742 : }
1743 : }
1744 :
1745 : /* -------------------------------------------------------------------- */
1746 : /* Get the table name. Remove the '.' used to qualify it */
1747 : /* relative to the datasource name if found. */
1748 : /* -------------------------------------------------------------------- */
1749 63 : if( datasource != NULL && (*token)[0] != '.' )
1750 : {
1751 1 : table = datasource;
1752 1 : datasource = NULL;
1753 : }
1754 61 : else if( (*token)[0] == '.' )
1755 : {
1756 4 : table = swq_strdup( (*token) + 1 );
1757 4 : SWQ_FREE( *token );
1758 4 : *token = swq_token( *input, input, is_literal );
1759 : }
1760 : else
1761 : {
1762 57 : table = *token;
1763 57 : *token = swq_token( *input, input, is_literal );
1764 : }
1765 :
1766 : /* -------------------------------------------------------------------- */
1767 : /* Was an alias provided? */
1768 : /* -------------------------------------------------------------------- */
1769 216 : if( *token != NULL && ! *is_literal
1770 47 : && strcasecmp(*token,"ON") != 0
1771 88 : && strcasecmp(*token,"ORDER") != 0
1772 75 : && strcasecmp(*token,"WHERE") != 0
1773 53 : && strcasecmp(*token,"LEFT") != 0
1774 32 : && strcasecmp(*token,"JOIN") != 0 )
1775 : {
1776 13 : alias = *token;
1777 13 : *token = swq_token( *input, input, is_literal );
1778 : }
1779 :
1780 : /* -------------------------------------------------------------------- */
1781 : /* Does this match an existing table definition? */
1782 : /* -------------------------------------------------------------------- */
1783 76 : for( i = 0; i < select_info->table_count; i++ )
1784 : {
1785 14 : swq_table_def *table_def = select_info->table_defs + i;
1786 :
1787 20 : if( datasource == NULL
1788 : && alias == NULL
1789 6 : && strcasecmp(table_def->table_alias,table) == 0 )
1790 0 : return i;
1791 :
1792 18 : if( datasource != NULL && table_def->data_source != NULL
1793 4 : && strcasecmp(datasource,table_def->data_source) == 0
1794 0 : && strcasecmp(table,table_def->table_name) == 0 )
1795 0 : return i;
1796 : }
1797 :
1798 : /* -------------------------------------------------------------------- */
1799 : /* Add a new entry to the tables table. */
1800 : /* -------------------------------------------------------------------- */
1801 62 : select_info->table_defs =
1802 124 : swq_realloc( select_info->table_defs,
1803 62 : sizeof(swq_table_def) * (select_info->table_count),
1804 : sizeof(swq_table_def) * (select_info->table_count+1) );
1805 :
1806 : /* -------------------------------------------------------------------- */
1807 : /* Populate the new entry. */
1808 : /* -------------------------------------------------------------------- */
1809 62 : if( alias == NULL )
1810 49 : alias = swq_strdup( table );
1811 :
1812 62 : select_info->table_defs[select_info->table_count].data_source = datasource;
1813 62 : select_info->table_defs[select_info->table_count].table_name = table;
1814 62 : select_info->table_defs[select_info->table_count].table_alias = alias;
1815 :
1816 62 : select_info->table_count++;
1817 :
1818 62 : return select_info->table_count - 1;
1819 : }
1820 :
1821 : /************************************************************************/
1822 : /* swq_select_expand_wildcard() */
1823 : /* */
1824 : /* This function replaces the '*' in a "SELECT *" with the list */
1825 : /* provided list of fields. Itis used by swq_select_parse(), */
1826 : /* but may be called in advance by applications wanting the */
1827 : /* "default" field list to be different than the full list of */
1828 : /* fields. */
1829 : /************************************************************************/
1830 :
1831 98 : const char *swq_select_expand_wildcard( swq_select *select_info,
1832 : swq_field_list *field_list )
1833 :
1834 : {
1835 : int isrc;
1836 :
1837 : /* ==================================================================== */
1838 : /* Check each pre-expansion field. */
1839 : /* ==================================================================== */
1840 399 : for( isrc = 0; isrc < select_info->result_columns; isrc++ )
1841 : {
1842 301 : const char *src_fieldname = select_info->column_defs[isrc].field_name;
1843 : int itable, new_fields, i, iout;
1844 :
1845 301 : if( src_fieldname[strlen(src_fieldname)-1] != '*' )
1846 268 : continue;
1847 :
1848 : /* We don't want to expand COUNT(*) */
1849 33 : if( select_info->column_defs[isrc].col_func_name != NULL )
1850 2 : continue;
1851 :
1852 : /* -------------------------------------------------------------------- */
1853 : /* Parse out the table name, verify it, and establish the */
1854 : /* number of fields to insert from it. */
1855 : /* -------------------------------------------------------------------- */
1856 31 : if( strcmp(src_fieldname,"*") == 0 )
1857 : {
1858 23 : itable = -1;
1859 23 : new_fields = field_list->count;
1860 : }
1861 16 : else if( strlen(src_fieldname) < 3
1862 16 : || src_fieldname[strlen(src_fieldname)-2] != '.' )
1863 : {
1864 0 : SNPRINTF_ERR2( "Ill formatted field definition '%s'.",
1865 : src_fieldname );
1866 0 : return swq_get_errbuf();
1867 : }
1868 : else
1869 : {
1870 8 : char *table_name = swq_strdup( src_fieldname );
1871 8 : table_name[strlen(src_fieldname)-2] = '\0';
1872 :
1873 9 : for( itable = 0; itable < field_list->table_count; itable++ )
1874 : {
1875 9 : if( strcasecmp(table_name,
1876 9 : field_list->table_defs[itable].table_alias ) == 0 )
1877 8 : break;
1878 : }
1879 :
1880 8 : if( itable == field_list->table_count )
1881 : {
1882 0 : SNPRINTF_ERR3(
1883 : "Table %s not recognised from %s definition.",
1884 : table_name, src_fieldname );
1885 0 : swq_free( table_name );
1886 0 : return swq_get_errbuf();
1887 : }
1888 8 : swq_free( table_name );
1889 :
1890 : /* count the number of fields in this table. */
1891 8 : new_fields = 0;
1892 46 : for( i = 0; i < field_list->count; i++ )
1893 : {
1894 38 : if( field_list->table_ids[i] == itable )
1895 21 : new_fields++;
1896 : }
1897 : }
1898 :
1899 31 : if (new_fields > 0)
1900 : {
1901 : /* -------------------------------------------------------------------- */
1902 : /* Reallocate the column list larger. */
1903 : /* -------------------------------------------------------------------- */
1904 29 : SWQ_FREE( select_info->column_defs[isrc].field_name );
1905 87 : select_info->column_defs = (swq_col_def *)
1906 29 : swq_realloc( select_info->column_defs,
1907 29 : sizeof(swq_col_def) * select_info->result_columns,
1908 : sizeof(swq_col_def) *
1909 29 : (select_info->result_columns + new_fields - 1 ) );
1910 :
1911 : /* -------------------------------------------------------------------- */
1912 : /* Push the old definitions that came after the one to be */
1913 : /* replaced further up in the array. */
1914 : /* -------------------------------------------------------------------- */
1915 29 : if (new_fields != 1)
1916 : {
1917 32 : for( i = select_info->result_columns-1; i > isrc; i-- )
1918 : {
1919 12 : memcpy( select_info->column_defs + i + new_fields - 1,
1920 6 : select_info->column_defs + i,
1921 : sizeof( swq_col_def ) );
1922 : }
1923 : }
1924 :
1925 29 : select_info->result_columns += (new_fields - 1 );
1926 :
1927 : /* -------------------------------------------------------------------- */
1928 : /* Zero out all the stuff in the target column definitions. */
1929 : /* -------------------------------------------------------------------- */
1930 29 : memset( select_info->column_defs + isrc, 0,
1931 : new_fields * sizeof(swq_col_def) );
1932 : }
1933 : else
1934 : {
1935 : /* -------------------------------------------------------------------- */
1936 : /* The wildcard expands to nothing */
1937 : /* -------------------------------------------------------------------- */
1938 2 : SWQ_FREE( select_info->column_defs[isrc].field_name );
1939 4 : memmove( select_info->column_defs + isrc,
1940 2 : select_info->column_defs + isrc + 1,
1941 2 : sizeof( swq_col_def ) * (select_info->result_columns-1-isrc) );
1942 :
1943 2 : select_info->result_columns --;
1944 : }
1945 :
1946 : /* -------------------------------------------------------------------- */
1947 : /* Assign the selected fields. */
1948 : /* -------------------------------------------------------------------- */
1949 31 : iout = isrc;
1950 :
1951 148 : for( i = 0; i < field_list->count; i++ )
1952 : {
1953 : swq_col_def *def;
1954 117 : int compose = itable != -1;
1955 :
1956 : /* skip this field if it isn't in the target table. */
1957 193 : if( itable != -1 && field_list->table_ids != NULL
1958 76 : && itable != field_list->table_ids[i] )
1959 17 : continue;
1960 :
1961 : /* set up some default values. */
1962 100 : def = select_info->column_defs + iout;
1963 100 : def->field_precision = -1;
1964 100 : def->target_type = SWQ_OTHER;
1965 :
1966 : /* does this field duplicate an earlier one? */
1967 200 : if( field_list->table_ids != NULL
1968 200 : && field_list->table_ids[i] != 0
1969 : && !compose )
1970 : {
1971 : int other;
1972 :
1973 71 : for( other = 0; other < i; other++ )
1974 : {
1975 59 : if( strcasecmp(field_list->names[i],
1976 59 : field_list->names[other]) == 0 )
1977 : {
1978 3 : compose = 1;
1979 3 : break;
1980 : }
1981 : }
1982 : }
1983 :
1984 100 : if( !compose )
1985 76 : def->field_name = swq_strdup( field_list->names[i] );
1986 : else
1987 : {
1988 24 : int itable = field_list->table_ids[i];
1989 : char *composed_name;
1990 24 : const char *field_name = field_list->names[i];
1991 : const char *table_alias =
1992 24 : field_list->table_defs[itable].table_alias;
1993 :
1994 24 : composed_name = (char *)
1995 24 : swq_malloc(strlen(field_name)+strlen(table_alias)+2);
1996 :
1997 24 : sprintf( composed_name, "%s.%s", table_alias, field_name );
1998 :
1999 24 : def->field_name = composed_name;
2000 : }
2001 :
2002 100 : iout++;
2003 :
2004 : /* All the other table info will be provided by the later
2005 : parse operation. */
2006 : }
2007 :
2008 : /* If there are several occurrences of '*', go on, but stay on the */
2009 : /* same index in case '*' is expanded to nothing */
2010 : /* (the -- is to compensate the fact that isrc will be incremented in */
2011 : /* the after statement of the for loop) */
2012 31 : isrc --;
2013 : }
2014 :
2015 :
2016 :
2017 98 : return NULL;
2018 : }
2019 :
2020 : /************************************************************************/
2021 : /* swq_select_parse() */
2022 : /************************************************************************/
2023 :
2024 49 : const char *swq_select_parse( swq_select *select_info,
2025 : swq_field_list *field_list,
2026 : int parse_flags )
2027 :
2028 : {
2029 : int i;
2030 : const char *error;
2031 :
2032 49 : error = swq_select_expand_wildcard( select_info, field_list );
2033 49 : if( error != NULL )
2034 0 : return error;
2035 :
2036 : /* -------------------------------------------------------------------- */
2037 : /* Identify field information. */
2038 : /* -------------------------------------------------------------------- */
2039 184 : for( i = 0; i < select_info->result_columns; i++ )
2040 : {
2041 135 : swq_col_def *def = select_info->column_defs + i;
2042 : swq_field_type this_type;
2043 :
2044 : /* identify field */
2045 135 : def->field_index = swq_identify_field( def->field_name, field_list,
2046 : &this_type,
2047 : &(def->table_index) );
2048 :
2049 : /* record field type */
2050 135 : def->field_type = this_type;
2051 :
2052 : /* identify column function if present */
2053 135 : if( def->col_func_name != NULL )
2054 : {
2055 3 : if( strcasecmp(def->col_func_name,"AVG") == 0 )
2056 0 : def->col_func = SWQCF_AVG;
2057 3 : else if( strcasecmp(def->col_func_name,"MIN") == 0 )
2058 0 : def->col_func = SWQCF_MIN;
2059 3 : else if( strcasecmp(def->col_func_name,"MAX") == 0 )
2060 2 : def->col_func = SWQCF_MAX;
2061 1 : else if( strcasecmp(def->col_func_name,"SUM") == 0 )
2062 0 : def->col_func = SWQCF_SUM;
2063 1 : else if( strcasecmp(def->col_func_name,"COUNT") == 0 )
2064 1 : def->col_func = SWQCF_COUNT;
2065 : else
2066 : {
2067 0 : def->col_func = SWQCF_CUSTOM;
2068 0 : if( !(parse_flags & SWQP_ALLOW_UNDEFINED_COL_FUNCS) )
2069 : {
2070 0 : SNPRINTF_ERR2( "Unrecognised field function %s.",
2071 : def->col_func_name );
2072 0 : return swq_get_errbuf();
2073 : }
2074 : }
2075 :
2076 10 : if( (def->col_func == SWQCF_MIN
2077 3 : || def->col_func == SWQCF_MAX
2078 3 : || def->col_func == SWQCF_AVG
2079 2 : || def->col_func == SWQCF_SUM)
2080 2 : && this_type == SWQ_STRING )
2081 : {
2082 0 : SNPRINTF_ERR3(
2083 : "Use of field function %s() on string field %s illegal.",
2084 : def->col_func_name, def->field_name );
2085 0 : return swq_get_errbuf();
2086 : }
2087 : }
2088 : else
2089 132 : def->col_func = SWQCF_NONE;
2090 :
2091 135 : if( def->field_index == -1 && def->col_func != SWQCF_COUNT )
2092 : {
2093 0 : SNPRINTF_ERR2( "Unrecognised field name %s.",
2094 : def->field_name );
2095 0 : return swq_get_errbuf();
2096 : }
2097 : }
2098 :
2099 : /* -------------------------------------------------------------------- */
2100 : /* Check if we are producing a one row summary result or a set */
2101 : /* of records. Generate an error if we get conflicting */
2102 : /* indications. */
2103 : /* -------------------------------------------------------------------- */
2104 49 : select_info->query_mode = -1;
2105 184 : for( i = 0; i < select_info->result_columns; i++ )
2106 : {
2107 135 : swq_col_def *def = select_info->column_defs + i;
2108 135 : int this_indicator = -1;
2109 :
2110 672 : if( def->col_func == SWQCF_MIN
2111 135 : || def->col_func == SWQCF_MAX
2112 135 : || def->col_func == SWQCF_AVG
2113 133 : || def->col_func == SWQCF_SUM
2114 266 : || def->col_func == SWQCF_COUNT )
2115 3 : this_indicator = SWQM_SUMMARY_RECORD;
2116 132 : else if( def->col_func == SWQCF_NONE )
2117 : {
2118 132 : if( def->distinct_flag )
2119 8 : this_indicator = SWQM_DISTINCT_LIST;
2120 : else
2121 124 : this_indicator = SWQM_RECORDSET;
2122 : }
2123 :
2124 183 : if( this_indicator != select_info->query_mode
2125 135 : && this_indicator != -1
2126 48 : && select_info->query_mode != -1 )
2127 : {
2128 0 : return "Field list implies mixture of regular recordset mode, summary mode or distinct field list mode.";
2129 : }
2130 :
2131 135 : if( this_indicator != -1 )
2132 135 : select_info->query_mode = this_indicator;
2133 : }
2134 :
2135 81 : if( select_info->result_columns > 1
2136 81 : && select_info->query_mode == SWQM_DISTINCT_LIST )
2137 : {
2138 0 : return "SELECTing more than one DISTINCT field is a query not supported.";
2139 : }
2140 49 : else if (select_info->result_columns == 0)
2141 : {
2142 1 : select_info->query_mode = SWQM_RECORDSET;
2143 : }
2144 :
2145 : /* -------------------------------------------------------------------- */
2146 : /* Process column names in JOIN specs. */
2147 : /* -------------------------------------------------------------------- */
2148 62 : for( i = 0; i < select_info->join_count; i++ )
2149 : {
2150 13 : swq_join_def *def = select_info->join_defs + i;
2151 : int table_id;
2152 :
2153 : /* identify primary field */
2154 13 : def->primary_field = swq_identify_field( def->primary_field_name,
2155 : field_list, NULL, &table_id );
2156 13 : if( def->primary_field == -1 )
2157 : {
2158 0 : SNPRINTF_ERR2(
2159 : "Unrecognised primary field %s in JOIN clause..",
2160 : def->primary_field_name );
2161 0 : return swq_get_errbuf();
2162 : }
2163 :
2164 13 : if( table_id != 0 )
2165 : {
2166 0 : SNPRINTF_ERR2(
2167 : "Currently the primary key must come from the primary table in\n"
2168 : "JOIN, %s is not from the primary table.",
2169 : def->primary_field_name );
2170 0 : return swq_get_errbuf();
2171 : }
2172 :
2173 : /* identify secondary field */
2174 13 : def->secondary_field = swq_identify_field( def->secondary_field_name,
2175 : field_list, NULL,&table_id);
2176 13 : if( def->secondary_field == -1 )
2177 : {
2178 0 : SNPRINTF_ERR2(
2179 : "Unrecognised secondary field %s in JOIN clause..",
2180 : def->primary_field_name );
2181 0 : return swq_get_errbuf();
2182 : }
2183 :
2184 13 : if( table_id != def->secondary_table )
2185 : {
2186 0 : SNPRINTF_ERR3(
2187 : "Currently the secondary key must come from the secondary table\n"
2188 : "listed in the JOIN. %s is not from table %s..",
2189 : def->primary_field_name,
2190 : select_info->table_defs[def->secondary_table].table_name);
2191 0 : return swq_get_errbuf();
2192 : }
2193 : }
2194 :
2195 : /* -------------------------------------------------------------------- */
2196 : /* Process column names in order specs. */
2197 : /* -------------------------------------------------------------------- */
2198 60 : for( i = 0; i < select_info->order_specs; i++ )
2199 : {
2200 11 : swq_order_def *def = select_info->order_defs + i;
2201 :
2202 : /* identify field */
2203 11 : def->field_index = swq_identify_field( def->field_name, field_list,
2204 : NULL, &(def->table_index) );
2205 11 : if( def->field_index == -1 )
2206 : {
2207 0 : SNPRINTF_ERR2( "Unrecognised field name %s in ORDER BY.",
2208 : def->field_name );
2209 0 : return swq_get_errbuf();
2210 : }
2211 : }
2212 :
2213 : /* -------------------------------------------------------------------- */
2214 : /* Parse the WHERE clause. */
2215 : /* -------------------------------------------------------------------- */
2216 49 : if( select_info->whole_where_clause != NULL )
2217 : {
2218 : const char *error;
2219 :
2220 23 : error = swq_expr_compile2( select_info->whole_where_clause,
2221 : field_list, &(select_info->where_expr) );
2222 :
2223 23 : if( error != NULL )
2224 0 : return error;
2225 : }
2226 :
2227 49 : return NULL;
2228 : }
2229 :
2230 : /************************************************************************/
2231 : /* swq_select_summarize() */
2232 : /************************************************************************/
2233 :
2234 : const char *
2235 183 : swq_select_summarize( swq_select *select_info,
2236 : int dest_column, const char *value )
2237 :
2238 : {
2239 183 : swq_col_def *def = select_info->column_defs + dest_column;
2240 : swq_summary *summary;
2241 :
2242 : /* -------------------------------------------------------------------- */
2243 : /* Do various checking. */
2244 : /* -------------------------------------------------------------------- */
2245 : if( !select_info->query_mode == SWQM_RECORDSET )
2246 : return "swq_select_summarize() called on non-summary query.";
2247 :
2248 183 : if( dest_column < 0 || dest_column >= select_info->result_columns )
2249 0 : return "dest_column out of range in swq_select_summarize().";
2250 :
2251 183 : if( def->col_func == SWQCF_NONE && !def->distinct_flag )
2252 0 : return NULL;
2253 :
2254 : /* -------------------------------------------------------------------- */
2255 : /* Create the summary information if this is the first row */
2256 : /* being processed. */
2257 : /* -------------------------------------------------------------------- */
2258 183 : if( select_info->column_summary == NULL )
2259 : {
2260 : int i;
2261 :
2262 8 : select_info->column_summary = (swq_summary *)
2263 : SWQ_MALLOC(sizeof(swq_summary) * select_info->result_columns);
2264 8 : memset( select_info->column_summary, 0,
2265 : sizeof(swq_summary) * select_info->result_columns );
2266 :
2267 16 : for( i = 0; i < select_info->result_columns; i++ )
2268 : {
2269 8 : select_info->column_summary[i].min = 1e20;
2270 8 : select_info->column_summary[i].max = -1e20;
2271 : }
2272 : }
2273 :
2274 : /* -------------------------------------------------------------------- */
2275 : /* If distinct processing is on, process that now. */
2276 : /* -------------------------------------------------------------------- */
2277 183 : summary = select_info->column_summary + dest_column;
2278 :
2279 183 : if( def->distinct_flag )
2280 : {
2281 : int i;
2282 :
2283 : /* This should be implemented with a much more complicated
2284 : data structure to achieve any sort of efficiency. */
2285 779 : for( i = 0; i < summary->count; i++ )
2286 : {
2287 730 : if( strcmp(value,summary->distinct_list[i]) == 0 )
2288 127 : break;
2289 : }
2290 :
2291 176 : if( i == summary->count )
2292 : {
2293 49 : char **old_list = summary->distinct_list;
2294 :
2295 49 : summary->distinct_list = (char **)
2296 : SWQ_MALLOC(sizeof(char *) * (summary->count+1));
2297 49 : memcpy( summary->distinct_list, old_list,
2298 : sizeof(char *) * summary->count );
2299 98 : summary->distinct_list[(summary->count)++] =
2300 49 : swq_strdup( value );
2301 :
2302 49 : SWQ_FREE(old_list);
2303 : }
2304 : }
2305 :
2306 : /* -------------------------------------------------------------------- */
2307 : /* Process various options. */
2308 : /* -------------------------------------------------------------------- */
2309 :
2310 183 : switch( def->col_func )
2311 : {
2312 : case SWQCF_MIN:
2313 0 : if( value != NULL && value[0] != '\0' )
2314 : {
2315 0 : double df_val = atof(value);
2316 0 : if( df_val < summary->min )
2317 0 : summary->min = df_val;
2318 : }
2319 0 : break;
2320 : case SWQCF_MAX:
2321 7 : if( value != NULL && value[0] != '\0' )
2322 : {
2323 7 : double df_val = atof(value);
2324 7 : if( df_val > summary->max )
2325 2 : summary->max = df_val;
2326 : }
2327 7 : break;
2328 : case SWQCF_AVG:
2329 : case SWQCF_SUM:
2330 0 : if( value != NULL && value[0] != '\0' )
2331 : {
2332 0 : summary->count++;
2333 0 : summary->sum += atof(value);
2334 : }
2335 0 : break;
2336 :
2337 : case SWQCF_COUNT:
2338 0 : if( value != NULL && !def->distinct_flag )
2339 0 : summary->count++;
2340 0 : break;
2341 :
2342 : case SWQCF_NONE:
2343 176 : break;
2344 :
2345 : case SWQCF_CUSTOM:
2346 0 : return "swq_select_summarize() called on custom field function.";
2347 :
2348 : default:
2349 0 : return "swq_select_summarize() - unexpected col_func";
2350 : }
2351 :
2352 183 : return NULL;
2353 : }
2354 : /************************************************************************/
2355 : /* sort comparison functions. */
2356 : /************************************************************************/
2357 :
2358 50 : static int FORCE_CDECL swq_compare_int( const void *item1, const void *item2 )
2359 : {
2360 : int v1, v2;
2361 :
2362 50 : v1 = atoi(*((const char **) item1));
2363 50 : v2 = atoi(*((const char **) item2));
2364 :
2365 50 : if( v1 < v2 )
2366 16 : return -1;
2367 34 : else if( v1 == v2 )
2368 0 : return 0;
2369 : else
2370 34 : return 1;
2371 : }
2372 :
2373 23 : static int FORCE_CDECL swq_compare_real( const void *item1, const void *item2 )
2374 : {
2375 : double v1, v2;
2376 :
2377 23 : v1 = atof(*((const char **) item1));
2378 23 : v2 = atof(*((const char **) item2));
2379 :
2380 23 : if( v1 < v2 )
2381 9 : return -1;
2382 14 : else if( v1 == v2 )
2383 0 : return 0;
2384 : else
2385 14 : return 1;
2386 : }
2387 :
2388 12 : static int FORCE_CDECL swq_compare_string( const void *item1, const void *item2 )
2389 : {
2390 12 : return strcmp( *((const char **) item1), *((const char **) item2) );
2391 : }
2392 :
2393 : /************************************************************************/
2394 : /* swq_select_finish_summarize() */
2395 : /* */
2396 : /* Call to complete summarize work. Does stuff like ordering */
2397 : /* the distinct list for instance. */
2398 : /************************************************************************/
2399 :
2400 10 : const char *swq_select_finish_summarize( swq_select *select_info )
2401 :
2402 : {
2403 : int (FORCE_CDECL *compare_func)(const void *, const void*);
2404 10 : int count = 0;
2405 10 : char **distinct_list = NULL;
2406 :
2407 18 : if( select_info->query_mode != SWQM_DISTINCT_LIST
2408 18 : || select_info->order_specs == 0 )
2409 5 : return NULL;
2410 :
2411 5 : if( select_info->order_specs > 1 )
2412 0 : return "Can't ORDER BY a DISTINCT list by more than one key.";
2413 :
2414 10 : if( select_info->order_defs[0].field_index !=
2415 5 : select_info->column_defs[0].field_index )
2416 0 : return "Only selected DISTINCT field can be used for ORDER BY.";
2417 :
2418 5 : if( select_info->column_summary == NULL )
2419 0 : return NULL;
2420 :
2421 5 : if( select_info->column_defs[0].field_type == SWQ_INTEGER )
2422 2 : compare_func = swq_compare_int;
2423 3 : else if( select_info->column_defs[0].field_type == SWQ_FLOAT )
2424 2 : compare_func = swq_compare_real;
2425 : else
2426 1 : compare_func = swq_compare_string;
2427 :
2428 5 : distinct_list = select_info->column_summary[0].distinct_list;
2429 5 : count = select_info->column_summary[0].count;
2430 :
2431 5 : qsort( distinct_list, count, sizeof(char *), compare_func );
2432 :
2433 : /* -------------------------------------------------------------------- */
2434 : /* Do we want the list ascending in stead of descending? */
2435 : /* -------------------------------------------------------------------- */
2436 5 : if( !select_info->order_defs[0].ascending_flag )
2437 : {
2438 : char *saved;
2439 : int i;
2440 :
2441 15 : for( i = 0; i < count/2; i++ )
2442 : {
2443 12 : saved = distinct_list[i];
2444 12 : distinct_list[i] = distinct_list[count-i-1];
2445 12 : distinct_list[count-i-1] = saved;
2446 : }
2447 : }
2448 :
2449 5 : return NULL;
2450 : }
2451 :
2452 : /************************************************************************/
2453 : /* swq_select_free() */
2454 : /************************************************************************/
2455 :
2456 49 : void swq_select_free( swq_select *select_info )
2457 :
2458 : {
2459 : int i;
2460 :
2461 49 : if( select_info == NULL )
2462 0 : return;
2463 :
2464 49 : if( select_info->where_expr != NULL )
2465 23 : swq_expr_free(select_info->where_expr);
2466 :
2467 49 : if( select_info->raw_select != NULL )
2468 49 : SWQ_FREE( select_info->raw_select );
2469 :
2470 49 : if( select_info->whole_where_clause != NULL )
2471 23 : SWQ_FREE( select_info->whole_where_clause );
2472 :
2473 111 : for( i = 0; i < select_info->table_count; i++ )
2474 : {
2475 62 : swq_table_def *table_def = select_info->table_defs + i;
2476 :
2477 62 : if( table_def->data_source != NULL )
2478 4 : SWQ_FREE( table_def->data_source );
2479 62 : SWQ_FREE( table_def->table_name );
2480 62 : SWQ_FREE( table_def->table_alias );
2481 : }
2482 49 : if( select_info->table_defs != NULL )
2483 49 : SWQ_FREE( select_info->table_defs );
2484 :
2485 184 : for( i = 0; i < select_info->result_columns; i++ )
2486 : {
2487 135 : if( select_info->column_defs[i].field_name != NULL )
2488 135 : SWQ_FREE( select_info->column_defs[i].field_name );
2489 135 : if( select_info->column_defs[i].col_func_name != NULL )
2490 3 : SWQ_FREE( select_info->column_defs[i].col_func_name );
2491 :
2492 143 : if( select_info->column_summary != NULL
2493 143 : && select_info->column_summary[i].distinct_list != NULL )
2494 : {
2495 : int j;
2496 :
2497 56 : for( j = 0; j < select_info->column_summary[i].count; j++ )
2498 49 : SWQ_FREE( select_info->column_summary[i].distinct_list[j] );
2499 :
2500 7 : SWQ_FREE( select_info->column_summary[i].distinct_list );
2501 : }
2502 : }
2503 :
2504 49 : if( select_info->column_defs != NULL )
2505 49 : SWQ_FREE( select_info->column_defs );
2506 :
2507 49 : if( select_info->column_summary != NULL )
2508 8 : SWQ_FREE( select_info->column_summary );
2509 :
2510 60 : for( i = 0; i < select_info->order_specs; i++ )
2511 : {
2512 11 : if( select_info->order_defs[i].field_name != NULL )
2513 11 : SWQ_FREE( select_info->order_defs[i].field_name );
2514 : }
2515 :
2516 49 : if( select_info->order_defs != NULL )
2517 11 : SWQ_FREE( select_info->order_defs );
2518 :
2519 62 : for( i = 0; i < select_info->join_count; i++ )
2520 : {
2521 13 : SWQ_FREE( select_info->join_defs[i].primary_field_name );
2522 13 : if( select_info->join_defs[i].secondary_field_name != NULL )
2523 13 : SWQ_FREE( select_info->join_defs[i].secondary_field_name );
2524 : }
2525 49 : if( select_info->join_defs != NULL )
2526 12 : SWQ_FREE( select_info->join_defs );
2527 :
2528 49 : SWQ_FREE( select_info );
2529 : }
2530 :
2531 : /************************************************************************/
2532 : /* swq_reform_command() */
2533 : /* */
2534 : /* Rebuild the command string from the components in the */
2535 : /* swq_select structure. The where expression is taken from */
2536 : /* the whole_where_clause instead of being reformed. The */
2537 : /* results of forming the command are applied to the raw_select */
2538 : /* field. */
2539 : /************************************************************************/
2540 :
2541 : #define CHECK_COMMAND( new_bytes ) grow_command( &command, &max_cmd_size, &cmd_size, new_bytes );
2542 :
2543 : static void grow_command( char **p_command, int *max_cmd_size, int *cmd_size,
2544 : int new_bytes );
2545 :
2546 0 : const char *swq_reform_command( swq_select *select_info )
2547 :
2548 : {
2549 : char *command;
2550 0 : int max_cmd_size = 10;
2551 0 : int cmd_size = 0;
2552 : int i;
2553 :
2554 0 : command = SWQ_MALLOC(max_cmd_size);
2555 :
2556 0 : strcpy( command, "SELECT " );
2557 :
2558 : /* -------------------------------------------------------------------- */
2559 : /* Handle the field list. */
2560 : /* -------------------------------------------------------------------- */
2561 0 : for( i = 0; i < select_info->result_columns; i++ )
2562 : {
2563 0 : swq_col_def *def = select_info->column_defs + i;
2564 0 : const char *distinct = "";
2565 :
2566 0 : if( def->distinct_flag )
2567 0 : distinct = "DISTINCT ";
2568 :
2569 0 : if( i != 0 )
2570 : {
2571 0 : CHECK_COMMAND(3);
2572 0 : strcat( command + cmd_size, ", " );
2573 : }
2574 :
2575 0 : if( def->col_func_name != NULL )
2576 : {
2577 0 : CHECK_COMMAND( strlen(def->col_func_name)
2578 : + strlen(def->field_name) + 15 );
2579 0 : sprintf( command + cmd_size, "%s(%s%s)",
2580 : def->col_func_name, distinct, def->field_name );
2581 : }
2582 : else
2583 : {
2584 0 : CHECK_COMMAND( strlen(def->field_name) + 15 );
2585 0 : sprintf( command + cmd_size, "%s\"%s\"",
2586 : distinct, def->field_name );
2587 : }
2588 : }
2589 :
2590 : /* -------------------------------------------------------------------- */
2591 : /* Handle the FROM tablename. */
2592 : /* -------------------------------------------------------------------- */
2593 0 : if( select_info->table_count > 0 )
2594 : {
2595 0 : CHECK_COMMAND( 10 + strlen(select_info->table_defs[0].table_name) );
2596 0 : sprintf( command + cmd_size, " FROM \"%s\"",
2597 0 : select_info->table_defs[0].table_name );
2598 : }
2599 :
2600 : /* -------------------------------------------------------------------- */
2601 : /* Handle the JOIN clause(s). */
2602 : /* -------------------------------------------------------------------- */
2603 : /* TODO notdef */
2604 :
2605 : /* -------------------------------------------------------------------- */
2606 : /* Add WHERE statement if it exists. */
2607 : /* -------------------------------------------------------------------- */
2608 0 : if( select_info->whole_where_clause != NULL )
2609 : {
2610 0 : CHECK_COMMAND( 12 + strlen(select_info->whole_where_clause) );
2611 0 : sprintf( command + cmd_size, " WHERE %s",
2612 : select_info->whole_where_clause );
2613 : }
2614 :
2615 : /* -------------------------------------------------------------------- */
2616 : /* Add order by clause(s) if appropriate. */
2617 : /* -------------------------------------------------------------------- */
2618 0 : for( i = 0; i < select_info->order_specs; i++ )
2619 : {
2620 0 : swq_order_def *def = select_info->order_defs + i;
2621 :
2622 0 : if( i == 0 )
2623 : {
2624 0 : CHECK_COMMAND( 12 );
2625 0 : sprintf( command + cmd_size, " ORDER BY " );
2626 : }
2627 : else
2628 : {
2629 0 : CHECK_COMMAND( 3 );
2630 0 : sprintf( command + cmd_size, ", " );
2631 : }
2632 :
2633 0 : CHECK_COMMAND( strlen(def->field_name)+1 );
2634 0 : sprintf( command + cmd_size, "\"%s\"", def->field_name );
2635 :
2636 0 : CHECK_COMMAND( 6 );
2637 0 : if( def->ascending_flag )
2638 0 : strcat( command + cmd_size, " ASC" );
2639 : else
2640 0 : strcat( command + cmd_size, " DESC" );
2641 : }
2642 :
2643 : /* -------------------------------------------------------------------- */
2644 : /* Assign back to the select info. */
2645 : /* -------------------------------------------------------------------- */
2646 0 : SWQ_FREE( select_info->raw_select );
2647 0 : select_info->raw_select = command;
2648 :
2649 0 : return NULL;
2650 : }
2651 :
2652 : /* helper for the swq_reform_command() function. */
2653 :
2654 0 : static void grow_command( char **p_command, int *max_cmd_size, int *cmd_size,
2655 : int new_bytes )
2656 :
2657 : {
2658 : char *new_command;
2659 :
2660 0 : *cmd_size += strlen(*p_command + *cmd_size);
2661 :
2662 0 : if( *cmd_size + new_bytes < *max_cmd_size - 1 )
2663 0 : return;
2664 :
2665 0 : *max_cmd_size = 2 * *max_cmd_size;
2666 0 : if( *max_cmd_size < *cmd_size + new_bytes )
2667 0 : *max_cmd_size = *cmd_size + new_bytes + 100;
2668 :
2669 0 : new_command = SWQ_MALLOC(*max_cmd_size);
2670 :
2671 0 : strcpy( new_command, *p_command );
2672 0 : SWQ_FREE( *p_command );
2673 0 : *p_command = new_command;
2674 : }
|