8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-28 03:23:03 +01:00
firebird-mirror/src/dsql/parse.y
alexpeshkoff 27a97e2a6a 1. Modified syntax of ALTER ROLE command according to Dmitry's request.
2. Avoid any use of predefined NT group name "Domain Admins".
3. Fixed DYN code generation for USER operations.

                     ***** WARNING *****
After this commit all previous backups of 2.5 databases with turned on
admins mapping become unrestorable. ODS is not changed.
2008-05-14 11:24:45 +00:00

6192 lines
150 KiB
Plaintext

%{
/*
* PROGRAM: Dynamic SQL runtime support
* MODULE: parse.y
* DESCRIPTION: Dynamic SQL parser
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
* 2001.05.20 Neil McCalden: Allow a udf to be used in a 'group by' clause.
* 2001.05.30 Claudio Valderrama: DROP TABLE and DROP VIEW lead now to two
* different node types so DDL can tell which is which.
* 2001.06.13 Claudio Valderrama: SUBSTRING is being surfaced.
* 2001.06.30 Claudio valderrama: Feed (line,column) for each node. See node.h.
* 2001.07.10 Claudio Valderrama: Better (line,column) report and "--" for comments.
* 2001.07.28 John Bellardo: Changes to support parsing LIMIT and FIRST
* 2001.08.03 John Bellardo: Finalized syntax for LIMIT, change LIMIT to SKIP
* 2001.08.05 Claudio Valderrama: closed Bug #448062 and other spaces that appear
* in rdb$*_source fields when altering domains plus one unexpected null pointer.
* 2001.08.12 Claudio Valderrama: adjust SUBSTRING's starting pos argument here
* and not in gen.c; this closes Bug #450301.
* 2001.10.01 Claudio Valderrama: enable explicit GRANT...to ROLE role_name.
* 2001.10.06 Claudio Valderrama: Honor explicit USER keyword in GRANTs and REVOKEs.
* 2002.07.05 Mark O'Donohue: change keyword DEBUG to KW_DEBUG to avoid
* clashes with normal DEBUG macro.
* 2002.07.30 Arno Brinkman:
* 2002.07.30 Let IN predicate handle value_expressions
* 2002.07.30 tokens CASE, NULLIF, COALESCE added
* 2002.07.30 See block < CASE expression > what is added to value as case_expression
* 2002.07.30 function is split up into aggregate_function, numeric_value_function, string_value_function, generate_value_function
* 2002.07.30 new group_by_function and added to grp_column_elem
* 2002.07.30 cast removed from function and added as cast_specification to value
* 2002.08.04 Claudio Valderrama: allow declaring and defining variables at the same time
* 2002.08.04 Dmitry Yemanov: ALTER VIEW
* 2002.08.06 Arno Brinkman: ordinal added to grp_column_elem for using positions in group by
* 2002.08.07 Dmitry Yemanov: INT64/LARGEINT are replaced with BIGINT and available in dialect 3 only
* 2002.08.31 Dmitry Yemanov: allowed user-defined index names for PK/FK/UK constraints
* 2002.09.01 Dmitry Yemanov: RECREATE VIEW
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
* exception handling in SPs/triggers,
* implemented ROWS_AFFECTED system variable
* 2002.10.21 Nickolay Samofatov: Added support for explicit pessimistic locks
* 2002.10.29 Nickolay Samofatov: Added support for savepoints
* 2002.12.03 Dmitry Yemanov: Implemented ORDER BY clause in subqueries.
* 2002.12.18 Dmitry Yemanov: Added support for SQL-compliant labels and LEAVE statement
* 2002.12.28 Dmitry Yemanov: Added support for parametrized events.
* 2003.01.14 Dmitry Yemanov: Fixed bug with cursors in triggers.
* 2003.01.15 Dmitry Yemanov: Added support for runtime trigger action checks.
* 2003.02.10 Mike Nordell : Undefined Microsoft introduced macros to get a clean compile.
* 2003.05.24 Nickolay Samofatov: Make SKIP and FIRST non-reserved keywords
* 2003.06.13 Nickolay Samofatov: Make INSERTING/UPDATING/DELETING non-reserved keywords
* 2003.07.01 Blas Rodriguez Somoza: Change DEBUG and IN to avoid conflicts in win32 build/bison
* 2003.08.11 Arno Brinkman: Changed GROUP BY to support all expressions and added "AS" support
* with table alias. Also removed group_by_function and ordinal.
* 2003.08.14 Arno Brinkman: Added support for derived tables.
* 2003.10.05 Dmitry Yemanov: Added support for explicit cursors in PSQL.
* 2004.01.16 Vlad Horsun: added support for default parameters and
* EXECUTE BLOCK statement
* Adriano dos Santos Fernandes
*/
#include "firebird.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../jrd/common.h"
#include <stdarg.h>
#include "gen/iberror.h"
#include "../dsql/dsql.h"
#include "../dsql/node.h"
#include "../jrd/ibase.h"
#include "../jrd/flags.h"
#include "../jrd/jrd.h"
#include "../dsql/errd_proto.h"
#include "../dsql/hsh_proto.h"
#include "../dsql/make_proto.h"
#include "../dsql/keywords.h"
#include "../dsql/misc_func.h"
#include "../jrd/gds_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/intlobj_new.h"
/* since UNIX isn't standard, we have to define
stuff which is in <limits.h> (which isn't available
on all UNIXes... */
const long SHRT_POS_MAX = 32767;
const long SHRT_UNSIGNED_MAX = 65535;
const long SHRT_NEG_MAX = 32768;
const long LONG_POS_MAX = 2147483647;
const int POSITIVE = 0;
const int NEGATIVE = 1;
const int UNSIGNED = 2;
//const int MIN_CACHE_BUFFERS = 250;
//const int DEF_CACHE_BUFFERS = 1000;
/* Fix 69th procedure problem - solution from Oleg Loa */
#define YYSTACKSIZE 2048
#define YYMAXDEPTH 2048
/* Make bison allocate static stack */
#define YYINITDEPTH 2048
// Using this option causes build problems on Win32 with bison 1.28
//#define YYSTACK_USE_ALLOCA 1
#define YYSTYPE YYSTYPE
#if defined(DEBUG) || defined(DEV_BUILD)
#define YYDEBUG 1
#endif
#define YYMALLOC gds__alloc
#define YYFREE gds__free
static const char INTERNAL_FIELD_NAME[] = "DSQL internal"; /* NTX: placeholder */
inline SLONG trigger_type_suffix(const int slot1, const int slot2, const int slot3)
{
return ((slot1 << 1) | (slot2 << 3) | (slot3 << 5));
}
#include "../dsql/chars.h"
const int MAX_TOKEN_LEN = 256;
using namespace Jrd;
using namespace Dsql;
#ifdef NOT_USED_OR_REPLACED
static bool long_int(dsql_nod*, SLONG*);
#endif
static dsql_fld* make_field (dsql_nod*);
static dsql_fil* make_file();
static void prepare_console_debug (int, int *);
#ifdef NOT_USED_OR_REPLACED
static bool short_int(dsql_nod*, SLONG*, SSHORT);
#endif
static void stack_nodes (dsql_nod*, DsqlNodStack&);
static Firebird::MetaName toName(dsql_nod* node);
static void yyabandon (SLONG, ISC_STATUS);
inline void check_bound(const char* const to, const char* const string)
{
if ((to - string) >= MAX_TOKEN_LEN)
yyabandon (-104, isc_token_too_long);
}
inline void check_copy_incr(char*& to, const char ch, const char* const string)
{
check_bound(to, string);
*to++ = ch;
}
%}
/* token declarations */
/* Tokens are organized chronologically by date added.
See dsql/keywords.cpp for a list organized alphabetically */
/* Tokens in v4.0 -- not separated into v3 and v4 tokens */
%token ACTIVE
%token ADD
%token AFTER
%token ALL
%token ALTER
%token AND
%token ANY
%token AS
%token ASC
%token AT
%token AVG
%token AUTO
%token BEFORE
%token BEGIN
%token BETWEEN
%token BLOB
%token BY
%token CAST
%token CHARACTER
%token CHECK
%token COLLATE
%token COMMA
%token COMMIT
%token COMMITTED
%token COMPUTED
%token CONCATENATE
%token CONDITIONAL
%token CONSTRAINT
%token CONTAINING
%token COUNT
%token CREATE
%token CSTRING
%token CURRENT
%token CURSOR
%token DATABASE
%token DATE
%token DB_KEY
%token KW_DEBUG
%token DECIMAL
%token DECLARE
%token DEFAULT
%token KW_DELETE
%token DESC
%token DISTINCT
%token DO
%token DOMAIN
%token DROP
%token ELSE
%token END
%token ENTRY_POINT
%token EQL
%token ESCAPE
%token EXCEPTION
%token EXECUTE
%token EXISTS
%token EXIT
%token EXTERNAL
%token FILTER
%token FOR
%token FOREIGN
%token FROM
%token FULL
%token FUNCTION
%token GDSCODE
%token GEQ
%token GENERATOR
%token GEN_ID
%token GRANT
%token GROUP
%token GTR
%token HAVING
%token IF
%token KW_IN
%token INACTIVE
%token INNER
%token INPUT_TYPE
%token INDEX
%token INSERT
%token INTEGER
%token INTO
%token IS
%token ISOLATION
%token JOIN
%token KEY
%token KW_CHAR
%token KW_DEC
%token KW_DOUBLE
%token KW_FILE
%token KW_FLOAT
%token KW_INT
%token KW_LONG
%token KW_NULL
%token KW_NUMERIC
%token KW_UPPER
%token KW_VALUE
%token LENGTH
%token LPAREN
%token LEFT
%token LEQ
%token LEVEL
%token LIKE
%token LSS
%token MANUAL
%token MAXIMUM
%token MAX_SEGMENT
%token MERGE
%token MINIMUM
%token MODULE_NAME
%token NAMES
%token NATIONAL
%token NATURAL
%token NCHAR
%token NEQ
%token NO
%token NOT
%token NOT_GTR
%token NOT_LSS
%token OF
%token ON
%token ONLY
%token OPTION
%token OR
%token ORDER
%token OUTER
%token OUTPUT_TYPE
%token OVERFLOW
%token PAGE
%token PAGES
%token KW_PAGE_SIZE
%token PARAMETER
%token PASSWORD
%token PLAN
%token POSITION
%token POST_EVENT
%token PRECISION
%token PRIMARY
%token PRIVILEGES
%token PROCEDURE
%token PROTECTED
%token READ
%token REAL
%token REFERENCES
%token RESERVING
%token RETAIN
%token RETURNING_VALUES
%token RETURNS
%token REVOKE
%token RIGHT
%token RPAREN
%token ROLLBACK
%token SEGMENT
%token SELECT
%token SET
%token SHADOW
%token KW_SHARED
%token SINGULAR
%token KW_SIZE
%token SMALLINT
%token SNAPSHOT
%token SOME
%token SORT
%token SQLCODE
%token STABILITY
%token STARTING
%token STATISTICS
%token SUB_TYPE
%token SUSPEND
%token SUM
%token TABLE
%token THEN
%token TO
%token TRANSACTION
%token TRIGGER
%token UNCOMMITTED
%token UNION
%token UNIQUE
%token UPDATE
%token USER
%token VALUES
%token VARCHAR
%token VARIABLE
%token VARYING
%token VERSION
%token VIEW
%token WAIT
%token WHEN
%token WHERE
%token WHILE
%token WITH
%token WORK
%token WRITE
%token FLOAT_NUMBER NUMBER NUMERIC SYMBOL STRING INTRODUCER
/* New tokens added v5.0 */
%token ACTION
%token ADMIN
%token CASCADE
%token FREE_IT /* ISC SQL extension */
%token RESTRICT
%token ROLE
/* New tokens added v6.0 */
%token COLUMN
%token KW_TYPE
%token EXTRACT
%token YEAR
%token MONTH
%token DAY
%token HOUR
%token MINUTE
%token SECOND
%token WEEKDAY /* ISC SQL extension */
%token YEARDAY /* ISC SQL extension */
%token TIME
%token TIMESTAMP
%token CURRENT_DATE
%token CURRENT_TIME
%token CURRENT_TIMESTAMP
/* special aggregate token types returned by lex in v6.0 */
%token NUMBER64BIT SCALEDINT
/* CVC: Special Firebird additions. */
%token CURRENT_USER
%token CURRENT_ROLE
%token KW_BREAK
%token SUBSTRING
%token RECREATE
%token KW_DESCRIPTOR
%token FIRST
%token SKIP
/* tokens added for Firebird 1.5 */
%token CURRENT_CONNECTION
%token CURRENT_TRANSACTION
%token BIGINT
%token CASE
%token NULLIF
%token COALESCE
%token USING
%token NULLS
%token LAST
%token ROW_COUNT
%token LOCK
%token SAVEPOINT
%token RELEASE
%token STATEMENT
%token LEAVE
%token INSERTING
%token UPDATING
%token DELETING
/* tokens added for Firebird 2.0 */
%token BACKUP
%token KW_DIFFERENCE
%token OPEN
%token CLOSE
%token FETCH
%token ROWS
%token BLOCK
%token IIF
%token SCALAR_ARRAY
%token CROSS
%token NEXT
%token SEQUENCE
%token RESTART
%token BOTH
%token COLLATION
%token COMMENT
%token BIT_LENGTH
%token CHAR_LENGTH
%token CHARACTER_LENGTH
%token LEADING
%token KW_LOWER
%token OCTET_LENGTH
%token TRAILING
%token TRIM
%token RETURNING
%token KW_IGNORE
%token LIMBO
%token UNDO
%token REQUESTS
%token TIMEOUT
/* tokens added for Firebird 2.1 */
%token ABS
%token ACCENT
%token ACOS
%token ALWAYS
%token ASCII_CHAR
%token ASCII_VAL
%token ASIN
%token ATAN
%token ATAN2
%token BIN_AND
%token BIN_OR
%token BIN_SHL
%token BIN_SHR
%token BIN_XOR
%token CEIL
%token CONNECT
%token COS
%token COSH
%token COT
%token DATEADD
%token DATEDIFF
%token DECODE
%token DISCONNECT
%token EXP
%token FLOOR
%token GEN_UUID
%token GENERATED
%token GLOBAL
%token HASH
%token INSENSITIVE
%token LIST
%token LN
%token LOG
%token LOG10
%token LPAD
%token MATCHED
%token MATCHING
%token MAXVALUE
%token MILLISECOND
%token MINVALUE
%token MOD
%token OVERLAY
%token PAD
%token PI
%token PLACING
%token POWER
%token PRESERVE
%token RAND
%token RECURSIVE
%token REPLACE
%token REVERSE
%token ROUND
%token RPAD
%token SENSITIVE
%token SIGN
%token SIN
%token SINH
%token SPACE
%token SQRT
%token START
%token TAN
%token TANH
%token TEMPORARY
%token TRUNC
%token WEEK
// tokens added for Firebird 2.5
%token AUTONOMOUS
%token CHAR_TO_UUID
%token FIRSTNAME
%token LASTNAME
%token MIDDLENAME
%token MAPPING
%token OS_NAME
%token SIMILAR
%token UUID_TO_CHAR
// new execute statement
%token COMMON
%token DATA
%token SOURCE
%token TWO_PHASE
%token BIND_PARAM
%token BIN_NOT
/* precedence declarations for expression evaluation */
%left OR
%left AND
%left NOT
%left '=' '<' '>' LIKE EQL NEQ GTR LSS GEQ LEQ NOT_GTR NOT_LSS
%left '+' '-'
%left '*' '/'
%left CONCATENATE
%left COLLATE
/* Fix the dangling IF-THEN-ELSE problem */
%nonassoc THEN
%nonassoc ELSE
/* The same issue exists with ALTER COLUMN now that keywords can be used
in order to change their names. The syntax which shows the issue is:
ALTER COLUMN where column is part of the alter statement
or
ALTER COLUMN where column is the name of the column in the relation
*/
%nonassoc ALTER
%nonassoc COLUMN
%%
/* list of possible statements */
top : statement
{ DSQL_parse = $1; }
| statement ';'
{ DSQL_parse = $1; }
;
statement : alter
| blob_io
| comment
| commit
| create
| create_or_alter
| declare
| delete
| drop
| grant
| insert
| merge
| exec_procedure
| exec_block
| recreate
| revoke
| rollback
| savepoint
| select
| set
| update
| update_or_insert
| KW_DEBUG signed_short_integer
{ prepare_console_debug ((IPTR) $2, &yydebug);
$$ = make_node (nod_null, (int) 0, NULL); }
;
/* GRANT statement */
grant : GRANT privileges ON table_noise simple_table_name
TO non_role_grantee_list grant_option
{ $$ = make_node (nod_grant, (int) e_grant_count,
$2, $5, make_list($7), $8); }
| GRANT proc_privileges ON PROCEDURE simple_proc_name
TO non_role_grantee_list grant_option
{ $$ = make_node (nod_grant, (int) e_grant_count,
$2, $5, make_list($7), $8); }
| GRANT role_name_list TO role_grantee_list role_admin_option
{ $$ = make_node (nod_grant, (int) e_grant_count,
make_list($2), make_list($4), NULL, $5); }
;
table_noise : TABLE
|
;
privileges : ALL
{ $$ = make_node (nod_all, (int) 0, NULL); }
| ALL PRIVILEGES
{ $$ = make_node (nod_all, (int) 0, NULL); }
| privilege_list
{ $$ = make_list ($1); }
;
privilege_list : privilege
| privilege_list ',' privilege
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
proc_privileges : EXECUTE
{ $$ = make_list (make_node (nod_execute, (int) 0, NULL)); }
;
privilege : SELECT
{ $$ = make_node (nod_select, (int) 0, NULL); }
| INSERT
{ $$ = make_node (nod_insert, (int) 0, NULL); }
| KW_DELETE
{ $$ = make_node (nod_delete, (int) 0, NULL); }
| UPDATE column_parens_opt
{ $$ = make_node (nod_update, (int) 1, $2); }
| REFERENCES column_parens_opt
{ $$ = make_node (nod_references, (int) 1, $2); }
;
grant_option : WITH GRANT OPTION
{ $$ = make_node (nod_grant, (int) 0, NULL); }
|
{ $$ = NULL; }
;
role_admin_option : WITH ADMIN OPTION
{ $$ = make_node (nod_grant_admin, (int) 0, NULL); }
|
{ $$ = NULL; }
;
simple_proc_name: symbol_procedure_name
{ $$ = make_node (nod_procedure_name, (int) 1, $1); }
;
/* REVOKE statement */
revoke : REVOKE rev_grant_option privileges ON table_noise simple_table_name
FROM non_role_grantee_list
{ $$ = make_node (nod_revoke, (int) e_grant_count,
$3, $6, make_list($8), $2); }
| REVOKE rev_grant_option proc_privileges ON PROCEDURE simple_proc_name
FROM non_role_grantee_list
{ $$ = make_node (nod_revoke, (int) e_grant_count,
$3, $6, make_list($8), $2); }
| REVOKE rev_admin_option role_name_list FROM role_grantee_list
{ $$ = make_node (nod_revoke, (int) e_grant_count,
make_list($3), make_list($5), NULL, $2); }
;
rev_grant_option : GRANT OPTION FOR
{ $$ = make_node (nod_grant, (int) 0, NULL); }
|
{ $$ = NULL; }
;
rev_admin_option : ADMIN OPTION FOR
{ $$ = make_node (nod_grant_admin, (int) 0, NULL); }
|
{ $$ = NULL; }
;
non_role_grantee_list : grantee_list
| user_grantee_list
;
grantee_list : grantee
| grantee_list ',' grantee
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
| grantee_list ',' user_grantee
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
| user_grantee_list ',' grantee
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
grantee : PROCEDURE symbol_procedure_name
{ $$ = make_node (nod_proc_obj, (int) 1, $2); }
| TRIGGER symbol_trigger_name
{ $$ = make_node (nod_trig_obj, (int) 1, $2); }
| VIEW symbol_view_name
{ $$ = make_node (nod_view_obj, (int) 1, $2); }
| ROLE symbol_role_name
{ $$ = make_node (nod_role_name, (int) 1, $2); }
;
user_grantee_list : user_grantee
| user_grantee_list ',' user_grantee
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
/* CVC: In the future we can deprecate the first implicit form since we'll support
explicit grant/revoke for both USER and ROLE keywords & object types. */
user_grantee : symbol_user_name
{ $$ = make_node (nod_user_name, (int) 1, $1); }
| USER symbol_user_name
{ $$ = make_node (nod_user_name, (int) 2, $2, NULL); }
| GROUP symbol_user_name
{ $$ = make_node (nod_user_group, (int) 1, $2); }
;
role_name_list : role_name
| role_name_list ',' role_name
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
role_name : symbol_role_name
{ $$ = make_node (nod_role_name, (int) 1, $1); }
;
role_grantee_list : role_grantee
| role_grantee_list ',' role_grantee
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
role_grantee : symbol_user_name
{ $$ = make_node (nod_user_name, (int) 1, $1); }
| USER symbol_user_name
{ $$ = make_node (nod_user_name, (int) 1, $2); }
;
/* DECLARE operations */
declare : DECLARE declare_clause
{ $$ = $2;}
;
declare_clause : FILTER filter_decl_clause
{ $$ = $2; }
| EXTERNAL FUNCTION udf_decl_clause
{ $$ = $3; }
;
udf_decl_clause : symbol_UDF_name arg_desc_list1 RETURNS return_value1
ENTRY_POINT sql_string MODULE_NAME sql_string
{ $$ = make_node (nod_def_udf, (int) e_udf_count,
$1, $6, $8, make_list ($2), $4); }
;
udf_data_type : simple_type
| BLOB
{ lex.g_field->fld_dtype = dtype_blob; }
| CSTRING '(' pos_short_integer ')' charset_clause
{
lex.g_field->fld_dtype = dtype_cstring;
lex.g_field->fld_character_length = (USHORT)(IPTR) $3; }
;
arg_desc_list1 :
{ $$ = NULL; }
| arg_desc_list
| '(' arg_desc_list ')'
{ $$ = $2; }
;
arg_desc_list : arg_desc
| arg_desc_list ',' arg_desc
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
/*arg_desc : init_data_type udf_data_type
{ $$ = $1; } */
arg_desc : init_data_type udf_data_type param_mechanism
{ $$ = make_node (nod_udf_param, (int) e_udf_param_count,
$1, $3); }
;
param_mechanism :
{ $$ = NULL; } /* Beware: ddl.cpp converts this to mean FUN_reference. */
| BY KW_DESCRIPTOR
{ $$ = MAKE_const_slong (FUN_descriptor); }
| BY SCALAR_ARRAY
{ $$ = MAKE_const_slong (FUN_scalar_array); }
| KW_NULL
{ $$ = MAKE_const_slong (FUN_ref_with_null); }
;
return_value1 : return_value
| '(' return_value ')'
{ $$ = $2; }
;
return_value : init_data_type udf_data_type return_mechanism
{ $$ = make_node (nod_udf_return_value, (int) e_udf_param_count,
$1, $3); }
| PARAMETER pos_short_integer
{ $$ = make_node (nod_udf_return_value, (int) e_udf_param_count,
NULL, MAKE_const_slong ((IPTR) $2));}
;
return_mechanism :
{ $$ = MAKE_const_slong (FUN_reference); }
| BY KW_VALUE
{ $$ = MAKE_const_slong (FUN_value); }
| BY KW_DESCRIPTOR
{ $$ = MAKE_const_slong (FUN_descriptor); }
| FREE_IT
{ $$ = MAKE_const_slong (-1 * FUN_reference); }
/* FUN_refrence with FREE_IT is -ve */
| BY KW_DESCRIPTOR FREE_IT
{ $$ = MAKE_const_slong (-1 * FUN_descriptor); }
;
filter_decl_clause : symbol_filter_name INPUT_TYPE blob_filter_subtype OUTPUT_TYPE blob_filter_subtype
ENTRY_POINT sql_string MODULE_NAME sql_string
{ $$ = make_node (nod_def_filter, (int) e_filter_count,
$1, $3, $5, $7, $9); }
;
blob_filter_subtype : symbol_blob_subtype_name
{ $$ = MAKE_constant ((dsql_str*) $1, CONSTANT_STRING); }
|
signed_short_integer
{ $$ = MAKE_const_slong ((IPTR) $1); }
;
/* CREATE metadata operations */
create : CREATE create_clause
{ $$ = $2; }
;
create_clause : EXCEPTION exception_clause
{ $$ = $2; }
| unique_opt order_direction INDEX symbol_index_name ON simple_table_name index_definition
{ $$ = make_node (nod_def_index, (int) e_idx_count,
$1, $2, $4, $6, $7); }
| PROCEDURE procedure_clause
{ $$ = $2; }
| TABLE table_clause
{ $$ = $2; }
| GLOBAL TEMPORARY TABLE gtt_table_clause
{ $$ = $4; }
| TRIGGER trigger_clause
{ $$ = $2; }
| VIEW view_clause
{ $$ = $2; }
| GENERATOR generator_clause
{ $$ = $2; }
| SEQUENCE generator_clause
{ $$ = $2; }
| DATABASE db_clause
{ $$ = $2; }
| DOMAIN domain_clause
{ $$ = $2; }
| SHADOW shadow_clause
{ $$ = $2; }
| ROLE role_clause
{ $$ = $2; }
| COLLATION collation_clause
{ $$ = $2; }
| USER create_user_clause
{ $$ = $2; }
;
recreate : RECREATE recreate_clause
{ $$ = $2; }
;
recreate_clause : PROCEDURE rprocedure_clause
{ $$ = $2; }
| TABLE rtable_clause
{ $$ = $2; }
| GLOBAL TEMPORARY TABLE gtt_recreate_clause
{ $$ = $4; }
| VIEW rview_clause
{ $$ = $2; }
| TRIGGER rtrigger_clause
{ $$ = $2; }
/*
| DOMAIN rdomain_clause
{ $$ = $2; }
*/
| EXCEPTION rexception_clause
{ $$ = $2; }
;
create_or_alter : CREATE OR ALTER replace_clause
{ $$ = $4; }
;
replace_clause : PROCEDURE replace_procedure_clause
{ $$ = $2; }
| TRIGGER replace_trigger_clause
{ $$ = $2; }
| VIEW replace_view_clause
{ $$ = $2; }
| EXCEPTION replace_exception_clause
{ $$ = $2; }
;
/* CREATE EXCEPTION */
exception_clause : symbol_exception_name sql_string
{ $$ = make_node (nod_def_exception, (int) e_xcp_count,
$1, $2); }
;
rexception_clause : symbol_exception_name sql_string
{ $$ = make_node (nod_redef_exception, (int) e_xcp_count,
$1, $2); }
;
replace_exception_clause : symbol_exception_name sql_string
{ $$ = make_node (nod_replace_exception, (int) e_xcp_count,
$1, $2); }
;
alter_exception_clause : symbol_exception_name sql_string
{ $$ = make_node (nod_mod_exception, (int) e_xcp_count,
$1, $2); }
;
/* CREATE INDEX */
unique_opt : UNIQUE
{ $$ = make_node (nod_unique, 0, NULL); }
|
{ $$ = NULL; }
;
index_definition : column_list
{ $$ = make_list ($1); }
| column_parens
| computed_by '(' begin_trigger value end_trigger ')'
{ $$ = make_node (nod_def_computed, 2, $4, $5); }
;
/* CREATE SHADOW */
shadow_clause : pos_short_integer manual_auto conditional sql_string
first_file_length sec_shadow_files
{ $$ = make_node (nod_def_shadow, (int) e_shadow_count,
$1, $2, $3, $4, $5, make_list ($6)); }
;
manual_auto : MANUAL
{ $$ = MAKE_const_slong (1); }
| AUTO
{ $$ = MAKE_const_slong (0); }
|
{ $$ = MAKE_const_slong (0); }
;
conditional :
{ $$ = MAKE_const_slong (0); }
| CONDITIONAL
{ $$ = MAKE_const_slong (1); }
;
first_file_length :
{ $$ = (dsql_nod*) 0;}
| LENGTH equals long_integer page_noise
{ $$ = $3; }
;
sec_shadow_files :
{ $$ = NULL; }
| db_file_list
;
db_file_list : db_file
| db_file_list db_file
{ $$ = make_node (nod_list, (int) 2, $1, $2); }
;
/* CREATE DOMAIN */
domain_clause : column_def_name
as_opt
data_type
domain_default_opt
domain_constraint_clause
collate_clause
{ $$ = make_node (nod_def_domain, (int) e_dom_count, $1, $4, make_list ($5), $6); }
;
/*
rdomain_clause : DOMAIN alter_column_name alter_domain_ops
{ $$ = make_node (nod_mod_domain, (int) e_alt_count,
$2, make_list ($3)); }
*/
as_opt : AS
{ $$ = NULL; }
|
{ $$ = NULL; }
;
domain_default : DEFAULT begin_trigger default_value end_trigger
{ $$ = make_node (nod_def_default, (int) e_dft_count, $3, $4); }
;
domain_default_opt : domain_default
|
{ $$ = NULL; }
;
domain_constraint_clause : domain_constraint_list
|
{ $$ = NULL; }
;
domain_constraint_list : domain_constraint_def
| domain_constraint_list domain_constraint_def
{ $$ = make_node (nod_list, (int) 2, $1, $2); }
;
domain_constraint_def : domain_constraint
{ $$ = make_node (nod_rel_constraint, (int) 2, NULL, $1);}
;
domain_constraint : null_constraint
| check_constraint
;
null_constraint : NOT KW_NULL
{ $$ = make_node (nod_null, (int) 0, NULL); }
;
check_constraint : CHECK begin_trigger '(' search_condition ')' end_trigger
{ $$ = make_node (nod_def_constraint, (int) e_cnstr_count,
NULL, NULL, $4, NULL, $6); }
;
/* CREATE SEQUENCE/GENERATOR */
generator_clause : symbol_generator_name
{ $$ = make_node (nod_def_generator, (int) e_gen_count, $1); }
;
/* CREATE ROLE */
role_clause : symbol_role_name
{ $$ = make_node (nod_def_role, (int) 1, $1); }
;
/* CREATE COLLATION */
collation_clause : symbol_collation_name FOR symbol_character_set_name
collation_sequence_definition
collation_attribute_list_opt collation_specific_attribute_opt
{ $$ = make_node (nod_def_collation,
(int) e_def_coll_count, $1, $3, $4, make_list($5), $6); }
;
collation_sequence_definition :
FROM symbol_collation_name
{ $$ = make_node(nod_collation_from, 1, $2); }
| FROM EXTERNAL '(' sql_string ')'
{ $$ = make_node(nod_collation_from_external, 1, $4); }
|
{ $$ = NULL; }
;
collation_attribute_list_opt :
{ $$ = NULL; }
| collation_attribute_list
;
collation_attribute_list : collation_attribute
| collation_attribute_list collation_attribute
{ $$ = make_node(nod_list, 2, $1, $2); }
;
collation_attribute :
collation_pad_attribute
| collation_case_attribute
| collation_accent_attribute
;
collation_pad_attribute : NO PAD
{ $$ = make_node(nod_collation_attr, 1, -TEXTTYPE_ATTR_PAD_SPACE); }
| PAD SPACE
{ $$ = make_node(nod_collation_attr, 1, TEXTTYPE_ATTR_PAD_SPACE); }
;
collation_case_attribute : CASE SENSITIVE
{ $$ = make_node(nod_collation_attr, 1, -TEXTTYPE_ATTR_CASE_INSENSITIVE); }
| CASE INSENSITIVE
{ $$ = make_node(nod_collation_attr, 1, TEXTTYPE_ATTR_CASE_INSENSITIVE); }
;
collation_accent_attribute : ACCENT SENSITIVE
{ $$ = make_node(nod_collation_attr, 1, -TEXTTYPE_ATTR_ACCENT_INSENSITIVE); }
| ACCENT INSENSITIVE
{ $$ = make_node(nod_collation_attr, 1, TEXTTYPE_ATTR_ACCENT_INSENSITIVE); }
;
collation_specific_attribute_opt :
{ $$ = NULL; }
| sql_string
{ $$ = make_node(nod_collation_specific_attr, 1,
MAKE_constant((dsql_str*)$1, CONSTANT_STRING)); }
;
// ALTER CHARACTER SET
alter_charset_clause
: symbol_character_set_name SET DEFAULT COLLATION symbol_collation_name
{
$$ = makeClassNode(FB_NEW(getPool())
AlterCharSetNode(getPool(), toName($1), toName($5)));
}
;
/* CREATE DATABASE */
db_clause : db_name db_initial_desc1 db_rem_desc1
{ $$ = make_node (nod_def_database, (int) e_cdb_count,
$1, make_list($2), make_list ($3));}
;
equals :
| '='
;
db_name : sql_string
{ $$ = (dsql_nod*) $1; }
;
db_initial_desc1 :
{$$ = NULL;}
| db_initial_desc
;
db_initial_desc : db_initial_option
| db_initial_desc db_initial_option
{ $$ = make_node (nod_list, 2, $1, $2); }
;
db_initial_option: KW_PAGE_SIZE equals pos_short_integer
{ $$ = make_node (nod_page_size, 1, $3);}
| LENGTH equals long_integer page_noise
{ $$ = make_node (nod_file_length, 1, $3);}
| USER sql_string
{ $$ = make_node (nod_user_name, 1, $2);}
| PASSWORD sql_string
{ $$ = make_node (nod_password, 1, $2);}
| SET NAMES sql_string
{ $$ = make_node (nod_lc_ctype, 1, $3);}
;
db_rem_desc1 :
{$$ = NULL;}
| db_rem_desc
;
db_rem_desc : db_rem_option
| db_rem_desc db_rem_option
{ $$ = make_node (nod_list, 2, $1, $2); }
;
db_rem_option : db_file
| DEFAULT CHARACTER SET symbol_character_set_name
{ $$ = make_node (nod_dfl_charset, 1, $4);}
| DEFAULT CHARACTER SET symbol_character_set_name COLLATION symbol_collation_name
{ $$ = make_node (nod_list, 2,
make_node (nod_dfl_charset, 1, $4),
make_node (nod_dfl_collate, 1, $6));
}
| KW_DIFFERENCE KW_FILE sql_string
{ $$ = make_node (nod_difference_file, 1, $3); }
;
db_file : file1 sql_string file_desc1
{ lex.g_file->fil_name = (dsql_str*) $2;
$$ = (dsql_nod*) make_node (nod_file_desc, (int) 1,
(dsql_nod*) lex.g_file); }
;
file1 : KW_FILE
{ lex.g_file = make_file();}
;
file_desc1 :
| file_desc
;
file_desc : file_clause
| file_desc file_clause
;
file_clause : STARTING file_clause_noise long_integer
{ lex.g_file->fil_start = (IPTR) $3;}
| LENGTH equals long_integer page_noise
{ lex.g_file->fil_length = (IPTR) $3;}
;
file_clause_noise :
| AT
| AT PAGE
;
page_noise :
| PAGE
| PAGES
;
/* CREATE TABLE */
table_clause : simple_table_name external_file '(' table_elements ')'
{ $$ = make_flag_node (nod_def_relation, NOD_PERMANENT_TABLE,
(int) e_drl_count, $1, make_list ($4), $2); }
;
rtable_clause : simple_table_name external_file '(' table_elements ')'
{ $$ = make_flag_node (nod_redef_relation, NOD_PERMANENT_TABLE,
(int) e_drl_count, $1, make_list ($4), $2); }
;
gtt_table_clause : simple_table_name '(' table_elements ')' gtt_scope
{ $$ = make_flag_node (nod_def_relation, (SSHORT) (IPTR) ($5),
(int) e_drl_count, $1, make_list ($3), NULL); }
;
gtt_recreate_clause : simple_table_name '(' table_elements ')' gtt_scope
{ $$ = make_flag_node (nod_redef_relation, (SSHORT) (IPTR) ($5),
(int) e_drl_count, $1, make_list ($3), NULL); }
;
gtt_scope : ON COMMIT PRESERVE ROWS
{ $$ = (dsql_nod*) NOD_GLOBAL_TEMP_TABLE_PRESERVE_ROWS; }
| ON COMMIT KW_DELETE ROWS
{ $$ = (dsql_nod*) NOD_GLOBAL_TEMP_TABLE_DELETE_ROWS; }
|
{ $$ = (dsql_nod*) NOD_GLOBAL_TEMP_TABLE_DELETE_ROWS; }
;
external_file : EXTERNAL KW_FILE sql_string
{ $$ = $3; }
| EXTERNAL sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
table_elements : table_element
| table_elements ',' table_element
{ $$ = make_node (nod_list, 2, $1, $3); }
;
table_element : column_def
| table_constraint_definition
;
/* column definition */
column_def : column_def_name data_type_or_domain domain_default_opt
column_constraint_clause collate_clause
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, $3, make_list ($4), $5, $2, NULL); }
| column_def_name non_array_type def_computed
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, NULL, NULL, NULL, NULL, $3); }
| column_def_name def_computed
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, NULL, NULL, NULL, NULL, $2); }
;
/* value does allow parens around it, but there is a problem getting the
* source text
*/
def_computed : computed_clause '(' begin_trigger value end_trigger ')'
{
lex.g_field->fld_flags |= FLD_computed;
$$ = make_node (nod_def_computed, 2, $4, $5);
}
;
computed_clause : computed_by
| GENERATED ALWAYS AS
;
computed_by : COMPUTED BY
| COMPUTED
;
data_type_or_domain : data_type
{ $$ = NULL; }
| simple_column_name
{ $$ = make_node (nod_def_domain, (int) e_dom_count, $1, NULL, NULL, NULL); }
;
collate_clause : COLLATE symbol_collation_name
{ $$ = $2; }
|
{ $$ = NULL; }
;
column_def_name : simple_column_name
{
lex.g_field_name = $1;
lex.g_field = make_field ($1);
$$ = (dsql_nod*) lex.g_field;
}
;
simple_column_def_name : simple_column_name
{
lex.g_field = make_field ($1);
$$ = (dsql_nod*) lex.g_field;
}
;
data_type_descriptor : init_data_type data_type
{ $$ = $1; }
| KW_TYPE OF column_def_name
{
((dsql_fld*) $3)->fld_type_of_name = ((dsql_fld*) $3)->fld_name;
$$ = $3;
}
| KW_TYPE OF COLUMN symbol_column_name '.' symbol_column_name
{
lex.g_field = make_field(NULL);
lex.g_field->fld_type_of_table = ((dsql_str*) $4);
lex.g_field->fld_type_of_name = ((dsql_str*) $6)->str_data;
$$ = (dsql_nod*) lex.g_field;
}
| column_def_name
{
((dsql_fld*) $1)->fld_type_of_name = ((dsql_fld*) $1)->fld_name;
((dsql_fld*) $1)->fld_full_domain = true;
$$ = $1;
}
;
init_data_type :
{ lex.g_field = make_field (NULL);
$$ = (dsql_nod*) lex.g_field; }
;
default_value : constant
| current_user
| current_role
| internal_info
| null_value
| datetime_value_expression
;
column_constraint_clause :
{ $$ = NULL; }
| column_constraint_list
;
column_constraint_list : column_constraint_def
| column_constraint_list column_constraint_def
{ $$ = make_node (nod_list, (int) 2, $1, $2); }
;
column_constraint_def : constraint_name_opt column_constraint
{ $$ = make_node (nod_rel_constraint, (int) 2, $1, $2);}
;
column_constraint : null_constraint
| check_constraint
| REFERENCES simple_table_name column_parens_opt
referential_trigger_action constraint_index_opt
{ $$ = make_node (nod_foreign, (int) e_for_count,
make_node (nod_list, (int) 1, lex.g_field_name), $2, $3, $4, $5); }
| UNIQUE constraint_index_opt
{ $$ = make_node (nod_unique, 2, NULL, $2); }
| PRIMARY KEY constraint_index_opt
{ $$ = make_node (nod_primary, (int) e_pri_count, NULL, $3); }
;
/* table constraints */
table_constraint_definition : constraint_name_opt table_constraint
{ $$ = make_node (nod_rel_constraint, (int) 2, $1, $2);}
;
constraint_name_opt : CONSTRAINT symbol_constraint_name
{ $$ = $2; }
|
{ $$ = NULL ;}
;
table_constraint : unique_constraint
| primary_constraint
| referential_constraint
| check_constraint
;
unique_constraint : UNIQUE column_parens constraint_index_opt
{ $$ = make_node (nod_unique, 2, $2, $3); }
;
primary_constraint : PRIMARY KEY column_parens constraint_index_opt
{ $$ = make_node (nod_primary, (int) e_pri_count, $3, $4); }
;
referential_constraint : FOREIGN KEY column_parens REFERENCES
simple_table_name column_parens_opt
referential_trigger_action constraint_index_opt
{ $$ = make_node (nod_foreign, (int) e_for_count, $3, $5,
$6, $7, $8); }
;
constraint_index_opt : USING order_direction INDEX symbol_index_name
{ $$ = make_node (nod_def_index, (int) e_idx_count,
NULL, $2, $4, NULL, NULL); }
/*
| NO INDEX
{ $$ = NULL; }
*/
|
{ $$ = make_node (nod_def_index, (int) e_idx_count,
NULL, NULL, NULL, NULL, NULL); }
;
referential_trigger_action:
update_rule
{ $$ = make_node (nod_ref_upd_del, (int) e_ref_upd_del_count, $1, NULL);}
| delete_rule
{ $$ = make_node (nod_ref_upd_del, (int) e_ref_upd_del_count, NULL, $1);}
| delete_rule update_rule
{ $$ = make_node (nod_ref_upd_del, (int) e_ref_upd_del_count, $2, $1); }
| update_rule delete_rule
{ $$ = make_node (nod_ref_upd_del, (int) e_ref_upd_del_count, $1, $2);}
| /* empty */
{ $$ = NULL;}
;
update_rule : ON UPDATE referential_action
{ $$ = $3;}
;
delete_rule : ON KW_DELETE referential_action
{ $$ = $3;}
;
referential_action: CASCADE
{ $$ = make_flag_node (nod_ref_trig_action,
REF_ACTION_CASCADE, (int) e_ref_trig_action_count, NULL);}
| SET DEFAULT
{ $$ = make_flag_node (nod_ref_trig_action,
REF_ACTION_SET_DEFAULT, (int) e_ref_trig_action_count, NULL);}
| SET KW_NULL
{ $$ = make_flag_node (nod_ref_trig_action,
REF_ACTION_SET_NULL, (int) e_ref_trig_action_count, NULL);}
| NO ACTION
{ $$ = make_flag_node (nod_ref_trig_action,
REF_ACTION_NONE, (int) e_ref_trig_action_count, NULL);}
;
/* PROCEDURE */
procedure_clause : symbol_procedure_name input_parameters
output_parameters
AS begin_string
local_declaration_list
full_proc_block
end_trigger
{ $$ = make_node (nod_def_procedure,
(int) e_prc_count, $1, $2, $3, $6, $7, $8); }
;
rprocedure_clause : symbol_procedure_name input_parameters
output_parameters
AS begin_string
local_declaration_list
full_proc_block
end_trigger
{ $$ = make_node (nod_redef_procedure,
(int) e_prc_count, $1, $2, $3, $6, $7, $8); }
;
replace_procedure_clause : symbol_procedure_name input_parameters
output_parameters
AS begin_string
local_declaration_list
full_proc_block
end_trigger
{ $$ = make_node (nod_replace_procedure,
(int) e_prc_count, $1, $2, $3, $6, $7, $8); }
;
alter_procedure_clause : symbol_procedure_name input_parameters
output_parameters
AS begin_string
local_declaration_list
full_proc_block
end_trigger
{ $$ = make_node (nod_mod_procedure,
(int) e_prc_count, $1, $2, $3, $6, $7, $8); }
;
input_parameters : '(' input_proc_parameters ')'
{ $$ = make_list ($2); }
|
{ $$ = NULL; }
;
output_parameters : RETURNS '(' output_proc_parameters ')'
{ $$ = make_list ($3); }
|
{ $$ = NULL; }
;
input_proc_parameters : input_proc_parameter
| input_proc_parameters ',' input_proc_parameter
{ $$ = make_node (nod_list, 2, $1, $3); }
;
input_proc_parameter : simple_column_def_name domain_or_non_array_type collate_clause
default_par_opt
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, $4, NULL, $3, NULL, NULL); }
;
output_proc_parameters : proc_parameter
| output_proc_parameters ',' proc_parameter
{ $$ = make_node (nod_list, 2, $1, $3); }
;
proc_parameter : simple_column_def_name domain_or_non_array_type collate_clause
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, NULL, NULL, $3, NULL, NULL); }
;
default_par_opt : DEFAULT begin_trigger default_value end_trigger
{ $$ = make_node (nod_def_default, (int) e_dft_count, $3, $4); }
| '=' begin_trigger default_value end_trigger
{ $$ = make_node (nod_def_default, (int) e_dft_count, $3, $4); }
|
{ $$ = NULL; }
;
local_declaration_list : local_declarations
{ $$ = make_list ($1); }
|
{ $$ = NULL; }
;
local_declarations : local_declaration
| local_declarations local_declaration
{ $$ = make_node (nod_list, 2, $1, $2); }
;
local_declaration : stmt_start_line stmt_start_column DECLARE var_decl_opt local_declaration_item ';'
{
$$ = $5;
$$->nod_line = (IPTR) $1;
$$->nod_column = (IPTR) $2;
}
;
local_declaration_item : var_declaration_item
| cursor_declaration_item
;
var_declaration_item : column_def_name domain_or_non_array_type collate_clause default_par_opt
{ $$ = make_node (nod_def_field, (int) e_dfl_count,
$1, $4, NULL, $3, NULL, NULL); }
;
var_decl_opt : VARIABLE
{ $$ = NULL; }
|
{ $$ = NULL; }
;
cursor_declaration_item : symbol_cursor_name CURSOR FOR '(' select ')'
{ $$ = make_flag_node (nod_cursor, NOD_CURSOR_EXPLICIT,
(int) e_cur_count, $1, $5, NULL, NULL); }
;
proc_block : proc_statement
| full_proc_block
;
full_proc_block : stmt_start_line stmt_start_column BEGIN full_proc_block_body END
{
$$ = make_node (nod_src_info, e_src_info_count, $1, $2, $4);
}
;
full_proc_block_body : proc_statements
{ $$ = make_node (nod_block, (int) e_blk_count, make_list ($1), NULL); }
| proc_statements excp_hndl_statements
{ $$ = make_node (nod_block, (int) e_blk_count, make_list ($1), make_list ($2)); }
|
{ $$ = make_node (nod_block, (int) e_blk_count, NULL, NULL);}
;
proc_statements : proc_block
| proc_statements proc_block
{ $$ = make_node (nod_list, 2, $1, $2); }
;
proc_statement : stmt_start_line stmt_start_column simple_proc_statement ';'
{
$$ = make_node (nod_src_info, e_src_info_count, $1, $2, $3);
}
| stmt_start_line stmt_start_column complex_proc_statement
{
$$ = make_node (nod_src_info, e_src_info_count, $1, $2, $3);
}
;
stmt_start_line :
{ $$ = (dsql_nod*) (IPTR) lex.lines_bk; }
stmt_start_column :
{
const USHORT column = (lex.last_token_bk - lex.line_start_bk + 1);
$$ = (dsql_nod*) (IPTR) column;
}
simple_proc_statement : assignment
| insert
| merge
| update
| update_or_insert
| delete
| singleton_select
| exec_procedure
| exec_sql
| exec_into
| exec_function
| excp_statement
| raise_statement
| post_event
| cursor_statement
| breakleave
| SUSPEND
{ $$ = make_node (nod_return, (int) e_rtn_count, NULL); }
| EXIT
{ $$ = make_node (nod_exit, 0, NULL); }
;
complex_proc_statement
: in_autonomous_transaction
| if_then_else
| while
| for_select
| for_exec_into
;
in_autonomous_transaction
: KW_IN AUTONOMOUS TRANSACTION DO proc_block
{ $$ = make_node(nod_auto_trans, (int) e_auto_trans_count, $5); }
;
excp_statement : EXCEPTION symbol_exception_name
{ $$ = make_node (nod_exception_stmt, (int) e_xcp_count, $2, NULL); }
| EXCEPTION symbol_exception_name value
{ $$ = make_node (nod_exception_stmt, (int) e_xcp_count, $2, $3); }
;
raise_statement : EXCEPTION
{ $$ = make_node (nod_exception_stmt, (int) e_xcp_count, NULL, NULL); }
;
//exec_sql : EXECUTE STATEMENT value
// { $$ = make_node (nod_exec_sql, (int) e_exec_sql_count, $3); }
// ;
for_select : label_opt FOR select INTO variable_list cursor_def DO proc_block
{ $$ = make_node (nod_for_select, (int) e_flp_count, $3,
make_list ($5), $6, $8, $1); }
;
//for_exec_into : label_opt FOR EXECUTE STATEMENT value INTO variable_list DO proc_block
// { $$ = make_node (nod_exec_into, (int) e_exec_into_count, $5, $9, make_list ($7), $1); }
// ;
//
//exec_into : EXECUTE STATEMENT value INTO variable_list
// { $$ = make_node (nod_exec_into, (int) e_exec_into_count, $3, 0, make_list ($5)); }
// ;
exec_sql
: EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($3)->nod_arg[0], ($3)->nod_arg[1], 0, 0, $4, $5, $6, $7, 0);
}
;
exec_into
: EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
INTO variable_list
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($3)->nod_arg[0], ($3)->nod_arg[1], make_list ($9), 0, $4, $5, $6, $7, 0);
}
;
for_exec_into
: label_opt FOR EXECUTE STATEMENT exec_stmt_inputs
ext_datasrc_opt ext_user_opt ext_pwd_opt ext_tran_opt
INTO variable_list
DO proc_block
{
$$ = make_node (nod_exec_stmt, int (e_exec_stmt_count),
($5)->nod_arg[0], ($5)->nod_arg[1], make_list ($11), $13, $6, $7, $8, $9, $1);
}
;
exec_stmt_inputs
: value
{ $$ = make_node (nod_exec_stmt_inputs, e_exec_stmt_inputs_count, $1, NULL); }
| '(' value ')' '(' named_params_list ')'
{ $$ = make_node (nod_exec_stmt_inputs, e_exec_stmt_inputs_count, $2, make_list ($5)); }
| '(' value ')' '(' not_named_params_list ')'
{ $$ = make_node (nod_exec_stmt_inputs, e_exec_stmt_inputs_count, $2, make_list ($5)); }
;
named_params_list
: named_param
| named_params_list ',' named_param
{ $$ = make_node (nod_list, 2, $1, $3); }
;
named_param
: symbol_variable_name BIND_PARAM value
{ $$ = make_node (nod_named_param, e_named_param_count, $1, $3); }
;
not_named_params_list
: not_named_param
| not_named_params_list ',' not_named_param
{ $$ = make_node (nod_list, 2, $1, $3); }
;
not_named_param
: value
{ $$ = make_node (nod_named_param, e_named_param_count, NULL, $1); }
;
ext_datasrc_opt
: ON EXTERNAL DATA SOURCE value
{ $$ = $5; }
| ON EXTERNAL value
{ $$ = $3; }
|
{ $$ = make_node (nod_null, 0, NULL); }
;
ext_user_opt
: AS USER value
{ $$ = $3; }
|
{ $$ = make_node (nod_null, 0, NULL); }
;
ext_pwd_opt
: PASSWORD value
{ $$ = $2; }
|
{ $$ = make_node (nod_null, 0, NULL); }
;
ext_tran_opt
: WITH AUTONOMOUS TRANSACTION
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_AUTONOMOUS, 1, NULL); }
| WITH COMMON TRANSACTION
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_COMMON, 1, NULL); }
// | WITH TWO_PHASE TRANSACTION
// { $$ = make_flag_node(nod_tran_params, NOD_TRAN_2PC, 1, NULL); }
|
{ $$ = make_flag_node(nod_tran_params, NOD_TRAN_COMMON, 1, NULL); }
;
if_then_else : IF '(' search_condition ')' THEN proc_block ELSE proc_block
{ $$ = make_node (nod_if, (int) e_if_count, $3, $6, $8); }
| IF '(' search_condition ')' THEN proc_block
{ $$ = make_node (nod_if, (int) e_if_count, $3, $6, NULL); }
;
post_event : POST_EVENT value event_argument_opt
{ $$ = make_node (nod_post, (int) e_pst_count, $2, $3); }
;
event_argument_opt : /*',' value
{ $$ = $2; }
|*/
{ $$ = NULL; }
;
singleton_select : select INTO variable_list
{ $$ = make_node (nod_for_select, (int) e_flp_count, $1,
make_list ($3), NULL, NULL, NULL); }
;
variable : ':' symbol_variable_name
{ $$ = make_node (nod_var_name, (int) e_vrn_count,
$2); }
;
variable_list : variable
| column_name
| variable_list ',' column_name
{ $$ = make_node (nod_list, 2, $1, $3); }
| variable_list ',' variable
{ $$ = make_node (nod_list, 2, $1, $3); }
;
while : label_opt WHILE '(' search_condition ')' DO proc_block
{ $$ = make_node (nod_while, (int) e_while_count, $4, $7, $1); }
;
label_opt : symbol_label_name ':'
{ $$ = make_node (nod_label, (int) e_label_count, $1, NULL); }
|
{ $$ = NULL; }
;
breakleave : KW_BREAK
{ $$ = make_node (nod_breakleave, (int) e_breakleave_count, NULL); }
| LEAVE
{ $$ = make_node (nod_breakleave, (int) e_breakleave_count, NULL); }
| LEAVE symbol_label_name
{ $$ = make_node (nod_breakleave, (int) e_breakleave_count,
make_node (nod_label, (int) e_label_count, $2, NULL)); }
;
cursor_def : AS CURSOR symbol_cursor_name
{ $$ = make_flag_node (nod_cursor, NOD_CURSOR_FOR,
(int) e_cur_count, $3, NULL, NULL, NULL); }
|
{ $$ = NULL; }
;
excp_hndl_statements : excp_hndl_statement
| excp_hndl_statements excp_hndl_statement
{ $$ = make_node (nod_list, 2, $1, $2); }
;
excp_hndl_statement : WHEN errors DO proc_block
{ $$ = make_node (nod_on_error, (int) e_err_count,
make_list ($2), $4); }
;
errors : err
| errors ',' err
{ $$ = make_node (nod_list, 2, $1, $3); }
;
err : SQLCODE signed_short_integer
{ $$ = make_node (nod_sqlcode, 1, $2); }
| GDSCODE symbol_gdscode_name
{ $$ = make_node (nod_gdscode, 1, $2); }
| EXCEPTION symbol_exception_name
{ $$ = make_node (nod_exception, 1, $2); }
| ANY
{ $$ = make_node (nod_default, 1, NULL); }
;
cursor_statement : open_cursor
| fetch_cursor
| close_cursor
;
open_cursor : OPEN symbol_cursor_name
{ $$ = make_node (nod_cursor_open, (int) e_cur_stmt_count, $2, NULL, NULL); }
;
close_cursor : CLOSE symbol_cursor_name
{ $$ = make_node (nod_cursor_close, (int) e_cur_stmt_count, $2, NULL, NULL); }
;
fetch_cursor : FETCH fetch_opt symbol_cursor_name INTO variable_list
{ $$ = make_node (nod_cursor_fetch, (int) e_cur_stmt_count, $3, $2, make_list ($5)); }
;
fetch_opt :
{ $$ = NULL; }
;
/*
fetch_opt : fetch_seek_opt FROM
;
fetch_seek_opt :
| FIRST
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_bof_forward, 0)
MAKE_const_slong (3),
MAKE_const_slong (0)); }
| LAST
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_eof_backward, 0)
MAKE_const_slong (4),
MAKE_const_slong (0)); }
| PRIOR
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_backward, 1)
MAKE_const_slong (2),
MAKE_const_slong (1)); }
| NEXT
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_forward, 1)
MAKE_const_slong (1),
MAKE_const_slong (1)); }
| ABSOLUTE value
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_bof_forward, value)
MAKE_const_slong (3),
$2); }
| RELATIVE value
{ $$ = make_node (nod_fetch_seek, 2,
// corresponds to (blr_forward, value)
MAKE_const_slong (1),
$2); }
;
*/
/* EXECUTE PROCEDURE */
exec_procedure : EXECUTE PROCEDURE symbol_procedure_name proc_inputs proc_outputs_opt
{ $$ = make_node (nod_exec_procedure, (int) e_exe_count,
$3, $4, $5); }
;
proc_inputs : value_list
{ $$ = make_list ($1); }
| '(' value_list ')'
{ $$ = make_list ($2); }
|
{ $$ = NULL; }
;
proc_outputs_opt : RETURNING_VALUES variable_list
{ $$ = make_list ($2); }
| RETURNING_VALUES '(' variable_list ')'
{ $$ = make_list ($3); }
|
{ $$ = NULL; }
;
/* EXECUTE BLOCK */
exec_block : EXECUTE BLOCK block_input_params output_parameters AS
local_declaration_list
full_proc_block
{ $$ = make_node (nod_exec_block,
(int) e_exe_blk_count,
$3, $4, $6, $7, make_node (nod_all, (int) 0, NULL)); }
;
block_input_params : '(' block_parameters ')'
{ $$ = make_list ($2); }
|
{ $$ = NULL; }
;
block_parameters : block_parameter
| block_parameters ',' block_parameter
{ $$ = make_node (nod_list, 2, $1, $3); }
;
block_parameter : proc_parameter '=' parameter
{ $$ = make_node (nod_param_val, e_prm_val_count, $1, $3); }
;
/* CREATE VIEW */
view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_def_view, (int) e_view_count,
$1, $2, $5, $6, $7); }
;
rview_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_redef_view, (int) e_view_count,
$1, $2, $5, $6, $7); }
;
replace_view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_replace_view, (int) e_view_count,
$1, $2, $5, $6, $7); }
;
alter_view_clause : symbol_view_name column_parens_opt AS begin_string select_expr
check_opt end_trigger
{ $$ = make_node (nod_mod_view, (int) e_view_count,
$1, $2, $5, $6, $7); }
;
/* these rules will capture the input string for storage in metadata */
begin_string :
{ lex.beginnings.push(lex_position()); }
;
/*
end_string :
{
const TEXT* start = lex.beginnings.pop();
$$ = (dsql_nod*) MAKE_string(start,
(lex_position() == lex.end) ? lex_position() - start : lex.last_token - start);
}
;
*/
begin_trigger :
{ lex.beginnings.push(lex.last_token); }
;
end_trigger :
{
const TEXT* start = lex.beginnings.pop();
$$ = (dsql_nod*) MAKE_string(start, lex_position() - start);
}
;
check_opt : WITH CHECK OPTION
{ $$ = make_node (nod_def_constraint, (int) e_cnstr_count,
NULL, NULL, NULL, NULL, NULL); }
|
{ $$ = 0; }
;
/* CREATE TRIGGER */
trigger_clause
: symbol_trigger_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_def_trigger, (int) e_trg_count,
$1, NULL, $2, $3, $4, $5, $6);
}
| symbol_trigger_name FOR simple_table_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_def_trigger, (int) e_trg_count,
$1, $3, $4, $5, $6, $7, $8);
}
| symbol_trigger_name
trigger_active
trigger_type
trigger_position
ON simple_table_name
trigger_action
end_trigger
{
$$ = make_node (nod_def_trigger, (int) e_trg_count,
$1, $6, $2, $3, $4, $7, $8);
}
;
rtrigger_clause
: symbol_trigger_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_redef_trigger, (int) e_trg_count,
$1, NULL, $2, $3, $4, $5, $6);
}
| symbol_trigger_name FOR simple_table_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_redef_trigger, (int) e_trg_count,
$1, $3, $4, $5, $6, $7, $8);
}
| symbol_trigger_name
trigger_active
trigger_type
trigger_position
ON simple_table_name
trigger_action
end_trigger
{
$$ = make_node (nod_redef_trigger, (int) e_trg_count,
$1, $6, $2, $3, $4, $7, $8);
}
;
replace_trigger_clause
: symbol_trigger_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_replace_trigger, (int) e_trg_count,
$1, NULL, $2, $3, $4, $5, $6);
}
| symbol_trigger_name FOR simple_table_name
trigger_active
trigger_type
trigger_position
trigger_action
end_trigger
{
$$ = make_node (nod_replace_trigger, (int) e_trg_count,
$1, $3, $4, $5, $6, $7, $8);
}
| symbol_trigger_name
trigger_active
trigger_type
trigger_position
ON simple_table_name
trigger_action
end_trigger
{
$$ = make_node (nod_replace_trigger, (int) e_trg_count,
$1, $6, $2, $3, $4, $7, $8);
}
;
trigger_active : ACTIVE
{ $$ = MAKE_const_slong (0); }
| INACTIVE
{ $$ = MAKE_const_slong (1); }
|
{ $$ = NULL; }
;
trigger_type
: trigger_type_prefix trigger_type_suffix
{ $$ = MAKE_trigger_type ($1, $2); }
| ON trigger_db_type
{ $$ = $2; }
;
trigger_db_type
: CONNECT
{ $$ = MAKE_const_slong (TRIGGER_TYPE_DB | DB_TRIGGER_CONNECT); }
| DISCONNECT
{ $$ = MAKE_const_slong (TRIGGER_TYPE_DB | DB_TRIGGER_DISCONNECT); }
| TRANSACTION START
{ $$ = MAKE_const_slong (TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_START); }
| TRANSACTION COMMIT
{ $$ = MAKE_const_slong (TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_COMMIT); }
| TRANSACTION ROLLBACK
{ $$ = MAKE_const_slong (TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_ROLLBACK); }
;
trigger_type_prefix : BEFORE
{ $$ = MAKE_const_slong (0); }
| AFTER
{ $$ = MAKE_const_slong (1); }
;
trigger_type_suffix : INSERT
{ $$ = MAKE_const_slong (trigger_type_suffix (1, 0, 0)); }
| UPDATE
{ $$ = MAKE_const_slong (trigger_type_suffix (2, 0, 0)); }
| KW_DELETE
{ $$ = MAKE_const_slong (trigger_type_suffix (3, 0, 0)); }
| INSERT OR UPDATE
{ $$ = MAKE_const_slong (trigger_type_suffix (1, 2, 0)); }
| INSERT OR KW_DELETE
{ $$ = MAKE_const_slong (trigger_type_suffix (1, 3, 0)); }
| UPDATE OR INSERT
{ $$ = MAKE_const_slong (trigger_type_suffix (2, 1, 0)); }
| UPDATE OR KW_DELETE
{ $$ = MAKE_const_slong (trigger_type_suffix (2, 3, 0)); }
| KW_DELETE OR INSERT
{ $$ = MAKE_const_slong (trigger_type_suffix (3, 1, 0)); }
| KW_DELETE OR UPDATE
{ $$ = MAKE_const_slong (trigger_type_suffix (3, 2, 0)); }
| INSERT OR UPDATE OR KW_DELETE
{ $$ = MAKE_const_slong (trigger_type_suffix (1, 2, 3)); }
| INSERT OR KW_DELETE OR UPDATE
{ $$ = MAKE_const_slong (trigger_type_suffix (1, 3, 2)); }
| UPDATE OR INSERT OR KW_DELETE
{ $$ = MAKE_const_slong (trigger_type_suffix (2, 1, 3)); }
| UPDATE OR KW_DELETE OR INSERT
{ $$ = MAKE_const_slong (trigger_type_suffix (2, 3, 1)); }
| KW_DELETE OR INSERT OR UPDATE
{ $$ = MAKE_const_slong (trigger_type_suffix (3, 1, 2)); }
| KW_DELETE OR UPDATE OR INSERT
{ $$ = MAKE_const_slong (trigger_type_suffix (3, 2, 1)); }
;
trigger_position : POSITION nonneg_short_integer
{ $$ = MAKE_const_slong ((IPTR) $2); }
|
{ $$ = NULL; }
;
trigger_action : AS begin_trigger local_declaration_list full_proc_block
{ $$ = make_node (nod_list, (int) e_trg_act_count, $3, $4); }
;
/* ALTER statement */
alter : ALTER alter_clause
{ $$ = $2; }
;
alter_clause : EXCEPTION alter_exception_clause
{ $$ = $2; }
| TABLE simple_table_name alter_ops
{ $$ = make_node (nod_mod_relation, (int) e_alt_count,
$2, make_list ($3)); }
| VIEW alter_view_clause
{ $$ = $2; }
| TRIGGER alter_trigger_clause
{ $$ = $2; }
| PROCEDURE alter_procedure_clause
{ $$ = $2; }
| DATABASE init_alter_db alter_db
{ $$ = make_node (nod_mod_database, (int) e_adb_count,
make_list ($3)); }
| DOMAIN alter_column_name alter_domain_ops
{ $$ = make_node (nod_mod_domain, (int) e_alt_count,
$2, make_list ($3)); }
| INDEX alter_index_clause
{ $$ = make_node (nod_mod_index, (int) e_mod_idx_count, $2); }
| SEQUENCE alter_sequence_clause
{ $$ = $2; }
| EXTERNAL FUNCTION alter_udf_clause
{ $$ = $3; }
| ROLE alter_role_clause
{ $$ = $2; }
| USER alter_user_clause
{ $$ = $2; }
| CHARACTER SET alter_charset_clause
{ $$ = $3; }
;
alter_domain_ops : alter_domain_op
| alter_domain_ops alter_domain_op
{ $$ = make_node (nod_list, 2, $1, $2); }
;
alter_domain_op : SET domain_default
{ $$ = $2; }
| ADD CONSTRAINT check_constraint
{ $$ = $3; }
| ADD check_constraint
{ $$ = $2; }
| DROP DEFAULT
{$$ = make_node (nod_del_default, (int) 0, NULL); }
| DROP CONSTRAINT
{ $$ = make_node (nod_delete_rel_constraint, (int) 1, NULL); }
| TO simple_column_name
{ $$ = $2; }
| KW_TYPE init_data_type non_array_type
{ $$ = make_node (nod_mod_domain_type, 2, $2); }
;
alter_ops : alter_op
| alter_ops ',' alter_op
{ $$ = make_node (nod_list, 2, $1, $3); }
;
alter_op : DROP simple_column_name drop_behaviour
{ $$ = make_node (nod_del_field, 2, $2, $3); }
| DROP CONSTRAINT symbol_constraint_name
{ $$ = make_node (nod_delete_rel_constraint, (int) 1, $3);}
| ADD column_def
{ $$ = $2; }
| ADD table_constraint_definition
{ $$ = $2; }
/* CVC: From SQL, field positions start at 1, not zero. Think in ORDER BY, for example.
| col_opt simple_column_name POSITION nonneg_short_integer
{ $$ = make_node (nod_mod_field_pos, 2, $2,
MAKE_const_slong ((IPTR) $4)); } */
| col_opt simple_column_name POSITION pos_short_integer
{ $$ = make_node(nod_mod_field_pos, 2, $2,
MAKE_const_slong((IPTR) $4)); }
| col_opt alter_column_name TO simple_column_name
{ $$ = make_node(nod_mod_field_name, 2, $2, $4); }
| col_opt alter_col_name KW_TYPE alter_data_type_or_domain
{ $$ = make_node(nod_mod_field_type, e_mod_fld_type_count, $2, $4, NULL, NULL); }
| col_opt alter_col_name KW_TYPE non_array_type def_computed
{
// Due to parser hacks, we should not pass $4 (non_array_type) to make_node.
$$ = make_node(nod_mod_field_type, e_mod_fld_type_count, $2, NULL, NULL, $5);
}
| col_opt alter_col_name def_computed
{ $$ = make_node(nod_mod_field_type, e_mod_fld_type_count, $2, NULL, NULL, $3); }
| col_opt alter_col_name SET domain_default
{ $$ = make_node(nod_mod_field_type, e_mod_fld_type_count, $2, NULL, $4, NULL); }
| col_opt alter_col_name DROP DEFAULT
{ $$ = make_node(nod_mod_field_type, e_mod_fld_type_count, $2, NULL,
make_node(nod_del_default, (int) 0, NULL), NULL); }
;
alter_column_name : keyword_or_column
{ $$ = make_node (nod_field_name, (int) e_fln_count,
NULL, $1); }
;
/* below are reserved words that could be used as column identifiers
in the previous versions */
keyword_or_column : valid_symbol_name
| ADMIN /* added in IB 5.0 */
| COLUMN /* added in IB 6.0 */
| EXTRACT
| YEAR
| MONTH
| DAY
| HOUR
| MINUTE
| SECOND
| TIME
| TIMESTAMP
| CURRENT_DATE
| CURRENT_TIME
| CURRENT_TIMESTAMP
| CURRENT_USER /* added in FB 1.0 */
| CURRENT_ROLE
| RECREATE
| CURRENT_CONNECTION /* added in FB 1.5 */
| CURRENT_TRANSACTION
| BIGINT
| CASE
| RELEASE
| ROW_COUNT
| SAVEPOINT
| OPEN /* added in FB 2.0 */
| CLOSE
| FETCH
| ROWS
| USING
| CROSS
| BIT_LENGTH
| BOTH
| CHAR_LENGTH
| CHARACTER_LENGTH
| COMMENT
| LEADING
| KW_LOWER
| OCTET_LENGTH
| TRAILING
| TRIM
| CONNECT /* added in FB 2.1 */
| DISCONNECT
| GLOBAL
| INSENSITIVE
| RECURSIVE
| SENSITIVE
| START
;
col_opt : ALTER
{ $$ = NULL; }
| ALTER COLUMN
{ $$ = NULL; }
;
alter_data_type_or_domain : non_array_type
{ $$ = NULL; }
| simple_column_name
{ $$ = make_node (nod_def_domain, (int) e_dom_count, $1, NULL, NULL, NULL); }
;
alter_col_name : simple_column_name
{ lex.g_field_name = $1;
lex.g_field = make_field ($1);
$$ = (dsql_nod*) lex.g_field; }
;
drop_behaviour : RESTRICT
{ $$ = make_node (nod_restrict, 0, NULL); }
| CASCADE
{ $$ = make_node (nod_cascade, 0, NULL); }
|
{ $$ = make_node (nod_restrict, 0, NULL); }
;
alter_index_clause : symbol_index_name ACTIVE
{ $$ = make_node (nod_idx_active, 1, $1); }
| symbol_index_name INACTIVE
{ $$ = make_node (nod_idx_inactive, 1, $1); }
;
alter_sequence_clause : symbol_generator_name RESTART WITH signed_long_integer
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $1,
MAKE_const_slong ((IPTR) $4)); }
| symbol_generator_name RESTART WITH NUMBER64BIT
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $1,
MAKE_constant((dsql_str*) $4, CONSTANT_SINT64)); }
| symbol_generator_name RESTART WITH '-' NUMBER64BIT
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $1,
make_node(nod_negate, 1, MAKE_constant((dsql_str*) $5, CONSTANT_SINT64))); }
;
alter_udf_clause : symbol_UDF_name entry_op module_op
{ $$ = make_node(nod_mod_udf, e_mod_udf_count, $1, $2, $3); }
;
/*
alter_role_clause : symbol_role_name alter_role_action OS_NAME os_security_name
{ $$ = make_node(nod_mod_role, e_mod_role_count, $4, $1, $2); }
;
alter_role_action : ADD
{ $$ = MAKE_const_slong (isc_dyn_map_role); }
| DROP
{ $$ = MAKE_const_slong (isc_dyn_unmap_role); }
;
*/
alter_role_clause : symbol_role_name alter_role_enable AUTO ADMIN MAPPING
{ $$ = make_node(nod_mod_role, e_mod_role_count, NULL, $1, $2); }
;
alter_role_enable : SET
{ $$ = MAKE_const_slong (isc_dyn_automap_role); }
| DROP
{ $$ = MAKE_const_slong (isc_dyn_autounmap_role); }
;
os_security_name : STRING
{ $$ = $1; }
;
entry_op : ENTRY_POINT sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
module_op : MODULE_NAME sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
/* ALTER DATABASE */
init_alter_db :
{ $$ = NULL; }
;
alter_db : db_alter_clause
| alter_db db_alter_clause
{ $$ = make_node (nod_list, (int) 2, $1, $2); }
;
db_alter_clause : ADD db_file_list
{ $$ = $2; }
| ADD KW_DIFFERENCE KW_FILE sql_string
{ $$ = make_node (nod_difference_file, (int) 1, $4); }
| DROP KW_DIFFERENCE KW_FILE
{ $$ = make_node (nod_drop_difference, (int) 0, NULL); }
| BEGIN BACKUP
{ $$ = make_node (nod_begin_backup, (int) 0, NULL); }
| END BACKUP
{ $$ = make_node (nod_end_backup, (int) 0, NULL); }
;
/* ALTER TRIGGER */
alter_trigger_clause : symbol_trigger_name trigger_active
new_trigger_type
trigger_position
begin_trigger
new_trigger_action
end_trigger
{ $$ = make_node (nod_mod_trigger, (int) e_trg_count,
$1, NULL, $2, $3, $4, $6, $7); }
;
new_trigger_type : trigger_type
|
{ $$ = NULL; }
;
new_trigger_action : trigger_action
|
{ $$ = NULL; }
;
/* DROP metadata operations */
drop : DROP drop_clause
{ $$ = $2; }
;
drop_clause : EXCEPTION symbol_exception_name
{ $$ = make_node (nod_del_exception, 1, $2); }
| INDEX symbol_index_name
{ $$ = make_node (nod_del_index, (int) 1, $2); }
| PROCEDURE symbol_procedure_name
{ $$ = make_node (nod_del_procedure, (int) 1, $2); }
| TABLE symbol_table_name
{ $$ = make_node (nod_del_relation, (int) 1, $2); }
| TRIGGER symbol_trigger_name
{ $$ = make_node (nod_del_trigger, (int) 1, $2); }
| VIEW symbol_view_name
{ $$ = make_node (nod_del_view, (int) 1, $2); }
| FILTER symbol_filter_name
{ $$ = make_node (nod_del_filter, (int) 1, $2); }
| DOMAIN symbol_domain_name
{ $$ = make_node (nod_del_domain, (int) 1, $2); }
| EXTERNAL FUNCTION symbol_UDF_name
{ $$ = make_node (nod_del_udf, (int) 1, $3); }
| SHADOW pos_short_integer
{ $$ = make_node (nod_del_shadow, (int) 1, $2); }
| ROLE symbol_role_name
{ $$ = make_node (nod_del_role, (int) 1, $2); }
| GENERATOR symbol_generator_name
{ $$ = make_node (nod_del_generator, (int) 1, $2); }
| SEQUENCE symbol_generator_name
{ $$ = make_node (nod_del_generator, (int) 1, $2); }
| COLLATION symbol_collation_name
{ $$ = make_node (nod_del_collation, (int) 1, $2); }
| USER drop_user_clause
{ $$ = $2; }
;
/* these are the allowable datatypes */
data_type : non_array_type
| array_type
;
domain_or_non_array_type
: domain_or_non_array_type_name
| domain_or_non_array_type_name NOT KW_NULL
{ lex.g_field->fld_not_nullable = true; }
;
domain_or_non_array_type_name
: non_array_type
| domain_type
;
domain_type
: KW_TYPE OF symbol_column_name
{ lex.g_field->fld_type_of_name = ((dsql_str*) $3)->str_data; }
| KW_TYPE OF COLUMN symbol_column_name '.' symbol_column_name
{
lex.g_field->fld_type_of_name = ((dsql_str*) $6)->str_data;
lex.g_field->fld_type_of_table = ((dsql_str*) $4);
}
| symbol_column_name
{
lex.g_field->fld_type_of_name = ((dsql_str*) $1)->str_data;
lex.g_field->fld_full_domain = true;
}
;
non_array_type : simple_type
| blob_type
;
array_type : non_charset_simple_type '[' array_spec ']'
{ lex.g_field->fld_ranges = make_list ($3);
lex.g_field->fld_dimensions = lex.g_field->fld_ranges->nod_count / 2;
lex.g_field->fld_element_dtype = lex.g_field->fld_dtype;
$$ = $1; }
| character_type '[' array_spec ']' charset_clause
{ lex.g_field->fld_ranges = make_list ($3);
lex.g_field->fld_dimensions = lex.g_field->fld_ranges->nod_count / 2;
lex.g_field->fld_element_dtype = lex.g_field->fld_dtype;
$$ = $1; }
;
array_spec : array_range
| array_spec ',' array_range
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
array_range : signed_long_integer
{ if ((IPTR) $1 < 1)
$$ = make_node (nod_list, (int) 2,
MAKE_const_slong ((IPTR) $1),
MAKE_const_slong (1));
else
$$ = make_node (nod_list, (int) 2,
MAKE_const_slong (1),
MAKE_const_slong ((IPTR) $1) ); }
| signed_long_integer ':' signed_long_integer
{ $$ = make_node (nod_list, (int) 2,
MAKE_const_slong ((IPTR) $1),
MAKE_const_slong ((IPTR) $3)); }
;
simple_type : non_charset_simple_type
| character_type charset_clause
;
non_charset_simple_type : national_character_type
| numeric_type
| float_type
| BIGINT
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "BIGINT",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "BIGINT",
0);
lex.g_field->fld_dtype = dtype_int64;
lex.g_field->fld_length = sizeof (SINT64);
}
| integer_keyword
{
lex.g_field->fld_dtype = dtype_long;
lex.g_field->fld_length = sizeof (SLONG);
}
| SMALLINT
{
lex.g_field->fld_dtype = dtype_short;
lex.g_field->fld_length = sizeof (SSHORT);
}
| DATE
{
stmt_ambiguous = true;
if (client_dialect <= SQL_DIALECT_V5)
{
/* Post warning saying that DATE is equivalent to TIMESTAMP */
ERRD_post_warning (isc_sqlwarn, isc_arg_number, (SLONG) 301,
isc_arg_warning, isc_dtype_renamed, 0);
lex.g_field->fld_dtype = dtype_timestamp;
lex.g_field->fld_length = sizeof (GDS_TIMESTAMP);
}
else if (client_dialect == SQL_DIALECT_V6_TRANSITION)
yyabandon (-104, isc_transitional_date);
else
{
lex.g_field->fld_dtype = dtype_sql_date;
lex.g_field->fld_length = sizeof (ULONG);
}
}
| TIME
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "TIME",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "TIME",
0);
lex.g_field->fld_dtype = dtype_sql_time;
lex.g_field->fld_length = sizeof (SLONG);
}
| TIMESTAMP
{
lex.g_field->fld_dtype = dtype_timestamp;
lex.g_field->fld_length = sizeof (GDS_TIMESTAMP);
}
;
integer_keyword : INTEGER
| KW_INT
;
/* allow a blob to be specified with any combination of
segment length and subtype */
blob_type : BLOB blob_subtype blob_segsize charset_clause
{
lex.g_field->fld_dtype = dtype_blob;
lex.g_field->fld_length = sizeof(ISC_QUAD);
}
| BLOB '(' unsigned_short_integer ')'
{
lex.g_field->fld_dtype = dtype_blob;
lex.g_field->fld_length = sizeof(ISC_QUAD);
lex.g_field->fld_seg_length = (USHORT)(IPTR) $3;
lex.g_field->fld_sub_type = 0;
}
| BLOB '(' unsigned_short_integer ',' signed_short_integer ')'
{
lex.g_field->fld_dtype = dtype_blob;
lex.g_field->fld_length = sizeof(ISC_QUAD);
lex.g_field->fld_seg_length = (USHORT)(IPTR) $3;
lex.g_field->fld_sub_type = (USHORT)(IPTR) $5;
}
| BLOB '(' ',' signed_short_integer ')'
{
lex.g_field->fld_dtype = dtype_blob;
lex.g_field->fld_length = sizeof(ISC_QUAD);
lex.g_field->fld_seg_length = 80;
lex.g_field->fld_sub_type = (USHORT)(IPTR) $4;
}
;
blob_segsize : SEGMENT KW_SIZE unsigned_short_integer
{
lex.g_field->fld_seg_length = (USHORT)(IPTR) $3;
}
|
{
lex.g_field->fld_seg_length = (USHORT) 80;
}
;
blob_subtype : SUB_TYPE signed_short_integer
{
lex.g_field->fld_sub_type = (USHORT)(IPTR) $2;
}
| SUB_TYPE symbol_blob_subtype_name
{
lex.g_field->fld_sub_type_name = $2;
}
|
{
lex.g_field->fld_sub_type = (USHORT) 0;
}
;
charset_clause : CHARACTER SET symbol_character_set_name
{
lex.g_field->fld_character_set = $3;
}
|
;
/* character type */
national_character_type : national_character_keyword '(' pos_short_integer ')'
{
lex.g_field->fld_dtype = dtype_text;
lex.g_field->fld_character_length = (USHORT)(IPTR) $3;
lex.g_field->fld_flags |= FLD_national;
}
| national_character_keyword
{
lex.g_field->fld_dtype = dtype_text;
lex.g_field->fld_character_length = 1;
lex.g_field->fld_flags |= FLD_national;
}
| national_character_keyword VARYING '(' pos_short_integer ')'
{
lex.g_field->fld_dtype = dtype_varying;
lex.g_field->fld_character_length = (USHORT)(IPTR) $4;
lex.g_field->fld_flags |= FLD_national;
}
;
character_type : character_keyword '(' pos_short_integer ')'
{
lex.g_field->fld_dtype = dtype_text;
lex.g_field->fld_character_length = (USHORT)(IPTR) $3;
}
| character_keyword
{
lex.g_field->fld_dtype = dtype_text;
lex.g_field->fld_character_length = 1;
}
| varying_keyword '(' pos_short_integer ')'
{
lex.g_field->fld_dtype = dtype_varying;
lex.g_field->fld_character_length = (USHORT)(IPTR) $3;
}
;
varying_keyword : VARCHAR
| CHARACTER VARYING
| KW_CHAR VARYING
;
character_keyword : CHARACTER
| KW_CHAR
;
national_character_keyword : NCHAR
| NATIONAL CHARACTER
| NATIONAL KW_CHAR
;
/* numeric type */
numeric_type : KW_NUMERIC prec_scale
{
lex.g_field->fld_sub_type = dsc_num_type_numeric;
}
| decimal_keyword prec_scale
{
lex.g_field->fld_sub_type = dsc_num_type_decimal;
if (lex.g_field->fld_dtype == dtype_short)
{
lex.g_field->fld_dtype = dtype_long;
lex.g_field->fld_length = sizeof (SLONG);
}
}
;
prec_scale :
{
lex.g_field->fld_dtype = dtype_long;
lex.g_field->fld_length = sizeof (SLONG);
lex.g_field->fld_precision = 9;
}
| '(' signed_long_integer ')'
{
if ( ((IPTR) $2 < 1) || ((IPTR) $2 > 18) )
yyabandon (-842, isc_precision_err);
/* Precision most be between 1 and 18. */
if ((IPTR) $2 > 9)
{
if ( ( (client_dialect <= SQL_DIALECT_V5) &&
(db_dialect > SQL_DIALECT_V5) ) ||
( (client_dialect > SQL_DIALECT_V5) &&
(db_dialect <= SQL_DIALECT_V5) ) )
ERRD_post (isc_sqlerr,
isc_arg_number, (SLONG) -817,
isc_arg_gds,
isc_ddl_not_allowed_by_db_sql_dial,
isc_arg_number, (SLONG) db_dialect,
0);
if (client_dialect <= SQL_DIALECT_V5)
{
lex.g_field->fld_dtype = dtype_double;
lex.g_field->fld_length = sizeof (double);
}
else
{
if (client_dialect == SQL_DIALECT_V6_TRANSITION)
{
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous,
isc_arg_end );
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous1,
isc_arg_end );
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous2,
isc_arg_end );
}
lex.g_field->fld_dtype = dtype_int64;
lex.g_field->fld_length = sizeof (SINT64);
}
}
else
if ((IPTR) $2 < 5)
{
lex.g_field->fld_dtype = dtype_short;
lex.g_field->fld_length = sizeof (SSHORT);
}
else
{
lex.g_field->fld_dtype = dtype_long;
lex.g_field->fld_length = sizeof (SLONG);
}
lex.g_field->fld_precision = (USHORT)(IPTR) $2;
}
| '(' signed_long_integer ',' signed_long_integer ')'
{
if ( ((IPTR) $2 < 1) || ((IPTR) $2 > 18) )
yyabandon (-842, isc_precision_err);
/* Precision should be between 1 and 18 */
if (((IPTR) $4 > (IPTR) $2) || ((IPTR) $4 < 0))
yyabandon (-842, isc_scale_nogt);
/* Scale must be between 0 and precision */
if ((IPTR) $2 > 9)
{
if ( ( (client_dialect <= SQL_DIALECT_V5) &&
(db_dialect > SQL_DIALECT_V5) ) ||
( (client_dialect > SQL_DIALECT_V5) &&
(db_dialect <= SQL_DIALECT_V5) ) )
ERRD_post (isc_sqlerr,
isc_arg_number, (SLONG) -817,
isc_arg_gds,
isc_ddl_not_allowed_by_db_sql_dial,
isc_arg_number, (SLONG) db_dialect,
0);
if (client_dialect <= SQL_DIALECT_V5)
{
lex.g_field->fld_dtype = dtype_double;
lex.g_field->fld_length = sizeof (double);
}
else
{
if (client_dialect == SQL_DIALECT_V6_TRANSITION)
{
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous,
isc_arg_end );
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous1,
isc_arg_end );
ERRD_post_warning (
isc_dsql_warn_precision_ambiguous2,
isc_arg_end );
}
/* client_dialect >= SQL_DIALECT_V6 */
lex.g_field->fld_dtype = dtype_int64;
lex.g_field->fld_length = sizeof (SINT64);
}
}
else
{
if ((IPTR) $2 < 5)
{
lex.g_field->fld_dtype = dtype_short;
lex.g_field->fld_length = sizeof (SSHORT);
}
else
{
lex.g_field->fld_dtype = dtype_long;
lex.g_field->fld_length = sizeof (SLONG);
}
}
lex.g_field->fld_precision = (USHORT)(IPTR) $2;
lex.g_field->fld_scale = - (SSHORT)(IPTR) $4;
}
;
decimal_keyword : DECIMAL
| KW_DEC
;
/* floating point type */
float_type : KW_FLOAT precision_opt
{
if ((IPTR) $2 > 7)
{
lex.g_field->fld_dtype = dtype_double;
lex.g_field->fld_length = sizeof (double);
}
else
{
lex.g_field->fld_dtype = dtype_real;
lex.g_field->fld_length = sizeof (float);
}
}
| KW_LONG KW_FLOAT precision_opt
{
lex.g_field->fld_dtype = dtype_double;
lex.g_field->fld_length = sizeof (double);
}
| REAL
{
lex.g_field->fld_dtype = dtype_real;
lex.g_field->fld_length = sizeof (float);
}
| KW_DOUBLE PRECISION
{
lex.g_field->fld_dtype = dtype_double;
lex.g_field->fld_length = sizeof (double);
}
;
precision_opt : '(' nonneg_short_integer ')'
{ $$ = $2; }
|
{ $$ = 0; }
;
/* SET statements */
set : set_transaction
| set_generator
| set_statistics
;
set_generator : SET GENERATOR symbol_generator_name TO signed_long_integer
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $3,
MAKE_const_slong ((IPTR) $5)); }
| SET GENERATOR symbol_generator_name TO NUMBER64BIT
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $3,
MAKE_constant((dsql_str*) $5, CONSTANT_SINT64)); }
| SET GENERATOR symbol_generator_name TO '-' NUMBER64BIT
{ $$ = make_node (nod_set_generator2, e_gen_id_count, $3,
make_node(nod_negate, 1, MAKE_constant((dsql_str*) $6, CONSTANT_SINT64))); }
;
/* transaction statements */
savepoint : set_savepoint
| release_savepoint
| undo_savepoint
;
set_savepoint : SAVEPOINT symbol_savepoint_name
{ $$ = make_node (nod_user_savepoint, 1, $2); }
;
release_savepoint : RELEASE SAVEPOINT symbol_savepoint_name release_only_opt
{ $$ = make_node (nod_release_savepoint, 2, $3, $4); }
;
release_only_opt : ONLY
{ $$ = make_node (nod_flag, 0, NULL); }
|
{ $$ = 0; }
;
undo_savepoint : ROLLBACK optional_work TO optional_savepoint symbol_savepoint_name
{ $$ = make_node (nod_undo_savepoint, 1, $5); }
;
optional_savepoint : SAVEPOINT
|
;
commit : COMMIT optional_work optional_retain
{ $$ = make_node (nod_commit, e_commit_count, $3); }
;
rollback : ROLLBACK optional_work optional_retain
{ $$ = make_node (nod_rollback, e_rollback_count, $3); }
;
optional_work : WORK
|
;
optional_retain : RETAIN opt_snapshot
{ $$ = make_node (nod_retain, 0, NULL); }
|
{ $$ = NULL; }
;
opt_snapshot : SNAPSHOT
|
{ $$ = NULL; }
;
set_transaction : SET TRANSACTION tran_opt_list_m
{$$ = make_node (nod_trans, 1, make_list ($3)); }
;
tran_opt_list_m : tran_opt_list
|
{ $$ = NULL; }
;
tran_opt_list : tran_opt
| tran_opt_list tran_opt
{ $$ = make_node (nod_list, (int) 2, $1, $2); }
;
tran_opt : access_mode
| lock_wait
| isolation_mode
| tra_misc_options
| tra_timeout
| tbl_reserve_options
;
access_mode : READ ONLY
{ $$ = make_flag_node (nod_access, NOD_READ_ONLY, (int) 0, NULL); }
| READ WRITE
{ $$ = make_flag_node (nod_access, NOD_READ_WRITE, (int) 0, NULL); }
;
lock_wait : WAIT
{ $$ = make_flag_node (nod_wait, NOD_WAIT, (int) 0, NULL); }
| NO WAIT
{ $$ = make_flag_node (nod_wait, NOD_NO_WAIT, (int) 0, NULL); }
;
isolation_mode : ISOLATION LEVEL iso_mode
{ $$ = $3;}
| iso_mode
;
iso_mode : snap_shot
{ $$ = $1;}
| READ UNCOMMITTED version_mode
{ $$ = make_flag_node (nod_isolation, NOD_READ_COMMITTED, 1, $3); }
| READ COMMITTED version_mode
{ $$ = make_flag_node (nod_isolation, NOD_READ_COMMITTED, 1, $3); }
;
snap_shot : SNAPSHOT
{ $$ = make_flag_node (nod_isolation, NOD_CONCURRENCY, 0, NULL); }
| SNAPSHOT TABLE
{ $$ = make_flag_node (nod_isolation, NOD_CONSISTENCY, 0, NULL); }
| SNAPSHOT TABLE STABILITY
{ $$ = make_flag_node (nod_isolation, NOD_CONSISTENCY, 0, NULL); }
;
version_mode : VERSION
{ $$ = make_flag_node (nod_version, NOD_VERSION, 0, NULL); }
| NO VERSION
{ $$ = make_flag_node (nod_version, NOD_NO_VERSION, 0, NULL); }
|
{ $$ = 0; }
;
tra_misc_options: NO AUTO UNDO
{ $$ = make_flag_node(nod_tra_misc, NOD_NO_AUTO_UNDO, 0, NULL); }
| KW_IGNORE LIMBO
{ $$ = make_flag_node(nod_tra_misc, NOD_IGNORE_LIMBO, 0, NULL); }
| RESTART REQUESTS
{ $$ = make_flag_node(nod_tra_misc, NOD_RESTART_REQUESTS, 0, NULL); }
;
tra_timeout: LOCK TIMEOUT nonneg_short_integer
{ $$ = make_node(nod_lock_timeout, 1, MAKE_const_slong ((IPTR) $3)); }
;
tbl_reserve_options: RESERVING restr_list
{ $$ = make_node (nod_reserve, 1, make_list ($2)); }
;
lock_type : KW_SHARED
{ $$ = (dsql_nod*) NOD_SHARED; }
| PROTECTED
{ $$ = (dsql_nod*) NOD_PROTECTED ; }
|
{ $$ = (dsql_nod*) 0; }
;
lock_mode : READ
{ $$ = (dsql_nod*) NOD_READ; }
| WRITE
{ $$ = (dsql_nod*) NOD_WRITE; }
;
restr_list : restr_option
| restr_list ',' restr_option
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
restr_option : table_list table_lock
{ $$ = make_node (nod_table_lock, (int) 2, make_list ($1), $2); }
;
table_lock : FOR lock_type lock_mode
{ $$ = make_flag_node (nod_lock_mode, (SSHORT) ((SSHORT)(IPTR) $2 | (SSHORT)(IPTR) $3), (SSHORT) 0, NULL); }
|
{ $$ = 0; }
;
table_list : simple_table_name
| table_list ',' simple_table_name
{ $$ = make_node (nod_list, (int) 2, $1, $3); }
;
set_statistics : SET STATISTICS INDEX symbol_index_name
{ $$ = make_node (nod_set_statistics, (int) e_stat_count, $4); }
;
comment : COMMENT ON ddl_type0 IS ddl_desc
{ $$ = make_node(nod_comment, e_comment_count, $3, NULL, NULL, $5); }
| COMMENT ON ddl_type1 symbol_ddl_name IS ddl_desc
{ $$ = make_node(nod_comment, e_comment_count, $3, $4, NULL, $6); }
| COMMENT ON ddl_type2 symbol_ddl_name ddl_subname IS ddl_desc
{ $$ = make_node(nod_comment, e_comment_count, $3, $4, $5, $7); }
;
ddl_type0 : DATABASE
{ $$ = MAKE_const_slong(ddl_database); }
;
ddl_type1 : DOMAIN
{ $$ = MAKE_const_slong(ddl_domain); }
| TABLE
{ $$ = MAKE_const_slong(ddl_relation); }
| VIEW
{ $$ = MAKE_const_slong(ddl_view); }
| PROCEDURE
{ $$ = MAKE_const_slong(ddl_procedure); }
| TRIGGER
{ $$ = MAKE_const_slong(ddl_trigger); }
| EXTERNAL FUNCTION
{ $$ = MAKE_const_slong(ddl_udf); }
| FILTER
{ $$ = MAKE_const_slong(ddl_blob_filter); }
| EXCEPTION
{ $$ = MAKE_const_slong(ddl_exception); }
| GENERATOR
{ $$ = MAKE_const_slong(ddl_generator); }
| SEQUENCE
{ $$ = MAKE_const_slong(ddl_generator); }
| INDEX
{ $$ = MAKE_const_slong(ddl_index); }
| ROLE
{ $$ = MAKE_const_slong(ddl_role); }
| CHARACTER SET
{ $$ = MAKE_const_slong(ddl_charset); }
| COLLATION
{ $$ = MAKE_const_slong(ddl_collation); }
/*
| SECURITY CLASS
{ $$ = MAKE_const_slong(ddl_sec_class); }
*/
;
ddl_type2 : COLUMN
{ $$ = MAKE_const_slong(ddl_relation); }
| PARAMETER
{ $$ = MAKE_const_slong(ddl_procedure); }
;
ddl_subname : '.' symbol_ddl_name
{ $$ = $2; }
;
ddl_desc : sql_string
| KW_NULL
{ $$ = NULL; }
;
/* SELECT statement */
select : select_expr for_update_clause lock_clause
{ $$ = make_node (nod_select, (int) e_select_count, $1, $2, $3); }
;
for_update_clause : FOR UPDATE for_update_list
{ $$ = make_node (nod_for_update, (int) e_fpd_count, $3); }
|
{ $$ = NULL; }
;
for_update_list : OF column_list
{ $$ = $2; }
|
{ $$ = make_node (nod_flag, 0, NULL); }
;
lock_clause : WITH LOCK
{ $$ = make_node (nod_flag, 0, NULL); }
|
{ $$ = NULL; }
;
/* SELECT expression */
select_expr : with_clause select_expr_body order_clause rows_clause
{ $$ = make_node (nod_select_expr, (int) e_sel_count, $2, $3, $4, $1); }
;
with_clause : WITH RECURSIVE with_list
{ $$ = make_flag_node (nod_with, NOD_UNION_RECURSIVE, 1, make_list($3)); }
| WITH with_list
{ $$ = make_node (nod_with, 1, make_list($2)); }
|
{ $$ = NULL; }
;
with_list : with_item
| with_item ',' with_list
{ $$ = make_node (nod_list, 2, $1, $3); }
;
with_item : symbol_table_alias_name derived_column_list AS '(' select_expr ')'
{ $$ = make_node (nod_derived_table, (int) e_derived_table_count, $5, $1, $2, NULL); }
;
column_select : with_clause select_expr_body order_clause rows_clause
{ $$ = make_flag_node (nod_select_expr, NOD_SELECT_EXPR_VALUE,
(int) e_sel_count, $2, $3, $4, $1); }
;
column_singleton : with_clause select_expr_body order_clause rows_clause
{ $$ = make_flag_node (nod_select_expr, NOD_SELECT_EXPR_VALUE | NOD_SELECT_EXPR_SINGLETON,
(int) e_sel_count, $2, $3, $4, $1); }
;
select_expr_body : query_term
| select_expr_body UNION distinct_noise query_term
{ $$ = make_node (nod_list, 2, $1, $4); }
| select_expr_body UNION ALL query_term
{ $$ = make_flag_node (nod_list, NOD_UNION_ALL, 2, $1, $4); }
;
query_term : query_spec
;
query_spec : SELECT limit_clause
distinct_clause
select_list
from_clause
where_clause
group_clause
having_clause
plan_clause
{ $$ = make_node (nod_query_spec, (int) e_qry_count,
$2, $3, $4, $5, $6, $7, $8, $9); }
;
limit_clause : first_clause skip_clause
{ $$ = make_node (nod_limit, (int) e_limit_count, $2, $1); }
| first_clause
{ $$ = make_node (nod_limit, (int) e_limit_count, NULL, $1); }
| skip_clause
{ $$ = make_node (nod_limit, (int) e_limit_count, $1, NULL); }
|
{ $$ = 0; }
;
first_clause : FIRST long_integer
{ $$ = MAKE_const_slong ((IPTR) $2); }
| FIRST '(' value ')'
{ $$ = $3; }
| FIRST parameter
{ $$ = $2; }
;
skip_clause : SKIP long_integer
{ $$ = MAKE_const_slong ((IPTR) $2); }
| SKIP '(' value ')'
{ $$ = $3; }
| SKIP parameter
{ $$ = $2; }
;
distinct_clause : DISTINCT
{ $$ = make_node (nod_flag, 0, NULL); }
| all_noise
{ $$ = 0; }
;
select_list : select_items
{ $$ = make_list ($1); }
| '*'
{ $$ = 0; }
;
select_items : select_item
| select_items ',' select_item
{ $$ = make_node (nod_list, 2, $1, $3); }
;
select_item : value
| value as_noise symbol_item_alias_name
{ $$ = make_node (nod_alias, 2, $1, $3); }
;
as_noise : AS
|
;
/* FROM clause */
from_clause : FROM from_list
{ $$ = make_list ($2); }
;
from_list : table_reference
| from_list ',' table_reference
{ $$ = make_node (nod_list, 2, $1, $3); }
;
table_reference : joined_table
| table_primary
;
table_primary : table_proc
| derived_table
| '(' joined_table ')'
{ $$ = $2; }
;
// AB: derived table support
// ASF: create derived table with nested union to fix CORE-1246
derived_table :
'(' select_expr ')' as_noise correlation_name derived_column_list
{ $$ = make_node(nod_derived_table, (int) e_derived_table_count, $2, $5, $6, NULL); }
;
correlation_name : symbol_table_alias_name
|
{ $$ = NULL; }
;
derived_column_list : '(' alias_list ')'
{ $$ = make_list ($2); }
|
{ $$ = NULL; }
;
alias_list : symbol_item_alias_name
| alias_list ',' symbol_item_alias_name
{ $$ = make_node (nod_list, 2, $1, $3); }
;
joined_table : cross_join
| natural_join
| qualified_join
;
cross_join : table_reference CROSS JOIN table_primary
{ $$ = make_node (nod_join, (int) e_join_count, $1,
make_node (nod_join_inner, (int) 0, NULL), $4, NULL); }
;
natural_join : table_reference NATURAL join_type JOIN table_primary
{ $$ = make_node (nod_join, (int) e_join_count, $1, $3, $5,
make_node (nod_flag, 0, NULL)); }
;
qualified_join : table_reference join_type JOIN table_reference join_specification
{ $$ = make_node (nod_join, (int) e_join_count, $1, $2, $4, $5); }
;
join_specification : join_condition
| named_columns_join
;
join_condition : ON search_condition
{ $$ = $2; }
;
named_columns_join : USING '(' column_list ')'
{ $$ = make_list ($3); }
;
table_proc : symbol_procedure_name table_proc_inputs as_noise symbol_table_alias_name
{ $$ = make_node (nod_rel_proc_name,
(int) e_rpn_count, $1, $4, $2); }
| symbol_procedure_name table_proc_inputs
{ $$ = make_node (nod_rel_proc_name,
(int) e_rpn_count, $1, NULL, $2); }
;
table_proc_inputs : '(' value_list ')'
{ $$ = make_list ($2); }
|
{ $$ = NULL; }
;
table_name : simple_table_name
| symbol_table_name as_noise symbol_table_alias_name
{ $$ = make_node (nod_relation_name,
(int) e_rln_count, $1, $3); }
;
simple_table_name: symbol_table_name
{ $$ = make_node (nod_relation_name,
(int) e_rln_count, $1, NULL); }
;
join_type : INNER
{ $$ = make_node (nod_join_inner, (int) 0, NULL); }
| LEFT outer_noise
{ $$ = make_node (nod_join_left, (int) 0, NULL); }
| RIGHT outer_noise
{ $$ = make_node (nod_join_right, (int) 0, NULL); }
| FULL outer_noise
{ $$ = make_node (nod_join_full, (int) 0, NULL); }
|
{ $$ = make_node (nod_join_inner, (int) 0, NULL); }
;
outer_noise : OUTER
|
;
/* other clauses in the select expression */
group_clause : GROUP BY group_by_list
{ $$ = make_list ($3); }
|
{ $$ = NULL; }
;
group_by_list : group_by_item
| group_by_list ',' group_by_item
{ $$ = make_node (nod_list, 2, $1, $3); }
;
/* Except aggregate-functions are all expressions supported in group_by_item,
they are caught inside pass1.cpp */
group_by_item : value
;
having_clause : HAVING search_condition
{ $$ = $2; }
|
{ $$ = NULL; }
;
where_clause : WHERE search_condition
{ $$ = $2; }
|
{ $$ = NULL; }
;
/* PLAN clause to specify an access plan for a query */
plan_clause : PLAN plan_expression
{ $$ = $2; }
|
{ $$ = NULL; }
;
plan_expression : plan_type '(' plan_item_list ')'
{ $$ = make_node (nod_plan_expr, 2, $1, make_list ($3)); }
;
plan_type : JOIN
{ $$ = 0; }
| SORT MERGE
{ $$ = make_node (nod_merge_plan, (int) 0, NULL); }
| MERGE
{ $$ = make_node (nod_merge_plan, (int) 0, NULL); }
/* for now the SORT operator is a no-op; it does not
change the place where a sort happens, but is just intended
to read the output from a SET PLAN */
| SORT
{ $$ = 0; }
|
{ $$ = 0; }
;
plan_item_list : plan_item
| plan_item ',' plan_item_list
{ $$ = make_node (nod_list, 2, $1, $3); }
;
plan_item : table_or_alias_list access_type
{ $$ = make_node (nod_plan_item, 2, make_list ($1), $2); }
| plan_expression
;
table_or_alias_list : symbol_table_name
| symbol_table_name table_or_alias_list
{ $$ = make_node (nod_list, 2, $1, $2); }
;
access_type : NATURAL
{ $$ = make_node (nod_natural, (int) 0, NULL); }
| INDEX '(' index_list ')'
{ $$ = make_node (nod_index, 1, make_list ($3)); }
| ORDER symbol_index_name extra_indices_opt
{ $$ = make_node (nod_index_order, 2, $2, $3); }
;
index_list : symbol_index_name
| symbol_index_name ',' index_list
{ $$ = make_node (nod_list, 2, $1, $3); }
;
extra_indices_opt : INDEX '(' index_list ')'
{ $$ = make_list ($3); }
|
{ $$ = 0; }
;
/* ORDER BY clause */
order_clause : ORDER BY order_list
{ $$ = make_list ($3); }
|
{ $$ = 0; }
;
order_list : order_item
| order_list ',' order_item
{ $$ = make_node (nod_list, 2, $1, $3); }
;
order_item : value order_direction nulls_clause
{ $$ = make_node (nod_order, (int) e_order_count, $1, $2, $3); }
;
order_direction : ASC
{ $$ = 0; }
| DESC
{ $$ = make_node (nod_flag, 0, NULL); }
|
{ $$ = 0; }
;
nulls_clause : NULLS nulls_placement
{ $$ = $2; }
|
{ $$ = 0; }
;
nulls_placement : FIRST
{ $$ = MAKE_const_slong(NOD_NULLS_FIRST); }
| LAST
{ $$ = MAKE_const_slong(NOD_NULLS_LAST); }
;
/* ROWS clause */
rows_clause : ROWS value
/* equivalent to FIRST value */
{ $$ = make_node (nod_rows, (int) e_rows_count, NULL, $2); }
| ROWS value TO value
/* equivalent to FIRST (upper_value - lower_value + 1) SKIP (lower_value - 1) */
{ $$ = make_node (nod_rows, (int) e_rows_count,
make_node (nod_subtract, 2, $2,
MAKE_const_slong (1)),
make_node (nod_add, 2,
make_node (nod_subtract, 2, $4, $2),
MAKE_const_slong (1))); }
|
{ $$ = NULL; }
;
/* INSERT statement */
/* IBO hack: replace column_parens_opt by ins_column_parens_opt. */
insert : INSERT INTO simple_table_name ins_column_parens_opt
VALUES '(' value_list ')' returning_clause
{ $$ = make_node (nod_insert, (int) e_ins_count,
$3, $4, make_list ($7), NULL, $9); }
| INSERT INTO simple_table_name ins_column_parens_opt select_expr returning_clause
{ $$ = make_node (nod_insert, (int) e_ins_count,
$3, $4, NULL, $5, $6); }
| INSERT INTO simple_table_name DEFAULT VALUES returning_clause
{ $$ = make_node (nod_insert, (int) e_ins_count,
$3, NULL, NULL, NULL, $6); }
;
/* MERGE statement */
merge
: MERGE INTO table_name USING table_reference ON search_condition
merge_when_clause
{
$$ = make_node(nod_merge, e_mrg_count, $3, $5, $7, $8);
}
;
merge_when_clause
: merge_when_matched_clause merge_when_not_matched_clause
{ $$ = make_node(nod_merge_when, e_mrg_when_count, $1, $2); }
| merge_when_not_matched_clause merge_when_matched_clause
{ $$ = make_node(nod_merge_when, e_mrg_when_count, $2, $1); }
| merge_when_matched_clause
{ $$ = make_node(nod_merge_when, e_mrg_when_count, $1, NULL); }
| merge_when_not_matched_clause
{ $$ = make_node(nod_merge_when, e_mrg_when_count, NULL, $1); }
;
merge_when_matched_clause
: WHEN MATCHED THEN merge_update_specification
{ $$ = $4; }
;
merge_when_not_matched_clause
: WHEN NOT MATCHED THEN merge_insert_specification
{ $$ = $5; }
;
merge_update_specification
: UPDATE SET assignments
{ $$ = make_node(nod_merge_update, e_mrg_update_count, make_list($3)); }
;
merge_insert_specification
: INSERT ins_column_parens_opt VALUES '(' value_list ')'
{ $$ = make_node(nod_merge_insert, e_mrg_insert_count, make_list($2), make_list($5)); }
;
/* DELETE statement */
delete : delete_searched
| delete_positioned
;
delete_searched : KW_DELETE FROM table_name where_clause
plan_clause order_clause rows_clause returning_clause
{ $$ = make_node (nod_delete, (int) e_del_count,
$3, $4, $5, $6, $7, NULL, $8); }
;
delete_positioned : KW_DELETE FROM table_name cursor_clause
{ $$ = make_node (nod_delete, (int) e_del_count,
$3, NULL, NULL, NULL, NULL, $4, NULL); }
;
/* UPDATE statement */
update : update_searched
| update_positioned
;
update_searched : UPDATE table_name SET assignments where_clause
plan_clause order_clause rows_clause returning_clause
{ $$ = make_node (nod_update, (int) e_upd_count,
$2, make_list ($4), $5, $6, $7, $8, NULL, $9, NULL); }
;
update_positioned : UPDATE table_name SET assignments cursor_clause
{ $$ = make_node (nod_update, (int) e_upd_count,
$2, make_list ($4), NULL, NULL, NULL, NULL, $5, NULL, NULL); }
;
/* UPDATE OR INSERT statement */
update_or_insert
: UPDATE OR INSERT INTO simple_table_name ins_column_parens_opt
VALUES '(' value_list ')'
update_or_insert_matching_opt
returning_clause
{
$$ = make_node (nod_update_or_insert, (int) e_upi_count,
$5, make_list ($6), make_list ($9), $11, $12);
}
;
update_or_insert_matching_opt
: MATCHING ins_column_parens
{ $$ = $2; }
|
{ $$ = NULL; }
;
returning_clause : RETURNING value_list
{ $$ = make_node (nod_returning, (int) e_ret_count,
make_list ($2), NULL); }
| RETURNING value_list INTO variable_list
{ $$ = make_node (nod_returning, (int) e_ret_count,
make_list ($2), make_list ($4)); }
|
{ $$ = NULL; }
;
cursor_clause : WHERE CURRENT OF symbol_cursor_name
{ $$ = make_node (nod_cursor, (int) e_cur_count, $4, NULL, NULL, NULL); }
;
/* Assignments */
assignments : assignment
| assignments ',' assignment
{ $$ = make_node (nod_list, 2, $1, $3); }
;
assignment : update_column_name '=' value
{ $$ = make_node (nod_assign, e_asgn_count, $3, $1); }
;
exec_function
: udf
{ $$ = make_node (nod_assign, e_asgn_count, $1, make_node (nod_null, 0, NULL)); }
| non_aggregate_function
{ $$ = make_node (nod_assign, e_asgn_count, $1, make_node (nod_null, 0, NULL)); }
;
/* BLOB get and put */
blob_io : READ BLOB simple_column_name FROM simple_table_name filter_clause_io segment_clause_io
{ $$ = make_node (nod_get_segment, (int) e_blb_count, $3, $5, $6, $7); }
| INSERT BLOB simple_column_name INTO simple_table_name filter_clause_io segment_clause_io
{ $$ = make_node (nod_put_segment, (int) e_blb_count, $3, $5, $6, $7); }
;
filter_clause_io : FILTER FROM blob_subtype_value_io TO blob_subtype_value_io
{ $$ = make_node (nod_list, 2, $3, $5); }
| FILTER TO blob_subtype_value_io
{ $$ = make_node (nod_list, 2, NULL, $3); }
|
{ $$ = NULL; }
;
blob_subtype_value_io : blob_subtype_io
| parameter
;
blob_subtype_io : signed_short_integer
{ $$ = MAKE_const_slong ((IPTR) $1); }
;
segment_clause_io : MAX_SEGMENT segment_length_io
{ $$ = $2; }
|
{ $$ = NULL; }
;
segment_length_io : unsigned_short_integer
{ $$ = MAKE_const_slong ((IPTR) $1); }
| parameter
;
/* column specifications */
column_parens_opt : column_parens
|
{ $$ = NULL; }
;
column_parens : '(' column_list ')'
{ $$ = make_list ($2); }
;
column_list : simple_column_name
| column_list ',' simple_column_name
{ $$ = make_node (nod_list, 2, $1, $3); }
;
/* begin IBO hack */
ins_column_parens_opt : ins_column_parens
|
{ $$ = NULL; }
;
ins_column_parens : '(' ins_column_list ')'
{ $$ = make_list ($2); }
;
ins_column_list : update_column_name
| ins_column_list ',' update_column_name
{ $$ = make_node (nod_list, 2, $1, $3); }
;
/* end IBO hack */
column_name : simple_column_name
| symbol_table_alias_name '.' symbol_column_name
{ $$ = make_node (nod_field_name, (int) e_fln_count,
$1, $3); }
| symbol_table_alias_name '.' '*'
{ $$ = make_node (nod_field_name, (int) e_fln_count,
$1, NULL); }
;
simple_column_name : symbol_column_name
{ $$ = make_node (nod_field_name, (int) e_fln_count,
NULL, $1); }
;
update_column_name : simple_column_name
/* CVC: This option should be deprecated! The only allowed syntax should be
Update...set column = expr, without qualifier for the column. */
| symbol_table_alias_name '.' symbol_column_name
{ $$ = make_node (nod_field_name, (int) e_fln_count,
$1, $3); }
;
/* boolean expressions */
search_condition : predicate
| search_condition OR search_condition
{ $$ = make_node (nod_or, 2, $1, $3); }
| search_condition AND search_condition
{ $$ = make_node (nod_and, 2, $1, $3); }
| NOT search_condition
{ $$ = make_node (nod_not, 1, $2); }
;
predicate : comparison_predicate
| distinct_predicate
| between_predicate
| like_predicate
| in_predicate
| null_predicate
| quantified_predicate
| exists_predicate
| containing_predicate
| similar_predicate
| starting_predicate
| singular_predicate
| trigger_action_predicate
| '(' search_condition ')'
{ $$ = $2; }
;
/* comparisons */
comparison_predicate : value '=' value
{ $$ = make_node (nod_eql, 2, $1, $3); }
| value '<' value
{ $$ = make_node (nod_lss, 2, $1, $3); }
| value '>' value
{ $$ = make_node (nod_gtr, 2, $1, $3); }
| value GEQ value
{ $$ = make_node (nod_geq, 2, $1, $3); }
| value LEQ value
{ $$ = make_node (nod_leq, 2, $1, $3); }
| value NOT_GTR value
{ $$ = make_node (nod_leq, 2, $1, $3); }
| value NOT_LSS value
{ $$ = make_node (nod_geq, 2, $1, $3); }
| value NEQ value
{ $$ = make_node (nod_neq, 2, $1, $3); }
;
/* quantified comparisons */
quantified_predicate : value '=' ALL '(' column_select ')'
{ $$ = make_node (nod_eql_all, 2, $1, $5); }
| value '<' ALL '(' column_select ')'
{ $$ = make_node (nod_lss_all, 2, $1, $5); }
| value '>' ALL '(' column_select ')'
{ $$ = make_node (nod_gtr_all, 2, $1, $5); }
| value GEQ ALL '(' column_select ')'
{ $$ = make_node (nod_geq_all, 2, $1, $5); }
| value LEQ ALL '(' column_select ')'
{ $$ = make_node (nod_leq_all, 2, $1, $5); }
| value NOT_GTR ALL '(' column_select ')'
{ $$ = make_node (nod_leq_all, 2, $1, $5); }
| value NOT_LSS ALL '(' column_select ')'
{ $$ = make_node (nod_geq_all, 2, $1, $5); }
| value NEQ ALL '(' column_select ')'
{ $$ = make_node (nod_neq_all, 2, $1, $5); }
| value '=' some '(' column_select ')'
{ $$ = make_node (nod_eql_any, 2, $1, $5); }
| value '<' some '(' column_select ')'
{ $$ = make_node (nod_lss_any, 2, $1, $5); }
| value '>' some '(' column_select ')'
{ $$ = make_node (nod_gtr_any, 2, $1, $5); }
| value GEQ some '(' column_select ')'
{ $$ = make_node (nod_geq_any, 2, $1, $5); }
| value LEQ some '(' column_select ')'
{ $$ = make_node (nod_leq_any, 2, $1, $5); }
| value NOT_GTR some '(' column_select ')'
{ $$ = make_node (nod_leq_any, 2, $1, $5); }
| value NOT_LSS some '(' column_select ')'
{ $$ = make_node (nod_geq_any, 2, $1, $5); }
| value NEQ some '(' column_select ')'
{ $$ = make_node (nod_neq_any, 2, $1, $5); }
;
some : SOME
| ANY
;
/* other predicates */
distinct_predicate : value IS DISTINCT FROM value
{ $$ = make_node (nod_not, 1, make_node (nod_equiv, 2, $1, $5)); }
| value IS NOT DISTINCT FROM value
{ $$ = make_node (nod_equiv, 2, $1, $6); }
;
between_predicate : value BETWEEN value AND value
{ $$ = make_node (nod_between, 3, $1, $3, $5); }
| value NOT BETWEEN value AND value
{ $$ = make_node (nod_not, 1, make_node (nod_between,
3, $1, $4, $6)); }
;
like_predicate : value LIKE value
{ $$ = make_node (nod_like, 2, $1, $3); }
| value NOT LIKE value
{ $$ = make_node (nod_not, 1, make_node (nod_like, 2, $1, $4)); }
| value LIKE value ESCAPE value
{ $$ = make_node (nod_like, 3, $1, $3, $5); }
| value NOT LIKE value ESCAPE value
{ $$ = make_node (nod_not, 1, make_node (nod_like,
3, $1, $4, $6)); }
;
in_predicate : value KW_IN in_predicate_value
{ $$ = make_node (nod_eql_any, 2, $1, $3); }
| value NOT KW_IN in_predicate_value
{ $$ = make_node (nod_not, 1, make_node (nod_eql_any, 2, $1, $4)); }
;
containing_predicate : value CONTAINING value
{ $$ = make_node (nod_containing, 2, $1, $3); }
| value NOT CONTAINING value
{ $$ = make_node (nod_not, 1, make_node (nod_containing, 2, $1, $4)); }
;
similar_predicate
: value SIMILAR TO value
{ $$ = make_node(nod_similar, e_similar_count, $1, $4, NULL); }
| value NOT SIMILAR TO value
{ $$ = make_node(nod_not, 1, make_node(nod_similar, e_similar_count, $1, $5, NULL)); }
| value SIMILAR TO value ESCAPE value
{ $$ = make_node(nod_similar, e_similar_count, $1, $4, $6); }
| value NOT SIMILAR TO value ESCAPE value
{ $$ = make_node(nod_not, 1, make_node(nod_similar, e_similar_count, $1, $5, $7)); }
;
starting_predicate : value STARTING value
{ $$ = make_node (nod_starting, 2, $1, $3); }
| value NOT STARTING value
{ $$ = make_node (nod_not, 1, make_node (nod_starting, 2, $1, $4)); }
| value STARTING WITH value
{ $$ = make_node (nod_starting, 2, $1, $4); }
| value NOT STARTING WITH value
{ $$ = make_node (nod_not, 1, make_node (nod_starting, 2, $1, $5)); }
;
exists_predicate : EXISTS '(' select_expr ')'
{ $$ = make_node (nod_exists, 1, $3); }
;
singular_predicate : SINGULAR '(' select_expr ')'
{ $$ = make_node (nod_singular, 1, $3); }
;
null_predicate : value IS KW_NULL
{ $$ = make_node (nod_missing, 1, $1); }
| value IS NOT KW_NULL
{ $$ = make_node (nod_not, 1, make_node (nod_missing, 1, $1)); }
;
trigger_action_predicate : INSERTING
{ $$ = make_node (nod_eql, 2,
make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_trigger_action)),
MAKE_const_slong (1)); }
| UPDATING
{ $$ = make_node (nod_eql, 2,
make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_trigger_action)),
MAKE_const_slong (2)); }
| DELETING
{ $$ = make_node (nod_eql, 2,
make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_trigger_action)),
MAKE_const_slong (3)); }
;
/* set values */
in_predicate_value : table_subquery
| '(' value_list ')'
{ $$ = make_list ($2); }
;
table_subquery : '(' column_select ')'
{ $$ = $2; }
;
/* USER control SQL interface */
create_user_clause : symbol_user_name passwd_clause firstname_opt middlename_opt lastname_opt
{ $$ = make_node(nod_add_user, (int) e_user_count, $1, $2, $3, $4, $5); }
;
alter_user_clause : symbol_user_name passwd_opt firstname_opt middlename_opt lastname_opt
{ $$ = make_node(nod_mod_user, (int) e_user_count, $1, $2, $3, $4, $5); }
| symbol_user_name SET passwd_opt firstname_opt middlename_opt lastname_opt
{ $$ = make_node(nod_mod_user, (int) e_user_count, $1, $3, $4, $5, $6); }
;
drop_user_clause : symbol_user_name
{ $$ = make_node(nod_del_user, (int) e_del_user_count, $1); }
passwd_clause : PASSWORD sql_string
{ $$ = $2; }
;
passwd_opt : passwd_clause
{ $$ = $1; }
|
{ $$ = NULL; }
;
firstname_opt : FIRSTNAME sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
middlename_opt : MIDDLENAME sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
lastname_opt : LASTNAME sql_string
{ $$ = $2; }
|
{ $$ = NULL; }
;
/* value types */
value : column_name
| array_element
| function
| u_constant
| parameter
| variable
| cast_specification
| case_expression
| next_value_expression
| udf
| '-' value
{ $$ = make_node (nod_negate, 1, $2); }
| '+' value
{ $$ = $2; }
| value '+' value
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_add2, 2, $1, $3);
else
$$ = make_node (nod_add, 2, $1, $3);
}
| value CONCATENATE value
{ $$ = make_node (nod_concatenate, 2, $1, $3); }
| value COLLATE symbol_collation_name
{ $$ = make_node (nod_collate, (int) e_coll_count, (dsql_nod*) $3, $1); }
| value '-' value
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_subtract2, 2, $1, $3);
else
$$ = make_node (nod_subtract, 2, $1, $3);
}
| value '*' value
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_multiply2, 2, $1, $3);
else
$$ = make_node (nod_multiply, 2, $1, $3);
}
| value '/' value
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_divide2, 2, $1, $3);
else
$$ = make_node (nod_divide, 2, $1, $3);
}
| '(' value ')'
{ $$ = $2; }
| '(' column_singleton ')'
{ $$ = $2; }
| current_user
| current_role
| internal_info
| DB_KEY
{ $$ = make_node (nod_dbkey, 1, NULL); }
| symbol_table_alias_name '.' DB_KEY
{ $$ = make_node (nod_dbkey, 1, $1); }
| KW_VALUE
{
$$ = make_node (nod_dom_value, 0, NULL);
}
| datetime_value_expression
| null_value
;
datetime_value_expression : CURRENT_DATE
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "DATE",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "DATE",
0);
$$ = make_node (nod_current_date, 0, NULL);
}
| CURRENT_TIME sec_precision_opt
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "TIME",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "TIME",
0);
$$ = make_node (nod_current_time, 1, $2);
}
| CURRENT_TIMESTAMP sec_precision_opt
{ $$ = make_node (nod_current_timestamp, 1, $2); }
;
sec_precision_opt : '(' nonneg_short_integer ')'
{ $$ = MAKE_const_slong ((IPTR) $2); }
|
{ $$ = NULL; }
;
array_element : column_name '[' value_list ']'
{ $$ = make_node (nod_array, (int) e_ary_count, $1, make_list ($3)); }
;
value_list_opt
: value_list
| // nothing
{ $$ = NULL; }
;
value_list : value
| value_list ',' value
{ $$ = make_node (nod_list, 2, $1, $3); }
;
constant : u_constant
| '-' u_numeric_constant
{ $$ = make_node (nod_negate, 1, $2); }
;
u_numeric_constant : NUMERIC
{ $$ = MAKE_constant ((dsql_str*) $1, CONSTANT_STRING); }
| NUMBER
{ $$ = MAKE_const_slong ((IPTR) $1); }
| FLOAT_NUMBER
{ $$ = MAKE_constant ((dsql_str*) $1, CONSTANT_DOUBLE); }
| NUMBER64BIT
{ $$ = MAKE_constant ((dsql_str*) $1, CONSTANT_SINT64); }
| SCALEDINT
{ $$ = MAKE_constant ((dsql_str*) $1, CONSTANT_SINT64); }
;
u_constant : u_numeric_constant
| sql_string
{ $$ = MAKE_str_constant ((dsql_str*) $1, lex.att_charset); }
| DATE STRING
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "DATE",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "DATE",
0);
$$ = MAKE_constant ((dsql_str*) $2, CONSTANT_DATE);
}
| TIME STRING
{
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_dialect_datatype_unsupport,
isc_arg_number, (SLONG) client_dialect,
isc_arg_string, "TIME",
0);
if (db_dialect < SQL_DIALECT_V6_TRANSITION)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_sql_db_dialect_dtype_unsupport,
isc_arg_number, (SLONG) db_dialect,
isc_arg_string, "TIME",
0);
$$ = MAKE_constant ((dsql_str*) $2, CONSTANT_TIME);
}
| TIMESTAMP STRING
{ $$ = MAKE_constant ((dsql_str*) $2, CONSTANT_TIMESTAMP); }
;
parameter : '?'
{ $$ = make_parameter (); }
;
current_user : USER
{ $$ = make_node (nod_user_name, 0, NULL); }
| CURRENT_USER
{ $$ = make_node (nod_user_name, 0, NULL); }
;
current_role : CURRENT_ROLE
{ $$ = make_node (nod_current_role, 0, NULL); }
;
internal_info : CURRENT_CONNECTION
{ $$ = make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_connection_id)); }
| CURRENT_TRANSACTION
{ $$ = make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_transaction_id)); }
| GDSCODE
{ $$ = make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_gdscode)); }
| SQLCODE
{ $$ = make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_sqlcode)); }
| ROW_COUNT
{ $$ = make_node (nod_internal_info, (int) e_internal_info_count,
MAKE_const_slong (internal_rows_affected)); }
;
sql_string : STRING /* string in current charset */
{ $$ = $1; }
| INTRODUCER STRING /* string in specific charset */
{ ((dsql_str*) $2)->str_charset = (TEXT *) $1;
$$ = $2; }
;
signed_short_integer : nonneg_short_integer
| '-' neg_short_integer
{ $$ = (dsql_nod*) - (IPTR) $2; }
;
nonneg_short_integer : NUMBER
{ if ((IPTR) $1 > SHRT_POS_MAX)
yyabandon (-842, isc_expec_short);
/* Short integer expected */
$$ = $1;}
;
neg_short_integer : NUMBER
{ if ((IPTR) $1 > SHRT_NEG_MAX)
yyabandon (-842, isc_expec_short);
/* Short integer expected */
$$ = $1;}
;
pos_short_integer : nonneg_short_integer
{ if ((IPTR) $1 == 0)
yyabandon (-842, isc_expec_positive);
/* Positive number expected */
$$ = $1;}
;
unsigned_short_integer : NUMBER
{ if ((IPTR) $1 > SHRT_UNSIGNED_MAX)
yyabandon (-842, isc_expec_ushort);
/* Unsigned short integer expected */
$$ = $1;}
;
signed_long_integer : long_integer
| '-' long_integer
{ $$ = (dsql_nod*) - (IPTR) $2; }
;
long_integer : NUMBER
{ $$ = $1;}
;
/* functions */
function
: aggregate_function
| non_aggregate_function
;
non_aggregate_function
: numeric_value_function
| string_value_function
| system_function_expression
;
aggregate_function : COUNT '(' '*' ')'
{ $$ = make_node (nod_agg_count, 0, NULL); }
| COUNT '(' all_noise value ')'
{ $$ = make_node (nod_agg_count, 1, $4); }
| COUNT '(' DISTINCT value ')'
{ $$ = make_flag_node (nod_agg_count,
NOD_AGG_DISTINCT, 1, $4); }
| SUM '(' all_noise value ')'
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_agg_total2, 1, $4);
else
$$ = make_node (nod_agg_total, 1, $4);
}
| SUM '(' DISTINCT value ')'
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_flag_node (nod_agg_total2,
NOD_AGG_DISTINCT, 1, $4);
else
$$ = make_flag_node (nod_agg_total,
NOD_AGG_DISTINCT, 1, $4);
}
| AVG '(' all_noise value ')'
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_agg_average2, 1, $4);
else
$$ = make_node (nod_agg_average, 1, $4);
}
| AVG '(' DISTINCT value ')'
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_flag_node (nod_agg_average2,
NOD_AGG_DISTINCT, 1, $4);
else
$$ = make_flag_node (nod_agg_average,
NOD_AGG_DISTINCT, 1, $4);
}
| MINIMUM '(' all_noise value ')'
{ $$ = make_node (nod_agg_min, 1, $4); }
| MINIMUM '(' DISTINCT value ')'
{ $$ = make_node (nod_agg_min, 1, $4); }
| MAXIMUM '(' all_noise value ')'
{ $$ = make_node (nod_agg_max, 1, $4); }
| MAXIMUM '(' DISTINCT value ')'
{ $$ = make_node (nod_agg_max, 1, $4); }
| LIST '(' all_noise value delimiter_opt ')'
{ $$ = make_node (nod_agg_list, 2, $4, $5); }
| LIST '(' DISTINCT value delimiter_opt ')'
{ $$ = make_flag_node (nod_agg_list, NOD_AGG_DISTINCT, 2, $4, $5); }
;
delimiter_opt
: ',' value
{ $$ = $2; }
|
{ $$ = MAKE_str_constant (MAKE_cstring(","), lex.att_charset); }
;
numeric_value_function
: extract_expression
| length_expression
;
extract_expression : EXTRACT '(' timestamp_part FROM value ')'
{ $$ = make_node (nod_extract, (int) e_extract_count, $3, $5); }
;
length_expression : bit_length_expression
| char_length_expression
| octet_length_expression
;
bit_length_expression : BIT_LENGTH '(' value ')'
{ $$ = make_node(nod_strlen, (int) e_strlen_count,
MAKE_const_slong(blr_strlen_bit), $3); }
;
char_length_expression : CHAR_LENGTH '(' value ')'
{ $$ = make_node(nod_strlen, (int) e_strlen_count,
MAKE_const_slong(blr_strlen_char), $3); }
| CHARACTER_LENGTH '(' value ')'
{ $$ = make_node(nod_strlen, (int) e_strlen_count,
MAKE_const_slong(blr_strlen_char), $3); }
;
octet_length_expression : OCTET_LENGTH '(' value ')'
{ $$ = make_node(nod_strlen, (int) e_strlen_count,
MAKE_const_slong(blr_strlen_octet), $3); }
;
system_function_expression
: system_function_std_syntax '(' value_list_opt ')'
{ $$ = make_node(nod_sys_function, e_sysfunc_count, $1, make_list($3)); }
| system_function_special_syntax
;
system_function_std_syntax
: ABS
| ACOS
| ASCII_CHAR
| ASCII_VAL
| ASIN
| ATAN
| ATAN2
| BIN_AND
| BIN_NOT
| BIN_OR
| BIN_SHL
| BIN_SHR
| BIN_XOR
| CEIL
| CHAR_TO_UUID
| COS
| COSH
| COT
| EXP
| FLOOR
| GEN_UUID
| HASH
| LEFT
| LN
| LOG
| LOG10
| LPAD
| MAXVALUE
| MINVALUE
| MOD
| PI
| POSITION
| POWER
| RAND
| REPLACE
| REVERSE
| RIGHT
| ROUND
| RPAD
| SIGN
| SIN
| SINH
| SQRT
| TAN
| TANH
| TRUNC
| UUID_TO_CHAR
;
system_function_special_syntax
: DATEADD '(' value timestamp_part TO value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 3, $3, $4, $6));
}
| DATEADD '(' timestamp_part ',' value ',' value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 3, $5, $3, $7));
}
| DATEDIFF '(' timestamp_part FROM value TO value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 3, $3, $5, $7));
}
| DATEDIFF '(' timestamp_part ',' value ',' value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 3, $3, $5, $7));
}
| OVERLAY '(' value PLACING value FROM value FOR value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 4, $3, $5, $7, $9));
}
| OVERLAY '(' value PLACING value FROM value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 3, $3, $5, $7));
}
| POSITION '(' value KW_IN value ')'
{
$$ = make_flag_node(nod_sys_function, NOD_SPECIAL_SYNTAX, e_sysfunc_count,
$1, make_node(nod_list, 2, $3, $5));
}
;
string_value_function : substring_function
| trim_function
| KW_UPPER '(' value ')'
{ $$ = make_node (nod_upcase, 1, $3); }
| KW_LOWER '(' value ')'
{ $$ = make_node (nod_lowcase, 1, $3); }
;
substring_function : SUBSTRING '(' value FROM value string_length_opt ')'
/* SQL spec requires numbering to start with 1,
hence we decrement the first parameter to make it
compatible with the engine's implementation */
{ $$ = make_node (nod_substr, (int) e_substr_count, $3,
make_node (nod_subtract, 2, $5,
MAKE_const_slong (1)), $6); }
;
string_length_opt : FOR value
{ $$ = $2; }
|
{ $$ = MAKE_const_slong (SHRT_POS_MAX); }
;
trim_function : TRIM '(' trim_specification value FROM value ')'
{ $$ = make_node (nod_trim, (int) e_trim_count, $3, $4, $6); }
| TRIM '(' value FROM value ')'
{ $$ = make_node (nod_trim, (int) e_trim_count,
MAKE_const_slong (blr_trim_both), $3, $5); }
| TRIM '(' trim_specification FROM value ')'
{ $$ = make_node (nod_trim, (int) e_trim_count, $3, NULL, $5); }
| TRIM '(' value ')'
{ $$ = make_node (nod_trim, (int) e_trim_count,
MAKE_const_slong (blr_trim_both), NULL, $3); }
;
trim_specification : BOTH
{ $$ = MAKE_const_slong (blr_trim_both); }
| TRAILING
{ $$ = MAKE_const_slong (blr_trim_trailing); }
| LEADING
{ $$ = MAKE_const_slong (blr_trim_leading); }
;
udf : symbol_UDF_name '(' value_list ')'
{ $$ = make_node (nod_udf, 2, $1, $3); }
| symbol_UDF_name '(' ')'
{ $$ = make_node (nod_udf, 1, $1); }
;
cast_specification : CAST '(' value AS data_type_descriptor ')'
{ $$ = make_node (nod_cast, (int) e_cast_count, $5, $3); }
;
/* case expressions */
case_expression : case_abbreviation
| case_specification
;
case_abbreviation : NULLIF '(' value ',' value ')'
{ $$ = make_node (nod_searched_case, 2,
make_node (nod_list, 2, make_node (nod_eql, 2, $3, $5),
make_node (nod_null, 0, NULL)), $3); }
| IIF '(' search_condition ',' value ',' value ')'
{ $$ = make_node (nod_searched_case, 2,
make_node (nod_list, 2, $3, $5), $7); }
| COALESCE '(' value ',' value_list ')'
{ $$ = make_node (nod_coalesce, 2, $3, $5); }
| DECODE '(' value ',' decode_pairs ')'
{ $$ = make_node(nod_simple_case, 3, $3, make_list($5), make_node(nod_null, 0, NULL)); }
| DECODE '(' value ',' decode_pairs ',' value ')'
{ $$ = make_node(nod_simple_case, 3, $3, make_list($5), $7); }
;
case_specification : simple_case
| searched_case
;
simple_case : CASE case_operand simple_when_clause END
{ $$ = make_node (nod_simple_case, 3, $2, make_list($3), make_node (nod_null, 0, NULL)); }
| CASE case_operand simple_when_clause ELSE case_result END
{ $$ = make_node (nod_simple_case, 3, $2, make_list($3), $5); }
;
simple_when_clause : WHEN when_operand THEN case_result
{ $$ = make_node (nod_list, 2, $2, $4); }
| simple_when_clause WHEN when_operand THEN case_result
{ $$ = make_node (nod_list, 2, $1, make_node (nod_list, 2, $3, $5)); }
;
searched_case : CASE searched_when_clause END
{ $$ = make_node (nod_searched_case, 2, make_list($2), make_node (nod_null, 0, NULL)); }
| CASE searched_when_clause ELSE case_result END
{ $$ = make_node (nod_searched_case, 2, make_list($2), $4); }
;
searched_when_clause : WHEN search_condition THEN case_result
{ $$ = make_node (nod_list, 2, $2, $4); }
| searched_when_clause WHEN search_condition THEN case_result
{ $$ = make_node (nod_list, 2, $1, make_node (nod_list, 2, $3, $5)); }
;
when_operand : value
;
case_operand : value
;
case_result : value
;
decode_pairs
: value ',' value
{ $$ = make_node(nod_list, 2, $1, $3); }
| decode_pairs ',' value ',' value
{ $$ = make_node(nod_list, 2, $1, make_node(nod_list, 2, $3, $5)); }
;
/* next value expression */
next_value_expression : NEXT KW_VALUE FOR symbol_generator_name
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_gen_id2, 2, $4,
MAKE_const_slong(1));
else
$$ = make_node (nod_gen_id, 2, $4,
MAKE_const_slong(1));
}
| GEN_ID '(' symbol_generator_name ',' value ')'
{
if (client_dialect >= SQL_DIALECT_V6_TRANSITION)
$$ = make_node (nod_gen_id2, 2, $3, $5);
else
$$ = make_node (nod_gen_id, 2, $3, $5);
}
;
timestamp_part : YEAR
{ $$ = MAKE_const_slong (blr_extract_year); }
| MONTH
{ $$ = MAKE_const_slong (blr_extract_month); }
| DAY
{ $$ = MAKE_const_slong (blr_extract_day); }
| HOUR
{ $$ = MAKE_const_slong (blr_extract_hour); }
| MINUTE
{ $$ = MAKE_const_slong (blr_extract_minute); }
| SECOND
{ $$ = MAKE_const_slong (blr_extract_second); }
| MILLISECOND
{ $$ = MAKE_const_slong (blr_extract_millisecond); }
| WEEK
{ $$ = MAKE_const_slong (blr_extract_week); }
| WEEKDAY
{ $$ = MAKE_const_slong (blr_extract_weekday); }
| YEARDAY
{ $$ = MAKE_const_slong (blr_extract_yearday); }
;
all_noise : ALL
|
;
distinct_noise : DISTINCT
|
;
null_value : KW_NULL
{ $$ = make_node (nod_null, 0, NULL); }
;
/* Performs special mapping of keywords into symbols */
symbol_UDF_name : SYMBOL
;
symbol_blob_subtype_name : valid_symbol_name
;
symbol_character_set_name : valid_symbol_name
;
symbol_collation_name : valid_symbol_name
;
symbol_column_name : valid_symbol_name
;
symbol_constraint_name : valid_symbol_name
;
symbol_cursor_name : valid_symbol_name
;
symbol_domain_name : valid_symbol_name
;
symbol_exception_name : valid_symbol_name
;
symbol_filter_name : valid_symbol_name
;
symbol_gdscode_name : valid_symbol_name
;
symbol_generator_name : valid_symbol_name
;
symbol_index_name : valid_symbol_name
;
symbol_item_alias_name : valid_symbol_name
;
symbol_label_name : valid_symbol_name
;
symbol_ddl_name : valid_symbol_name
;
symbol_procedure_name : valid_symbol_name
;
symbol_role_name : valid_symbol_name
;
symbol_table_alias_name : valid_symbol_name
;
symbol_table_name : valid_symbol_name
;
symbol_trigger_name : valid_symbol_name
;
symbol_user_name : valid_symbol_name
;
symbol_variable_name : valid_symbol_name
;
symbol_view_name : valid_symbol_name
;
symbol_savepoint_name : valid_symbol_name
;
/* symbols */
valid_symbol_name : SYMBOL
| non_reserved_word
;
/* list of non-reserved words */
non_reserved_word :
ACTION // added in IB 5.0/
| CASCADE
| FREE_IT
| RESTRICT
| ROLE
| KW_TYPE // added in IB 6.0
| KW_BREAK // added in FB 1.0
| KW_DESCRIPTOR
| SUBSTRING
| COALESCE // added in FB 1.5
| LAST
| LEAVE
| LOCK
| NULLIF
| NULLS
| STATEMENT
| INSERTING
| UPDATING
| DELETING
| FIRST
| SKIP
| BLOCK // added in FB 2.0
| BACKUP
| KW_DIFFERENCE
| IIF
| SCALAR_ARRAY
| WEEKDAY
| YEARDAY
| SEQUENCE
| NEXT
| RESTART
| COLLATION
| RETURNING
| KW_IGNORE
| LIMBO
| UNDO
| REQUESTS
| TIMEOUT
| ABS // added in FB 2.1
| ACCENT
| ACOS
| ALWAYS
| ASCII_CHAR
| ASCII_VAL
| ASIN
| ATAN
| ATAN2
| BIN_AND
| BIN_OR
| BIN_SHL
| BIN_SHR
| BIN_XOR
| CEIL
| COS
| COSH
| COT
| DATEADD
| DATEDIFF
| DECODE
| EXP
| FLOOR
| GEN_UUID
| GENERATED
| HASH
| LIST
| LN
| LOG
| LOG10
| LPAD
| MATCHED
| MATCHING
| MAXVALUE
| MILLISECOND
| MINVALUE
| MOD
| OVERLAY
| PAD
| PI
| PLACING
| POWER
| PRESERVE
| RAND
| REPLACE
| REVERSE
| ROUND
| RPAD
| SIGN
| SIN
| SINH
| SPACE
| SQRT
| TAN
| TANH
| TEMPORARY
| TRUNC
| WEEK
| AUTONOMOUS // added in FB 2.5
| CHAR_TO_UUID
| FIRSTNAME
| MIDDLENAME
| LASTNAME
| MAPPING
| OS_NAME
| UUID_TO_CHAR
| COMMON // new execute statement
| DATA
| SOURCE
| TWO_PHASE
| BIN_NOT
;
%%
/*
* PROGRAM: Dynamic SQL runtime support
* MODULE: lex.c
* DESCRIPTION: Lexical routine
*
*/
void LEX_dsql_init(MemoryPool& pool)
{
/**************************************
*
* L E X _ d s q l _ i n i t
*
**************************************
*
* Functional description
* Initialize LEX for processing. This is called only once
* per session.
*
**************************************/
for (const TOK* token = KEYWORD_getTokens(); token->tok_string; ++token)
{
DSQL_SYM symbol = FB_NEW_RPT(pool, 0) dsql_sym;
symbol->sym_string = (TEXT *) token->tok_string;
symbol->sym_length = strlen(token->tok_string);
symbol->sym_type = SYM_keyword;
symbol->sym_keyword = token->tok_ident;
symbol->sym_version = token->tok_version;
dsql_str* str = FB_NEW_RPT(pool, symbol->sym_length) dsql_str;
str->str_length = symbol->sym_length;
strncpy((char*) str->str_data, (char*) symbol->sym_string, symbol->sym_length);
symbol->sym_object = (void *) str;
HSHD_insert(symbol);
}
}
const TEXT* Parser::lex_position()
{
/**************************************
*
* l e x _ p o s i t i o n
*
**************************************
*
* Functional description
* Return the current position of LEX
* in the input string.
*
**************************************/
return lex.ptr;
}
#ifdef NOT_USED_OR_REPLACED
static bool long_int(dsql_nod* string,
SLONG *long_value)
{
/*************************************
*
* l o n g _ i n t
*
*************************************
*
* Functional description
* checks for all digits in the
* number and return an atol().
*
*************************************/
for (const UCHAR* p = (UCHAR*)((dsql_str*) string)->str_data;
classes(*p) & CHR_DIGIT; p++)
{
if (!(classes(*p) & CHR_DIGIT)) {
return false;
}
}
*long_value = atol(((dsql_str*) string)->str_data);
return true;
}
#endif
static dsql_fld* make_field (dsql_nod* field_name)
{
/**************************************
*
* m a k e _ f i e l d
*
**************************************
*
* Functional description
* Make a field block of given name.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
if (field_name == NULL)
{
dsql_fld* field = FB_NEW(*tdbb->getDefaultPool())
dsql_fld(*tdbb->getDefaultPool());
field->fld_name = INTERNAL_FIELD_NAME;
return field;
}
const dsql_str* string = (dsql_str*) field_name->nod_arg[1];
dsql_fld* field = FB_NEW(*tdbb->getDefaultPool())
dsql_fld(*tdbb->getDefaultPool());
field->fld_name = string->str_data;
field->fld_explicit_collation = false;
field->fld_not_nullable = false;
field->fld_full_domain = false;
return field;
}
static dsql_fil* make_file()
{
/**************************************
*
* m a k e _ f i l e
*
**************************************
*
* Functional description
* Make a file block
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dsql_fil* temp_file = FB_NEW(*tdbb->getDefaultPool()) dsql_fil;
return temp_file;
}
dsql_nod* Parser::make_list (dsql_nod* node)
{
/**************************************
*
* m a k e _ l i s t
*
**************************************
*
* Functional description
* Collapse nested list nodes into single list.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
if (node)
{
DsqlNodStack stack;
stack_nodes(node, stack);
USHORT l = stack.getCount();
const dsql_nod* old = node;
node = FB_NEW_RPT(*tdbb->getDefaultPool(), l) dsql_nod;
node->nod_count = l;
node->nod_type = nod_list;
node->nod_line = (USHORT) lex.lines_bk;
node->nod_column = (USHORT) (lex.last_token_bk - lex.line_start_bk + 1);
if (old->getType() == dsql_type_nod)
{
node->nod_flags = old->nod_flags;
}
dsql_nod** ptr = node->nod_arg + node->nod_count;
while (stack.hasData())
*--ptr = stack.pop();
}
return node;
}
dsql_nod* Parser::make_parameter()
{
/**************************************
*
* m a k e _ p a r a m e t e r
*
**************************************
*
* Functional description
* Make parameter node
* Any change should also be made to function below
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), e_par_count) dsql_nod;
node->nod_type = nod_parameter;
node->nod_line = (USHORT) lex.lines_bk;
node->nod_column = (USHORT) (lex.last_token_bk - lex.line_start_bk + 1);
node->nod_count = e_par_count;
node->nod_arg[e_par_index] = (dsql_nod*)(IPTR) lex.param_number++;
return node;
}
dsql_nod* Parser::make_node(NOD_TYPE type, int count, ...)
{
/**************************************
*
* m a k e _ n o d e
*
**************************************
*
* Functional description
* Make a node of given type.
* Any change should also be made to function below
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), count) dsql_nod;
node->nod_type = type;
node->nod_line = (USHORT) lex.lines_bk;
node->nod_column = (USHORT) (lex.last_token_bk - lex.line_start_bk + 1);
node->nod_count = count;
dsql_nod** p = node->nod_arg;
va_list ptr;
va_start (ptr, count);
while (--count >= 0)
*p++ = va_arg (ptr, dsql_nod*);
va_end(ptr);
return node;
}
dsql_nod* Parser::makeClassNode(Node* node)
{
return make_node(nod_class_node, 1, reinterpret_cast<dsql_nod*>(node));
}
dsql_nod* Parser::make_flag_node(NOD_TYPE type, SSHORT flag, int count, ...)
{
/**************************************
*
* m a k e _ f l a g _ n o d e
*
**************************************
*
* Functional description
* Make a node of given type. Set flag field
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
dsql_nod* node = FB_NEW_RPT(*tdbb->getDefaultPool(), count) dsql_nod;
node->nod_type = type;
node->nod_flags = flag;
node->nod_line = (USHORT) lex.lines_bk;
node->nod_column = (USHORT) (lex.last_token_bk - lex.line_start_bk + 1);
node->nod_count = count;
dsql_nod** p = node->nod_arg;
va_list ptr;
va_start (ptr, count);
while (--count >= 0)
*p++ = va_arg (ptr, dsql_nod*);
va_end(ptr);
return node;
}
static void prepare_console_debug (int level, int *yydeb)
{
/*************************************
*
* p r e p a r e _ c o n s o l e _ d e b u g
*
*************************************
*
* Functional description
* Activate debug info. In WinNT, redirect the standard
* output so one can see the generated information.
* Feel free to add your platform specific code.
*
*************************************/
#ifdef DSQL_DEBUG
DSQL_debug = level;
#endif
if (level >> 8)
*yydeb = level >> 8;
}
#ifdef NOT_USED_OR_REPLACED
static bool short_int(dsql_nod* string,
SLONG *long_value,
SSHORT range)
{
/*************************************
*
* s h o r t _ i n t
*
*************************************
*
* Functional description
* is the string a valid representation
* of a positive short int?
*
*************************************/
if (((dsql_str*) string)->str_length > 5) {
return false;
}
for (UCHAR* p = (UCHAR*)((dsql_str*) string)->str_data;
classes(*p) & CHR_DIGIT; p++)
{
if (!(classes(*p) & CHR_DIGIT)) {
return false;
}
}
/* there are 5 or fewer digits, it's value may still be greater
* than 32767... */
SCHAR buf[10];
buf[0] = ((dsql_str*) string)->str_data[0];
buf[1] = ((dsql_str*) string)->str_data[1];
buf[2] = ((dsql_str*) string)->str_data[2];
buf[3] = ((dsql_str*) string)->str_data[3];
buf[4] = ((dsql_str*) string)->str_data[4];
buf[5] = '\0';
*long_value = atoi (buf);
bool return_value;
switch (range)
{
case POSITIVE:
return_value = *long_value > SHRT_POS_MAX;
break;
case NEGATIVE:
return_value = *long_value > SHRT_NEG_MAX;
break;
case UNSIGNED:
return_value = *long_value > SHRT_UNSIGNED_MAX;
break;
}
return !return_value;
}
#endif
static void stack_nodes (dsql_nod* node,
DsqlNodStack& stack)
{
/**************************************
*
* s t a c k _ n o d e s
*
**************************************
*
* Functional description
* Assist in turning a tree of misc nodes into a clean list.
*
**************************************/
if (node->nod_type != nod_list)
{
stack.push(node);
return;
}
/* To take care of cases where long lists of nodes are in a chain
of list nodes with exactly one entry, this algorithm will look
for a pattern of repeated list nodes with two entries, the first
being a list node and the second being a non-list node. Such
a list will be reverse linked, and then re-reversed, stacking the
non-list nodes in the process. The purpose of this is to avoid
massive recursion of this function. */
dsql_nod* start_chain = node;
dsql_nod* end_chain = NULL;
dsql_nod* curr_node = node;
dsql_nod* next_node = node->nod_arg[0];
while ( curr_node->nod_count == 2 &&
curr_node->nod_arg[0]->nod_type == nod_list &&
curr_node->nod_arg[1]->nod_type != nod_list &&
next_node->nod_arg[0]->nod_type == nod_list &&
next_node->nod_arg[1]->nod_type != nod_list)
{
/* pattern was found so reverse the links and go to next node */
dsql_nod* save_link = next_node->nod_arg[0];
next_node->nod_arg[0] = curr_node;
curr_node = next_node;
next_node = save_link;
end_chain = curr_node;
}
/* see if any chain was found */
if (end_chain)
{
/* first, handle the rest of the nodes */
/* note that next_node still points to the first non-pattern node */
stack_nodes (next_node, stack);
/* stack the non-list nodes and reverse the chain on the way back */
curr_node = end_chain;
while (true)
{
stack.push(curr_node->nod_arg[1]);
if ( curr_node == start_chain)
break;
dsql_nod* save_link = curr_node->nod_arg[0];
curr_node->nod_arg[0] = next_node;
next_node = curr_node;
curr_node = save_link;
}
return;
}
dsql_nod** ptr = node->nod_arg;
for (const dsql_nod* const* const end = ptr + node->nod_count; ptr < end; ptr++)
stack_nodes (*ptr, stack);
}
static Firebird::MetaName toName(dsql_nod* node)
{
return Firebird::MetaName(((dsql_str*) node)->str_data);
}
int Parser::yylex()
{
lex.prev_keyword = yylexAux();
return lex.prev_keyword;
}
int Parser::yylexAux()
{
/**************************************
*
* y y l e x A u x
*
**************************************
*
* Functional description: lexer.
*
**************************************/
UCHAR tok_class;
char string[MAX_TOKEN_LEN];
SSHORT c;
/* Find end of white space and skip comments */
for (;;)
{
if (lex.ptr >= lex.end)
return -1;
c = *lex.ptr++;
/* Process comments */
if (c == '\n') {
lex.lines++;
lex.line_start = lex.ptr;
continue;
}
if (c == '-' && lex.ptr < lex.end && *lex.ptr == '-')
{
/* single-line */
lex.ptr++;
while (lex.ptr < lex.end) {
if ((c = *lex.ptr++) == '\n') {
lex.lines++;
lex.line_start = lex.ptr /* + 1*/; /* CVC: +1 left out. */
break;
}
}
if (lex.ptr >= lex.end)
return -1;
continue;
}
else if (c == '/' && lex.ptr < lex.end && *lex.ptr == '*')
{
/* multi-line */
const TEXT& start_block = lex.ptr[-1];
lex.ptr++;
while (lex.ptr < lex.end) {
if ((c = *lex.ptr++) == '*') {
if (*lex.ptr == '/')
break;
}
if (c == '\n') {
lex.lines++;
lex.line_start = lex.ptr /* + 1*/; /* CVC: +1 left out. */
}
}
if (lex.ptr >= lex.end)
{
// I need this to report the correct beginning of the block,
// since it's not a token really.
lex.last_token = &start_block;
yyerror("unterminated block comment");
return -1;
}
lex.ptr++;
continue;
}
tok_class = classes(c);
if (!(tok_class & CHR_WHITE))
break;
}
/* Depending on tok_class of token, parse token */
lex.last_token = lex.ptr - 1;
if (tok_class & CHR_INTRODUCER)
{
/* The Introducer (_) is skipped, all other idents are copied
* to become the name of the character set
*/
char* p = string;
for (; lex.ptr < lex.end && classes(*lex.ptr) & CHR_IDENT; lex.ptr++)
{
if (lex.ptr >= lex.end)
return -1;
check_copy_incr(p, UPPER7(*lex.ptr), string);
}
check_bound(p, string);
*p = 0;
/* make a string value to hold the name, the name
* is resolved in pass1_constant */
yylval = (dsql_nod*) (MAKE_string(string, p - string))->str_data;
return INTRODUCER;
}
/* parse a quoted string, being sure to look for double quotes */
if (tok_class & CHR_QUOTE)
{
char* buffer = string;
size_t buffer_len = sizeof (string);
const char* buffer_end = buffer + buffer_len - 1;
char* p;
for (p = buffer; ; ++p)
{
if (lex.ptr >= lex.end)
{
if (buffer != string)
gds__free (buffer);
yyerror("unterminated string");
return -1;
}
// Care about multi-line constants and identifiers
if (*lex.ptr == '\n') {
lex.lines++;
lex.line_start = lex.ptr + 1;
}
/* *lex.ptr is quote - if next != quote we're at the end */
if ((*lex.ptr == c) && ((++lex.ptr == lex.end) || (*lex.ptr != c)))
break;
if (p > buffer_end)
{
char* const new_buffer = (char*) gds__alloc (2 * buffer_len);
/* FREE: at outer block */
if (!new_buffer) /* NOMEM: */
{
if (buffer != string)
gds__free (buffer);
return -1;
}
memcpy (new_buffer, buffer, buffer_len);
if (buffer != string)
gds__free (buffer);
buffer = new_buffer;
p = buffer + buffer_len;
buffer_len = 2 * buffer_len;
buffer_end = buffer + buffer_len - 1;
}
*p = *lex.ptr++;
}
if (c == '"')
{
stmt_ambiguous = true; /* string delimited by double quotes could be
** either a string constant or a SQL delimited
** identifier, therefore marks the SQL
** statement as ambiguous */
if (client_dialect == SQL_DIALECT_V6_TRANSITION)
{
if (buffer != string)
gds__free (buffer);
yyabandon (-104, isc_invalid_string_constant);
}
else if (client_dialect >= SQL_DIALECT_V6)
{
if ((p - buffer) >= MAX_TOKEN_LEN)
{
if (buffer != string)
gds__free (buffer);
yyabandon (-104, isc_token_too_long);
}
yylval = (dsql_nod*) MAKE_string(buffer, p - buffer);
dsql_str* delimited_id_str = (dsql_str*) yylval;
delimited_id_str->str_flags |= STR_delimited_id;
if (buffer != string)
gds__free (buffer);
return SYMBOL;
}
}
yylval = (dsql_nod*) MAKE_string(buffer, p - buffer);
if (buffer != string)
gds__free (buffer);
return STRING;
}
/*
* Check for a numeric constant, which starts either with a digit or with
* a decimal point followed by a digit.
*
* This code recognizes the following token types:
*
* NUMBER: string of digits which fits into a 32-bit integer
*
* NUMBER64BIT: string of digits whose value might fit into an SINT64,
* depending on whether or not there is a preceding '-', which is to
* say that "9223372036854775808" is accepted here.
*
* SCALEDINT: string of digits and a single '.', where the digits
* represent a value which might fit into an SINT64, depending on
* whether or not there is a preceding '-'.
*
* FLOAT: string of digits with an optional '.', and followed by an "e"
* or "E" and an optionally-signed exponent.
*
* NOTE: we swallow leading or trailing blanks, but we do NOT accept
* embedded blanks:
*
* Another note: c is the first character which need to be considered,
* ptr points to the next character.
*/
fb_assert(lex.ptr <= lex.end);
// Hexadecimal string constant. This is treated the same as a
// string constant, but is defined as: X'bbbb'
//
// Where the X is a literal 'x' or 'X' character, followed
// by a set of nibble values in single quotes. The nibble
// can be 0-9, a-f, or A-F, and is converted from the hex.
// If an odd number of nibbles is given, a leading '0' is
// assumed.
//
// The resulting value is stored in a string descriptor and
// returned to the parser as a string. This can be stored
// in a character or binary item.
if ((c == 'x' || c == 'X') && lex.ptr < lex.end && *lex.ptr == '\'')
{
bool hexerror = false;
// Remember where we start from, to rescan later.
// Also we'll need to know the length of the buffer.
const char* hexstring = (char*) ++lex.ptr;
int charlen = 0;
// Time to scan the string. Make sure the characters are legal,
// and find out how long the hex digit string is.
for (;;)
{
if (lex.ptr >= lex.end) // Unexpected EOS
{
hexerror = true;
break;
}
c = *lex.ptr;
if (c == '\'') // Trailing quote, done
{
++lex.ptr; // Skip the quote
break;
}
if (!(classes(c) & CHR_HEX)) // Illegal character
{
hexerror = true;
break;
}
++charlen; // Okay, just count 'em
++lex.ptr; // and advance...
}
// If we made it this far with no error, then convert the string.
if (!hexerror)
{
// At this point, see if the string length is odd. If so,
// we'll assume a leading zero. Then figure out the length
// of the actual resulting hex string. Allocate a second
// temporary buffer for it.
bool nibble = (charlen & 1); // IS_ODD(charlen)
Firebird::string temp;
// Re-scan over the hex string we got earlier, converting
// adjacent bytes into nibble values. Every other nibble,
// write the saved byte to the temp space. At the end of
// this, the temp.space area will contain the binary
// representation of the hex constant.
UCHAR byte = 0;
for (int i = 0; i < charlen; i++)
{
c = UPPER7(hexstring[i]);
// Now convert the character to a nibble
if (c >= 'A')
c = (c - 'A') + 10;
else
c = (c - '0');
if (nibble)
{
byte = (byte << 4) + (UCHAR) c;
nibble = false;
temp.append(1, (char) byte);
}
else
{
byte = c;
nibble = true;
}
}
dsql_str* string = MAKE_string((char*) temp.c_str(), temp.length());
string->str_charset = "BINARY";
yylval = (dsql_nod*) string;
return STRING;
} // if (!hexerror)...
// If we got here, there was a parsing error. Set the
// position back to where it was before we messed with
// it. Then fall through to the next thing we might parse.
c = *lex.last_token;
lex.ptr = lex.last_token + 1;
}
// Hexadecimal numeric constants - 0xBBBBBB
//
// where the '0' and the 'X' (or 'x') are literal, followed
// by a set of nibbles, using 0-9, a-f, or A-F. Odd numbers
// of nibbles assume a leading '0'. The result is converted
// to an integer, and the result returned to the caller. The
// token is identified as a NUMBER if it's a 32-bit or less
// value, or a NUMBER64INT if it requires a 64-bit number.
if (c == '0' && lex.ptr + 1 < lex.end && (*lex.ptr == 'x' || *lex.ptr == 'X') &&
(classes(lex.ptr[1]) & CHR_HEX))
{
bool hexerror = false;
// Remember where we start from, to rescan later.
// Also we'll need to know the length of the buffer.
++lex.ptr; // Skip the 'X' and point to the first digit
const char* hexstring = (char*) lex.ptr;
int charlen = 0;
// Time to scan the string. Make sure the characters are legal,
// and find out how long the hex digit string is.
for (;;)
{
if (lex.ptr >= lex.end) // Unexpected EOS
{
hexerror = true;
break;
}
c = *lex.ptr;
if (!(classes(c) & CHR_HEX)) // End of digit string
break;
++charlen; // Okay, just count 'em
++lex.ptr; // and advance...
if (charlen > 16) // Too many digits...
{
hexerror = true;
break;
}
}
// we have a valid hex token. Now give it back, either as
// an NUMBER or NUMBER64BIT.
if (!hexerror)
{
// if charlen > 8 (something like FFFF FFFF 0, w/o the spaces)
// then we have to return a NUMBER64BIT. We'll make a string
// node here, and let make.cpp worry about converting the
// string to a number and building the node later.
if (charlen > 8)
{
char cbuff[32];
cbuff[0] = 'X';
strncpy(&cbuff[1], hexstring, charlen);
cbuff[charlen + 1] = '\0';
char* p = &cbuff[1];
while (*p != '\0')
{
if ((*p >= 'a') && (*p <= 'f'))
*p = UPPER(*p);
p++;
}
yylval = (dsql_nod*) MAKE_string(cbuff, strlen(cbuff));
return NUMBER64BIT;
}
else
{
// we have an integer value. we'll return NUMBER.
// but we have to make a number value to be compatible
// with existing code.
// See if the string length is odd. If so,
// we'll assume a leading zero. Then figure out the length
// of the actual resulting hex string. Allocate a second
// temporary buffer for it.
bool nibble = (charlen & 1); // IS_ODD(temp.length)
// Re-scan over the hex string we got earlier, converting
// adjacent bytes into nibble values. Every other nibble,
// write the saved byte to the temp space. At the end of
// this, the temp.space area will contain the binary
// representation of the hex constant.
UCHAR byte = 0;
SINT64 value = 0;
for (int i = 0; i < charlen; i++)
{
c = UPPER(hexstring[i]);
// Now convert the character to a nibble
if (c >= 'A')
c = (c - 'A') + 10;
else
c = (c - '0');
if (nibble)
{
byte = (byte << 4) + (UCHAR) c;
nibble = false;
value = (value << 8) + byte;
}
else
{
byte = c;
nibble = true;
}
}
yylval = (dsql_nod*)(long) value;
return NUMBER;
} // integer value
} // if (!hexerror)...
// If we got here, there was a parsing error. Set the
// position back to where it was before we messed with
// it. Then fall through to the next thing we might parse.
c = *lex.last_token;
lex.ptr = lex.last_token + 1;
} // headecimal numeric constants
if ((tok_class & CHR_DIGIT) ||
((c == '.') && (lex.ptr < lex.end) && (classes(*lex.ptr) & CHR_DIGIT)))
{
/* The following variables are used to recognize kinds of numbers. */
bool have_error = false; /* syntax error or value too large */
bool have_digit = false; /* we've seen a digit */
bool have_decimal = false; /* we've seen a '.' */
bool have_exp = false; /* digit ... [eE] */
bool have_exp_sign = false; /* digit ... [eE] {+-] */
bool have_exp_digit = false; /* digit ... [eE] ... digit */
FB_UINT64 number = 0;
FB_UINT64 limit_by_10 = MAX_SINT64 / 10;
for (--lex.ptr ; lex.ptr < lex.end ; lex.ptr++)
{
c = *lex.ptr;
if (have_exp_digit && (! (classes(c) & CHR_DIGIT)))
/* First non-digit after exponent and digit terminates
the token. */
break;
else if (have_exp_sign && (! (classes(c) & CHR_DIGIT)))
{
/* only digits can be accepted after "1E-" */
have_error = true;
break;
}
else if (have_exp)
{
/* We've seen e or E, but nothing beyond that. */
if ( ('-' == c) || ('+' == c) )
have_exp_sign = true;
else if ( classes(c) & CHR_DIGIT )
/* We have a digit: we haven't seen a sign yet,
but it's too late now. */
have_exp_digit = have_exp_sign = true;
else
{
/* end of the token */
have_error = true;
break;
}
}
else if ('.' == c)
{
if (!have_decimal)
have_decimal = true;
else
{
have_error = true;
break;
}
}
else if (classes(c) & CHR_DIGIT)
{
/* Before computing the next value, make sure there will be
no overflow. */
have_digit = true;
if (number >= limit_by_10)
{
/* possibility of an overflow */
if ((number > limit_by_10) || (c > '8'))
{
have_error = true;
break;
}
}
number = number * 10 + (c - '0');
}
else if ( (('E' == c) || ('e' == c)) && have_digit )
have_exp = true;
else
/* Unexpected character: this is the end of the number. */
break;
}
/* We're done scanning the characters: now return the right kind
of number token, if any fits the bill. */
if (!have_error)
{
fb_assert(have_digit);
if (have_exp_digit)
{
yylval = (dsql_nod*) MAKE_string(lex.last_token, lex.ptr - lex.last_token);
lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines;
return FLOAT_NUMBER;
}
else if (!have_exp)
{
/* We should return some kind (scaled-) integer type
except perhaps in dialect 1. */
if (!have_decimal && (number <= MAX_SLONG))
{
yylval = (dsql_nod*) (IPTR) number;
//printf ("parse.y %p %d\n", yylval, number);
return NUMBER;
}
else
{
/* We have either a decimal point with no exponent
or a string of digits whose value exceeds MAX_SLONG:
the returned type depends on the client dialect,
so warn of the difference if the client dialect is
SQL_DIALECT_V6_TRANSITION.
*/
if (SQL_DIALECT_V6_TRANSITION == client_dialect)
{
/* Issue a warning about the ambiguity of the numeric
* numeric literal. There are multiple calls because
* the message text exceeds the 119-character limit
* of our message database.
*/
ERRD_post_warning( isc_dsql_warning_number_ambiguous,
isc_arg_string,
ERR_string( lex.last_token, lex.ptr - lex.last_token ),
isc_arg_end );
ERRD_post_warning( isc_dsql_warning_number_ambiguous1,
isc_arg_end );
}
yylval = (dsql_nod*) MAKE_string(lex.last_token, lex.ptr - lex.last_token);
lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines;
if (client_dialect < SQL_DIALECT_V6_TRANSITION)
return FLOAT_NUMBER;
else if (have_decimal)
return SCALEDINT;
else
return NUMBER64BIT;
}
} /* else if (!have_exp) */
} /* if (!have_error) */
/* we got some kind of error or overflow, so don't recognize this
* as a number: just pass it through to the next part of the lexer.
*/
}
/* Restore the status quo ante, before we started our unsuccessful
attempt to recognize a number. */
lex.ptr = lex.last_token;
c = *lex.ptr++;
/* We never touched tok_class, so it doesn't need to be restored. */
/* end of number-recognition code */
if (tok_class & CHR_LETTER)
{
char* p = string;
check_copy_incr(p, UPPER (c), string);
for (; lex.ptr < lex.end && classes(*lex.ptr) & CHR_IDENT; lex.ptr++)
{
if (lex.ptr >= lex.end)
return -1;
check_copy_incr(p, UPPER (*lex.ptr), string);
}
check_bound(p, string);
*p = 0;
dsql_sym* sym =
HSHD_lookup (NULL, (TEXT *) string, (SSHORT)(p - string), SYM_keyword, parser_version);
if (sym && (sym->sym_keyword != COMMENT || lex.prev_keyword == -1))
{
yylval = (dsql_nod*) sym->sym_object;
lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines;
return sym->sym_keyword;
}
yylval = (dsql_nod*) MAKE_string(string, p - string);
lex.last_token_bk = lex.last_token;
lex.line_start_bk = lex.line_start;
lex.lines_bk = lex.lines;
return SYMBOL;
}
/* Must be punctuation -- test for double character punctuation */
if (lex.last_token + 1 < lex.end)
{
dsql_sym* sym =
HSHD_lookup (NULL, lex.last_token, (SSHORT) 2, SYM_keyword, (USHORT) parser_version);
if (sym)
{
++lex.ptr;
return sym->sym_keyword;
}
}
/* Single character punctuation are simply passed on */
return (UCHAR) c;
}
void Parser::yyerror_detailed(const TEXT* error_string, int yychar, YYSTYPE&, YYPOSN&)
{
/**************************************
*
* y y e r r o r _ d e t a i l e d
*
**************************************
*
* Functional description
* Print a syntax error.
*
**************************************/
const TEXT* line_start = lex.line_start;
SLONG lines = lex.lines;
if (lex.last_token < lex.line_start)
{
line_start = lex.line_start_bk;
lines--;
}
if (yychar < 1)
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
isc_arg_gds, isc_command_end_err2, /* Unexpected end of command */
isc_arg_number, lines,
isc_arg_number, (SLONG) (lex.last_token - line_start + 1),
0);
else
{
ERRD_post (isc_sqlerr, isc_arg_number, (SLONG) -104,
/* Token unknown - line %d, column %d */
isc_arg_gds, isc_dsql_token_unk_err,
isc_arg_number, (SLONG) lines,
isc_arg_number, (SLONG) (lex.last_token - line_start + 1), /*CVC: +1*/
/* Show the token */
isc_arg_gds, isc_random,
isc_arg_cstring, (int) (lex.ptr - lex.last_token), lex.last_token,
0);
}
}
// The argument passed to this function is ignored. Therefore, messages like
// "syntax error" and "yacc stack overflow" are never seen.
void Parser::yyerror(const TEXT* error_string)
{
YYSTYPE errt_value = 0;
YYPOSN errt_posn = -1;
yyerror_detailed(error_string, -1, errt_value, errt_posn);
}
static void yyabandon (SLONG sql_code,
ISC_STATUS error_symbol)
{
/**************************************
*
* y y a b a n d o n
*
**************************************
*
* Functional description
* Abandon the parsing outputting the supplied string
*
**************************************/
ERRD_post (isc_sqlerr, isc_arg_number, sql_code,
isc_arg_gds, error_symbol, 0);
}