mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-25 14:22:54 -06:00
879 lines
25 KiB
Text
879 lines
25 KiB
Text
%{
|
|
/******************************************************************************
|
|
*
|
|
* Component: OGR SQL Engine
|
|
* Purpose: expression and select parser grammar.
|
|
* Requires Bison 2.4.0 or newer to process. Use "make parser" target.
|
|
* Author: Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
|
|
#include "cpl_conv.h"
|
|
#include "cpl_string.h"
|
|
#include "ogr_geometry.h"
|
|
#include "swq.h"
|
|
|
|
#define YYSTYPE swq_expr_node*
|
|
|
|
/* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */
|
|
/* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */
|
|
/* increase YYINITDEPTH instead, but this will consume memory. */
|
|
/* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */
|
|
/* it appears to be a non documented feature of Bison */
|
|
#define YYSTYPE_IS_TRIVIAL 1
|
|
|
|
%}
|
|
|
|
%define api.pure
|
|
/* if the next %define is commented out, Bison 2.4 should be sufficient */
|
|
/* but will produce less prettier error messages */
|
|
%define parse.error verbose
|
|
%require "3.0"
|
|
|
|
%parse-param {swq_parse_context *context}
|
|
%lex-param {swq_parse_context *context}
|
|
|
|
%token SWQT_INTEGER_NUMBER "integer number"
|
|
%token SWQT_FLOAT_NUMBER "floating point number"
|
|
%token SWQT_STRING "string"
|
|
%token SWQT_IDENTIFIER "identifier"
|
|
%token SWQT_IN "IN"
|
|
%token SWQT_LIKE "LIKE"
|
|
%token SWQT_ESCAPE "ESCAPE"
|
|
%token SWQT_BETWEEN "BETWEEN"
|
|
%token SWQT_NULL "NULL"
|
|
%token SWQT_IS "IS"
|
|
%token SWQT_SELECT "SELECT"
|
|
%token SWQT_LEFT "LEFT"
|
|
%token SWQT_JOIN "JOIN"
|
|
%token SWQT_WHERE "WHERE"
|
|
%token SWQT_ON "ON"
|
|
%token SWQT_ORDER "ORDER"
|
|
%token SWQT_BY "BY"
|
|
%token SWQT_FROM "FROM"
|
|
%token SWQT_AS "AS"
|
|
%token SWQT_ASC "ASC"
|
|
%token SWQT_DESC "DESC"
|
|
%token SWQT_DISTINCT "DISTINCT"
|
|
%token SWQT_CAST "CAST"
|
|
%token SWQT_UNION "UNION"
|
|
%token SWQT_ALL "ALL"
|
|
|
|
%token SWQT_VALUE_START
|
|
%token SWQT_SELECT_START
|
|
|
|
%token END 0 "end of string"
|
|
|
|
%token SWQT_NOT "NOT"
|
|
%token SWQT_OR "OR"
|
|
%token SWQT_AND "AND"
|
|
|
|
%left SWQT_OR
|
|
%left SWQT_AND
|
|
%left SWQT_NOT
|
|
|
|
%left '=' '<' '>' '!' SWQT_BETWEEN SWQT_IN SWQT_LIKE SWQT_IS
|
|
%left SWQT_ESCAPE
|
|
|
|
%left '+' '-'
|
|
%left '*' '/' '%'
|
|
%left SWQT_UMINUS
|
|
|
|
%token SWQT_RESERVED_KEYWORD "reserved keyword"
|
|
|
|
/* Any grammar rule that does $$ = must be listed afterwards */
|
|
/* as well as SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER that are allocated by swqlex() */
|
|
%destructor { delete $$; } SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER
|
|
%destructor { delete $$; } value_expr_list field_value value_expr value_expr_non_logical type_def table_def
|
|
|
|
%%
|
|
|
|
input:
|
|
| SWQT_VALUE_START value_expr
|
|
{
|
|
context->poRoot = $2;
|
|
}
|
|
|
|
| SWQT_SELECT_START select_statement
|
|
{
|
|
context->poRoot = $2;
|
|
}
|
|
|
|
value_expr:
|
|
value_expr_non_logical
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
| value_expr SWQT_AND value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_AND );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr SWQT_OR value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_OR );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| SWQT_NOT value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $2 );
|
|
}
|
|
|
|
| value_expr '=' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_EQ );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr '<' '>' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_NE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr '!' '=' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_NE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr '<' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr '>' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_GT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr '<' '=' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr '=' '<' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr '=' '>' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr '>' '=' value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_GE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $4 );
|
|
}
|
|
|
|
| value_expr SWQT_LIKE value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LIKE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr SWQT_NOT SWQT_LIKE value_expr
|
|
{
|
|
swq_expr_node *like;
|
|
like = new swq_expr_node( SWQ_LIKE );
|
|
like->field_type = SWQ_BOOLEAN;
|
|
like->PushSubExpression( $1 );
|
|
like->PushSubExpression( $4 );
|
|
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( like );
|
|
}
|
|
|
|
| value_expr SWQT_LIKE value_expr SWQT_ESCAPE value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_LIKE );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $5 );
|
|
}
|
|
|
|
| value_expr SWQT_NOT SWQT_LIKE value_expr SWQT_ESCAPE value_expr
|
|
{
|
|
swq_expr_node *like;
|
|
like = new swq_expr_node( SWQ_LIKE );
|
|
like->field_type = SWQ_BOOLEAN;
|
|
like->PushSubExpression( $1 );
|
|
like->PushSubExpression( $4 );
|
|
like->PushSubExpression( $6 );
|
|
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( like );
|
|
}
|
|
|
|
| value_expr SWQT_IN '(' value_expr_list ')'
|
|
{
|
|
$$ = $4;
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->nOperation = SWQ_IN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->ReverseSubExpressions();
|
|
}
|
|
|
|
| value_expr SWQT_NOT SWQT_IN '(' value_expr_list ')'
|
|
{
|
|
swq_expr_node *in;
|
|
|
|
in = $5;
|
|
in->field_type = SWQ_BOOLEAN;
|
|
in->nOperation = SWQ_IN;
|
|
in->PushSubExpression( $1 );
|
|
in->ReverseSubExpressions();
|
|
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( in );
|
|
}
|
|
|
|
| value_expr SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_BETWEEN );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $5 );
|
|
}
|
|
|
|
| value_expr SWQT_NOT SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
|
|
{
|
|
swq_expr_node *between;
|
|
between = new swq_expr_node( SWQ_BETWEEN );
|
|
between->field_type = SWQ_BOOLEAN;
|
|
between->PushSubExpression( $1 );
|
|
between->PushSubExpression( $4 );
|
|
between->PushSubExpression( $6 );
|
|
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( between );
|
|
}
|
|
|
|
| value_expr SWQT_IS SWQT_NULL
|
|
{
|
|
$$ = new swq_expr_node( SWQ_ISNULL );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
| value_expr SWQT_IS SWQT_NOT SWQT_NULL
|
|
{
|
|
swq_expr_node *isnull;
|
|
|
|
isnull = new swq_expr_node( SWQ_ISNULL );
|
|
isnull->field_type = SWQ_BOOLEAN;
|
|
isnull->PushSubExpression( $1 );
|
|
|
|
$$ = new swq_expr_node( SWQ_NOT );
|
|
$$->field_type = SWQ_BOOLEAN;
|
|
$$->PushSubExpression( isnull );
|
|
}
|
|
|
|
value_expr_list:
|
|
value_expr ',' value_expr_list
|
|
{
|
|
$$ = $3;
|
|
$3->PushSubExpression( $1 );
|
|
}
|
|
|
|
| value_expr
|
|
{
|
|
$$ = new swq_expr_node( SWQ_ARGUMENT_LIST ); /* temporary value */
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
field_value:
|
|
SWQT_IDENTIFIER
|
|
{
|
|
$$ = $1; // validation deferred.
|
|
$$->eNodeType = SNT_COLUMN;
|
|
$$->field_index = $$->table_index = -1;
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
|
|
{
|
|
$$ = $1; // validation deferred.
|
|
$$->eNodeType = SNT_COLUMN;
|
|
$$->field_index = $$->table_index = -1;
|
|
$$->table_name = $$->string_value;
|
|
$$->string_value = CPLStrdup($3->string_value);
|
|
delete $3;
|
|
$3 = NULL;
|
|
}
|
|
|
|
value_expr_non_logical:
|
|
SWQT_INTEGER_NUMBER
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
| SWQT_FLOAT_NUMBER
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
| SWQT_STRING
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| field_value
|
|
{
|
|
$$ = $1;
|
|
}
|
|
|
|
| '(' value_expr ')'
|
|
{
|
|
$$ = $2;
|
|
}
|
|
|
|
| SWQT_NULL
|
|
{
|
|
$$ = new swq_expr_node((const char*)NULL);
|
|
}
|
|
|
|
| '-' value_expr_non_logical %prec SWQT_UMINUS
|
|
{
|
|
if ($2->eNodeType == SNT_CONSTANT)
|
|
{
|
|
$$ = $2;
|
|
$$->int_value *= -1;
|
|
$$->float_value *= -1;
|
|
}
|
|
else
|
|
{
|
|
$$ = new swq_expr_node( SWQ_MULTIPLY );
|
|
$$->PushSubExpression( new swq_expr_node(-1) );
|
|
$$->PushSubExpression( $2 );
|
|
}
|
|
}
|
|
|
|
| value_expr_non_logical '+' value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_ADD );
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr_non_logical '-' value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_SUBTRACT );
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr_non_logical '*' value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_MULTIPLY );
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr_non_logical '/' value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_DIVIDE );
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| value_expr_non_logical '%' value_expr_non_logical
|
|
{
|
|
$$ = new swq_expr_node( SWQ_MODULUS );
|
|
$$->PushSubExpression( $1 );
|
|
$$->PushSubExpression( $3 );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' value_expr_list ')'
|
|
{
|
|
const swq_operation *poOp =
|
|
swq_op_registrar::GetOperator( $1->string_value );
|
|
|
|
if( poOp == NULL )
|
|
{
|
|
if( context->bAcceptCustomFuncs )
|
|
{
|
|
$$ = $3;
|
|
$$->eNodeType = SNT_OPERATION;
|
|
$$->nOperation = SWQ_CUSTOM_FUNC;
|
|
$$->string_value = CPLStrdup($1->string_value);
|
|
$$->ReverseSubExpressions();
|
|
delete $1;
|
|
}
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Undefined function '%s' used.",
|
|
$1->string_value );
|
|
delete $1;
|
|
delete $3;
|
|
YYERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$$ = $3;
|
|
$$->eNodeType = SNT_OPERATION;
|
|
$$->nOperation = poOp->eOperation;
|
|
$$->ReverseSubExpressions();
|
|
delete $1;
|
|
}
|
|
}
|
|
|
|
| SWQT_CAST '(' value_expr SWQT_AS type_def ')'
|
|
{
|
|
$$ = $5;
|
|
$$->PushSubExpression( $3 );
|
|
$$->ReverseSubExpressions();
|
|
}
|
|
|
|
type_def:
|
|
SWQT_IDENTIFIER
|
|
{
|
|
$$ = new swq_expr_node( SWQ_CAST );
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' SWQT_INTEGER_NUMBER ')'
|
|
{
|
|
$$ = new swq_expr_node( SWQ_CAST );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' SWQT_INTEGER_NUMBER ',' SWQT_INTEGER_NUMBER ')'
|
|
{
|
|
$$ = new swq_expr_node( SWQ_CAST );
|
|
$$->PushSubExpression( $5 );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
/* e.g. GEOMETRY(POINT) */
|
|
| SWQT_IDENTIFIER '(' SWQT_IDENTIFIER ')'
|
|
{
|
|
OGRwkbGeometryType eType = OGRFromOGCGeomType($3->string_value);
|
|
if( !EQUAL($1->string_value,"GEOMETRY") ||
|
|
(wkbFlatten(eType) == wkbUnknown &&
|
|
!EQUALN($3->string_value, "GEOMETRY", strlen("GEOMETRY"))) )
|
|
{
|
|
yyerror (context, "syntax error");
|
|
delete $1;
|
|
delete $3;
|
|
YYERROR;
|
|
}
|
|
$$ = new swq_expr_node( SWQ_CAST );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
/* e.g. GEOMETRY(POINT,4326) */
|
|
| SWQT_IDENTIFIER '(' SWQT_IDENTIFIER ',' SWQT_INTEGER_NUMBER ')'
|
|
{
|
|
OGRwkbGeometryType eType = OGRFromOGCGeomType($3->string_value);
|
|
if( !EQUAL($1->string_value,"GEOMETRY") ||
|
|
(wkbFlatten(eType) == wkbUnknown &&
|
|
!EQUALN($3->string_value, "GEOMETRY", strlen("GEOMETRY"))) )
|
|
{
|
|
yyerror (context, "syntax error");
|
|
delete $1;
|
|
delete $3;
|
|
delete $5;
|
|
YYERROR;
|
|
}
|
|
$$ = new swq_expr_node( SWQ_CAST );
|
|
$$->PushSubExpression( $5 );
|
|
$$->PushSubExpression( $3 );
|
|
$$->PushSubExpression( $1 );
|
|
}
|
|
|
|
select_statement:
|
|
select_core opt_union_all
|
|
| '(' select_core ')' opt_union_all
|
|
|
|
select_core:
|
|
SWQT_SELECT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by
|
|
{
|
|
delete $4;
|
|
}
|
|
|
|
| SWQT_SELECT SWQT_DISTINCT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by
|
|
{
|
|
context->poCurSelect->query_mode = SWQM_DISTINCT_LIST;
|
|
delete $5;
|
|
}
|
|
|
|
opt_union_all:
|
|
| union_all select_statement
|
|
|
|
union_all: SWQT_UNION SWQT_ALL
|
|
{
|
|
swq_select* poNewSelect = new swq_select();
|
|
context->poCurSelect->PushUnionAll(poNewSelect);
|
|
context->poCurSelect = poNewSelect;
|
|
}
|
|
|
|
select_field_list:
|
|
column_spec
|
|
| column_spec ',' select_field_list
|
|
|
|
column_spec:
|
|
value_expr
|
|
{
|
|
if( !context->poCurSelect->PushField( $1 ) )
|
|
{
|
|
delete $1;
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| value_expr as_clause
|
|
{
|
|
if( !context->poCurSelect->PushField( $1, $2->string_value ) )
|
|
{
|
|
delete $1;
|
|
delete $2;
|
|
YYERROR;
|
|
}
|
|
delete $2;
|
|
}
|
|
|
|
| '*'
|
|
{
|
|
swq_expr_node *poNode = new swq_expr_node();
|
|
poNode->eNodeType = SNT_COLUMN;
|
|
poNode->string_value = CPLStrdup( "*" );
|
|
poNode->table_index = poNode->field_index = -1;
|
|
|
|
if( !context->poCurSelect->PushField( poNode ) )
|
|
{
|
|
delete poNode;
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '.' '*'
|
|
{
|
|
CPLString osTableName;
|
|
|
|
osTableName = $1->string_value;
|
|
|
|
delete $1;
|
|
$1 = NULL;
|
|
|
|
swq_expr_node *poNode = new swq_expr_node();
|
|
poNode->eNodeType = SNT_COLUMN;
|
|
poNode->table_name = CPLStrdup(osTableName );
|
|
poNode->string_value = CPLStrdup( "*" );
|
|
poNode->table_index = poNode->field_index = -1;
|
|
|
|
if( !context->poCurSelect->PushField( poNode ) )
|
|
{
|
|
delete poNode;
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' '*' ')'
|
|
{
|
|
// special case for COUNT(*), confirm it.
|
|
if( !EQUAL($1->string_value,"COUNT") )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Syntax Error with %s(*).",
|
|
$1->string_value );
|
|
delete $1;
|
|
YYERROR;
|
|
}
|
|
|
|
delete $1;
|
|
$1 = NULL;
|
|
|
|
swq_expr_node *poNode = new swq_expr_node();
|
|
poNode->eNodeType = SNT_COLUMN;
|
|
poNode->string_value = CPLStrdup( "*" );
|
|
poNode->table_index = poNode->field_index = -1;
|
|
|
|
swq_expr_node *count = new swq_expr_node( (swq_op)SWQ_COUNT );
|
|
count->PushSubExpression( poNode );
|
|
|
|
if( !context->poCurSelect->PushField( count ) )
|
|
{
|
|
delete count;
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' '*' ')' as_clause
|
|
{
|
|
// special case for COUNT(*), confirm it.
|
|
if( !EQUAL($1->string_value,"COUNT") )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Syntax Error with %s(*).",
|
|
$1->string_value );
|
|
delete $1;
|
|
delete $5;
|
|
YYERROR;
|
|
}
|
|
|
|
delete $1;
|
|
$1 = NULL;
|
|
|
|
swq_expr_node *poNode = new swq_expr_node();
|
|
poNode->eNodeType = SNT_COLUMN;
|
|
poNode->string_value = CPLStrdup( "*" );
|
|
poNode->table_index = poNode->field_index = -1;
|
|
|
|
swq_expr_node *count = new swq_expr_node( (swq_op)SWQ_COUNT );
|
|
count->PushSubExpression( poNode );
|
|
|
|
if( !context->poCurSelect->PushField( count, $5->string_value ) )
|
|
{
|
|
delete count;
|
|
delete $5;
|
|
YYERROR;
|
|
}
|
|
|
|
delete $5;
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')'
|
|
{
|
|
// special case for COUNT(DISTINCT x), confirm it.
|
|
if( !EQUAL($1->string_value,"COUNT") )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"DISTINCT keyword can only be used in COUNT() operator." );
|
|
delete $1;
|
|
delete $4;
|
|
YYERROR;
|
|
}
|
|
|
|
delete $1;
|
|
|
|
swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
|
|
count->PushSubExpression( $4 );
|
|
|
|
if( !context->poCurSelect->PushField( count, NULL, TRUE ) )
|
|
{
|
|
delete count;
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '(' SWQT_DISTINCT field_value ')' as_clause
|
|
{
|
|
// special case for COUNT(DISTINCT x), confirm it.
|
|
if( !EQUAL($1->string_value,"COUNT") )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"DISTINCT keyword can only be used in COUNT() operator." );
|
|
delete $1;
|
|
delete $4;
|
|
delete $6;
|
|
YYERROR;
|
|
}
|
|
|
|
swq_expr_node *count = new swq_expr_node( SWQ_COUNT );
|
|
count->PushSubExpression( $4 );
|
|
|
|
if( !context->poCurSelect->PushField( count, $6->string_value, TRUE ) )
|
|
{
|
|
delete $1;
|
|
delete count;
|
|
delete $6;
|
|
YYERROR;
|
|
}
|
|
|
|
delete $1;
|
|
delete $6;
|
|
}
|
|
|
|
as_clause:
|
|
SWQT_AS SWQT_IDENTIFIER
|
|
{
|
|
delete $1;
|
|
$$ = $2;
|
|
}
|
|
|
|
| SWQT_IDENTIFIER
|
|
|
|
|
|
opt_where:
|
|
| SWQT_WHERE value_expr
|
|
{
|
|
context->poCurSelect->where_expr = $2;
|
|
}
|
|
|
|
opt_joins:
|
|
| SWQT_JOIN table_def SWQT_ON value_expr opt_joins
|
|
{
|
|
context->poCurSelect->PushJoin( $2->int_value,
|
|
$4 );
|
|
delete $2;
|
|
}
|
|
| SWQT_LEFT SWQT_JOIN table_def SWQT_ON value_expr opt_joins
|
|
{
|
|
context->poCurSelect->PushJoin( $3->int_value,
|
|
$5 );
|
|
delete $3;
|
|
}
|
|
|
|
opt_order_by:
|
|
| SWQT_ORDER SWQT_BY sort_spec_list
|
|
|
|
sort_spec_list:
|
|
sort_spec ',' sort_spec_list
|
|
| sort_spec
|
|
|
|
sort_spec:
|
|
field_value
|
|
{
|
|
context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
|
|
delete $1;
|
|
$1 = NULL;
|
|
}
|
|
| field_value SWQT_ASC
|
|
{
|
|
context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
|
|
delete $1;
|
|
$1 = NULL;
|
|
}
|
|
| field_value SWQT_DESC
|
|
{
|
|
context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, FALSE );
|
|
delete $1;
|
|
$1 = NULL;
|
|
}
|
|
|
|
table_def:
|
|
SWQT_IDENTIFIER
|
|
{
|
|
int iTable;
|
|
iTable =context->poCurSelect->PushTableDef( NULL, $1->string_value,
|
|
NULL );
|
|
delete $1;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER as_clause
|
|
{
|
|
int iTable;
|
|
iTable = context->poCurSelect->PushTableDef( NULL, $1->string_value,
|
|
$2->string_value );
|
|
delete $1;
|
|
delete $2;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|
|
|
|
| SWQT_STRING '.' SWQT_IDENTIFIER
|
|
{
|
|
int iTable;
|
|
iTable = context->poCurSelect->PushTableDef( $1->string_value,
|
|
$3->string_value, NULL );
|
|
delete $1;
|
|
delete $3;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|
|
|
|
| SWQT_STRING '.' SWQT_IDENTIFIER as_clause
|
|
{
|
|
int iTable;
|
|
iTable = context->poCurSelect->PushTableDef( $1->string_value,
|
|
$3->string_value,
|
|
$4->string_value );
|
|
delete $1;
|
|
delete $3;
|
|
delete $4;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
|
|
{
|
|
int iTable;
|
|
iTable = context->poCurSelect->PushTableDef( $1->string_value,
|
|
$3->string_value, NULL );
|
|
delete $1;
|
|
delete $3;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|
|
|
|
| SWQT_IDENTIFIER '.' SWQT_IDENTIFIER as_clause
|
|
{
|
|
int iTable;
|
|
iTable = context->poCurSelect->PushTableDef( $1->string_value,
|
|
$3->string_value,
|
|
$4->string_value );
|
|
delete $1;
|
|
delete $3;
|
|
delete $4;
|
|
|
|
$$ = new swq_expr_node( iTable );
|
|
}
|