LCOV - code coverage report
Current view: directory - ogr - swq.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1121 742 66.2 %
Date: 2010-01-09 Functions: 30 27 90.0 %

       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                 : }

Generated by: LCOV version 1.7