ultimatepp/bazaar/plugin/gdal/ogr/swq_parser.y
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

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 );
}