%{ /* * 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 "dyn_consts.h" #include #include #include #include #include "iberror.h" #include "../dsql/dsql.h" #include "ibase.h" #include "../jrd/flags.h" #include "../jrd/jrd.h" #include "../jrd/DataTypeUtil.h" #include "../dsql/errd_proto.h" #include "../dsql/make_proto.h" #include "../yvalve/gds_proto.h" #include "../jrd/err_proto.h" #include "../common/intlobj_new.h" #include "../jrd/Attachment.h" #include "../common/StatusArg.h" // This is needed here to provide backward compatibility when working with SSPI plugin #include "../auth/trusted/AuthSspi.h" // since UNIX isn't standard, we have to define // stuff which is in (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 int POSITIVE = 0; const int NEGATIVE = 1; const int UNSIGNED = 2; //const int MIN_CACHE_BUFFERS = 250; //const int DEF_CACHE_BUFFERS = 1000; #define YYSTYPE YYSTYPE #if defined(DEBUG) || defined(DEV_BUILD) #define YYDEBUG 1 #endif #define YYREDUCEPOSNFUNC yyReducePosn #define YYREDUCEPOSNFUNCARG NULL // ASF: Inherited attributes (aka rule parameters) are executed even when in trial mode, but action // rules ({}) are executed only when in full parse mode. NOTRIAL should be used to avoid segfaults // due to accessing invalid pointers in parameters (not yet returned from action rules). #define NOTRIAL(x) (yytrial ? NULL : (x)) inline unsigned trigger_type_suffix(const unsigned slot1, const unsigned slot2, const unsigned slot3) { return ((slot1 << 1) | (slot2 << 3) | (slot3 << 5)); } #include "../dsql/chars.h" using namespace Jrd; using namespace Firebird; %} // token declarations // Tokens are organized chronologically by date added. // See yvalve/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 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 DECIMAL %token DECLARE %token DEFAULT %token DELETE %token DESC %token DISTINCT %token DO %token DOMAIN %token DROP %token ELSE %token END %token ENTRY_POINT %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 HAVING %token IF %token 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 CHAR %token DEC %token DOUBLE %token FILE %token FLOAT %token INT %token LONG %token NULL %token NUMERIC %token UPPER %token VALUE %token LENGTH %token LEFT %token LEQ %token LEVEL %token LIKE %token MANUAL %token MAXIMUM %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 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 ROLLBACK %token SEGMENT %token SELECT %token SET %token SHADOW %token SHARED %token SINGULAR %token 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 DECIMAL_NUMBER %token LIMIT64_NUMBER LIMIT64_INT NUM128 %token SYMBOL %token NUMBER32BIT %token STRING %token INTRODUCER // New tokens added v5.0 %token ACTION %token ADMIN %token BLOBID %token CASCADE %token FREE_IT // ISC SQL extension %token RESTRICT %token ROLE %token TEMP // New tokens added v6.0 %token COLUMN %token 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 BREAK %token SUBSTRING %token RECREATE %token 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 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 LOWER %token OCTET_LENGTH %token TRAILING %token TRIM %token RETURNING %token 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 GRANTED %token LASTNAME %token MIDDLENAME %token MAPPING %token OS_NAME %token SIMILAR %token UUID_TO_CHAR // new execute statement %token CALLER %token COMMON %token DATA %token SOURCE %token TWO_PHASE %token BIND_PARAM %token BIN_NOT // tokens added for Firebird 3.0 %token BODY %token CONTINUE %token DDL %token DECRYPT %token ENCRYPT %token ENGINE %token NAME %token OVER %token PACKAGE %token PARTITION %token RDB_GET_CONTEXT %token RDB_SET_CONTEXT %token SCROLL %token PRIOR %token ABSOLUTE %token RELATIVE %token ACOSH %token ASINH %token ATANH %token RETURN %token DETERMINISTIC %token IDENTITY %token DENSE_RANK %token FIRST_VALUE %token NTH_VALUE %token LAST_VALUE %token LAG %token LEAD %token RANK %token ROW_NUMBER %token SQLSTATE %token BOOLEAN %token FALSE %token TRUE %token UNKNOWN %token USAGE %token RDB_RECORD_VERSION %token LINGER %token TAGS %token PLUGIN %token SERVERWIDE %token INCREMENT %token TRUSTED %token ROW %token OFFSET %token STDDEV_SAMP %token STDDEV_POP %token VAR_SAMP %token VAR_POP %token COVAR_SAMP %token COVAR_POP %token CORR %token REGR_AVGX %token REGR_AVGY %token REGR_COUNT %token REGR_INTERCEPT %token REGR_R2 %token REGR_SLOPE %token REGR_SXX %token REGR_SXY %token REGR_SYY // tokens added for Firebird 4.0 %token BASE64_DECODE %token BASE64_ENCODE %token BINARY %token BIND %token COMPARE_DECFLOAT %token CONSISTENCY %token COUNTER %token CRYPT_HASH %token CTR_BIG_ENDIAN %token CTR_LENGTH %token CTR_LITTLE_ENDIAN %token CUME_DIST %token DECFLOAT %token DEFINER %token DISABLE %token ENABLE %token EXCESS %token EXCLUDE %token EXTENDED %token FIRST_DAY %token FOLLOWING %token HEX_DECODE %token HEX_ENCODE %token IDLE %token INCLUDE %token INT128 %token INVOKER %token IV %token LAST_DAY %token LATERAL %token LEGACY %token LOCAL %token LOCALTIME %token LOCALTIMESTAMP %token LPARAM %token MAKE_DBKEY %token MESSAGE %token MODE %token NATIVE %token NORMALIZE_DECFLOAT %token NTILE %token NUMBER %token OTHERS %token OVERRIDING %token PERCENT_RANK %token PRECEDING %token PRIVILEGE %token PUBLICATION %token QUANTIZE %token RANGE %token RESETTING %token RDB_ERROR %token RDB_GET_TRANSACTION_CN %token RDB_ROLE_IN_USE %token RDB_SYSTEM_PRIVILEGE %token RESET %token RSA_DECRYPT %token RSA_ENCRYPT %token RSA_PRIVATE %token RSA_PUBLIC %token RSA_SIGN_HASH %token RSA_VERIFY_HASH %token SALT_LENGTH %token SECURITY %token SESSION %token SIGNATURE %token SQL %token SYSTEM %token TIES %token TIMEZONE_HOUR %token TIMEZONE_MINUTE %token TOTALORDER %token TRAPS %token UNBOUNDED %token VARBINARY %token WINDOW %token WITHOUT %token ZONE // external connections pool management %token CONNECTIONS %token POOL %token LIFETIME %token CLEAR %token OLDEST // tokens added for Firebird 4.0.1 %token DEBUG %token PKCS_1_5 // tokens added for Firebird 4.0.2 %token BLOB_APPEND // tokens added for Firebird 5.0 %token LOCKED %token OPTIMIZE %token QUARTER %token TARGET %token TIMEZONE_NAME %token UNICODE_CHAR %token UNICODE_VAL %token OWNER // tokens added for Firebird 6.0 %token ANY_VALUE %token BTRIM %token CALL %token FORMAT %token LTRIM %token NAMED_ARG_ASSIGN %token RTRIM // precedence declarations for expression evaluation %left OR %left AND %left NOT %left '=' '<' '>' BETWEEN LIKE CONTAINING STARTING SIMILAR IN NEQ GEQ LEQ NOT_GTR NOT_LSS %left IS %left '+' '-' %left '*' '/' %left UMINUS UPLUS %left CONCATENATE %left COLLATE %left AT // 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 %union YYSTYPE { YYSTYPE() {} std::optional nullableIntVal; Firebird::TriState triState; std::optional nullableSqlSecurityVal; std::optional nullableOverrideClause; struct { bool first; bool second; } boolPair; bool boolVal; int intVal; unsigned uintVal; SLONG int32Val; SINT64 int64Val; FB_UINT64 uint64Val; std::optional nullableInt64Val; std::optional nullableUint64Val; Jrd::ScaledNumber scaledNumber; UCHAR blrOp; Jrd::OrderNode::NullsPlacement nullsPlacement; Jrd::ComparativeBoolNode::DsqlFlag cmpBoolFlag; Jrd::dsql_fld* legacyField; Jrd::ReturningClause* returningClause; Jrd::MetaName* metaNamePtr; Firebird::ObjectsArray* metaNameArray; Firebird::PathName* pathNamePtr; Jrd::QualifiedName* qualifiedNamePtr; Firebird::string* stringPtr; Jrd::IntlString* intlStringPtr; Jrd::Lim64String* lim64ptr; Jrd::ExternalClause* externalClause; Firebird::NonPooledPair* namedArgument; Firebird::NonPooledPair*, Jrd::ValueListNode*>* namedArguments; Firebird::Array >* parametersClause; Jrd::WindowClause* windowClause; Jrd::WindowClause::FrameExtent* windowClauseFrameExtent; Jrd::WindowClause::Frame* windowClauseFrame; Jrd::WindowClause::Exclusion windowClauseExclusion; Jrd::Node* node; Jrd::ExprNode* exprNode; Jrd::ValueExprNode* valueExprNode; Jrd::BoolExprNode* boolExprNode; Jrd::RecordSourceNode* recSourceNode; Jrd::RelationSourceNode* relSourceNode; Jrd::ValueListNode* valueListNode; Jrd::RecSourceListNode* recSourceListNode; Jrd::RseNode* rseNode; Jrd::PlanNode* planNode; Jrd::PlanNode::AccessType* accessType; Jrd::StmtNode* stmtNode; Jrd::DdlNode* ddlNode; Jrd::SelectExprNode* selectExprNode; Jrd::WithClause* withClause; Jrd::RowsClause* rowsClause; Jrd::FieldNode* fieldNode; Jrd::DecodeNode* decodeNode; Firebird::Array* fieldArray; Firebird::Array >* nestFieldArray; Jrd::NamedWindowClause* namedWindowClause; Jrd::NamedWindowsClause* namedWindowsClause; Jrd::TransactionNode* traNode; Jrd::SessionManagementNode* mngNode; Firebird::Array* privilegeArray; Jrd::GranteeClause* granteeClause; Firebird::Array* granteeArray; Jrd::GrantRevokeNode* grantRevokeNode; Jrd::CreateCollationNode* createCollationNode; Jrd::CreateDomainNode* createDomainNode; Jrd::AlterDomainNode* alterDomainNode; Jrd::CreateAlterFunctionNode* createAlterFunctionNode; Jrd::CreateAlterProcedureNode* createAlterProcedureNode; Jrd::CreateAlterTriggerNode* createAlterTriggerNode; Jrd::CreateAlterPackageNode* createAlterPackageNode; Jrd::CreateFilterNode::NameNumber* filterNameNumber; Jrd::CreateAlterExceptionNode* createAlterExceptionNode; Jrd::CreateAlterSequenceNode* createAlterSequenceNode; Jrd::CreateShadowNode* createShadowNode; Firebird::Array* packageItems; Jrd::ExceptionArray* exceptionArray; Jrd::CreateAlterPackageNode::Item packageItem; Jrd::CreatePackageBodyNode* createPackageBodyNode; Jrd::BoolSourceClause* boolSourceClause; Jrd::ValueSourceClause* valueSourceClause; Jrd::RelationNode* relationNode; Jrd::RelationNode::AddColumnClause* addColumnClause; Jrd::RelationNode::AddConstraintClause* addConstraintClause; Jrd::RelationNode::RefActionClause* refActionClause; Jrd::RelationNode::IndexConstraintClause* indexConstraintClause; Jrd::RelationNode::IdentityOptions* identityOptions; IdentityType identityType; Jrd::CreateRelationNode* createRelationNode; Jrd::CreateAlterViewNode* createAlterViewNode; Jrd::CreateIndexNode* createIndexNode; Jrd::AlterDatabaseNode* alterDatabaseNode; Jrd::ExecBlockNode* execBlockNode; Jrd::StoreNode* storeNode; Jrd::UpdateOrInsertNode* updInsNode; Jrd::AggNode* aggNode; Jrd::SysFuncCallNode* sysFuncCallNode; Jrd::ValueIfNode* valueIfNode; Jrd::CompoundStmtNode* compoundStmtNode; Jrd::CursorStmtNode* cursorStmtNode; Jrd::DeclareCursorNode* declCursorNode; Jrd::ErrorHandlerNode* errorHandlerNode; Jrd::ExecStatementNode* execStatementNode; Jrd::LocalDeclarationsNode* localDeclarationsNode; Jrd::MergeNode* mergeNode; Jrd::MergeNode::NotMatched* mergeNotMatchedClause; Jrd::MergeNode::Matched* mergeMatchedClause; Jrd::SelectNode* selectNode; Jrd::ForNode* forNode; Jrd::SetTransactionNode* setTransactionNode; Jrd::SetTransactionNode::RestrictionOption* setTransactionRestrictionClause; Jrd::DeclareSubProcNode* declareSubProcNode; Jrd::DeclareSubFuncNode* declareSubFuncNode; Jrd::DsqlStatement* dsqlStatement; Jrd::CreateAlterUserNode* createAlterUserNode; Jrd::MappingNode* mappingNode; Jrd::MappingNode::OP mappingOp; Jrd::SetRoleNode* setRoleNode; Jrd::SetSessionNode* setSessionNode; Jrd::CreateAlterRoleNode* createAlterRoleNode; Jrd::SetDecFloatRoundNode* setDecFloatRoundNode; Jrd::SetDecFloatTrapsNode* setDecFloatTrapsNode; Jrd::SetBindNode* setBindNode; Jrd::SessionResetNode* sessionResetNode; } %include types.y %% // list of possible statements top : statement { if (requireSemicolon) yyerrorIncompleteCmd(YYPOSNARG(1)); parsedStatement = $1; } | statement ';' { parsedStatement = $1; } ; %type statement statement : dml_statement { $$ = FB_NEW_POOL(*statementPool) DsqlDmlStatement(*statementPool, scratch->getAttachment(), $1); } | ddl_statement { $$ = FB_NEW_POOL(*statementPool) DsqlDdlStatement(*statementPool, scratch->getAttachment(), $1); } | tra_statement { $$ = FB_NEW_POOL(*statementPool) DsqlTransactionStatement(*statementPool, scratch->getAttachment(), $1); } | mng_statement { $$ = FB_NEW_POOL(*statementPool) DsqlSessionManagementStatement( *statementPool, scratch->getAttachment(), $1); } ; %type dml_statement dml_statement : delete { $$ = $1; } | insert { $$ = $1; } | merge { $$ = $1; } | exec_procedure { $$ = $1; } | call { $$ = $1; } | exec_block { $$ = $1; } | select { $$ = $1; } | update { $$ = $1; } | update_or_insert { $$ = $1; } ; %type ddl_statement ddl_statement : alter { $$ = $1; } | comment { $$ = $1; } | create { $$ = $1; } | create_or_alter { $$ = $1; } | declare { $$ = $1; } | drop { $$ = $1; } | grant { $$ = $1; } | recreate { $$ = $1; } | revoke { $$ = $1; } | set_statistics { $$ = $1; } ; %type tra_statement tra_statement : set_transaction { $$ = $1; } | savepoint { $$ = $1; } | commit { $$ = $1; } | rollback { $$ = $1; } ; %type mng_statement mng_statement : set_debug_option { $$ = $1; } | set_decfloat_round { $$ = $1; } | set_decfloat_traps { $$ = $1; } | session_statement { $$ = $1; } | set_role { $$ = $1; } | session_reset { $$ = $1; } | set_time_zone { $$ = $1; } | set_bind { $$ = $1; } | set_optimize { $$ = $1; } ; // GRANT statement %type grant grant : GRANT { $$ = newNode(true); } grant0($2) { $$ = $2; } ; %type grant0() grant0($node) : privileges(NOTRIAL(&$node->privileges)) ON table_noise symbol_table_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_relation, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | execute_privilege(NOTRIAL(&$node->privileges)) ON PROCEDURE symbol_procedure_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_procedure, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | execute_privilege(NOTRIAL(&$node->privileges)) ON FUNCTION symbol_UDF_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_udf, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | execute_privilege(NOTRIAL(&$node->privileges)) ON PACKAGE symbol_package_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_package_header, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | usage_privilege(NOTRIAL(&$node->privileges)) ON EXCEPTION symbol_exception_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_exception, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | usage_privilege(NOTRIAL(&$node->privileges)) ON GENERATOR symbol_generator_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_generator, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | usage_privilege(NOTRIAL(&$node->privileges)) ON SEQUENCE symbol_generator_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_generator, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } /*** | usage_privilege(NOTRIAL(&$node->privileges)) ON DOMAIN symbol_domain_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_field, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } | usage_privilege(NOTRIAL(&$node->privileges)) ON CHARACTER SET symbol_character_set_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_charset, *$5); $node->grantAdminOption = $8; $node->grantor = $9; } | usage_privilege(NOTRIAL(&$node->privileges)) ON COLLATION symbol_collation_name TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_collation, *$4); $node->grantAdminOption = $7; $node->grantor = $8; } ***/ | ddl_privileges(NOTRIAL(&$node->privileges)) object TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = $2; $node->grantAdminOption = $5; $node->grantor = $6; $node->isDdl = true; } | db_ddl_privileges(NOTRIAL(&$node->privileges)) DATABASE TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by { $node->object = newNode(obj_database, getSecurityClassName(obj_database)); $node->grantAdminOption = $5; $node->grantor = $6; $node->isDdl = true; } | role_name_list(NOTRIAL($node)) TO role_grantee_list(NOTRIAL(&$node->users)) role_admin_option granted_by { $node->grantAdminOption = $4; $node->grantor = $5; } ; %type object object : TABLE { $$ = newNode(obj_relations, getSecurityClassName(obj_relations)); } | VIEW { $$ = newNode(obj_views, getSecurityClassName(obj_views)); } | PROCEDURE { $$ = newNode(obj_procedures, getSecurityClassName(obj_procedures)); } | FUNCTION { $$ = newNode(obj_functions, getSecurityClassName(obj_functions)); } | PACKAGE { $$ = newNode(obj_packages, getSecurityClassName(obj_packages)); } | GENERATOR { $$ = newNode(obj_generators, getSecurityClassName(obj_generators)); } | SEQUENCE { $$ = newNode(obj_generators, getSecurityClassName(obj_generators)); } | DOMAIN { $$ = newNode(obj_domains, getSecurityClassName(obj_domains)); } | EXCEPTION { $$ = newNode(obj_exceptions, getSecurityClassName(obj_exceptions)); } | ROLE { $$ = newNode(obj_roles, getSecurityClassName(obj_roles)); } | CHARACTER SET { $$ = newNode(obj_charsets, getSecurityClassName(obj_charsets)); } | COLLATION { $$ = newNode(obj_collations, getSecurityClassName(obj_collations)); } | FILTER { $$ = newNode(obj_filters, getSecurityClassName(obj_filters)); } ; table_noise : // nothing | TABLE ; %type privileges() privileges($privilegeArray) : ALL { $privilegeArray->add(PrivilegeClause('A', NULL)); } | ALL PRIVILEGES { $privilegeArray->add(PrivilegeClause('A', NULL)); } | privilege_list($privilegeArray) ; %type privilege_list() privilege_list($privilegeArray) : privilege($privilegeArray) | privilege_list ',' privilege($privilegeArray) ; %type execute_privilege() execute_privilege($privilegeArray) : EXECUTE { $privilegeArray->add(PrivilegeClause('X', NULL)); } ; %type usage_privilege() usage_privilege($privilegeArray) : USAGE { $privilegeArray->add(PrivilegeClause('G', NULL)); } %type privilege() privilege($privilegeArray) : SELECT { $privilegeArray->add(PrivilegeClause('S', NULL)); } | INSERT { $privilegeArray->add(PrivilegeClause('I', NULL)); } | DELETE { $privilegeArray->add(PrivilegeClause('D', NULL)); } | UPDATE column_parens_opt { $privilegeArray->add(PrivilegeClause('U', $2)); } | REFERENCES column_parens_opt { $privilegeArray->add(PrivilegeClause('R', $2)); } ; %type ddl_privileges() ddl_privileges($privilegeArray) : ALL privileges_opt { $privilegeArray->add(PrivilegeClause('C', NULL)); $privilegeArray->add(PrivilegeClause('L', NULL)); $privilegeArray->add(PrivilegeClause('O', NULL)); } | ddl_privilege_list($privilegeArray) ; privileges_opt : // nothing | PRIVILEGES ; %type ddl_privilege_list() ddl_privilege_list($privilegeArray) : ddl_privilege($privilegeArray) | ddl_privilege_list ',' ddl_privilege($privilegeArray) ; %type ddl_privilege() ddl_privilege($privilegeArray) : CREATE { $privilegeArray->add(PrivilegeClause('C', NULL)); } | ALTER ANY { $privilegeArray->add(PrivilegeClause('L', NULL)); } | DROP ANY { $privilegeArray->add(PrivilegeClause('O', NULL)); } ; %type db_ddl_privileges() db_ddl_privileges($privilegeArray) : ALL privileges_opt { $privilegeArray->add(PrivilegeClause('L', NULL)); $privilegeArray->add(PrivilegeClause('O', NULL)); } | db_ddl_privilege_list($privilegeArray) ; %type db_ddl_privilege_list() db_ddl_privilege_list($privilegeArray) : db_ddl_privilege($privilegeArray) | db_ddl_privilege_list ',' db_ddl_privilege($privilegeArray) ; %type db_ddl_privilege() db_ddl_privilege($privilegeArray) : CREATE { $privilegeArray->add(PrivilegeClause('C', NULL)); } | ALTER { $privilegeArray->add(PrivilegeClause('L', NULL)); } | DROP { $privilegeArray->add(PrivilegeClause('O', NULL)); } ; %type grant_option grant_option : /* nothing */ { $$ = false; } | WITH GRANT OPTION { $$ = true; } ; %type role_admin_option role_admin_option : /* nothing */ { $$ = false; } | WITH ADMIN OPTION { $$ = true; } ; %type granted_by granted_by : /* nothing */ { $$ = NULL; } | granted_by_text grantor { $$ = $2; } ; granted_by_text : GRANTED BY | AS ; %type grantor grantor : symbol_user_name | USER symbol_user_name { $$ = $2; } ; // REVOKE statement %type revoke revoke : REVOKE { $$ = newNode(false); } revoke0($2) { $$ = $2; } ; %type revoke0() revoke0($node) : rev_grant_option privileges(NOTRIAL(&$node->privileges)) ON table_noise symbol_table_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_relation, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option execute_privilege(NOTRIAL(&$node->privileges)) ON PROCEDURE symbol_procedure_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_procedure, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option execute_privilege(NOTRIAL(&$node->privileges)) ON FUNCTION symbol_UDF_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_udf, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option execute_privilege(NOTRIAL(&$node->privileges)) ON PACKAGE symbol_package_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_package_header, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON EXCEPTION symbol_exception_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_exception, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON GENERATOR symbol_generator_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_generator, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON SEQUENCE symbol_generator_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_generator, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } /*** | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON DOMAIN symbol_domain_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_field, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON CHARACTER SET symbol_character_set_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_charset, *$6); $node->grantAdminOption = $1; $node->grantor = $9; } | rev_grant_option usage_privilege(NOTRIAL(&$node->privileges)) ON COLLATION symbol_collation_name FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_collation, *$5); $node->grantAdminOption = $1; $node->grantor = $8; } ***/ | rev_grant_option ddl_privileges(NOTRIAL(&$node->privileges)) object FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = $3; $node->grantAdminOption = $1; $node->grantor = $6; $node->isDdl = true; } | rev_grant_option db_ddl_privileges(NOTRIAL(&$node->privileges)) DATABASE FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->object = newNode(obj_database, getSecurityClassName(obj_database)); $node->grantAdminOption = $1; $node->grantor = $6; $node->isDdl = true; } | rev_admin_option role_name_list(NOTRIAL($node)) FROM role_grantee_list(NOTRIAL(&$node->users)) granted_by { $node->grantAdminOption = $1; $node->grantor = $5; } | ALL ON ALL FROM non_role_grantee_list(NOTRIAL(&$node->users)) ; %type rev_grant_option rev_grant_option : /* nothing */ { $$ = false; } | GRANT OPTION FOR { $$ = true; } ; %type rev_admin_option rev_admin_option : /* nothing */ { $$ = false; } | ADMIN OPTION FOR { $$ = true; } ; %type non_role_grantee_list() non_role_grantee_list($granteeArray) : grantee($granteeArray) | user_grantee($granteeArray) | non_role_grantee_list ',' grantee($granteeArray) | non_role_grantee_list ',' user_grantee($granteeArray) ; %type grantee() grantee($granteeArray) : PROCEDURE symbol_procedure_name { $granteeArray->add(GranteeClause(obj_procedure, *$2)); } | FUNCTION symbol_UDF_name { $granteeArray->add(GranteeClause(obj_udf, *$2)); } | PACKAGE symbol_package_name { $granteeArray->add(GranteeClause(obj_package_header, *$2)); } | TRIGGER symbol_trigger_name { $granteeArray->add(GranteeClause(obj_trigger, *$2)); } | VIEW symbol_view_name { $granteeArray->add(GranteeClause(obj_view, *$2)); } | ROLE symbol_role_name { $granteeArray->add(GranteeClause(obj_sql_role, *$2)); } | SYSTEM PRIVILEGE valid_symbol_name { $granteeArray->add(GranteeClause(obj_privilege, *$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. %type user_grantee() user_grantee($granteeArray) : symbol_user_name { $granteeArray->add(GranteeClause(obj_user_or_role, *$1)); } | USER symbol_user_name { $granteeArray->add(GranteeClause(obj_user, *$2)); } | GROUP symbol_user_name { $granteeArray->add(GranteeClause(obj_user_group, *$2)); } ; %type role_name_list() role_name_list($grantRevokeNode) : role_name($grantRevokeNode) | role_name_list ',' role_name($grantRevokeNode) ; %type role_name() role_name($grantRevokeNode) : symbol_role_name { $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$1)); $grantRevokeNode->defaultRoles.add(false); } | DEFAULT symbol_role_name { $grantRevokeNode->roles.add(GranteeClause(obj_sql_role, *$2)); $grantRevokeNode->defaultRoles.add(true); } ; %type role_grantee_list() role_grantee_list($granteeArray) : role_grantee($granteeArray) | role_grantee_list ',' role_grantee($granteeArray) ; %type role_grantee() role_grantee($granteeArray) : symbol_user_name { $granteeArray->add(GranteeClause(obj_user_or_role, *$1)); } | USER symbol_user_name { $granteeArray->add(GranteeClause(obj_user, *$2)); } | ROLE symbol_user_name { $granteeArray->add(GranteeClause(obj_sql_role, *$2)); } ; // DECLARE operations %type declare declare : DECLARE declare_clause { $$ = $2;} ; %type declare_clause declare_clause : FILTER filter_decl_clause { $$ = $2; } | EXTERNAL FUNCTION if_not_exists_opt udf_decl_clause { const auto node = $4; node->createIfNotExistsOnly = $3; $$ = node; } ; %type udf_decl_clause udf_decl_clause : symbol_UDF_name { $$ = newNode(*$1); } arg_desc_list1(NOTRIAL(&$2->parameters)) RETURNS return_value1($2) ENTRY_POINT utf_string MODULE_NAME utf_string { $$ = $2; $$->external = newNode(); $$->external->name = *$7; $$->external->udfModule = *$9; } ; %type udf_data_type udf_data_type : simple_type | BLOB { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(bid); } | CSTRING '(' pos_short_integer ')' charset_clause { $$ = newNode(); $$->dtype = dtype_cstring; $$->charLength = (USHORT) $3; if ($5) $$->charSet = *$5; } ; %type arg_desc_list1() arg_desc_list1($parameters) : | arg_desc_list($parameters) | '(' arg_desc_list($parameters) ')' ; %type arg_desc_list() arg_desc_list($parameters) : arg_desc($parameters) | arg_desc_list ',' arg_desc($parameters) ; %type arg_desc() arg_desc($parameters) : udf_data_type param_mechanism { $parameters->add(newNode($1)); $parameters->back()->udfMechanism = $2; } ; %type param_mechanism param_mechanism : /* nothing */ { $$ = std::nullopt; } // Beware: This means FUN_reference or FUN_blob_struct. | BY DESCRIPTOR { $$ = FUN_descriptor; } | BY SCALAR_ARRAY { $$ = FUN_scalar_array; } | NULL { $$ = FUN_ref_with_null; } ; %type return_value1() return_value1($function) : return_value($function) | '(' return_value($function) ')' ; %type return_value() return_value($function) : udf_data_type return_mechanism { $function->returnType = newNode($1); $function->returnType->udfMechanism = $2; } | PARAMETER pos_short_integer { $function->udfReturnPos = $2; } ; %type return_mechanism return_mechanism : /* nothing */ { $$ = FUN_reference; } | BY VALUE { $$ = FUN_value; } | BY DESCRIPTOR { $$ = FUN_descriptor; } // FUN_refrence with FREE_IT is -ve | FREE_IT { $$ = -1 * FUN_reference; } | BY DESCRIPTOR FREE_IT { $$ = -1 * FUN_descriptor; } ; %type filter_decl_clause filter_decl_clause : symbol_filter_name INPUT_TYPE blob_filter_subtype OUTPUT_TYPE blob_filter_subtype ENTRY_POINT utf_string MODULE_NAME utf_string { CreateFilterNode* node = newNode(*$1); node->inputFilter = $3; node->outputFilter = $5; node->entryPoint = *$7; node->moduleName = *$9; $$ = node; } ; %type blob_filter_subtype blob_filter_subtype : symbol_blob_subtype_name { $$ = newNode(*$1); } | signed_short_integer { $$ = newNode($1); } ; // CREATE metadata operations %type create create : CREATE create_clause { $$ = $2; } ; %type create_clause create_clause : EXCEPTION if_not_exists_opt exception_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | unique_opt order_direction INDEX if_not_exists_opt symbol_index_name index_active_opt ON simple_table_name { const auto node = newNode(*$5); node->active = $6; node->unique = $1; node->descending = $2; node->createIfNotExistsOnly = $4; node->relation = $8; $$ = node; } index_definition(static_cast($9)) { $$ = $9; } | FUNCTION if_not_exists_opt function_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | PROCEDURE if_not_exists_opt procedure_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | TABLE if_not_exists_opt table_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | GLOBAL TEMPORARY TABLE if_not_exists_opt gtt_table_clause { const auto node = $5; node->createIfNotExistsOnly = $4; $$ = node; } | TRIGGER if_not_exists_opt trigger_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | VIEW if_not_exists_opt view_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | GENERATOR if_not_exists_opt generator_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | SEQUENCE if_not_exists_opt generator_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | DATABASE db_clause { $$ = $2; } | DOMAIN if_not_exists_opt domain_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | SHADOW if_not_exists_opt shadow_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | ROLE if_not_exists_opt role_clause { const auto node = $3; node->createIfNotExistsOnly = $2; node->createFlag = true; $$ = node; } | COLLATION if_not_exists_opt collation_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | USER if_not_exists_opt create_user_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | PACKAGE if_not_exists_opt package_clause { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | PACKAGE BODY if_not_exists_opt package_body_clause { const auto node = $4; node->createIfNotExistsOnly = $3; $$ = node; } | MAPPING if_not_exists_opt create_map_clause(false) { const auto node = $3; node->createIfNotExistsOnly = $2; $$ = node; } | GLOBAL MAPPING if_not_exists_opt create_map_clause(true) { const auto node = $4; node->createIfNotExistsOnly = $3; $$ = node; } ; %type recreate recreate : RECREATE recreate_clause { $$ = $2; } ; %type recreate_clause recreate_clause : PROCEDURE procedure_clause { $$ = newNode($2); } | FUNCTION function_clause { $$ = newNode($2); } | TABLE table_clause { $$ = newNode($2); } | GLOBAL TEMPORARY TABLE gtt_table_clause { $$ = newNode($4); } | VIEW view_clause { $$ = newNode($2); } | TRIGGER trigger_clause { $$ = newNode($2); } | PACKAGE package_clause { $$ = newNode($2); } | PACKAGE BODY package_body_clause { $$ = newNode($3); } | EXCEPTION exception_clause { $$ = newNode($2); } | GENERATOR generator_clause { $$ = newNode($2); } | SEQUENCE generator_clause { $$ = newNode($2); } | USER create_user_clause { $$ = newNode($2); } ; %type create_or_alter create_or_alter : CREATE OR ALTER replace_clause { $$ = $4; } ; %type replace_clause replace_clause : PROCEDURE replace_procedure_clause { $$ = $2; } | FUNCTION replace_function_clause { $$ = $2; } | TRIGGER replace_trigger_clause { $$ = $2; } | PACKAGE replace_package_clause { $$ = $2; } | PACKAGE BODY replace_package_body_clause { $$ = $3; } | VIEW replace_view_clause { $$ = $2; } | EXCEPTION replace_exception_clause { $$ = $2; } | GENERATOR replace_sequence_clause { $$ = $2; } | SEQUENCE replace_sequence_clause { $$ = $2; } | USER replace_user_clause { $$ = $2; } | MAPPING replace_map_clause(false) { $$ = $2; } | GLOBAL MAPPING replace_map_clause(true) { $$ = $3; } ; // CREATE EXCEPTION // ASF: The charset from sql_string is discarded because the database column uses NONE. %type exception_clause exception_clause : symbol_exception_name sql_string { $$ = newNode(*$1, $2->getString()); } ; %type replace_exception_clause replace_exception_clause : symbol_exception_name sql_string { CreateAlterExceptionNode* node = newNode(*$1, $2->getString()); node->alter = true; $$ = node; } ; %type alter_exception_clause alter_exception_clause : symbol_exception_name sql_string { CreateAlterExceptionNode* node = newNode(*$1, $2->getString()); node->create = false; node->alter = true; $$ = node; } ; // CREATE INDEX %type index_active_opt index_active_opt : /* nothing */ { $$ = true; } | index_active { $$ = $1; } ; %type unique_opt unique_opt : /* nothing */ { $$ = false; } | UNIQUE { $$ = true; } ; %type index_definition() index_definition($createIndexNode) : index_column_expr($createIndexNode) index_condition_opt { $createIndexNode->partial = $2; } ; %type index_column_expr() index_column_expr($createIndexNode) : column_list { $createIndexNode->columns = $1; } | column_parens { $createIndexNode->columns = $1; } | computed_by '(' value ')' { $createIndexNode->computed = newNode(); $createIndexNode->computed->value = $3; $createIndexNode->computed->source = makeParseStr(YYPOSNARG(2), YYPOSNARG(4)); } ; %type index_condition_opt index_condition_opt : /* nothing */ { $$ = nullptr; } | WHERE search_condition { auto clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } ; // CREATE SHADOW %type shadow_clause shadow_clause : pos_short_integer manual_auto conditional utf_string { $$ = newNode($1, $2, $3, *$4); } ; %type manual_auto manual_auto : /* nothing */ { $$ = false; } | MANUAL { $$ = true; } | AUTO { $$ = false; } ; %type conditional conditional : /* nothing */ { $$ = false; } | CONDITIONAL { $$ = true; } ; // CREATE DOMAIN %type domain_clause domain_clause : symbol_column_name as_opt data_type domain_default_opt { $3->fld_name = *$1; $$ = newNode( newNode($3, $4)); } domain_constraints_opt($5) collate_clause { $$ = $5; setCollate($3, $7); } ; %type domain_constraints_opt() domain_constraints_opt($createDomainNode) : // nothing | domain_constraints($createDomainNode) ; %type domain_constraints() domain_constraints($createDomainNode) : domain_constraint($createDomainNode) | domain_constraints domain_constraint($createDomainNode) ; %type domain_constraint() domain_constraint($createDomainNode) : null_constraint { setClause($createDomainNode->notNull, "NOT NULL"); } | check_constraint { setClause($createDomainNode->check, "DOMAIN CHECK CONSTRAINT", $1); } ; as_opt : // nothing | AS ; %type domain_default domain_default : DEFAULT default_value { ValueSourceClause* clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } ; %type domain_default_opt domain_default_opt : /* nothing */ { $$ = NULL; } | domain_default ; null_constraint : NOT NULL ; %type check_constraint check_constraint : CHECK '(' search_condition ')' { BoolSourceClause* clause = newNode(); clause->value = $3; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(4)); $$ = clause; } ; // CREATE SEQUENCE/GENERATOR %type generator_clause generator_clause : symbol_generator_name { $$ = newNode(*$1); } create_sequence_options($2) { $$ = $2; } ; %type create_sequence_options() create_sequence_options($seqNode) : /* nothing */ | create_seq_option($seqNode) create_sequence_options($seqNode) ; %type create_seq_option() create_seq_option($seqNode) : start_with_opt($seqNode) | step_option($seqNode) ; %type start_with_opt() start_with_opt($seqNode) : START WITH sequence_value { setClause($seqNode->value, "START WITH", $3); setClause($seqNode->restartSpecified, "RESTART", true); } ; %type step_option() step_option($seqNode) : INCREMENT by_noise signed_long_integer { setClause($seqNode->step, "INCREMENT BY", $3); } ; by_noise : // nothing | BY %type replace_sequence_clause replace_sequence_clause : symbol_generator_name { CreateAlterSequenceNode* node = newNode(*$1); node->alter = true; $$ = node; } replace_sequence_options($2) { // Remove this to implement CORE-5137 if (!$2->restartSpecified && !$2->step.has_value()) yyerrorIncompleteCmd(YYPOSNARG(3)); $$ = $2; } ; %type replace_sequence_options() replace_sequence_options($seqNode) : /* nothing */ | replace_seq_option($seqNode) replace_sequence_options($seqNode) ; %type replace_seq_option() replace_seq_option($seqNode) : RESTART { setClause($seqNode->restartSpecified, "RESTART", true); } | start_with_opt($seqNode) | step_option($seqNode) ; %type alter_sequence_clause alter_sequence_clause : symbol_generator_name { CreateAlterSequenceNode* node = newNode(*$1); node->create = false; node->alter = true; $$ = node; } alter_sequence_options($2) { if (!$2->restartSpecified && !$2->value.has_value() && !$2->step.has_value()) yyerrorIncompleteCmd(YYPOSNARG(3)); $$ = $2; } %type alter_sequence_options() alter_sequence_options($seqNode) : /* nothing */ | alter_seq_option($seqNode) alter_sequence_options($seqNode) ; %type alter_seq_option() alter_seq_option($seqNode) : restart_option($seqNode) | step_option($seqNode) ; %type restart_option() restart_option($seqNode) : RESTART with_opt { setClause($seqNode->restartSpecified, "RESTART", true); setClause($seqNode->value, "RESTART WITH", $2); } %type with_opt with_opt : /* Nothign */ { $$ = std::nullopt; } | WITH sequence_value { $$ = $2; } ; %type set_generator_clause set_generator_clause : SET GENERATOR symbol_generator_name TO sequence_value { CreateAlterSequenceNode* node = newNode(*$3); node->create = false; node->alter = true; node->legacy = true; node->restartSpecified = true; node->value = $5; $$ = node; } ; %type sequence_value sequence_value : signed_long_integer { $$ = $1; } | NUMBER64BIT { SINT64 signedNumber = (SINT64) $1.number; if (!$1.hex && $1.number > MAX_SINT64) { ERRD_post( Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); } $$ = signedNumber; } | '-' NUMBER64BIT { SINT64 signedNumber = (SINT64) $2.number; if ($2.hex && signedNumber == MIN_SINT64) ERRD_post(Arg::Gds(isc_exception_integer_overflow)); $$ = -signedNumber; } | '-' LIMIT64_INT { $$ = MIN_SINT64; } ; // CREATE / ALTER ROLE %type role_clause role_clause : symbol_role_name { $$ = newNode(*$1); } opt_system_privileges($2) { $$ = $2; } ; %type opt_system_privileges() opt_system_privileges($createAlterRole) : // nothing | set_system_privileges($createAlterRole) | drop_system_privileges($createAlterRole) ; %type set_system_privileges() set_system_privileges($createAlterRole) : SET SYSTEM PRIVILEGES TO system_privileges_list($createAlterRole) %type drop_system_privileges() drop_system_privileges($createAlterRole) : DROP SYSTEM PRIVILEGES { $createAlterRole->sysPrivDrop = true; } %type system_privileges_list() system_privileges_list($createAlterRole) : system_privilege($createAlterRole) | system_privileges_list ',' system_privilege($createAlterRole) ; %type system_privilege() system_privilege($createAlterRole) : valid_symbol_name { $createAlterRole->addPrivilege($1); } ; // CREATE COLLATION %type collation_clause collation_clause : symbol_collation_name FOR symbol_character_set_name { $$ = newNode(*$1, *$3); } collation_sequence_definition($4) collation_attribute_list_opt($4) collation_specific_attribute_opt($4) { $$ = $4; } ; %type collation_sequence_definition() collation_sequence_definition($createCollation) : // nothing | FROM symbol_collation_name { $createCollation->fromName = *$2; } | FROM EXTERNAL '(' utf_string ')' { $createCollation->fromExternal = *$4; } ; %type collation_attribute_list_opt() collation_attribute_list_opt($createCollation) : // nothing | collation_attribute_list($createCollation) ; %type collation_attribute_list() collation_attribute_list($createCollation) : collation_attribute($createCollation) | collation_attribute_list collation_attribute($createCollation) ; %type collation_attribute() collation_attribute($createCollation) : collation_pad_attribute($createCollation) | collation_case_attribute($createCollation) | collation_accent_attribute($createCollation) ; %type collation_pad_attribute() collation_pad_attribute($createCollation) : NO PAD { $createCollation->unsetAttribute(TEXTTYPE_ATTR_PAD_SPACE); } | PAD SPACE { $createCollation->setAttribute(TEXTTYPE_ATTR_PAD_SPACE); } ; %type collation_case_attribute() collation_case_attribute($createCollation) : CASE SENSITIVE { $createCollation->unsetAttribute(TEXTTYPE_ATTR_CASE_INSENSITIVE); } | CASE INSENSITIVE { $createCollation->setAttribute(TEXTTYPE_ATTR_CASE_INSENSITIVE); } ; %type collation_accent_attribute() collation_accent_attribute($createCollation) : ACCENT SENSITIVE { $createCollation->unsetAttribute(TEXTTYPE_ATTR_ACCENT_INSENSITIVE); } | ACCENT INSENSITIVE { $createCollation->setAttribute(TEXTTYPE_ATTR_ACCENT_INSENSITIVE); } ; %type collation_specific_attribute_opt() collation_specific_attribute_opt($createCollation) : // nothing | utf_string { const string& s = *$1; $createCollation->specificAttributes.clear(); $createCollation->specificAttributes.add((const UCHAR*) s.begin(), s.length()); } ; // ALTER CHARACTER SET %type alter_charset_clause alter_charset_clause : symbol_character_set_name SET DEFAULT COLLATION symbol_collation_name { $$ = newNode(*$1, *$5); } ; // %type alter_eds_conn_pool_clause alter_eds_conn_pool_clause : SET SIZE unsigned_short_integer { $$ = newNode(AlterEDSPoolSetNode::POOL_SIZE, $3); } | SET LIFETIME unsigned_short_integer eds_pool_lifetime_mult { $$ = newNode(AlterEDSPoolSetNode::POOL_LIFETIME, $3 * $4); } | CLEAR sql_string { $$ = newNode(AlterEDSPoolClearNode::POOL_DB, $2->getString()); } | CLEAR ALL { $$ = newNode(AlterEDSPoolClearNode::POOL_ALL); } | CLEAR OLDEST { $$ = newNode(AlterEDSPoolClearNode::POOL_OLDEST); } ; %type eds_pool_lifetime_mult eds_pool_lifetime_mult : HOUR { $$ = 3600; } | MINUTE { $$ = 60; } | SECOND { $$ = 1; } ; // CREATE DATABASE // ASF: CREATE DATABASE command is divided in three pieces: name, initial options and // remote options. // Initial options are basic properties of a database and should be handled here and // in preparse.cpp. // Remote options always come after initial options, so they don't need to be parsed // in preparse.cpp. They are interpreted only in the server, using this grammar. // Although LENGTH is defined as an initial option, it's also used in the server. %type db_clause db_clause : db_name { $$ = newNode(); $$->create = true; } db_initial_desc1($2) db_rem_desc1($2) { $$ = $2; } ; equals : // nothing | '=' ; %type db_name db_name : utf_string ; %type db_initial_desc1() db_initial_desc1($alterDatabaseNode) : // nothing | db_initial_desc($alterDatabaseNode) ; %type db_initial_desc() db_initial_desc($alterDatabaseNode) : db_initial_option($alterDatabaseNode) | db_initial_desc db_initial_option($alterDatabaseNode) ; // With the exception of LENGTH, all clauses here are handled only at the client. %type db_initial_option() db_initial_option($alterDatabaseNode) : PAGE_SIZE equals NUMBER32BIT | USER symbol_user_name | USER utf_string | OWNER symbol_user_name | OWNER utf_string | ROLE valid_symbol_name | ROLE utf_string | PASSWORD utf_string | SET NAMES utf_string ; %type db_rem_desc1() db_rem_desc1($alterDatabaseNode) : // nothing | db_rem_desc($alterDatabaseNode) ; %type db_rem_desc() db_rem_desc($alterDatabaseNode) : db_rem_option($alterDatabaseNode) | db_rem_desc db_rem_option($alterDatabaseNode) ; %type db_rem_option() db_rem_option($alterDatabaseNode) : DEFAULT CHARACTER SET symbol_character_set_name { $alterDatabaseNode->setDefaultCharSet = *$4; } | DEFAULT CHARACTER SET symbol_character_set_name COLLATION symbol_collation_name { $alterDatabaseNode->setDefaultCharSet = *$4; $alterDatabaseNode->setDefaultCollation = *$6; } | DIFFERENCE FILE utf_string { $alterDatabaseNode->differenceFile = *$3; } ; // CREATE TABLE %type table_clause table_clause : simple_table_name external_file { $$ = newNode($1, $2); } '(' table_elements($3) ')' table_attributes($3) { $$ = $3; } ; %type table_attributes() table_attributes($relationNode) : /* nothing */ | table_attribute($relationNode) table_attributes($relationNode) ; %type table_attribute() table_attribute($relationNode) : sql_security_clause { setClause($relationNode->ssDefiner, "SQL SECURITY", $1); } | publication_state { setClause($relationNode->replicationState, "PUBLICATION", $1); } ; %type sql_security_clause sql_security_clause : SQL SECURITY DEFINER { $$ = true; } | SQL SECURITY INVOKER { $$ = false; } ; %type sql_security_clause_opt sql_security_clause_opt : /* nothing */ { $$ = TriState(); } | sql_security_clause { $$ = $1; } ; %type publication_state publication_state : ENABLE PUBLICATION { $$ = true; } | DISABLE PUBLICATION { $$ = false; } ; %type gtt_table_clause gtt_table_clause : simple_table_name { $$ = newNode($1); $$->relationType = std::nullopt; } '(' table_elements($2) ')' gtt_ops($2) { $$ = $2; if (!$$->relationType.has_value()) $$->relationType = rel_global_temp_delete; } ; %type gtt_ops() gtt_ops($createRelationNode) : gtt_op($createRelationNode) | gtt_ops ',' gtt_op($createRelationNode) ; %type gtt_op() gtt_op($createRelationNode) : // nothing by default. Will be set "on commit delete rows" in dsqlPass | sql_security_clause_opt { setClause($createRelationNode->ssDefiner, "SQL SECURITY", $1); } | ON COMMIT DELETE ROWS { setClause($createRelationNode->relationType, "ON COMMIT DELETE ROWS", rel_global_temp_delete); } | ON COMMIT PRESERVE ROWS { setClause($createRelationNode->relationType, "ON COMMIT PRESERVE ROWS", rel_global_temp_preserve); } ; %type external_file external_file : /* nothing */ { $$ = NULL; } | EXTERNAL FILE utf_string { $$ = $3; } | EXTERNAL utf_string { $$ = $2; } ; %type table_elements() table_elements($createRelationNode) : table_element($createRelationNode) | table_elements ',' table_element($createRelationNode) ; %type table_element() table_element($createRelationNode) : column_def($createRelationNode) | table_constraint_definition($createRelationNode) ; // column definition %type column_def() column_def($relationNode) : symbol_column_name data_type_or_domain domain_default_opt { RelationNode::AddColumnClause* clause = $$ = newNode(); clause->field = $2; clause->field->fld_name = *$1; clause->defaultValue = $3; $relationNode->clauses.add(clause); } column_constraint_clause(NOTRIAL($4)) collate_clause { setCollate($2, $6); $$ = $4; } | symbol_column_name data_type_or_domain identity_clause { RelationNode::AddColumnClause* clause = $$ = newNode(); clause->field = $2; clause->field->fld_name = *$1; clause->identityOptions = $3; $relationNode->clauses.add(clause); } column_constraint_clause(NOTRIAL($4)) collate_clause { setCollate($2, $6); $$ = $4; } | symbol_column_name non_array_type def_computed { RelationNode::AddColumnClause* clause = newNode(); clause->field = $2; clause->field->fld_name = *$1; clause->computed = $3; $relationNode->clauses.add(clause); clause->field->flags |= FLD_computed; $$ = clause; } | symbol_column_name def_computed { RelationNode::AddColumnClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$1; clause->computed = $2; $relationNode->clauses.add(clause); clause->field->flags |= FLD_computed; $$ = clause; } ; %type identity_clause identity_clause : GENERATED identity_clause_type AS IDENTITY { $$ = newNode($2); } identity_clause_options_opt($5) { $$ = $5; } ; %type identity_clause_type identity_clause_type : BY DEFAULT { $$ = IDENT_TYPE_BY_DEFAULT; } | ALWAYS { $$ = IDENT_TYPE_ALWAYS; } ; %type identity_clause_options_opt() identity_clause_options_opt($identityOptions) : // nothing | '(' identity_clause_options($identityOptions) ')' ; %type identity_clause_options() identity_clause_options($identityOptions) : identity_clause_options identity_clause_option($identityOptions) | identity_clause_option($identityOptions) ; %type identity_clause_option() identity_clause_option($identityOptions) : START WITH sequence_value { setClause($identityOptions->startValue, "START WITH", $3); } | INCREMENT by_noise signed_long_integer { setClause($identityOptions->increment, "INCREMENT BY", $3); } ; // value does allow parens around it, but there is a problem getting the source text. %type def_computed def_computed : computed_clause '(' value ')' { ValueSourceClause* clause = newNode(); clause->value = $3; clause->source = makeParseStr(YYPOSNARG(2), YYPOSNARG(4)); $$ = clause; } ; computed_clause : computed_by | generated_always_clause ; generated_always_clause : GENERATED ALWAYS AS ; computed_by : COMPUTED BY | COMPUTED ; %type data_type_or_domain data_type_or_domain : data_type | symbol_column_name { $$ = newNode(); $$->typeOfName = *$1; } ; %type collate_clause collate_clause : { $$ = NULL; } | COLLATE symbol_collation_name { $$ = $2; } ; %type data_type_descriptor data_type_descriptor : data_type | TYPE OF symbol_column_name { $$ = newNode(); $$->typeOfName = *$3; } | TYPE OF COLUMN symbol_column_name '.' symbol_column_name { $$ = newNode(); $$->typeOfTable = *$4; $$->typeOfName = *$6; } | symbol_column_name { $$ = newNode(); $$->typeOfName = *$1; $$->fullDomain = true; } ; %type default_value default_value : constant { $$ = $1; } | current_user { $$ = $1; } | current_role { $$ = $1; } | internal_info { $$ = $1; } | null_value { $$ = $1; } | datetime_value_expression { $$ = $1; } ; %type column_constraint_clause() column_constraint_clause($addColumnClause) : // nothing | column_constraint_list($addColumnClause) ; %type column_constraint_list() column_constraint_list($addColumnClause) : column_constraint_def($addColumnClause) | column_constraint_list column_constraint_def($addColumnClause) ; %type column_constraint_def() column_constraint_def($addColumnClause) : constraint_name_opt column_constraint($addColumnClause) { if ($1) $addColumnClause->constraints.back().name = *$1; } ; %type column_constraint() column_constraint($addColumnClause) : null_constraint { setClause($addColumnClause->notNullSpecified, "NOT NULL"); RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_NOT_NULL; } | check_constraint { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_CHECK; constraint.check = $1; } | REFERENCES symbol_table_name column_parens_opt referential_trigger_action constraint_index_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; constraint.columns.add($addColumnClause->field->fld_name); constraint.refRelation = *$2; constraint.refAction = $4; const ValueListNode* refColumns = $3; if (refColumns) { const NestConst* ptr = refColumns->items.begin(); for (const NestConst* const end = refColumns->items.end(); ptr != end; ++ptr) constraint.refColumns.add(nodeAs(*ptr)->dsqlName); } constraint.index = $5; } | UNIQUE constraint_index_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; constraint.index = $2; } | PRIMARY KEY constraint_index_opt { RelationNode::AddConstraintClause& constraint = $addColumnClause->constraints.add(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; constraint.index = $3; } ; // table constraints %type table_constraint_definition() table_constraint_definition($relationNode) : constraint_name_opt table_constraint($relationNode) { if ($1) $2->name = *$1; $$ = $2; } ; %type constraint_name_opt constraint_name_opt : /* nothing */ { $$ = NULL; } | CONSTRAINT symbol_constraint_name { $$ = $2; } ; %type table_constraint() table_constraint($relationNode) : UNIQUE column_parens constraint_index_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_UNIQUE; const ValueListNode* columns = $2; const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.index = $3; $relationNode->clauses.add(&constraint); $$ = &constraint; } | PRIMARY KEY column_parens constraint_index_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_PK; const ValueListNode* columns = $3; const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.index = $4; $relationNode->clauses.add(&constraint); $$ = &constraint; } | FOREIGN KEY column_parens REFERENCES symbol_table_name column_parens_opt referential_trigger_action constraint_index_opt { RelationNode::AddConstraintClause& constraint = *newNode(); constraint.constraintType = RelationNode::AddConstraintClause::CTYPE_FK; const ValueListNode* columns = $3; const NestConst* ptr = columns->items.begin(); for (const NestConst* const end = columns->items.end(); ptr != end; ++ptr) constraint.columns.add(nodeAs(*ptr)->dsqlName); constraint.refRelation = *$5; constraint.refAction = $7; const ValueListNode* refColumns = $6; if (refColumns) { const NestConst* ptr = refColumns->items.begin(); for (const NestConst* const end = refColumns->items.end(); ptr != end; ++ptr) constraint.refColumns.add(nodeAs(*ptr)->dsqlName); } constraint.index = $8; $relationNode->clauses.add(&constraint); $$ = &constraint; } | check_constraint { RelationNode::AddConstraintClause* constraint = newNode(); constraint->constraintType = RelationNode::AddConstraintClause::CTYPE_CHECK; constraint->check = $1; $relationNode->clauses.add(constraint); $$ = constraint; } ; %type constraint_index_opt constraint_index_opt : // nothing { $$ = newNode(); } | USING order_direction INDEX symbol_index_name { RelationNode::IndexConstraintClause* clause = $$ = newNode(); clause->descending = $2; clause->name = *$4; } /*** | NO INDEX { $$ = NULL; } ***/ ; %type referential_trigger_action referential_trigger_action : /* nothing */ { $$ = NULL; } | update_rule { $$ = newNode($1, 0); } | delete_rule { $$ = newNode(0, $1); } | delete_rule update_rule { $$ = newNode($2, $1); } | update_rule delete_rule { $$ = newNode($1, $2); } ; %type update_rule update_rule : ON UPDATE referential_action { $$ = $3;} ; %type delete_rule delete_rule : ON DELETE referential_action { $$ = $3;} ; %type referential_action referential_action : CASCADE { $$ = RelationNode::RefActionClause::ACTION_CASCADE; } | SET DEFAULT { $$ = RelationNode::RefActionClause::ACTION_SET_DEFAULT; } | SET NULL { $$ = RelationNode::RefActionClause::ACTION_SET_NULL; } | NO ACTION { $$ = RelationNode::RefActionClause::ACTION_NONE; } ; // PROCEDURE %type procedure_clause procedure_clause : psql_procedure_clause | external_procedure_clause ; %type psql_procedure_clause psql_procedure_clause : procedure_clause_start optional_sql_security_full_alter_clause AS local_declarations_opt full_proc_block { $$ = $1; $$->ssDefiner = $2; $$->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5)); $$->localDeclList = $4; $$->body = $5; } ; %type external_procedure_clause external_procedure_clause : procedure_clause_start external_clause external_body_clause_opt { $$ = $1; $$->external = $2; if ($3) $$->source = *$3; } ; %type procedure_clause_start procedure_clause_start : symbol_procedure_name { $$ = newNode(*$1); } input_parameters(NOTRIAL(&$2->parameters)) output_parameters(NOTRIAL(&$2->returns)) { $$ = $2; } ; %type partial_alter_procedure_clause partial_alter_procedure_clause : symbol_procedure_name { $$ = newNode(*$1); } optional_sql_security_partial_alter_clause { $$ = $2; $$->ssDefiner = $3; } ; %type alter_procedure_clause alter_procedure_clause : procedure_clause { $$ = $1; $$->alter = true; $$->create = false; } | partial_alter_procedure_clause { $$ = $1; $$->alter = true; $$->create = false; } ; %type replace_procedure_clause replace_procedure_clause : procedure_clause { $$ = $1; $$->alter = true; } ; %type input_parameters() input_parameters($parameters) : | '(' ')' | '(' input_proc_parameters($parameters) ')' ; %type output_parameters() output_parameters($parameters) : | RETURNS '(' output_proc_parameters($parameters) ')' ; %type input_proc_parameters() input_proc_parameters($parameters) : input_proc_parameter($parameters) | input_proc_parameters ',' input_proc_parameter($parameters) ; %type input_proc_parameter() input_proc_parameter($parameters) : column_domain_or_non_array_type collate_clause default_par_opt { setCollate($1, $2); $parameters->add(newNode($1, $3)); } ; %type output_proc_parameters() output_proc_parameters($parameters) : output_proc_parameter | output_proc_parameters ',' output_proc_parameter($parameters) ; %type output_proc_parameter() output_proc_parameter($parameters) : column_domain_or_non_array_type collate_clause { setCollate($1, $2); $parameters->add(newNode($1)); } ; %type column_domain_or_non_array_type column_domain_or_non_array_type : symbol_column_name domain_or_non_array_type { $$ = $2; $$->fld_name = *$1; } ; %type default_par_opt default_par_opt : // nothing { $$ = NULL; } | DEFAULT default_value { ValueSourceClause* clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } | '=' default_value { ValueSourceClause* clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } ; // FUNCTION %type function_clause function_clause : psql_function_clause | external_function_clause; %type psql_function_clause psql_function_clause : function_clause_start optional_sql_security_full_alter_clause AS local_declarations_opt full_proc_block { $$ = $1; $$->ssDefiner = $2; $$->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5)); $$->localDeclList = $4; $$->body = $5; } ; %type external_function_clause external_function_clause : function_clause_start external_clause external_body_clause_opt { $$ = $1; $$->external = $2; if ($3) $$->source = *$3; } ; %type function_clause_start function_clause_start : symbol_UDF_name { $$ = newNode(*$1); } input_parameters(NOTRIAL(&$2->parameters)) RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $2; $$->returnType = newNode($5); setCollate($5, $6); $$->deterministic = $7; } ; %type partial_alter_function_clause partial_alter_function_clause : symbol_UDF_name { $$ = newNode(*$1); } alter_individual_ops($2) { $$ = $2; } ; %type alter_individual_ops() alter_individual_ops($createAlterFunctionNode) : alter_individual_op($createAlterFunctionNode) | alter_individual_ops alter_individual_op($createAlterFunctionNode) ; %type alter_individual_op() alter_individual_op($createAlterFunctionNode) : deterministic_clause { setClause($createAlterFunctionNode->deterministic, "DETERMINISTIC", $1); } | optional_sql_security_partial_alter_clause { setClause($createAlterFunctionNode->ssDefiner, "SQL SECURITY", $1); } ; %type deterministic_clause deterministic_clause : NOT DETERMINISTIC { $$ = false; } | DETERMINISTIC { $$ = true; } ; %type deterministic_clause_opt deterministic_clause_opt : { $$ = false; } | deterministic_clause { $$ = $1; } ; %type external_clause external_clause : EXTERNAL NAME utf_string ENGINE valid_symbol_name { $$ = newNode(); $$->name = *$3; $$->engine = *$5; } | EXTERNAL ENGINE valid_symbol_name { $$ = newNode(); $$->engine = *$3; } ; %type external_body_clause_opt external_body_clause_opt : /* nothing */ { $$ = NULL; } | AS utf_string { $$ = $2; } ; %type alter_function_clause alter_function_clause : function_clause { $$ = $1; $$->alter = true; $$->create = false; } | partial_alter_function_clause { $$ = $1; $$->alter = true; $$->create = false; } ; %type replace_function_clause replace_function_clause : function_clause { $$ = $1; $$->alter = true; } ; // PACKAGE %type package_clause package_clause : symbol_package_name optional_sql_security_full_alter_clause AS BEGIN package_items_opt END { CreateAlterPackageNode* node = newNode(*$1); node->ssDefiner = $2; node->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(6)); node->items = $5; $$ = node; } ; %type partial_alter_package_clause partial_alter_package_clause : symbol_package_name optional_sql_security_partial_alter_clause { CreateAlterPackageNode* node = newNode(*$1); node->ssDefiner = $2; $$ = node; } ; %type package_items_opt package_items_opt : package_items | { $$ = newNode >(); } ; %type package_items package_items : package_item { $$ = newNode >(); $$->add($1); } | package_items package_item { $$ = $1; $$->add($2); } ; %type package_item package_item : FUNCTION function_clause_start ';' { $$ = CreateAlterPackageNode::Item::create($2); } | PROCEDURE procedure_clause_start ';' { $$ = CreateAlterPackageNode::Item::create($2); } ; %type alter_package_clause alter_package_clause : package_clause { $$ = $1; $$->alter = true; $$->create = false; } | partial_alter_package_clause { $$ = $1; $$->alter = true; $$->create = false; } ; %type replace_package_clause replace_package_clause : package_clause { $$ = $1; $$->alter = true; } ; // PACKAGE BODY %type package_body_clause package_body_clause : symbol_package_name AS BEGIN package_items package_body_items_opt END { CreatePackageBodyNode* node = newNode(*$1); node->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(6)); node->declaredItems = $4; node->items = $5; $$ = node; } | symbol_package_name AS BEGIN package_body_items_opt END { CreatePackageBodyNode* node = newNode(*$1); node->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(5)); node->items = $4; $$ = node; } ; %type package_body_items_opt package_body_items_opt : /* nothing */ { $$ = newNode >(); } | package_body_items ; %type package_body_items package_body_items : package_body_item { $$ = newNode >(); $$->add($1); } | package_body_items package_body_item { $$ = $1; $$->add($2); } ; %type package_body_item package_body_item : FUNCTION psql_function_clause { $$ = CreateAlterPackageNode::Item::create($2); } | FUNCTION external_function_clause ';' { $$ = CreateAlterPackageNode::Item::create($2); } | PROCEDURE psql_procedure_clause { $$ = CreateAlterPackageNode::Item::create($2); } | PROCEDURE external_procedure_clause ';' { $$ = CreateAlterPackageNode::Item::create($2); } ; %type replace_package_body_clause replace_package_body_clause : package_body_clause { $$ = newNode($1); } ; %type local_declarations_opt local_declarations_opt : local_forward_declarations_opt local_nonforward_declarations_opt { LocalDeclarationsNode* forward = $1; LocalDeclarationsNode* nonForward = $2; if (!forward) $$ = nonForward; else { if (nonForward) forward->statements.add(nonForward->statements.begin(), nonForward->statements.getCount()); $$ = forward; } } ; %type local_forward_declarations_opt local_forward_declarations_opt : /* nothing */ { $$ = nullptr; } | local_forward_declarations ; %type local_forward_declarations local_forward_declarations : local_forward_declaration { $$ = newNode(); $$->statements.add($1); } | local_forward_declarations local_forward_declaration { $1->statements.add($2); $$ = $1; } ; %type local_forward_declaration local_forward_declaration : local_declaration_subproc_start ';' { $$ = $1; } | local_declaration_subfunc_start ';' { $$ = $1; } ; %type local_nonforward_declarations_opt local_nonforward_declarations_opt : /* nothing */ { $$ = nullptr; } | local_nonforward_declarations ; %type local_nonforward_declarations local_nonforward_declarations : local_nonforward_declaration { $$ = newNode(); $$->statements.add($1); } | local_nonforward_declarations local_nonforward_declaration { $1->statements.add($2); $$ = $1; } ; %type local_nonforward_declaration local_nonforward_declaration : DECLARE var_decl_opt local_declaration_item ';' { $$ = $3; $$->line = YYPOSNARG(1).firstLine; $$->column = YYPOSNARG(1).firstColumn; } | local_declaration_subproc_start AS local_declarations_opt full_proc_block { DeclareSubProcNode* node = $1; node->dsqlBlock->localDeclList = $3; node->dsqlBlock->body = $4; for (FB_SIZE_T i = 0; i < node->dsqlBlock->parameters.getCount(); ++i) node->dsqlBlock->parameters[i]->parameterExpr = make_parameter(); $$ = node; } | local_declaration_subfunc_start AS local_declarations_opt full_proc_block { DeclareSubFuncNode* node = $1; node->dsqlBlock->localDeclList = $3; node->dsqlBlock->body = $4; for (FB_SIZE_T i = 0; i < node->dsqlBlock->parameters.getCount(); ++i) node->dsqlBlock->parameters[i]->parameterExpr = make_parameter(); $$ = node; } ; %type local_declaration_subproc_start local_declaration_subproc_start : DECLARE PROCEDURE symbol_procedure_name { $$ = newNode(NOTRIAL(*$3)); $$->dsqlBlock = newNode(); } input_parameters(NOTRIAL(&$4->dsqlBlock->parameters)) output_parameters(NOTRIAL(&$4->dsqlBlock->returns)) { $$ = $4; } ; %type local_declaration_subfunc_start local_declaration_subfunc_start : DECLARE FUNCTION symbol_UDF_name { $$ = newNode(NOTRIAL(*$3)); $$->dsqlBlock = newNode(); } input_parameters(NOTRIAL(&$4->dsqlBlock->parameters)) RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $4; setCollate($7, $8); $$->dsqlBlock->returns.add(newNode($7)); $$->dsqlDeterministic = $9; } ; %type local_declaration_item local_declaration_item : var_declaration_item | cursor_declaration_item ; %type var_declaration_item var_declaration_item : column_domain_or_non_array_type collate_clause var_declaration_initializer { // Set collate before node allocation to prevent memory leak on throw setCollate($1, $2); DeclareVariableNode* node = newNode(); node->dsqlDef = newNode($1, $3); $$ = node; } ; %type var_declaration_initializer var_declaration_initializer : // nothing { $$ = nullptr; } | DEFAULT value { const auto clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } | '=' value { const auto clause = newNode(); clause->value = $2; clause->source = makeParseStr(YYPOSNARG(1), YYPOSNARG(2)); $$ = clause; } ; var_decl_opt : // nothing | VARIABLE ; %type cursor_declaration_item cursor_declaration_item : symbol_cursor_name scroll_opt CURSOR FOR '(' select ')' { DeclareCursorNode* node = newNode(*$1, DeclareCursorNode::CUR_TYPE_EXPLICIT); node->dsqlScroll = $2; node->dsqlSelect = $6; $$ = node; } ; %type scroll_opt scroll_opt : /* nothing */ { $$ = false; } | NO SCROLL { $$ = false; } | SCROLL { $$ = true; } ; %type proc_block proc_block : proc_statement | full_proc_block ; %type full_proc_block full_proc_block : BEGIN full_proc_block_body END { $$ = newNode(YYPOSNARG(1).firstLine, YYPOSNARG(1).firstColumn, $2); } ; %type full_proc_block_body full_proc_block_body : // nothing { $$ = newNode(); } | proc_statements { BlockNode* node = newNode(); node->action = $1; $$ = node; } | proc_statements excp_hndl_statements { BlockNode* node = newNode(); node->action = $1; node->handlers = $2; $$ = node; } ; %type proc_statements proc_statements : proc_block { $$ = newNode(); $$->statements.add($1); } | proc_statements proc_block { $1->statements.add($2); $$ = $1; } ; %type proc_statement proc_statement : simple_proc_statement ';' [YYVALID;] { $$ = newNode(YYPOSNARG(1).firstLine, YYPOSNARG(1).firstColumn, $1); } | complex_proc_statement [YYVALID;] { $$ = newNode(YYPOSNARG(1).firstLine, YYPOSNARG(1).firstColumn, $1); } ; %type simple_proc_statement simple_proc_statement : assignment_statement | insert { $$ = $1; } | merge { $$ = $1; } | update | update_or_insert { $$ = $1; } | delete | singleton_select | exec_procedure | call { $$ = $1; } | exec_sql { $$ = $1; } | exec_into { $$ = $1; } | exec_function | excp_statement { $$ = $1; } | raise_statement | post_event | cursor_statement | breakleave | continue | SUSPEND { $$ = newNode(); } | EXIT { $$ = newNode(); } | RETURN value { $$ = newNode($2); } | mng_statement { $$ = newNode($1, makeParseStr(YYPOSNARG(1), YYPOSNARG(1))); } ; %type assignment_statement assignment_statement : assignment | ':' assignment { $$ = $2; } ; %type complex_proc_statement complex_proc_statement : in_autonomous_transaction | if_then_else | while | for_select { $$ = $1; } | for_exec_into { $$ = $1; } ; %type in_autonomous_transaction in_autonomous_transaction : IN AUTONOMOUS TRANSACTION DO proc_block { InAutonomousTransactionNode* node = newNode(); node->action = $5; $$ = node; } ; %type excp_statement excp_statement : EXCEPTION symbol_exception_name { $$ = newNode(*$2); } | EXCEPTION symbol_exception_name value { $$ = newNode(*$2, $3); } | EXCEPTION symbol_exception_name USING '(' value_list ')' { $$ = newNode(*$2, (ValueExprNode*) NULL, $5); } ; %type raise_statement raise_statement : EXCEPTION { $$ = newNode(); } ; %type for_select for_select : label_def_opt FOR select { ForNode* node = newNode(); node->dsqlLabelName = $1; node->dsqlSelect = $3; $$ = node; } for_select_into_cursor($4) DO proc_block { ForNode* node = $4; node->statement = $7; $$ = node; } ; %type for_select_into_cursor() for_select_into_cursor($forNode) : into_variable_list cursor_def_opt { $forNode->dsqlInto = $1; $forNode->dsqlCursor = $2; } | into_variable_list_opt cursor_def { $forNode->dsqlInto = $1; $forNode->dsqlCursor = $2; } ; %type into_variable_list_opt into_variable_list_opt : /* nothing */ { $$ = NULL; } | into_variable_list ; %type into_variable_list into_variable_list : INTO variable_list { $$ = $2; } ; %type exec_sql exec_sql : EXECUTE STATEMENT { $$ = newNode(); } exec_stmt_inputs($3) exec_stmt_options($3) { $$ = $3; } ; %type exec_into exec_into : exec_sql INTO variable_list { $$ = $1; $$->outputs = $3; } ; %type for_exec_into for_exec_into : label_def_opt FOR exec_into DO proc_block { $$ = $3; $$->dsqlLabelName = $1; $$->innerStmt = $5; } ; %type exec_stmt_inputs() exec_stmt_inputs($execStatementNode) : value { $execStatementNode->sql = $1; } | '(' value ')' '(' named_params_list($execStatementNode) ')' { $execStatementNode->sql = $2; } | '(' value ')' '(' not_named_params_list($execStatementNode) ')' { $execStatementNode->sql = $2; } ; %type named_params_list() named_params_list($execStatementNode) : named_param($execStatementNode) | named_params_list ',' named_param($execStatementNode) ; %type named_param() named_param($execStatementNode) : symbol_variable_name BIND_PARAM value { if (!$execStatementNode->inputNames) $execStatementNode->inputNames = FB_NEW_POOL(getPool()) EDS::ParamNames(getPool()); $execStatementNode->inputNames->add($1); if (!$execStatementNode->inputs) $execStatementNode->inputs = newNode($3); else $execStatementNode->inputs->add($3); } | EXCESS symbol_variable_name BIND_PARAM value { if (!$execStatementNode->inputNames) $execStatementNode->inputNames = FB_NEW_POOL(getPool()) EDS::ParamNames(getPool()); if (!$execStatementNode->excessInputs) $execStatementNode->excessInputs = FB_NEW_POOL(getPool()) EDS::ParamNumbers(getPool()); $execStatementNode->excessInputs->add($execStatementNode->inputNames->getCount()); $execStatementNode->inputNames->add($2); if (!$execStatementNode->inputs) $execStatementNode->inputs = newNode($4); else $execStatementNode->inputs->add($4); } ; %type not_named_params_list() not_named_params_list($execStatementNode) : not_named_param($execStatementNode) | not_named_params_list ',' not_named_param($execStatementNode) ; %type not_named_param() not_named_param($execStatementNode) : value { if (!$execStatementNode->inputs) $execStatementNode->inputs = newNode($1); else $execStatementNode->inputs->add($1); } ; %type exec_stmt_options() exec_stmt_options($execStatementNode) : // nothing | exec_stmt_options_list($execStatementNode) ; %type exec_stmt_options_list() exec_stmt_options_list($execStatementNode) : exec_stmt_options_list exec_stmt_option($execStatementNode) | exec_stmt_option($execStatementNode) ; %type exec_stmt_option() exec_stmt_option($execStatementNode) : ON EXTERNAL DATA SOURCE value { setClause($execStatementNode->dataSource, "EXTERNAL DATA SOURCE", $5); } | ON EXTERNAL value { setClause($execStatementNode->dataSource, "EXTERNAL DATA SOURCE", $3); } | AS USER value { setClause($execStatementNode->userName, "USER", $3); } | PASSWORD value { setClause($execStatementNode->password, "PASSWORD", $2); } | ROLE value { setClause($execStatementNode->role, "ROLE", $2); } | WITH AUTONOMOUS TRANSACTION { setClause($execStatementNode->traScope, "TRANSACTION", EDS::traAutonomous); } | WITH COMMON TRANSACTION { setClause($execStatementNode->traScope, "TRANSACTION", EDS::traCommon); } | WITH CALLER PRIVILEGES { setClause($execStatementNode->useCallerPrivs, "CALLER PRIVILEGES"); } /* | WITH TWO_PHASE TRANSACTION { setClause($execStatementNode->traScope, "TRANSACTION", EDS::traTwoPhase); } */ ; %type if_then_else if_then_else : IF '(' search_condition ')' THEN proc_block ELSE proc_block { IfNode* node = newNode(); node->condition = $3; node->trueAction = $6; node->falseAction = $8; $$ = node; } | IF '(' search_condition ')' THEN proc_block { IfNode* node = newNode(); node->condition = $3; node->trueAction = $6; $$ = node; } ; %type post_event post_event : POST_EVENT value event_argument_opt { PostEventNode* node = newNode(); node->event = $2; node->argument = $3; $$ = node; } ; %type event_argument_opt event_argument_opt : /* nothing */ { $$ = NULL; } ///| ',' value { $$ = $2; } ; %type singleton_select singleton_select : select INTO variable_list { ForNode* node = newNode(); node->dsqlSelect = $1; node->dsqlInto = $3; $$ = node; } ; %type variable variable : ':' symbol_variable_name { VariableNode* node = newNode(); node->dsqlName = *$2; $$ = node; } ; %type variable_list variable_list : variable { $$ = newNode($1); } | column_name { $$ = newNode($1); } | variable_list ',' column_name { $$ = $1->add($3); } | variable_list ',' variable { $$ = $1->add($3); } ; %type while while : label_def_opt WHILE '(' search_condition ')' DO proc_block { LoopNode* node = newNode(); node->dsqlLabelName = $1; node->dsqlExpr = $4; node->statement = $7; $$ = node; } ; %type label_def_opt label_def_opt : /* nothing */ { $$ = NULL; } | symbol_label_name ':' { $$ = $1; } ; %type breakleave breakleave : BREAK { $$ = newNode(blr_leave); } | LEAVE label_use_opt { ContinueLeaveNode* node = newNode(blr_leave); node->dsqlLabelName = $2; $$ = node; } ; %type continue continue : CONTINUE label_use_opt { ContinueLeaveNode* node = newNode(blr_continue_loop); node->dsqlLabelName = $2; $$ = node; } ; %type label_use_opt label_use_opt : /* nothing */ { $$ = NULL; } | symbol_label_name ; %type cursor_def_opt cursor_def_opt : /* nothing */ { $$ = NULL; } | cursor_def ; %type cursor_def cursor_def : AS CURSOR symbol_cursor_name { $$ = newNode(*$3, DeclareCursorNode::CUR_TYPE_FOR); } ; %type excp_hndl_statements excp_hndl_statements : excp_hndl_statement { $$ = newNode(); $$->statements.add($1); } | excp_hndl_statements excp_hndl_statement { $1->statements.add($2); $$ = $1; } ; %type excp_hndl_statement excp_hndl_statement : WHEN { $$ = newNode(); } errors(NOTRIAL(&$2->conditions)) DO proc_block { ErrorHandlerNode* node = $2; node->action = $5; $$ = node; } ; %type errors() errors($exceptionArray) : err($exceptionArray) | errors ',' err($exceptionArray) ; %type err() err($exceptionArray) : SQLCODE signed_short_integer { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::SQL_CODE; item.code = $2; } | SQLSTATE STRING { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::SQL_STATE; item.name = $2->getString(); } | GDSCODE symbol_gdscode_name { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::GDS_CODE; item.name = $2->c_str(); } | EXCEPTION symbol_exception_name { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::XCP_CODE; item.name = $2->c_str(); } | ANY { ExceptionItem& item = $exceptionArray->add(); item.type = ExceptionItem::XCP_DEFAULT; } ; %type cursor_statement cursor_statement : open_cursor | fetch_cursor | close_cursor ; %type open_cursor open_cursor : OPEN symbol_cursor_name { $$ = newNode(blr_cursor_open, *$2); } ; %type close_cursor close_cursor : CLOSE symbol_cursor_name { $$ = newNode(blr_cursor_close, *$2); } ; %type fetch_cursor fetch_cursor : FETCH { $$ = newNode(blr_cursor_fetch_scroll); } fetch_scroll($2) FROM symbol_cursor_name into_variable_list_opt { CursorStmtNode* cursorStmt = $2; cursorStmt->dsqlName = *$5; cursorStmt->dsqlIntoStmt = $6; $$ = cursorStmt; } | FETCH symbol_cursor_name into_variable_list_opt { $$ = newNode(blr_cursor_fetch, *$2, $3); } ; %type fetch_scroll() fetch_scroll($cursorStmtNode) : FIRST { $cursorStmtNode->scrollOp = blr_scroll_bof; } | LAST { $cursorStmtNode->scrollOp = blr_scroll_eof; } | PRIOR { $cursorStmtNode->scrollOp = blr_scroll_backward; } | NEXT { $cursorStmtNode->scrollOp = blr_scroll_forward; } | ABSOLUTE value { $cursorStmtNode->scrollOp = blr_scroll_absolute; $cursorStmtNode->scrollExpr = $2; } | RELATIVE value { $cursorStmtNode->scrollOp = blr_scroll_relative; $cursorStmtNode->scrollExpr = $2; } ; // EXECUTE PROCEDURE %type exec_procedure exec_procedure : EXECUTE PROCEDURE symbol_procedure_name proc_inputs proc_outputs_opt { $$ = newNode( QualifiedName(*$3), ($4 ? $4->second : nullptr), $5, ($4 ? $4->first : nullptr)); } | EXECUTE PROCEDURE symbol_package_name '.' symbol_procedure_name proc_inputs proc_outputs_opt { $$ = newNode( QualifiedName(*$5, *$3), ($6 ? $6->second : nullptr), $7, ($6 ? $6->first : nullptr)); } ; %type proc_inputs proc_inputs : /* nothing */ { $$ = nullptr; } | argument_list { $$ = $1; } | '(' argument_list ')' { $$ = $2; } ; %type proc_outputs_opt proc_outputs_opt : /* nothing */ { $$ = NULL; } | RETURNING_VALUES variable_list { $$ = $2; } | RETURNING_VALUES '(' variable_list ')' { $$ = $3; } ; // CALL %type call call : CALL symbol_procedure_name '(' argument_list_opt ')' { auto node = newNode(QualifiedName(*$2), ($4 ? $4->second : nullptr), nullptr, ($4 ? $4->first : nullptr)); node->dsqlCallSyntax = true; $$ = node; } | CALL symbol_package_name '.' symbol_procedure_name '(' argument_list_opt ')' into_variable_list_opt { auto node = newNode(QualifiedName(*$4, *$2), ($6 ? $6->second : nullptr), nullptr, ($6 ? $6->first : nullptr)); node->dsqlCallSyntax = true; $$ = node; } ; // EXECUTE BLOCK %type exec_block exec_block : EXECUTE BLOCK { $$ = newNode(); } block_input_params(NOTRIAL(&$3->parameters)) output_parameters(NOTRIAL(&$3->returns)) AS local_declarations_opt full_proc_block { ExecBlockNode* node = $3; node->localDeclList = $7; node->body = $8; $$ = node; } ; %type block_input_params() block_input_params($parameters) : // nothing | '(' block_parameters($parameters) ')' ; %type block_parameters() block_parameters($parameters) : block_parameter($parameters) | block_parameters ',' block_parameter($parameters) ; %type block_parameter() block_parameter($parameters) : column_domain_or_non_array_type collate_clause '=' parameter { setCollate($1, $2); $parameters->add(newNode($1, (ValueSourceClause*) NULL, $4)); } ; // CREATE VIEW %type view_clause view_clause : simple_table_name column_parens_opt AS select_expr check_opt { CreateAlterViewNode* node = newNode($1, $2, $4); node->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5)); node->withCheckOption = $5; $$ = node; } ; %type replace_view_clause replace_view_clause : view_clause { $1->alter = true; $$ = $1; } ; %type alter_view_clause alter_view_clause : view_clause { $1->alter = true; $1->create = false; $$ = $1; } ; %type check_opt check_opt : /* nothing */ { $$ = false; } | WITH CHECK OPTION { $$ = true; } ; // CREATE TRIGGER %type trigger_clause trigger_clause : create_trigger_start trg_sql_security_clause AS local_declarations_opt full_proc_block { $$ = $1; $$->ssDefiner = $2; $$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(5)); $$->localDeclList = $4; $$->body = $5; } | create_trigger_start external_clause external_body_clause_opt { $$ = $1; $$->external = $2; if ($3) $$->source = *$3; } ; %type create_trigger_start create_trigger_start : symbol_trigger_name { $$ = newNode(*$1); } create_trigger_common(NOTRIAL($2)) { $$ = $2; } ; %type create_trigger_common() create_trigger_common($trigger) : trigger_active trigger_type(NOTRIAL($trigger)) trigger_position { $trigger->active = $1; $trigger->type = $2; setClause($trigger->position, "POSITION", $3); } | FOR symbol_table_name trigger_active table_trigger_type trigger_position { $trigger->relationName = *$2; $trigger->active = $3; $trigger->type = $4; setClause($trigger->position, "POSITION", $5); } ; %type replace_trigger_clause replace_trigger_clause : trigger_clause { $$ = $1; $$->alter = true; } ; %type trigger_active trigger_active : ACTIVE { $$ = TriState(true); } | INACTIVE { $$ = TriState(false); } | // nothing { $$ = TriState(); } ; %type trigger_type() trigger_type($trigger) : table_trigger_type trigger_position ON symbol_table_name { $$ = $1; setClause($trigger->position, "POSITION", $2); $trigger->relationName = *$4; } | ON trigger_db_type { $$ = $2; } | trigger_type_prefix trigger_ddl_type { $$ = $1 + $2; } ; %type table_trigger_type table_trigger_type : trigger_type_prefix trigger_type_suffix { $$ = $1 + $2 - 1; } ; %type trigger_db_type trigger_db_type : CONNECT { $$ = TRIGGER_TYPE_DB | DB_TRIGGER_CONNECT; } | DISCONNECT { $$ = TRIGGER_TYPE_DB | DB_TRIGGER_DISCONNECT; } | TRANSACTION START { $$ = TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_START; } | TRANSACTION COMMIT { $$ = TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_COMMIT; } | TRANSACTION ROLLBACK { $$ = TRIGGER_TYPE_DB | DB_TRIGGER_TRANS_ROLLBACK; } ; %type trigger_ddl_type trigger_ddl_type : trigger_ddl_type_items | ANY DDL STATEMENT { $$ = TRIGGER_TYPE_DDL | DDL_TRIGGER_ANY; } ; %type trigger_ddl_type_items trigger_ddl_type_items : CREATE TABLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_TABLE); } | ALTER TABLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_TABLE); } | DROP TABLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_TABLE); } | CREATE PROCEDURE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_PROCEDURE); } | ALTER PROCEDURE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_PROCEDURE); } | DROP PROCEDURE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_PROCEDURE); } | CREATE FUNCTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_FUNCTION); } | ALTER FUNCTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_FUNCTION); } | DROP FUNCTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_FUNCTION); } | CREATE TRIGGER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_TRIGGER); } | ALTER TRIGGER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_TRIGGER); } | DROP TRIGGER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_TRIGGER); } | CREATE EXCEPTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_EXCEPTION); } | ALTER EXCEPTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_EXCEPTION); } | DROP EXCEPTION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_EXCEPTION); } | CREATE VIEW { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_VIEW); } | ALTER VIEW { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_VIEW); } | DROP VIEW { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_VIEW); } | CREATE DOMAIN { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_DOMAIN); } | ALTER DOMAIN { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_DOMAIN); } | DROP DOMAIN { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_DOMAIN); } | CREATE ROLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_ROLE); } | ALTER ROLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_ROLE); } | DROP ROLE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_ROLE); } | CREATE SEQUENCE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_SEQUENCE); } | ALTER SEQUENCE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_SEQUENCE); } | DROP SEQUENCE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_SEQUENCE); } | CREATE USER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_USER); } | ALTER USER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_USER); } | DROP USER { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_USER); } | CREATE INDEX { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_INDEX); } | ALTER INDEX { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_INDEX); } | DROP INDEX { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_INDEX); } | CREATE COLLATION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_COLLATION); } | DROP COLLATION { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_COLLATION); } | ALTER CHARACTER SET { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_CHARACTER_SET); } | CREATE PACKAGE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_PACKAGE); } | ALTER PACKAGE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_PACKAGE); } | DROP PACKAGE { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_PACKAGE); } | CREATE PACKAGE BODY { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_PACKAGE_BODY); } | DROP PACKAGE BODY { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_PACKAGE_BODY); } | CREATE MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_CREATE_MAPPING); } | ALTER MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_ALTER_MAPPING); } | DROP MAPPING { $$ = TRIGGER_TYPE_DDL | (1LL << DDL_TRIGGER_DROP_MAPPING); } | trigger_ddl_type OR trigger_ddl_type { $$ = $1 | $3; } ; %type trigger_type_prefix trigger_type_prefix : BEFORE { $$ = 0; } | AFTER { $$ = 1; } ; %type trigger_type_suffix trigger_type_suffix : INSERT { $$ = trigger_type_suffix(1, 0, 0); } | UPDATE { $$ = trigger_type_suffix(2, 0, 0); } | DELETE { $$ = trigger_type_suffix(3, 0, 0); } | INSERT OR UPDATE { $$ = trigger_type_suffix(1, 2, 0); } | INSERT OR DELETE { $$ = trigger_type_suffix(1, 3, 0); } | UPDATE OR INSERT { $$ = trigger_type_suffix(2, 1, 0); } | UPDATE OR DELETE { $$ = trigger_type_suffix(2, 3, 0); } | DELETE OR INSERT { $$ = trigger_type_suffix(3, 1, 0); } | DELETE OR UPDATE { $$ = trigger_type_suffix(3, 2, 0); } | INSERT OR UPDATE OR DELETE { $$ = trigger_type_suffix(1, 2, 3); } | INSERT OR DELETE OR UPDATE { $$ = trigger_type_suffix(1, 3, 2); } | UPDATE OR INSERT OR DELETE { $$ = trigger_type_suffix(2, 1, 3); } | UPDATE OR DELETE OR INSERT { $$ = trigger_type_suffix(2, 3, 1); } | DELETE OR INSERT OR UPDATE { $$ = trigger_type_suffix(3, 1, 2); } | DELETE OR UPDATE OR INSERT { $$ = trigger_type_suffix(3, 2, 1); } ; %type trigger_position trigger_position : /* nothing */ { $$ = std::nullopt; } | POSITION nonneg_short_integer { $$ = $2; } ; // ALTER statement %type alter alter : ALTER alter_clause { $$ = $2; } | set_generator_clause { $$ = $1; } ; %type alter_clause alter_clause : EXCEPTION alter_exception_clause { $$ = $2; } | TABLE simple_table_name { $$ = newNode($2); } alter_ops($3) { $$ = $3; } | VIEW alter_view_clause { $$ = $2; } | TRIGGER alter_trigger_clause { $$ = $2; } | PROCEDURE alter_procedure_clause { $$ = $2; } | PACKAGE alter_package_clause { $$ = $2; } | PACKAGE BODY replace_package_body_clause { $$ = $3; } | DATABASE { $$ = newNode(); } alter_db($2) { $$ = $2; } | DOMAIN alter_domain { $$ = $2; } | INDEX alter_index_clause { $$ = $2; } | EXTERNAL FUNCTION alter_udf_clause { $$ = $3; } | FUNCTION alter_function_clause { $$ = $2; } | ROLE alter_role_clause { $$ = $2; } | USER alter_user_clause { $$ = $2; } | CURRENT USER alter_cur_user_clause { $$ = $3; } | CHARACTER SET alter_charset_clause { $$ = $3; } | GENERATOR alter_sequence_clause { $$ = $2; } | SEQUENCE alter_sequence_clause { $$ = $2; } | MAPPING alter_map_clause(false) { $$ = $2; } | GLOBAL MAPPING alter_map_clause(true) { $$ = $3; } | EXTERNAL CONNECTIONS POOL alter_eds_conn_pool_clause { $$ = $4; } ; %type alter_domain alter_domain : keyword_or_column { $$ = newNode(*$1); } alter_domain_ops($2) { $$ = $2; } ; %type alter_domain_ops() alter_domain_ops($alterDomainNode) : alter_domain_op($alterDomainNode) | alter_domain_ops alter_domain_op($alterDomainNode) ; %type alter_domain_op() alter_domain_op($alterDomainNode) : SET domain_default { setClause($alterDomainNode->setDefault, "DOMAIN DEFAULT", $2); } | ADD CONSTRAINT check_constraint { setClause($alterDomainNode->setConstraint, "DOMAIN CONSTRAINT", $3); } | ADD check_constraint { setClause($alterDomainNode->setConstraint, "DOMAIN CONSTRAINT", $2); } | DROP DEFAULT { setClause($alterDomainNode->dropDefault, "DOMAIN DROP DEFAULT"); } | DROP CONSTRAINT { setClause($alterDomainNode->dropConstraint, "DOMAIN DROP CONSTRAINT"); } | DROP NOT NULL { setClause($alterDomainNode->notNullFlag, "{SET | DROP} NOT NULL", false); } | SET NOT NULL { setClause($alterDomainNode->notNullFlag, "{SET | DROP} NOT NULL", true); } | TO symbol_column_name { setClause($alterDomainNode->renameTo, "DOMAIN NAME", *$2); } | TYPE non_array_type { //// FIXME: ALTER DOMAIN doesn't support collations, and altered domain's //// collation is always lost. dsql_fld* type = $2; type->collate = ""; setClause($alterDomainNode->type, "DOMAIN TYPE", type); } ; %type alter_ops() alter_ops($relationNode) : alter_op($relationNode) | alter_ops ',' alter_op($relationNode) ; %type alter_op() alter_op($relationNode) : DROP if_exists_opt symbol_column_name drop_behaviour { RelationNode::DropColumnClause* clause = newNode(); clause->silent = $2; clause->name = *$3; clause->cascade = $4; $relationNode->clauses.add(clause); } | DROP CONSTRAINT if_exists_opt symbol_constraint_name { RelationNode::DropConstraintClause* clause = newNode(); clause->silent = $3; clause->name = *$4; $relationNode->clauses.add(clause); } | ADD if_not_exists_opt column_def($relationNode) { const auto node = $3; node->createIfNotExistsOnly = $2; } | ADD table_constraint($relationNode) | ADD CONSTRAINT if_not_exists_opt symbol_constraint_name table_constraint($relationNode) { const auto node = $5; node->name = *$4; node->createIfNotExistsOnly = $3; } | col_opt alter_column_name POSITION pos_short_integer { RelationNode::AlterColPosClause* clause = newNode(); clause->name = *$2; clause->newPos = $4; $relationNode->clauses.add(clause); } | col_opt alter_column_name TO symbol_column_name { RelationNode::AlterColNameClause* clause = newNode(); clause->fromName = *$2; clause->toName = *$4; $relationNode->clauses.add(clause); } | col_opt alter_column_name DROP NOT NULL { RelationNode::AlterColNullClause* clause = newNode(); clause->name = *$2; clause->notNullFlag = false; $relationNode->clauses.add(clause); } | col_opt alter_column_name SET NOT NULL { RelationNode::AlterColNullClause* clause = newNode(); clause->name = *$2; clause->notNullFlag = true; $relationNode->clauses.add(clause); } | col_opt symbol_column_name TYPE alter_data_type_or_domain { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = $4; clause->field->fld_name = *$2; $relationNode->clauses.add(clause); } | col_opt symbol_column_name TYPE non_array_type def_computed { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = $4; clause->field->fld_name = *$2; clause->computed = $5; $relationNode->clauses.add(clause); clause->field->flags |= FLD_computed; } | col_opt symbol_column_name def_computed { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$2; clause->computed = $3; $relationNode->clauses.add(clause); clause->field->flags |= FLD_computed; } | col_opt symbol_column_name SET domain_default { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$2; clause->defaultValue = $4; $relationNode->clauses.add(clause); } | col_opt symbol_column_name DROP DEFAULT { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$2; clause->dropDefault = true; $relationNode->clauses.add(clause); } | col_opt symbol_column_name { $$ = newNode(); } alter_identity_clause_spec($3) { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$2; clause->identityOptions = $3; $relationNode->clauses.add(clause); } | col_opt symbol_column_name DROP IDENTITY { RelationNode::AlterColTypeClause* clause = newNode(); clause->field = newNode(); clause->field->fld_name = *$2; clause->dropIdentity = true; $relationNode->clauses.add(clause); } | ALTER SQL SECURITY DEFINER { setClause($relationNode->ssDefiner, "SQL SECURITY", true); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_SQL_SECURITY); $relationNode->clauses.add(clause); } | ALTER SQL SECURITY INVOKER { setClause($relationNode->ssDefiner, "SQL SECURITY", false); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_SQL_SECURITY); $relationNode->clauses.add(clause); } | DROP SQL SECURITY { setClause($relationNode->ssDefiner, "SQL SECURITY", TriState()); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_SQL_SECURITY); $relationNode->clauses.add(clause); } | ENABLE PUBLICATION { setClause($relationNode->replicationState, "PUBLICATION", true); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_PUBLICATION); $relationNode->clauses.add(clause); } | DISABLE PUBLICATION { setClause($relationNode->replicationState, "PUBLICATION", false); RelationNode::Clause* clause = newNode(RelationNode::Clause::TYPE_ALTER_PUBLICATION); $relationNode->clauses.add(clause); } ; %type alter_column_name alter_column_name : keyword_or_column ; // below are reserved words that could be used as column identifiers // in the previous versions %type keyword_or_column 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 | LOWER | OCTET_LENGTH | TRAILING | TRIM | CONNECT // added in FB 2.1 | DISCONNECT | GLOBAL | INSENSITIVE | RECURSIVE | SENSITIVE | START | SIMILAR // added in FB 2.5 | BOOLEAN // added in FB 3.0 | CORR | COVAR_POP | COVAR_SAMP | DELETING | DETERMINISTIC | FALSE | INSERTING | OFFSET | OVER | REGR_AVGX | REGR_AVGY | REGR_COUNT | REGR_INTERCEPT | REGR_R2 | REGR_SLOPE | REGR_SXX | REGR_SXY | REGR_SYY | RETURN | ROW | SCROLL | SQLSTATE | STDDEV_SAMP | STDDEV_POP | TRUE | UNKNOWN | UPDATING | VAR_SAMP | VAR_POP | BINARY // added in FB 4.0 | DECFLOAT | INT128 | LATERAL | LOCAL | LOCALTIME | LOCALTIMESTAMP | PUBLICATION | RESETTING | TIMEZONE_HOUR | TIMEZONE_MINUTE | UNBOUNDED | VARBINARY | WINDOW | WITHOUT | BTRIM // added in FB 6.0 | CALL | LTRIM | RTRIM ; col_opt : ALTER | ALTER COLUMN ; %type alter_data_type_or_domain alter_data_type_or_domain : non_array_type | symbol_column_name { $$ = newNode(); $$->typeOfName = *$1; } ; %type alter_identity_clause_spec() alter_identity_clause_spec($identityOptions) : alter_identity_clause_generation($identityOptions) alter_identity_clause_options_opt($identityOptions) | alter_identity_clause_options($identityOptions) ; %type alter_identity_clause_generation() alter_identity_clause_generation($identityOptions) : SET GENERATED ALWAYS { $identityOptions->type = IDENT_TYPE_ALWAYS; } | SET GENERATED BY DEFAULT { $identityOptions->type = IDENT_TYPE_BY_DEFAULT; } ; %type alter_identity_clause_options_opt() alter_identity_clause_options_opt($identityOptions) : // nothing | alter_identity_clause_options($identityOptions) ; %type alter_identity_clause_options() alter_identity_clause_options($identityOptions) : alter_identity_clause_options alter_identity_clause_option($identityOptions) | alter_identity_clause_option($identityOptions) ; %type alter_identity_clause_option() alter_identity_clause_option($identityOptions) : RESTART with_opt { setClause($identityOptions->restart, "RESTART"); $identityOptions->startValue = $2; } | SET INCREMENT by_noise signed_long_integer { setClause($identityOptions->increment, "SET INCREMENT BY", $4); } ; %type drop_behaviour drop_behaviour : { $$ = false; } | RESTRICT { $$ = false; } | CASCADE { $$ = true; } ; %type alter_index_clause alter_index_clause : symbol_index_name index_active { $$ = newNode(*$1, $2); } ; %type index_active index_active : ACTIVE { $$ = true; } | INACTIVE { $$ = false; } ; %type alter_udf_clause alter_udf_clause : symbol_UDF_name entry_op module_op { AlterExternalFunctionNode* node = newNode(*$1); if ($2) node->clauses.name = *$2; if ($3) node->clauses.udfModule = *$3; $$ = node; } ; %type entry_op entry_op : /* nothing */ { $$ = NULL; } | ENTRY_POINT utf_string { $$ = $2; } ; %type module_op module_op : /* nothing */ { $$ = NULL; } | MODULE_NAME utf_string { $$ = $2; } ; %type alter_role_2X_compatibility alter_role_2X_compatibility : symbol_role_name alter_role_enable AUTO ADMIN MAPPING { MappingNode* mn = newNode(MappingNode::MAP_RPL, "AutoAdminImplementationMapping"); mn->op = $2 ? MappingNode::MAP_RPL : MappingNode::MAP_DROP; mn->from = newNode(FB_DOMAIN_ANY_RID_ADMINS); mn->fromType = newNode(FB_PREDEFINED_GROUP); mn->mode = 'P'; mn->plugin = newNode("Win_Sspi"); mn->role = true; mn->to = $1; mn->validateAdmin(); $$ = mn; } ; %type alter_role_clause alter_role_clause : role_clause { $$ = $1; } | alter_role_2X_compatibility { $$ = $1; } ; %type alter_role_enable alter_role_enable : SET { $$ = true; } | DROP { $$ = false; } ; // ALTER DATABASE %type alter_db() alter_db($alterDatabaseNode) : db_alter_clause($alterDatabaseNode) | alter_db db_alter_clause($alterDatabaseNode) ; %type db_alter_clause() db_alter_clause($alterDatabaseNode) : ADD DIFFERENCE FILE utf_string { $alterDatabaseNode->differenceFile = *$4; } | DROP DIFFERENCE FILE { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DROP_DIFFERENCE; } | BEGIN BACKUP { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_BEGIN_BACKUP; } | END BACKUP { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_END_BACKUP; } | SET DEFAULT CHARACTER SET symbol_character_set_name { $alterDatabaseNode->setDefaultCharSet = *$5; } | ENCRYPT WITH valid_symbol_name crypt_key_clause($alterDatabaseNode) { setClauseFlag($alterDatabaseNode->clauses, AlterDatabaseNode::CLAUSE_CRYPT, "CRYPT"); $alterDatabaseNode->cryptPlugin = *$3; } | DECRYPT { setClauseFlag($alterDatabaseNode->clauses, AlterDatabaseNode::CLAUSE_CRYPT, "CRYPT"); } | SET LINGER TO long_integer { $alterDatabaseNode->linger = $4; } | DROP LINGER { $alterDatabaseNode->linger = 0; } | SET DEFAULT sql_security_clause { $alterDatabaseNode->ssDefiner = $3; } | ENABLE PUBLICATION { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_ENABLE_PUB; } | DISABLE PUBLICATION { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DISABLE_PUB; } | INCLUDE pub_table_filter($alterDatabaseNode) TO PUBLICATION { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_PUB_INCL_TABLE; } | EXCLUDE pub_table_filter($alterDatabaseNode) FROM PUBLICATION { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_PUB_EXCL_TABLE; } ; %type crypt_key_clause() crypt_key_clause($alterDatabaseNode) : // nothing | KEY valid_symbol_name { $alterDatabaseNode->keyName = *$2; } ; %type pub_table_filter() pub_table_filter($alterDatabaseNode) : ALL | TABLE pub_table_list($alterDatabaseNode) ; %type pub_table_list() pub_table_list($alterDatabaseNode) : pub_table_clause($alterDatabaseNode) | pub_table_list ',' pub_table_clause($alterDatabaseNode) ; %type pub_table_clause() pub_table_clause($alterDatabaseNode) : symbol_table_name { $alterDatabaseNode->pubTables.add(*$1); } ; // ALTER TRIGGER %type alter_trigger_clause alter_trigger_clause : symbol_trigger_name trigger_active trigger_type_opt trigger_position trg_sql_security_clause AS local_declarations_opt full_proc_block { $$ = newNode(*$1); $$->alter = true; $$->create = false; $$->active = $2; $$->type = $3; $$->position = $4; $$->ssDefiner = $5; $$->source = makeParseStr(YYPOSNARG(6), YYPOSNARG(8)); $$->localDeclList = $7; $$->body = $8; } | symbol_trigger_name trigger_active trigger_type_opt trigger_position external_clause external_body_clause_opt { $$ = newNode(*$1); $$->alter = true; $$->create = false; $$->active = $2; $$->type = $3; $$->position = $4; $$->external = $5; if ($6) $$->source = *$6; } | symbol_trigger_name trigger_active trigger_type_opt trigger_position trg_sql_security_clause { $$ = newNode(*$1); $$->alter = true; $$->create = false; $$->active = $2; $$->type = $3; $$->position = $4; $$->ssDefiner = $5; } ; %type trigger_type_opt trigger_type_opt // we do not allow alter database triggers, hence we do not use trigger_type here : trigger_type_prefix trigger_type_suffix { $$ = $1 + $2 - 1; } | { $$ = std::nullopt; } ; %type optional_sql_security_clause optional_sql_security_clause : SQL SECURITY DEFINER { $$ = SS_DEFINER; } | SQL SECURITY INVOKER { $$ = SS_INVOKER; } ; %type optional_sql_security_full_alter_clause optional_sql_security_full_alter_clause : optional_sql_security_clause { $$ = $1; } | // nothing { $$ = std::nullopt; } ; %type optional_sql_security_partial_alter_clause optional_sql_security_partial_alter_clause : optional_sql_security_clause { $$ = $1; } | DROP SQL SECURITY { $$ = SS_DROP; } ; %type trg_sql_security_clause trg_sql_security_clause : // nothing { $$ = std::nullopt; } | optional_sql_security_clause { $$ = $1; } | DROP SQL SECURITY { $$ = SS_DROP; } ; // DROP metadata operations %type drop drop : DROP drop_clause { $$ = $2; } ; %type drop_clause drop_clause : EXCEPTION if_exists_opt symbol_exception_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | INDEX if_exists_opt symbol_index_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | PROCEDURE if_exists_opt symbol_procedure_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | TABLE if_exists_opt symbol_table_name { const auto node = newNode(*$3, false); node->silent = $2; $$ = node; } | TRIGGER if_exists_opt symbol_trigger_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | VIEW if_exists_opt symbol_view_name { const auto node = newNode(*$3, true); node->silent = $2; $$ = node; } | FILTER if_exists_opt symbol_filter_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | DOMAIN if_exists_opt symbol_domain_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | EXTERNAL FUNCTION if_exists_opt symbol_UDF_name { const auto node = newNode(*$4); node->silent = $3; $$ = node; } | FUNCTION if_exists_opt symbol_UDF_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | SHADOW if_exists_opt pos_short_integer opt_no_file_delete { const auto node = newNode($3, $4); // DROP SHADOW implicitly has IF EXISTS behavior $$ = node; } | ROLE if_exists_opt symbol_role_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | GENERATOR if_exists_opt symbol_generator_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | SEQUENCE if_exists_opt symbol_generator_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | COLLATION if_exists_opt symbol_collation_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | USER if_exists_opt symbol_user_name USING PLUGIN valid_symbol_name { const auto node = newNode(*$3, $6); node->silent = $2; $$ = node; } | USER if_exists_opt symbol_user_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | PACKAGE if_exists_opt symbol_package_name { const auto node = newNode(*$3); node->silent = $2; $$ = node; } | PACKAGE BODY if_exists_opt symbol_package_name { const auto node = newNode(*$4); node->silent = $3; $$ = node; } | MAPPING if_exists_opt drop_map_clause(false) { const auto node = $3; node->silentDrop = $2; $$ = node; } | GLOBAL MAPPING if_exists_opt drop_map_clause(true) { const auto node = $4; node->silentDrop = $3; $$ = node; } ; %type if_exists_opt if_exists_opt : /* nothing */ { $$ = false; } | IF EXISTS { $$ = true; } ; %type if_not_exists_opt if_not_exists_opt : /* nothing */ { $$ = false; } | IF NOT EXISTS { $$ = true; } ; %type opt_no_file_delete opt_no_file_delete : /* nothing */ { $$ = false; } | PRESERVE FILE { $$ = true; } | DELETE FILE { $$ = false; } ; // these are the allowable datatypes %type data_type data_type : non_array_type | array_type ; %type domain_or_non_array_type domain_or_non_array_type : domain_or_non_array_type_name | domain_or_non_array_type_name NOT NULL { $$ = $1; $$->notNull = true; } ; %type domain_or_non_array_type_name domain_or_non_array_type_name : non_array_type | domain_type ; %type domain_type domain_type : TYPE OF symbol_column_name { $$ = newNode(); $$->typeOfName = *$3; } | TYPE OF COLUMN symbol_column_name '.' symbol_column_name { $$ = newNode(); $$->typeOfName = *$6; $$->typeOfTable = *$4; } | symbol_column_name { $$ = newNode(); $$->typeOfName = *$1; $$->fullDomain = true; } ; %type non_array_type non_array_type : simple_type | blob_type ; %type array_type array_type : non_charset_simple_type '[' array_spec ']' { $1->ranges = $3; $1->dimensions = $1->ranges->items.getCount() / 2; $1->elementDtype = $1->dtype; $$ = $1; } | character_type '[' array_spec ']' charset_clause { $1->ranges = $3; $1->dimensions = $1->ranges->items.getCount() / 2; $1->elementDtype = $1->dtype; if ($5) $1->charSet = *$5; $$ = $1; } ; %type array_spec array_spec : array_range | array_spec ',' array_range { $$ = $1->add($3->items[0])->add($3->items[1]); } ; %type array_range array_range : signed_long_integer { if ($1 < 1) $$ = newNode(MAKE_const_slong($1))->add(MAKE_const_slong(1)); else $$ = newNode(MAKE_const_slong(1))->add(MAKE_const_slong($1)); } | signed_long_integer ':' signed_long_integer { $$ = newNode(MAKE_const_slong($1))->add(MAKE_const_slong($3)); } ; %type simple_type simple_type : non_charset_simple_type | character_type charset_clause collate_clause { $$ = $1; if ($2) { $$->charSet = *$2; $$->flags |= FLD_has_chset; } if ($3) $$->collate = *$3; } ; %type non_charset_simple_type non_charset_simple_type : national_character_type collate_clause { $$ = $1; if ($2) $$->collate = *$2; } | binary_character_type | numeric_type | float_type | decfloat_type | date_time_type | BIGINT { $$ = newNode(); if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post (Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("BIGINT")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post (Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("BIGINT")); } $$->dtype = dtype_int64; $$->length = sizeof(SINT64); $$->flags |= FLD_has_prec; } | INT128 { $$ = newNode(); $$->dtype = dtype_int128; $$->length = sizeof(Int128); $$->flags |= FLD_has_prec; } | integer_keyword { $$ = newNode(); $$->dtype = dtype_long; $$->length = sizeof(SLONG); $$->flags |= FLD_has_prec; } | SMALLINT { $$ = newNode(); $$->dtype = dtype_short; $$->length = sizeof(SSHORT); $$->flags |= FLD_has_prec; } | BOOLEAN { $$ = newNode(); $$->dtype = dtype_boolean; $$->length = sizeof(UCHAR); } ; integer_keyword : INTEGER | INT ; without_time_zone_opt : // nothing | WITHOUT TIME ZONE ; // allow a blob to be specified with any combination of segment length and subtype %type blob_type blob_type : BLOB { $$ = newNode(); } blob_subtype(NOTRIAL($2)) blob_segsize charset_clause { $$ = $2; $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = $4; if ($5) { $$->charSet = *$5; $$->flags |= FLD_has_chset; } } | BLOB '(' unsigned_short_integer ')' { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = (USHORT) $3; $$->subType = 0; } | BLOB '(' unsigned_short_integer ',' signed_short_integer ')' { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = (USHORT) $3; $$->subType = (USHORT) $5; $$->flags |= FLD_has_sub; } | BLOB '(' ',' signed_short_integer ')' { $$ = newNode(); $$->dtype = dtype_blob; $$->length = sizeof(ISC_QUAD); $$->segLength = 80; $$->subType = (USHORT) $4; $$->flags |= FLD_has_sub; } ; %type blob_segsize blob_segsize : /* nothing */ { $$ = (USHORT) 80; } | SEGMENT SIZE unsigned_short_integer { $$ = (USHORT) $3; } ; %type blob_subtype() blob_subtype($field) : // nothing { $field->subType = (USHORT) 0; } | SUB_TYPE signed_short_integer { $field->subType = (USHORT) $2; $field->flags |= FLD_has_sub; } | SUB_TYPE symbol_blob_subtype_name { $field->subTypeName = *$2; $field->flags |= FLD_has_sub; } ; %type charset_clause charset_clause : /* nothing */ { $$ = NULL; } | CHARACTER SET symbol_character_set_name { $$ = $3; } ; // character type %type national_character_type national_character_type : national_character_keyword '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = (USHORT) $3; $$->flags |= (FLD_national | FLD_has_len); } | national_character_keyword { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = 1; $$->flags |= FLD_national; } | national_character_keyword VARYING '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_varying; $$->charLength = (USHORT) $4; $$->flags |= (FLD_national | FLD_has_len); } ; %type binary_character_type binary_character_type : binary_character_keyword '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = (USHORT) $3; $$->length = (USHORT) $3; $$->textType = ttype_binary; $$->charSetId = CS_BINARY; $$->subType = fb_text_subtype_binary; $$->flags |= (FLD_has_len | FLD_has_chset); } | binary_character_keyword { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = 1; $$->length = 1; $$->textType = ttype_binary; $$->charSetId = CS_BINARY; $$->subType = fb_text_subtype_binary; $$->flags |= FLD_has_chset; } | varbinary_character_keyword '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_varying; $$->charLength = (USHORT) $3; $$->length = (USHORT) $3 + sizeof(USHORT); $$->textType = ttype_binary; $$->charSetId = CS_BINARY; $$->subType = fb_text_subtype_binary; $$->flags |= (FLD_has_len | FLD_has_chset); } ; %type character_type character_type : character_keyword '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = (USHORT) $3; $$->flags |= FLD_has_len; } | character_keyword { $$ = newNode(); $$->dtype = dtype_text; $$->charLength = 1; } | varying_keyword '(' pos_short_integer ')' { $$ = newNode(); $$->dtype = dtype_varying; $$->charLength = (USHORT) $3; $$->flags |= FLD_has_len; } ; varying_keyword : VARCHAR | CHARACTER VARYING | CHAR VARYING ; character_keyword : CHARACTER | CHAR ; national_character_keyword : NCHAR | NATIONAL CHARACTER | NATIONAL CHAR ; binary_character_keyword : BINARY ; varbinary_character_keyword : VARBINARY | BINARY VARYING ; // numeric type %type decfloat_type decfloat_type : DECFLOAT precision_opt_nz { SLONG precision = $2; if (precision != 0 && precision != 16 && precision != 34) yyabandon(YYPOSNARG(2), -842, isc_decprecision_err); // DecFloat precision must be 16 or 34. $$ = newNode(); if (precision) $$->flags |= FLD_has_prec; $$->precision = precision == 0 ? 34 : (USHORT) precision; $$->dtype = precision == 16 ? dtype_dec64 : dtype_dec128; $$->length = precision == 16 ? sizeof(Decimal64) : sizeof(Decimal128); } ; %type numeric_type numeric_type : NUMERIC prec_scale { $$ = $2; $$->subType = dsc_num_type_numeric; $$->flags |= FLD_has_sub; } | decimal_keyword prec_scale { $$ = $2; $$->subType = dsc_num_type_decimal; $$->flags |= FLD_has_sub; if ($$->dtype == dtype_short) { $$->dtype = dtype_long; $$->length = sizeof(SLONG); } } ; %type prec_scale prec_scale : // nothing { $$ = newNode(); $$->dtype = dtype_long; $$->length = sizeof(SLONG); $$->precision = 9; } | '(' signed_long_integer ')' { $$ = newNode(); $$->flags |= FLD_has_prec; if ($2 < 1 || $2 > 38) yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38)); // Precision must be between 1 and 38 if ($2 > 18) { $$->dtype = dtype_int128; $$->length = sizeof(Int128); } else if ($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(Arg::Gds(isc_sqlerr) << Arg::Num(-817) << Arg::Gds(isc_ddl_not_allowed_by_db_sql_dial) << Arg::Num(db_dialect)); } if (client_dialect <= SQL_DIALECT_V5) { $$->dtype = dtype_double; $$->length = sizeof(double); } else { if (client_dialect == SQL_DIALECT_V6_TRANSITION) { ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous)); ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous1)); ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous2)); } $$->dtype = dtype_int64; $$->length = sizeof(SINT64); } } else { if ($2 < 5) { $$->dtype = dtype_short; $$->length = sizeof(SSHORT); } else { $$->dtype = dtype_long; $$->length = sizeof(SLONG); } } $$->precision = (USHORT) $2; } | '(' signed_long_integer ',' signed_long_integer ')' { $$ = newNode(); $$->flags |= (FLD_has_prec | FLD_has_scale); if ($2 < 1 || $2 > 38) yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(38)); // Precision must be between 1 and 38 if ($4 > $2 || $4 < 0) yyabandon(YYPOSNARG(4), -842, isc_scale_nogt); // Scale must be between 0 and precision if ($2 > 18) { $$->dtype = dtype_int128; $$->length = sizeof(Int128); } else if ($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(Arg::Gds(isc_sqlerr) << Arg::Num(-817) << Arg::Gds(isc_ddl_not_allowed_by_db_sql_dial) << Arg::Num(db_dialect)); } if (client_dialect <= SQL_DIALECT_V5) { $$->dtype = dtype_double; $$->length = sizeof(double); } else { if (client_dialect == SQL_DIALECT_V6_TRANSITION) { ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous)); ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous1)); ERRD_post_warning(Arg::Warning(isc_dsql_warn_precision_ambiguous2)); } // client_dialect >= SQL_DIALECT_V6 $$->dtype = dtype_int64; $$->length = sizeof(SINT64); } } else { if ($2 < 5) { $$->dtype = dtype_short; $$->length = sizeof(SSHORT); } else { $$->dtype = dtype_long; $$->length = sizeof(SLONG); } } $$->precision = (USHORT) $2; $$->scale = - (SSHORT) $4; } ; decimal_keyword : DECIMAL | DEC ; // floating point type %type float_type float_type : FLOAT precision_opt_nz { // Precision is binary digits of the significand: 1-24 for 32 bit single precision, 25-53 for 64 bit double precision // Precision 0 is the 'no precision specified' case, which defaults to 32 bit single precision SLONG precision = $2; if (precision != 0 && (precision < 1 || precision > 53)) yyabandon(YYPOSNARG(2), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(53)); // Precision must be between 1 and 53 $$ = newNode(); if (precision > 24) { $$->dtype = dtype_double; $$->length = sizeof(double); } else { $$->dtype = dtype_real; $$->length = sizeof(float); } } | LONG FLOAT precision_opt_nz { // Precision is binary digits of the significand: 1-53 for 64 bit double precision // Precision 0 is the 'no precision specified case', which defaults to 64 bit double precision SLONG precision = $3; if (precision != 0 && (precision < 1 || precision > 53)) yyabandon(YYPOSNARG(3), -842, Arg::Gds(isc_precision_err2) << Arg::Num(1) << Arg::Num(53)); // Precision must be between 1 and 53 $$ = newNode(); $$->dtype = dtype_double; $$->length = sizeof(double); } | REAL { $$ = newNode(); $$->dtype = dtype_real; $$->length = sizeof(float); } | DOUBLE PRECISION { $$ = newNode(); $$->dtype = dtype_double; $$->length = sizeof(double); } ; // optional precision that does not allow zero %type precision_opt_nz precision_opt_nz : /* nothing */ { $$ = 0; } | '(' pos_short_integer ')' { $$ = $2; } ; // transaction statements %type savepoint savepoint : set_savepoint | release_savepoint | undo_savepoint ; %type set_savepoint set_savepoint : SAVEPOINT symbol_savepoint_name { $$ = newNode(UserSavepointNode::CMD_SET, *$2); } ; %type release_savepoint release_savepoint : RELEASE SAVEPOINT symbol_savepoint_name { $$ = newNode(UserSavepointNode::CMD_RELEASE, *$3); } | RELEASE SAVEPOINT symbol_savepoint_name ONLY { $$ = newNode(UserSavepointNode::CMD_RELEASE_ONLY, *$3); } ; %type undo_savepoint undo_savepoint : ROLLBACK optional_work TO optional_savepoint symbol_savepoint_name { $$ = newNode(UserSavepointNode::CMD_ROLLBACK, *$5); } ; optional_savepoint : // nothing | SAVEPOINT ; %type commit commit : COMMIT optional_work optional_retain { $$ = newNode(CommitRollbackNode::CMD_COMMIT, $3); } ; %type rollback rollback : ROLLBACK optional_work optional_retain { $$ = newNode(CommitRollbackNode::CMD_ROLLBACK, $3); } ; optional_work : // nothing | WORK ; %type optional_retain optional_retain : /* nothing */ { $$ = false; } | RETAIN opt_snapshot { $$ = true; } ; opt_snapshot : // nothing | SNAPSHOT ; %type set_transaction set_transaction : SET TRANSACTION { $$ = newNode(); } tran_option_list_opt($3) { $$ = $3; } ; %type session_reset session_reset : ALTER SESSION RESET { $$ = newNode(); } ; %type set_role set_role : SET ROLE valid_symbol_name { $$ = newNode($3); } | SET TRUSTED ROLE { $$ = newNode(); } ; %type set_debug_option set_debug_option : SET DEBUG OPTION valid_symbol_name '=' constant { $$ = newNode($4, $6); } ; %type set_decfloat_round set_decfloat_round : SET DECFLOAT ROUND valid_symbol_name { $$ = newNode($4); } ; %type set_decfloat_traps set_decfloat_traps : SET DECFLOAT TRAPS TO { $$ = newNode(); } decfloat_traps_list_opt($5) { $$ = $5; } ; %type set_bind set_bind : SET BIND OF set_bind_from TO set_bind_to { $$ = newNode(); $$->from = $4; $$->to = $6; } ; %type set_bind_from set_bind_from : bind_type | TIME ZONE { $$ = newNode(); $$->dtype = dtype_timestamp_tz; $$->length = 0; } ; %type bind_type bind_type : non_array_type | varying_keyword { $$ = newNode(); $$->dtype = dtype_varying; $$->charLength = 0; } ; %type set_bind_to set_bind_to : bind_type { $$ = $1; } | LEGACY { $$ = newNode(); $$->flags = FLD_legacy; } | NATIVE { $$ = newNode(); $$->flags = FLD_native; } | EXTENDED { $$ = newNode(); $$->flags = FLD_extended; } | EXTENDED TIME WITH TIME ZONE { $$ = newNode(); checkTimeDialect(); $$->dtype = dtype_ex_time_tz; $$->length = sizeof(ISC_TIME_TZ_EX); $$->flags |= FLD_has_prec; } | EXTENDED TIMESTAMP WITH TIME ZONE { $$ = newNode(); $$->dtype = dtype_ex_timestamp_tz; $$->length = sizeof(ISC_TIMESTAMP_TZ_EX); $$->flags |= FLD_has_prec; } ; %type decfloat_traps_list_opt() decfloat_traps_list_opt($setDecFloatTrapsNode) : // nothing | decfloat_traps_list($setDecFloatTrapsNode) ; %type decfloat_traps_list() decfloat_traps_list($setDecFloatTrapsNode) : decfloat_trap($setDecFloatTrapsNode) | decfloat_traps_list ',' decfloat_trap($setDecFloatTrapsNode) ; %type decfloat_trap() decfloat_trap($setDecFloatTrapsNode) : valid_symbol_name { $setDecFloatTrapsNode->trap($1); } ; %type set_optimize set_optimize : SET OPTIMIZE optimize_mode { $$ = newNode($3); } | SET OPTIMIZE TO DEFAULT { $$ = newNode(); } ; %type session_statement session_statement : SET SESSION IDLE TIMEOUT long_integer timepart_sesion_idle_tout { $$ = newNode(SetSessionNode::TYPE_IDLE_TIMEOUT, $5, $6); } | SET STATEMENT TIMEOUT long_integer timepart_ses_stmt_tout { $$ = newNode(SetSessionNode::TYPE_STMT_TIMEOUT, $4, $5); } ; %type timepart_sesion_idle_tout timepart_sesion_idle_tout : /* nothing */ { $$ = blr_extract_minute; } | HOUR { $$ = blr_extract_hour; } | MINUTE { $$ = blr_extract_minute; } | SECOND { $$ = blr_extract_second; } ; %type timepart_ses_stmt_tout timepart_ses_stmt_tout : /* nothing */ { $$ = blr_extract_second; } | HOUR { $$ = blr_extract_hour; } | MINUTE { $$ = blr_extract_minute; } | SECOND { $$ = blr_extract_second; } | MILLISECOND { $$ = blr_extract_millisecond; } ; %type set_time_zone set_time_zone : SET TIME ZONE set_time_zone_option { $$ = $4; } ; %type set_time_zone_option set_time_zone_option : sql_string { $$ = newNode($1->getString()); } | LOCAL { $$ = newNode(); } ; %type tran_option_list_opt() tran_option_list_opt($setTransactionNode) : // nothing | tran_option_list($setTransactionNode) ; %type tran_option_list() tran_option_list($setTransactionNode) : tran_option($setTransactionNode) | tran_option_list tran_option($setTransactionNode) ; %type tran_option() tran_option($setTransactionNode) // access mode : READ ONLY { setClause($setTransactionNode->readOnly, "READ {ONLY | WRITE}", true); } | READ WRITE { setClause($setTransactionNode->readOnly, "READ {ONLY | WRITE}", false); } // wait mode | WAIT { setClause($setTransactionNode->wait, "[NO] WAIT", true); } | NO WAIT { setClause($setTransactionNode->wait, "[NO] WAIT", false); } // isolation mode | isolation_mode($setTransactionNode) { setClause($setTransactionNode->isoLevel, "ISOLATION LEVEL", $1); } // misc options | NO AUTO UNDO { setClause($setTransactionNode->noAutoUndo, "NO AUTO UNDO", true); } | IGNORE LIMBO { setClause($setTransactionNode->ignoreLimbo, "IGNORE LIMBO", true); } | RESTART REQUESTS { setClause($setTransactionNode->restartRequests, "RESTART REQUESTS", true); } | AUTO COMMIT { setClause($setTransactionNode->autoCommit, "AUTO COMMIT", true); } | AUTO RELEASE TEMP BLOBID { setClause($setTransactionNode->autoReleaseTempBlobID, "AUTO RELEASE TEMP BLOBID", true); } // timeout | LOCK TIMEOUT nonneg_short_integer { setClause($setTransactionNode->lockTimeout, "LOCK TIMEOUT", (USHORT) $3); } // reserve options | RESERVING { checkDuplicateClause($setTransactionNode->reserveList, "RESERVING"); } restr_list($setTransactionNode) ; %type isolation_mode() isolation_mode($setTransactionNode) : ISOLATION LEVEL iso_mode($setTransactionNode) { $$ = $3;} | iso_mode ; %type iso_mode() iso_mode($setTransactionNode) : snap_shot($setTransactionNode) { $$ = $1; } | READ UNCOMMITTED version_mode { $$ = $3; } | READ COMMITTED version_mode { $$ = $3; } ; %type snap_shot() snap_shot($setTransactionNode) : SNAPSHOT { $$ = SetTransactionNode::ISO_LEVEL_CONCURRENCY; } | SNAPSHOT AT NUMBER snapshot_number { setClause($setTransactionNode->atSnapshotNumber, "SNAPSHOT AT NUMBER", (CommitNumber) $4); $$ = SetTransactionNode::ISO_LEVEL_CONCURRENCY; } | SNAPSHOT TABLE { $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; } | SNAPSHOT TABLE STABILITY { $$ = SetTransactionNode::ISO_LEVEL_CONSISTENCY; } ; %type snapshot_number snapshot_number : NUMBER32BIT { $$ = $1; } | NUMBER64BIT { $$ = $1.number; } ; %type version_mode version_mode : /* nothing */ { $$ = SetTransactionNode::ISO_LEVEL_READ_COMMITTED_NO_REC_VERSION; } | VERSION { $$ = SetTransactionNode::ISO_LEVEL_READ_COMMITTED_REC_VERSION; } | NO VERSION { $$ = SetTransactionNode::ISO_LEVEL_READ_COMMITTED_NO_REC_VERSION; } | READ CONSISTENCY { $$ = SetTransactionNode::ISO_LEVEL_READ_COMMITTED_READ_CONSISTENCY; } ; %type lock_type lock_type : /* nothing */ { $$ = 0; } | SHARED { $$ = SetTransactionNode::LOCK_MODE_SHARED; } | PROTECTED { $$ = SetTransactionNode::LOCK_MODE_PROTECTED; } ; %type lock_mode lock_mode : READ { $$ = SetTransactionNode::LOCK_MODE_READ; } | WRITE { $$ = SetTransactionNode::LOCK_MODE_WRITE; } ; %type restr_list() restr_list($setTransactionNode) : restr_option { $setTransactionNode->reserveList.add($1); } | restr_list ',' restr_option { $setTransactionNode->reserveList.add($3); } ; %type restr_option restr_option : table_list table_lock { $$ = newNode($1, $2); } ; %type table_lock table_lock : /* nothing */ { $$ = 0; } | FOR lock_type lock_mode { $$ = $2 | $3; } ; %type table_list table_list : symbol_table_name { ObjectsArray* node = newNode >(); node->add(*$1); $$ = node; } | table_list ',' symbol_table_name { ObjectsArray* node = $1; node->add(*$3); $$ = node; } ; %type set_statistics set_statistics : SET STATISTICS INDEX symbol_index_name { $$ = newNode(*$4); } ; %type comment comment : COMMENT ON ddl_type0 IS ddl_desc { $$ = newNode($3, QualifiedName(""), "", *$5); } | COMMENT ON ddl_type1 symbol_ddl_name IS ddl_desc { $$ = newNode($3, QualifiedName(*$4), "", *$6); } | COMMENT ON ddl_type2 symbol_ddl_name ddl_subname IS ddl_desc { $$ = newNode($3, QualifiedName(*$4), *$5, *$7); } | COMMENT ON ddl_type3 ddl_qualified_name ddl_subname IS ddl_desc { $$ = newNode($3, *$4, *$5, *$7); } | COMMENT ON ddl_type4 ddl_qualified_name IS ddl_desc { $$ = newNode($3, *$4, "", *$6); } | comment_on_user { $$ = $1; } | comment_on_mapping { $$ = $1; } ; %type comment_on_user comment_on_user : COMMENT ON USER symbol_user_name { $$ = newNode(CreateAlterUserNode::USER_MOD, *$4); } opt_use_plugin($5) IS ddl_desc { CreateAlterUserNode* node = $$ = $5; node->comment = $8; } ; %type opt_use_plugin() opt_use_plugin($node) : // nothing | use_plugin($node) ; %type ddl_type0 ddl_type0 : DATABASE { $$ = obj_database; } ; %type ddl_type1 ddl_type1 : DOMAIN { $$ = obj_field; } | TABLE { $$ = obj_relation; } | VIEW { $$ = obj_view; } | TRIGGER { $$ = obj_trigger; } | FILTER { $$ = obj_blob_filter; } | EXCEPTION { $$ = obj_exception; } | GENERATOR { $$ = obj_generator; } | SEQUENCE { $$ = obj_generator; } | INDEX { $$ = obj_index; } | ROLE { $$ = obj_sql_role; } | CHARACTER SET { $$ = obj_charset; } | COLLATION { $$ = obj_collation; } | PACKAGE { $$ = obj_package_header; } /*** | SECURITY CLASS { $$ = ddl_sec_class; } ***/ ; %type ddl_type2 ddl_type2 : COLUMN { $$ = obj_relation; } ; %type ddl_type3 ddl_type3 : PARAMETER { $$ = obj_parameter; } | PROCEDURE PARAMETER { $$ = obj_procedure; } | FUNCTION PARAMETER { $$ = obj_udf; } ; %type ddl_type4 ddl_type4 : PROCEDURE { $$ = obj_procedure; } | EXTERNAL FUNCTION { $$ = obj_udf; } | FUNCTION { $$ = obj_udf; } ; %type ddl_subname ddl_subname : '.' symbol_ddl_name { $$ = $2; } ; %type ddl_qualified_name ddl_qualified_name : symbol_ddl_name { $$ = newNode(*$1); } | symbol_ddl_name '.' symbol_ddl_name { $$ = newNode(*$3, *$1); } ; %type ddl_desc ddl_desc : utf_string { $$ = $1; } | NULL { $$ = newString(""); } ; // SELECT statement %type select select : select_expr for_update_clause lock_clause optimize_clause { SelectNode* node = newNode(); node->selectExpr = $1; node->forUpdate = $2; node->withLock = $3.first; node->skipLocked = $3.second; node->optimizeForFirstRows = $4; $$ = node; } ; %type for_update_clause for_update_clause : /* nothing */ { $$ = false; } | FOR UPDATE for_update_list { $$ = true; /* for_update_list is ignored */ } ; %type for_update_list for_update_list : /* nothing */ { $$ = NULL; } | OF column_list { $$ = $2; } ; %type lock_clause lock_clause : /* nothing */ { $$ = {false, false}; } | WITH LOCK skip_locked_clause_opt { $$ = {true, $3}; } ; %type skip_locked_clause_opt skip_locked_clause_opt : /* nothing */ { $$ = false; } | SKIP LOCKED { $$ = true; } ; %type optimize_clause optimize_clause : OPTIMIZE optimize_mode { $$ = TriState($2); } | // nothing { $$ = TriState(); } ; %type optimize_mode optimize_mode : FOR FIRST ROWS { $$ = true; } | FOR ALL ROWS { $$ = false; } ; // SELECT expression %type select_expr select_expr : with_clause select_expr_body order_clause_opt rows_clause { SelectExprNode* node = $$ = newNode(); node->querySpec = $2; node->orderClause = $3; node->rowsClause = $4; node->withClause = $1; } | with_clause select_expr_body order_clause_opt result_offset_clause fetch_first_clause { SelectExprNode* node = $$ = newNode(); node->querySpec = $2; node->orderClause = $3; if ($4 || $5) { RowsClause* rowsNode = newNode(); rowsNode->skip = $4; rowsNode->length = $5; node->rowsClause = rowsNode; } node->withClause = $1; } ; %type with_clause with_clause : // nothing { $$ = NULL; } | WITH RECURSIVE with_list { $$ = $3; $$->recursive = true; } | WITH with_list { $$ = $2; } ; %type with_list with_list : with_item { $$ = newNode(); $$->add($1); } | with_list ',' with_item { $$ = $1; $$->add($3); } ; %type with_item with_item : symbol_table_alias_name derived_column_list AS '(' select_expr ')' { $$ = $5; $$->dsqlFlags |= RecordSourceNode::DFLAG_DERIVED; $$->alias = $1->c_str(); $$->columns = $2; } ; %type column_select column_select : select_expr { $$ = $1; $$->dsqlFlags |= RecordSourceNode::DFLAG_VALUE; } ; %type column_singleton column_singleton : column_select { $1->dsqlFlags |= RecordSourceNode::DFLAG_SINGLETON; $$ = newNode(blr_via, $1); } ; %type select_expr_body select_expr_body : query_term { $$ = $1; } | select_expr_body UNION distinct_noise query_term { UnionSourceNode* node = nodeAs($1); if (node && !node->dsqlAll) node->dsqlClauses->add($4); else { node = newNode(); node->dsqlClauses = newNode($1)->add($4); } $$ = node; } | select_expr_body UNION ALL query_term { UnionSourceNode* node = nodeAs($1); if (node && node->dsqlAll) node->dsqlClauses->add($4); else { node = newNode(); node->dsqlAll = true; node->dsqlClauses = newNode($1)->add($4); } $$ = node; } ; %type query_term query_term : query_primary ; %type query_primary query_primary : query_spec { $$ = $1; } | '(' select_expr_body order_clause_opt result_offset_clause fetch_first_clause ')' { if ($3 || $4 || $5) { const auto selectExpr = newNode(); selectExpr->dsqlFlags |= RecordSourceNode::DFLAG_DERIVED; selectExpr->querySpec = $2; selectExpr->orderClause = $3; if ($4 || $5) { const auto rowsNode = newNode(); rowsNode->skip = $4; rowsNode->length = $5; selectExpr->rowsClause = rowsNode; } const auto rse = newNode(); rse->dsqlFlags |= RecordSourceNode::DFLAG_BODY_WRAPPER; rse->dsqlFrom = newNode(selectExpr); $$ = rse; } else $$ = $2; } ; %type query_spec query_spec : SELECT limit_clause distinct_clause select_list from_clause where_clause group_clause having_clause named_windows_clause plan_clause { RseNode* rse = newNode(); rse->dsqlFirst = $2 ? $2->items[1] : NULL; rse->dsqlSkip = $2 ? $2->items[0] : NULL; rse->dsqlDistinct = $3; rse->dsqlSelectList = $4->items.hasData() ? $4 : nullptr; rse->dsqlFrom = $5; rse->dsqlWhere = $6; rse->dsqlGroup = $7; rse->dsqlHaving = $8; rse->dsqlNamedWindows = $9; rse->rse_plan = $10; $$ = rse; } ; %type limit_clause limit_clause : /* nothing */ { $$ = NULL; } | first_clause skip_clause { $$ = newNode($2)->add($1); } | first_clause { $$ = newNode(1u)->add($1); } | skip_clause { $$ = newNode($1)->add(NULL); } ; %type first_clause first_clause : FIRST long_integer { $$ = MAKE_const_slong($2); } | FIRST '(' value ')' { $$ = $3; } | FIRST parameter { $$ = $2; } ; %type skip_clause skip_clause : SKIP long_integer { $$ = MAKE_const_slong($2); } | SKIP '(' value ')' { $$ = $3; } | SKIP parameter { $$ = $2; } ; %type distinct_clause distinct_clause : DISTINCT { $$ = newNode(0u); } | all_noise { $$ = NULL; } ; %type select_list select_list : select_items { $$ = $1; } | '*' { $$ = newNode(0u); } ; %type select_items select_items : select_item { $$ = newNode($1); } | select_items ',' select_item { $$ = $1->add($3); } ; %type select_item select_item : value_opt_alias | symbol_table_alias_name '.' '*' { FieldNode* fieldNode = newNode(); fieldNode->dsqlQualifier = *$1; $$ = fieldNode; } ; %type value_opt_alias value_opt_alias : value | value as_noise symbol_item_alias_name { $$ = newNode(*$3, $1); } ; as_noise : | AS ; // FROM clause %type from_clause from_clause : FROM from_list { $$ = $2; } ; %type from_list from_list : table_reference { $$ = newNode($1); } | from_list ',' table_reference { $$ = $1->add($3); } ; %type table_reference table_reference : joined_table | table_primary ; %type table_primary table_primary : table_proc | derived_table { $$ = $1; } | lateral_derived_table { $$ = $1; } | parenthesized_joined_table { $$ = $1; } ; %type parenthesized_joined_table parenthesized_joined_table : '(' parenthesized_joined_table ')' { $$ = $2; } | '(' joined_table ')' { $$ = $2; } ; %type derived_table derived_table : '(' select_expr ')' correlation_name_opt derived_column_list { $$ = $2; $$->dsqlFlags |= RecordSourceNode::DFLAG_DERIVED; if ($4) $$->alias = $4->c_str(); $$->columns = $5; } ; %type lateral_derived_table lateral_derived_table : LATERAL derived_table { $$ = $2; $$->dsqlFlags |= RecordSourceNode::DFLAG_LATERAL; } ; %type correlation_name_opt correlation_name_opt : /* nothing */ { $$ = nullptr; } | symbol_table_alias_name | AS symbol_table_alias_name { $$ = $2; } ; %type derived_column_list derived_column_list : /* nothing */ { $$ = NULL; } | '(' alias_list ')' { $$ = $2; } ; %type alias_list alias_list : symbol_item_alias_name { ObjectsArray* node = newNode >(); node->add(*$1); $$ = node; } | alias_list ',' symbol_item_alias_name { ObjectsArray* node = $1; node->add(*$3); $$ = node; } ; %type joined_table joined_table : cross_join | natural_join | qualified_join ; %type cross_join cross_join : table_reference CROSS JOIN table_primary { RseNode* rse = newNode(); rse->dsqlExplicitJoin = true; rse->rse_jointype = blr_inner; rse->dsqlFrom = newNode($1)->add($4); $$ = rse; } ; %type natural_join natural_join : table_reference NATURAL join_type JOIN table_primary { RseNode* rse = newNode(); rse->dsqlExplicitJoin = true; rse->rse_jointype = $3; rse->dsqlFrom = newNode($1)->add($5); rse->dsqlJoinUsing = newNode(0u); // using list with size 0 -> natural $$ = rse; } ; %type qualified_join qualified_join : table_reference join_type JOIN table_reference join_condition { RseNode* rse = newNode(); rse->dsqlExplicitJoin = true; rse->rse_jointype = $2; rse->dsqlFrom = newNode($1); rse->dsqlFrom->add($4); rse->dsqlWhere = $5; $$ = rse; } | table_reference join_type JOIN table_reference named_columns_join { RseNode* rse = newNode(); rse->dsqlExplicitJoin = true; rse->rse_jointype = $2; rse->dsqlFrom = newNode($1); rse->dsqlFrom->add($4); rse->dsqlJoinUsing = $5; $$ = rse; } ; %type join_condition join_condition : ON search_condition { $$ = $2; } ; %type named_columns_join named_columns_join : USING '(' column_list ')' { $$ = $3; } ; %type table_proc table_proc : symbol_procedure_name table_proc_inputs as_noise symbol_table_alias_name { const auto node = newNode(QualifiedName(*$1)); node->inputSources = $2 ? $2->second : nullptr; node->dsqlInputArgNames = $2 ? $2->first : nullptr; node->alias = $4->c_str(); $$ = node; } | symbol_procedure_name table_proc_inputs { const auto node = newNode(QualifiedName(*$1)); node->inputSources = $2 ? $2->second : nullptr; node->dsqlInputArgNames = $2 ? $2->first : nullptr; $$ = node; } | symbol_package_name '.' symbol_procedure_name table_proc_inputs as_noise symbol_table_alias_name { const auto node = newNode( QualifiedName(*$3, *$1)); node->inputSources = $4 ? $4->second : nullptr; node->dsqlInputArgNames = $4 ? $4->first : nullptr; node->alias = $6->c_str(); $$ = node; } | symbol_package_name '.' symbol_procedure_name table_proc_inputs { const auto node = newNode( QualifiedName(*$3, *$1)); node->inputSources = $4 ? $4->second : nullptr; node->dsqlInputArgNames = $4 ? $4->first : nullptr; $$ = node; } ; %type table_proc_inputs table_proc_inputs : /* nothing */ { $$ = nullptr; } | '(' argument_list ')' { $$ = $2; } ; %type table_name table_name : simple_table_name | symbol_table_name as_noise symbol_table_alias_name { RelationSourceNode* node = newNode(*$1); node->alias = $3->c_str(); $$ = node; } ; %type simple_table_name simple_table_name : symbol_table_name { $$ = newNode(*$1); } ; %type join_type join_type : /* nothing */ { $$ = blr_inner; } | INNER { $$ = blr_inner; } | LEFT outer_noise { $$ = blr_left; } | RIGHT outer_noise { $$ = blr_right; } | FULL outer_noise { $$ = blr_full; } ; outer_noise : | OUTER ; // other clauses in the select expression %type group_clause group_clause : /* nothing */ { $$ = NULL; } | GROUP BY group_by_list { $$ = $3; } ; %type group_by_list group_by_list : group_by_item { $$ = newNode($1); } | group_by_list ',' group_by_item { $$ = $1->add($3); } ; // Except aggregate-functions are all expressions supported in group_by_item, // they are caught inside pass1.cpp %type group_by_item group_by_item : value ; %type having_clause having_clause : /* nothing */ { $$ = NULL; } | HAVING search_condition { $$ = $2; } ; %type where_clause where_clause : /* nothing */ { $$ = NULL; } | WHERE search_condition { $$ = $2; } ; %type named_windows_clause named_windows_clause : /* nothing */ { $$ = NULL; } | WINDOW window_definition_list { $$ = $2; } ; %type window_definition_list window_definition_list : window_definition { NamedWindowsClause* node = newNode(); node->add(*$1); $$ = node; } | window_definition_list ',' window_definition { NamedWindowsClause* node = $1; node->add(*$3); $$ = node; } ; %type window_definition window_definition : symbol_window_name AS '(' window_clause ')' { $$ = newNode(*$1, $4); } ; %type symbol_window_name_opt symbol_window_name_opt : /* nothing */ { $$ = NULL; } | symbol_window_name ; // PLAN clause to specify an access plan for a query %type plan_clause plan_clause : /* nothing */ { $$ = NULL; } | PLAN plan_expression { $$ = $2; } ; %type plan_expression plan_expression : plan_type { $$ = newNode(PlanNode::TYPE_RETRIEVE); } '(' plan_item_list($2) ')' { $$ = $2; } ; plan_type : // nothing | JOIN | SORT MERGE | MERGE | HASH | SORT ; %type plan_item_list() plan_item_list($planNode) : plan_item { $planNode->subNodes.add($1); } | plan_item_list ',' plan_item { $planNode->subNodes.add($3); } ; %type plan_item plan_item : table_or_alias_list access_type { $$ = newNode(PlanNode::TYPE_RETRIEVE); $$->dsqlNames = $1; $$->accessType = $2; } | plan_expression ; %type table_or_alias_list table_or_alias_list : symbol_table_name { ObjectsArray* node = newNode >(); node->add(*$1); $$ = node; } | table_or_alias_list symbol_table_name { ObjectsArray* node = $1; node->add(*$2); $$ = node; } ; %type access_type access_type : NATURAL { $$ = newNode(PlanNode::AccessType::TYPE_SEQUENTIAL); } | INDEX { $$ = newNode(PlanNode::AccessType::TYPE_INDICES); } '(' index_list($2) ')' { $$ = $2; } | ORDER { $$ = newNode(PlanNode::AccessType::TYPE_NAVIGATIONAL); } symbol_index_name extra_indices_opt($2) { $$ = $2; $$->items.insert(0).indexName = *$3; } ; %type index_list() index_list($accessType) : symbol_index_name { PlanNode::AccessItem& item = $accessType->items.add(); item.indexName = *$1; } | index_list ',' symbol_index_name { PlanNode::AccessItem& item = $accessType->items.add(); item.indexName = *$3; } ; %type extra_indices_opt() extra_indices_opt($accessType) : // nothing | INDEX '(' index_list($accessType) ')' ; // ORDER BY clause %type order_clause_opt order_clause_opt : /* nothing */ { $$ = NULL; } | order_clause ; %type order_clause order_clause : ORDER BY order_list { $$ = $3; } ; %type order_list order_list : order_item { $$ = newNode($1); } | order_list ',' order_item { $$ = $1->add($3); } ; %type order_item order_item : value order_direction nulls_clause { OrderNode* node = newNode($1); node->descending = $2; node->nullsPlacement = $3; $$ = node; } ; %type order_direction order_direction : /* nothing */ { $$ = false; } | ASC { $$ = false; } | DESC { $$ = true; } ; %type nulls_clause nulls_clause : /* nothing */ { $$ = OrderNode::NULLS_DEFAULT; } | NULLS nulls_placement { $$ = $2; } ; %type nulls_placement nulls_placement : FIRST { $$ = OrderNode::NULLS_FIRST; } | LAST { $$ = OrderNode::NULLS_LAST; } ; // ROWS clause - ROWS clause is a non-standard alternative to OFFSET .. FETCH .. // Non-optional - for use in select_expr (so it doesn't cause conflicts with OFFSET .. FETCH ..) %type rows_clause rows_clause // equivalent to FIRST value : ROWS value { $$ = newNode(); $$->length = $2; } // equivalent to FIRST (upper_value - lower_value + 1) SKIP (lower_value - 1) | ROWS value TO value { $$ = newNode(); $$->skip = newNode(blr_subtract, true, $2, MAKE_const_slong(1)); $$->length = newNode(blr_add, true, newNode(blr_subtract, true, $4, $2), MAKE_const_slong(1)); } ; // Optional - for use in delete_searched and update_searched %type rows_clause_optional rows_clause_optional : /* nothing */ { $$ = NULL; } | rows_clause ; // OFFSET n {ROW | ROWS} row_noise : ROW | ROWS ; %type result_offset_clause result_offset_clause : /* nothing */ { $$ = NULL; } | OFFSET simple_value_spec row_noise { $$ = $2; } ; // FETCH {FIRST | NEXT} [ n ] {ROW | ROWS} ONLY first_next_noise : FIRST | NEXT ; %type fetch_first_clause fetch_first_clause : /* nothing */ { $$ = NULL; } | FETCH first_next_noise simple_value_spec row_noise ONLY { $$ = $3; } | FETCH first_next_noise row_noise ONLY { $$ = MAKE_const_slong(1); } ; // INSERT statement // IBO hack: replace column_parens_opt by ins_column_parens_opt. %type insert insert : insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt VALUES '(' value_or_default_list ')' returning_clause { StoreNode* node = $$ = $1; node->overrideClause = $3; node->dsqlValues = $6; node->dsqlReturning = $8; } | insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt select_expr returning_clause { StoreNode* node = $$ = $1; node->overrideClause = $3; node->dsqlRse = $4; node->dsqlReturning = $5; $$ = node; } | insert_start DEFAULT VALUES returning_clause { StoreNode* node = $$ = $1; node->dsqlReturning = $4; $$ = node; } ; %type insert_start insert_start : INSERT INTO simple_table_name { StoreNode* node = newNode(); node->target = $3; $$ = node; } ; %type override_opt override_opt : /* nothing */ { $$ = std::nullopt; } | OVERRIDING USER VALUE { $$ = OverrideClause::USER_VALUE; } | OVERRIDING SYSTEM VALUE { $$ = OverrideClause::SYSTEM_VALUE; } ; %type value_or_default_list value_or_default_list : value_or_default { $$ = newNode($1); } | value_or_default_list ',' value_or_default { $$ = $1->add($3); } ; %type value_or_default value_or_default : value | DEFAULT { $$ = NULL; } ; // MERGE statement %type merge merge : MERGE INTO table_name USING table_reference ON search_condition { MergeNode* node = $$ = newNode(); node->relation = $3; node->usingClause = $5; node->condition = $7; } merge_when_clause($8) plan_clause order_clause_opt returning_clause { MergeNode* node = $$ = $8; node->plan = $10; node->order = $11; node->returning = $12; } ; %type merge_when_clause() merge_when_clause($mergeNode) : merge_when_matched_clause($mergeNode) | merge_when_not_matched_clause($mergeNode) | merge_when_clause merge_when_matched_clause($mergeNode) | merge_when_clause merge_when_not_matched_clause($mergeNode) ; %type merge_when_matched_clause() merge_when_matched_clause($mergeNode) : WHEN MATCHED { $$ = &$mergeNode->whenMatched.add(); } merge_update_specification(NOTRIAL($3), NOTRIAL(&$mergeNode->relation->dsqlName)) ; %type merge_when_not_matched_clause() merge_when_not_matched_clause($mergeNode) : WHEN NOT MATCHED by_target_noise { $$ = &$mergeNode->whenNotMatchedByTarget.add(); } merge_insert_specification(NOTRIAL($5)) | WHEN NOT MATCHED BY SOURCE { $$ = &$mergeNode->whenNotMatchedBySource.add(); } merge_update_specification(NOTRIAL($6), NOTRIAL(&$mergeNode->relation->dsqlName)) ; by_target_noise : // empty | BY TARGET ; %type merge_update_specification(, ) merge_update_specification($mergeMatchedClause, $relationName) : THEN UPDATE SET update_assignments(NOTRIAL($relationName)) { $mergeMatchedClause->assignments = $4; } | AND search_condition THEN UPDATE SET update_assignments(NOTRIAL($relationName)) { $mergeMatchedClause->condition = $2; $mergeMatchedClause->assignments = $6; } | THEN DELETE | AND search_condition THEN DELETE { $mergeMatchedClause->condition = $2; } ; %type merge_insert_specification() merge_insert_specification($mergeNotMatchedClause) : THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt VALUES '(' value_or_default_list ')' { $mergeNotMatchedClause->overrideClause = $4; $mergeNotMatchedClause->values = $7; } | AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt VALUES '(' value_or_default_list ')' { $mergeNotMatchedClause->overrideClause = $6; $mergeNotMatchedClause->values = $9; $mergeNotMatchedClause->condition = $2; } ; // DELETE statement %type delete delete : delete_searched | delete_positioned ; %type delete_searched delete_searched : DELETE FROM table_name where_clause plan_clause order_clause_opt rows_clause_optional skip_locked_clause_opt returning_clause { const auto node = newNode(); node->dsqlRelation = $3; node->dsqlBoolean = $4; node->dsqlPlan = $5; node->dsqlOrder = $6; node->dsqlRows = $7; node->dsqlSkipLocked = $8; node->dsqlReturning = $9; $$ = node; } ; %type delete_positioned delete_positioned : DELETE FROM table_name cursor_clause returning_clause { EraseNode* node = newNode(); node->dsqlRelation = $3; node->dsqlCursorName = *$4; node->dsqlReturning = $5; $$ = node; } ; // UPDATE statement %type update update : update_searched | update_positioned ; %type update_searched update_searched : UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) where_clause plan_clause order_clause_opt rows_clause_optional skip_locked_clause_opt returning_clause { ModifyNode* node = newNode(); node->dsqlRelation = $2; node->statement = $4; node->dsqlBoolean = $5; node->dsqlPlan = $6; node->dsqlOrder = $7; node->dsqlRows = $8; node->dsqlSkipLocked = $9; node->dsqlReturning = $10; $$ = node; } ; %type update_positioned update_positioned : UPDATE table_name SET update_assignments(NOTRIAL(&$2->dsqlName)) cursor_clause returning_clause { ModifyNode* node = newNode(); node->dsqlRelation = $2; node->statement = $4; node->dsqlCursorName = *$5; node->dsqlReturning = $6; $$ = node; } ; // UPDATE OR INSERT statement %type update_or_insert update_or_insert : UPDATE OR INSERT INTO simple_table_name { UpdateOrInsertNode* node = $$ = newNode(); node->relation = $5; } ins_column_parens_opt(NOTRIAL(&$6->fields)) override_opt VALUES '(' value_or_default_list ')' update_or_insert_matching_opt(NOTRIAL(&$6->matching)) plan_clause order_clause_opt rows_clause_optional returning_clause { UpdateOrInsertNode* node = $$ = $6; node->overrideClause = $8; node->values = $11; node->plan = $14; node->order = $15; node->rows = $16; node->returning = $17; } ; %type update_or_insert_matching_opt() update_or_insert_matching_opt($fieldArray) : // nothing | MATCHING ins_column_parens($fieldArray) ; %type returning_clause returning_clause : /* nothing */ { $$ = NULL; } | RETURNING select_list { $$ = FB_NEW_POOL(getPool()) ReturningClause(getPool()); $$->first = $2; } | RETURNING select_list INTO variable_list { $$ = FB_NEW_POOL(getPool()) ReturningClause(getPool()); $$->first = $2; $$->second = $4; } ; %type cursor_clause cursor_clause : WHERE CURRENT OF symbol_cursor_name { $$ = newNode(*$4); } ; // Assignments %type assignment assignment : update_column_name '=' value { AssignmentNode* node = newNode(); node->asgnTo = $1; node->asgnFrom = $3; $$ = node; } ; %type update_assignments() update_assignments($relationName) : update_assignment($relationName) { $$ = newNode(); $$->statements.add($1); } | update_assignments ',' update_assignment($relationName) { $1->statements.add($3); $$ = $1; } ; %type update_assignment() update_assignment($relationName) : update_column_name '=' value { AssignmentNode* node = newNode(); node->asgnTo = $1; node->asgnFrom = $3; $$ = node; } | update_column_name '=' DEFAULT { AssignmentNode* node = newNode(); node->asgnTo = $1; node->asgnFrom = newNode(*$relationName, $1->dsqlName); $$ = node; } ; %type exec_function exec_function : udf { AssignmentNode* node = newNode(); node->asgnTo = NullNode::instance(); node->asgnFrom = $1; $$ = node; } | non_aggregate_function { AssignmentNode* node = newNode(); node->asgnTo = NullNode::instance(); node->asgnFrom = $1; $$ = node; } ; // column specifications %type column_parens_opt column_parens_opt : /* nothing */ { $$ = NULL; } | column_parens ; %type column_parens column_parens : '(' column_list ')' { $$ = $2; } ; %type column_list column_list : simple_column_name { $$ = newNode($1); } | column_list ',' simple_column_name { $$ = $1->add($3); } ; // begin IBO hack %type ins_column_parens_opt() ins_column_parens_opt($fieldArray) : // nothing | ins_column_parens($fieldArray) ; %type ins_column_parens() ins_column_parens($fieldArray) : '(' ins_column_list($fieldArray) ')' ; %type ins_column_list() ins_column_list($fieldArray) : update_column_name { $fieldArray->add($1); } | ins_column_list ',' update_column_name { $fieldArray->add($3); } ; // end IBO hack %type column_name column_name : simple_column_name | symbol_table_alias_name '.' symbol_column_name { FieldNode* fieldNode = newNode(); fieldNode->dsqlQualifier = *$1; fieldNode->dsqlName = *$3; $$ = fieldNode; } | ':' symbol_table_alias_name '.' symbol_column_name { FieldNode* fieldNode = newNode(); fieldNode->dsqlQualifier = *$2; fieldNode->dsqlName = *$4; fieldNode->dsqlCursorField = true; $$ = fieldNode; } ; %type simple_column_name simple_column_name : symbol_column_name { FieldNode* fieldNode = newNode(); fieldNode->dsqlName = *$1; $$ = fieldNode; } ; %type update_column_name 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 { FieldNode* fieldNode = newNode(); fieldNode->dsqlQualifier = *$1; fieldNode->dsqlName = *$3; $$ = fieldNode; } ; // boolean expressions %type search_condition search_condition : value { $$ = valueToBool($1); } ; %type boolean_value_expression boolean_value_expression : predicate | value OR value { $$ = newNode(blr_or, valueToBool($1), valueToBool($3)); } | value AND value { $$ = newNode(blr_and, valueToBool($1), valueToBool($3)); } | NOT value { $$ = newNode(valueToBool($2)); } | '(' boolean_value_expression ')' { $$ = $2; } | value IS boolean_literal { ComparativeBoolNode* node = newNode(blr_equiv, $1, $3); node->dsqlCheckBoolean = true; $$ = node; } | value IS NOT boolean_literal { ComparativeBoolNode* node = newNode(blr_equiv, $1, $4); node->dsqlCheckBoolean = true; $$ = newNode(node); } ; %type predicate predicate : comparison_predicate | distinct_predicate | between_predicate | binary_pattern_predicate | ternary_pattern_predicate | in_predicate | null_predicate | quantified_predicate | exists_predicate | singular_predicate | trigger_action_predicate | session_reset_predicate ; // comparisons %type comparison_predicate comparison_predicate : value comparison_operator value %prec '=' { $$ = newNode($2, $1, $3); } ; %type comparison_operator comparison_operator : '=' { $$ = blr_eql; } | '<' { $$ = blr_lss; } | '>' { $$ = blr_gtr; } | GEQ { $$ = blr_geq; } | LEQ { $$ = blr_leq; } | NOT_GTR { $$ = blr_leq; } | NOT_LSS { $$ = blr_geq; } | NEQ { $$ = blr_neq; } // quantified comparisons %type quantified_predicate quantified_predicate : value comparison_operator quantified_flag '(' column_select ')' { $$ = newNode($2, $1, $3, $5); } ; %type quantified_flag quantified_flag : ALL { $$ = ComparativeBoolNode::DFLAG_ANSI_ALL; } | SOME { $$ = ComparativeBoolNode::DFLAG_ANSI_ANY; } | ANY { $$ = ComparativeBoolNode::DFLAG_ANSI_ANY; } ; // other predicates %type distinct_predicate distinct_predicate : value IS DISTINCT FROM value %prec IS { ComparativeBoolNode* node = newNode(blr_equiv, $1, $5); $$ = newNode(node); } | value IS NOT DISTINCT FROM value %prec IS { $$ = newNode(blr_equiv, $1, $6); } ; %type between_predicate between_predicate : value BETWEEN value_special AND value_special %prec BETWEEN { $$ = newNode(blr_between, $1, $3, $5); } | value NOT BETWEEN value_special AND value_special %prec BETWEEN { ComparativeBoolNode* node = newNode(blr_between, $1, $4, $6); $$ = newNode(node); } ; %type binary_pattern_predicate binary_pattern_predicate : value binary_pattern_operator value %prec CONTAINING { $$ = newNode($2, $1, $3); } | value NOT binary_pattern_operator value %prec CONTAINING { ComparativeBoolNode* cmpNode = newNode($3, $1, $4); $$ = newNode(cmpNode); } ; %type binary_pattern_operator binary_pattern_operator : CONTAINING { $$ = blr_containing; } | STARTING { $$ = blr_starting; } | STARTING WITH { $$ = blr_starting; } ; %type ternary_pattern_predicate ternary_pattern_predicate : value LIKE value %prec LIKE { $$ = newNode(blr_like, $1, $3); } | value LIKE value ESCAPE value %prec LIKE { $$ = newNode(blr_like, $1, $3, $5); } | value NOT LIKE value %prec LIKE { ComparativeBoolNode* node = newNode(blr_like, $1, $4); $$ = newNode(node); } | value NOT LIKE value ESCAPE value %prec LIKE { ComparativeBoolNode* node = newNode(blr_like, $1, $4, $6); $$ = newNode(node); } | value SIMILAR TO value %prec SIMILAR { $$ = newNode(blr_similar, $1, $4); } | value SIMILAR TO value ESCAPE value %prec SIMILAR { $$ = newNode(blr_similar, $1, $4, $6); } | value NOT SIMILAR TO value %prec SIMILAR { ComparativeBoolNode* node = newNode(blr_similar, $1, $5); $$ = newNode(node); } | value NOT SIMILAR TO value ESCAPE value %prec SIMILAR { ComparativeBoolNode* node = newNode(blr_similar, $1, $5, $7); $$ = newNode(node); } ; %type in_predicate in_predicate : value IN in_predicate_value { $$ = newNode(blr_eql, $1, ComparativeBoolNode::DFLAG_ANSI_ANY, $3); } | value NOT IN in_predicate_value { const auto node = newNode(blr_eql, $1, ComparativeBoolNode::DFLAG_ANSI_ANY, $4); $$ = newNode(node); } ; %type exists_predicate exists_predicate : EXISTS '(' select_expr ')' { $$ = newNode(blr_any, $3); } ; %type singular_predicate singular_predicate : SINGULAR '(' select_expr ')' { $$ = newNode(blr_unique, $3); } ; %type trigger_action_predicate trigger_action_predicate : INSERTING { $$ = newNode(blr_eql, newNode(MAKE_const_slong(INFO_TYPE_TRIGGER_ACTION)), MAKE_const_slong(1)); } | UPDATING { $$ = newNode(blr_eql, newNode(MAKE_const_slong(INFO_TYPE_TRIGGER_ACTION)), MAKE_const_slong(2)); } | DELETING { $$ = newNode(blr_eql, newNode(MAKE_const_slong(INFO_TYPE_TRIGGER_ACTION)), MAKE_const_slong(3)); } ; %type session_reset_predicate session_reset_predicate : RESETTING { $$ = newNode(blr_eql, newNode(MAKE_const_slong(INFO_TYPE_SESSION_RESETTING)), MAKE_const_slong(1)); } %type null_predicate null_predicate : value IS NULL { $$ = newNode($1); } | value IS UNKNOWN { $$ = newNode($1, true); } | value IS NOT NULL { $$ = newNode(newNode($1)); } | value IS NOT UNKNOWN { $$ = newNode(newNode($1, true)); } ; // set values %type in_predicate_value in_predicate_value : table_subquery { $$ = $1; } | '(' value_list ')' { $$ = $2; } ; %type table_subquery table_subquery : '(' column_select ')' { $$ = $2; } ; // USER control SQL interface %type create_user_clause create_user_clause : symbol_user_name { $$ = newNode(CreateAlterUserNode::USER_ADD, *$1); } user_fixed_list_opt($2) { $$ = $2; } ; %type alter_user_clause alter_user_clause : symbol_user_name set_noise { $$ = newNode(CreateAlterUserNode::USER_MOD, *$1); } user_fixed_list_opt($3) { $$ = $3; } ; %type alter_cur_user_clause alter_cur_user_clause : set_noise { $$ = newNode(CreateAlterUserNode::USER_MOD, ""); } user_fixed_list_opt($2) { $$ = $2; } ; %type replace_user_clause replace_user_clause : symbol_user_name set_noise { $$ = newNode(CreateAlterUserNode::USER_RPL, *$1); } user_fixed_list_opt($3) { $$ = $3; } ; set_noise : // nothing | SET ; %type user_fixed_list_opt() user_fixed_list_opt($node) : // nothing | user_fixed_list($node) ; %type user_fixed_list() user_fixed_list($node) : user_fixed_option($node) | user_fixed_list user_fixed_option($node) ; %type user_fixed_option() user_fixed_option($node) : FIRSTNAME utf_string { setClause($node->firstName, "FIRSTNAME", $2); } | MIDDLENAME utf_string { setClause($node->middleName, "MIDDLENAME", $2); } | LASTNAME utf_string { setClause($node->lastName, "LASTNAME", $2); } | PASSWORD utf_string { setClause($node->password, "PASSWORD", $2); } | GRANT ADMIN ROLE { setClause($node->adminRole, "ADMIN ROLE", true); } | REVOKE ADMIN ROLE { setClause($node->adminRole, "ADMIN ROLE", false); } | ACTIVE { setClause($node->active, "ACTIVE/INACTIVE", true); } | INACTIVE { setClause($node->active, "ACTIVE/INACTIVE", false); } | use_plugin($node) | TAGS '(' user_var_list($node) ')' ; %type use_plugin() use_plugin($node) : USING PLUGIN valid_symbol_name { setClause($node->plugin, "USING PLUGIN", $3); } ; %type user_var_list() user_var_list($node) : user_var_option($node) | user_var_list ',' user_var_option($node) ; %type user_var_option() user_var_option($node) : valid_symbol_name '=' utf_string { $node->addProperty($1, $3); } | DROP valid_symbol_name { $node->addProperty($2); } ; // logons mapping %type create_map_clause() create_map_clause($global) : map_clause(MappingNode::MAP_ADD) { $$ = $1; $$->global = $global; } map_to($2) { $$ = $2; } ; %type alter_map_clause() alter_map_clause($global) : map_clause(MappingNode::MAP_MOD) { $$ = $1; $$->global = $global; } map_to($2) { $$ = $2; } ; %type replace_map_clause() replace_map_clause($global) : map_clause(MappingNode::MAP_RPL) { $$ = $1; $$->global = $global; } map_to($2) { $$ = $2; } ; %type drop_map_clause() drop_map_clause($global) : map_name { MappingNode* node = newNode(MappingNode::MAP_DROP, *$1); node->global = $global; $$ = node; } ; %type comment_on_mapping comment_on_mapping : COMMENT ON MAPPING map_comment(false) { $$ = $4; } | COMMENT ON GLOBAL MAPPING map_comment(true) { $$ = $5; } ; %type map_comment() map_comment($global) : map_name IS ddl_desc { $$ = newNode(MappingNode::MAP_COMMENT, *$1); $$->global = $global; $$->comment = $3; } ; %type map_clause() map_clause($op) : map_name { $$ = newNode($op, *$1); } USING map_using($2) FROM map_from($2) { $$ = $2; } ; %type map_name map_name : valid_symbol_name { $$ = $1; } ; %type map_from() map_from($node) : map_from_symbol_name map_logoninfo { $node->fromType = $1; $node->from = $2; } | ANY map_from_symbol_name { $node->fromType = $2; $node->from = newNode("*"); } ; %type map_from_symbol_name map_from_symbol_name : valid_symbol_name | USER { $$ = newNode("USER"); } | GROUP { $$ = newNode("GROUP"); } ; %type map_logoninfo map_logoninfo : sql_string | valid_symbol_name { $$ = newIntlString($1->c_str(), metadataCharSet->getName()); } ; %type map_using() map_using($node) : PLUGIN valid_symbol_name map_in { $node->mode = 'P'; $node->plugin = $2; $node->db = $3; } | ANY PLUGIN map_in { $node->mode = 'P'; $node->db = $3; } | ANY PLUGIN SERVERWIDE { $node->mode = 'S'; } | MAPPING map_in { $node->mode = 'M'; $node->db = $2; } | '*' map_in { $node->mode = '*'; $node->db = $2; } ; %type map_in map_in : /* nothing */ { $$ = NULL; } | IN valid_symbol_name { $$ = $2; } ; %type map_to() map_to($node) : TO map_role valid_symbol_name { $node->role = $2; $node->to = $3; } | TO map_role { $node->role = $2; } ; %type map_role map_role : ROLE { $$ = true; } | USER { $$ = false; } ; // value types %type value value : value_primary | boolean_value_expression { $$ = newNode($1); } ; // Used in situations that is not possible to use non-parenthesized boolean expressions. %type value_special value_special : value_primary | '(' boolean_value_expression ')' { $$ = newNode($2); } ; %type value_primary value_primary : nonparenthesized_value | '(' value_primary ')' { $$ = $2; } ; // Matches definition of in SQL standard %type simple_value_spec simple_value_spec : constant | variable | parameter ; %type nonparenthesized_value nonparenthesized_value : column_name { $$ = $1; } | array_element | function { $$ = $1; } | u_constant | boolean_literal | parameter | variable | cast_specification | case_expression | next_value_expression { $$ = $1; } | udf { $$ = $1; } | '-' value_special %prec UMINUS { $$ = newNode($2); } | '+' value_special %prec UPLUS { $$ = $2; } | value_special '+' value_special { $$ = newNode(blr_add, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | value_special CONCATENATE value_special { $$ = newNode($1, $3); } | value_special COLLATE symbol_collation_name { $$ = newNode($1, *$3); } | value_special AT LOCAL %prec AT { $$ = newNode($1, nullptr); } | value_special AT TIME ZONE value_special %prec AT { $$ = newNode($1, $5); } | value_special '-' value_special { $$ = newNode(blr_subtract, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | value_special '*' value_special { $$ = newNode(blr_multiply, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | value_special '/' value_special { $$ = newNode(blr_divide, (client_dialect < SQL_DIALECT_V6_TRANSITION), $1, $3); } | '(' column_singleton ')' { $$ = $2; } | current_user { $$ = $1; } | current_role { $$ = $1; } | internal_info { $$ = $1; } | recordKeyType { $$ = newNode($1); } | symbol_table_alias_name '.' recordKeyType { $$ = newNode($3, *$1); } | VALUE { $$ = newNode(); } | datetime_value_expression { $$ = $1; } | null_value { $$ = $1; } ; %type recordKeyType recordKeyType : DB_KEY { $$ = blr_dbkey; } | RDB_RECORD_VERSION { $$ = blr_record_version2; } ; %type datetime_value_expression datetime_value_expression : CURRENT_DATE { if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("DATE")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("DATE")); } $$ = newNode(); } | LOCALTIME time_precision_opt { if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("TIME")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("TIME")); } $$ = newNode($2); } | CURRENT_TIME time_precision_opt { if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("TIME")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("TIME")); } $$ = newNode($2); } | LOCALTIMESTAMP timestamp_precision_opt { $$ = newNode($2); } | CURRENT_TIMESTAMP timestamp_precision_opt { $$ = newNode($2); } ; %type time_precision_opt time_precision_opt : /* nothing */ { $$ = DEFAULT_TIME_PRECISION; } | '(' nonneg_short_integer ')' { $$ = $2; } ; %type timestamp_precision_opt timestamp_precision_opt : /* nothing */ { $$ = DEFAULT_TIMESTAMP_PRECISION; } | '(' nonneg_short_integer ')' { $$ = $2; } ; %type array_element array_element : column_name '[' value_list ']' { ArrayNode* node = newNode($1); node->field->dsqlIndices = $3; $$ = node; } ; %type value_list_opt value_list_opt : /* nothing */ { $$ = newNode(0); } | value_list { $$ = $1; } ; %type value_list value_list : value { $$ = newNode($1); } | value_list ',' value { $$ = $1->add($3); } ; %type constant constant : u_constant | '-' ul_numeric_constant { $$ = newNode($2); } | '-' LIMIT64_INT { $$ = MAKE_const_sint64(MIN_SINT64, 0); } | '-' LIMIT64_NUMBER { $$ = MAKE_const_sint64(MIN_SINT64, $2->getScale()); } | '-' u_constant_128 { $$ = newNode($2); } | boolean_literal ; %type u_numeric_constant u_numeric_constant : ul_numeric_constant { $$ = $1; } | LIMIT64_NUMBER { $$ = MAKE_constant($1->c_str(), CONSTANT_NUM128, $1->getScale()); } | LIMIT64_INT { $$ = MAKE_constant($1->c_str(), CONSTANT_NUM128); } | u_constant_128 ; %type u_constant_128 u_constant_128 : NUM128 { $$ = MAKE_constant($1->c_str(), CONSTANT_NUM128, $1->getScale()); } ; %type ul_numeric_constant ul_numeric_constant : NUMBER32BIT { $$ = MAKE_const_slong($1); } | FLOAT_NUMBER { $$ = MAKE_constant($1->c_str(), CONSTANT_DOUBLE); } | DECIMAL_NUMBER { $$ = MAKE_constant($1->c_str(), CONSTANT_DECIMAL); } | NUMBER64BIT { SINT64 signedNumber = (SINT64) $1.number; if ($1.hex && signedNumber < 0) $$ = newNode(MAKE_const_sint64(-signedNumber, $1.scale)); else $$ = MAKE_const_sint64(signedNumber, $1.scale); } | SCALEDINT { $$ = MAKE_const_sint64((SINT64) $1.number, $1.scale); } ; %type u_constant u_constant : u_numeric_constant | sql_string { $$ = MAKE_str_constant($1, lex.charSetId); } | DATE STRING { if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("DATE")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("DATE")); } $$ = MAKE_constant($2->getString().c_str(), CONSTANT_DATE); } | TIME STRING { if (client_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_dialect_datatype_unsupport) << Arg::Num(client_dialect) << Arg::Str("TIME")); } if (db_dialect < SQL_DIALECT_V6_TRANSITION) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << Arg::Gds(isc_sql_db_dialect_dtype_unsupport) << Arg::Num(db_dialect) << Arg::Str("TIME")); } $$ = MAKE_constant($2->getString().c_str(), CONSTANT_TIME); } | TIMESTAMP STRING { $$ = MAKE_constant($2->getString().c_str(), CONSTANT_TIMESTAMP); } ; %type boolean_literal boolean_literal : FALSE { $$ = MAKE_constant("", CONSTANT_BOOLEAN); } | TRUE { $$ = MAKE_constant("1", CONSTANT_BOOLEAN); } ; %type parameter parameter : '?' { $$ = make_parameter(); } ; %type current_user current_user : USER { $$ = newNode(); } | CURRENT_USER { $$ = newNode(); } ; %type current_role current_role : CURRENT_ROLE { $$ = newNode(); } ; %type internal_info internal_info : CURRENT_CONNECTION { $$ = newNode(MAKE_const_slong(INFO_TYPE_CONNECTION_ID)); } | CURRENT_TRANSACTION { $$ = newNode(MAKE_const_slong(INFO_TYPE_TRANSACTION_ID)); } | GDSCODE { $$ = newNode(MAKE_const_slong(INFO_TYPE_GDSCODE)); } | SQLCODE { $$ = newNode(MAKE_const_slong(INFO_TYPE_SQLCODE)); } | SQLSTATE { $$ = newNode(MAKE_const_slong(INFO_TYPE_SQLSTATE)); } | ROW_COUNT { $$ = newNode(MAKE_const_slong(INFO_TYPE_ROWS_AFFECTED)); } | RDB_ERROR '(' error_context ')' { $$ = newNode(MAKE_const_slong($3)); } ; %type error_context error_context : GDSCODE { $$ = INFO_TYPE_GDSCODE; } | SQLCODE { $$ = INFO_TYPE_SQLCODE; } | SQLSTATE { $$ = INFO_TYPE_SQLSTATE; } | EXCEPTION { $$ = INFO_TYPE_EXCEPTION; } | MESSAGE { $$ = INFO_TYPE_ERROR_MSG; } ; %type sql_string sql_string : STRING // string in current charset | INTRODUCER [ // feedback for lexer introducerCharSetName = $1; ] STRING // string in specific charset [ introducerCharSetName = nullptr; ] { $$ = $3; $$->setCharSet(*$1); StrMark* mark = strMarks.get($3); if (mark) // hex string is not in strMarks mark->introduced = true; } ; %type utf_string utf_string : sql_string { $$ = newString($1->toUtf8(scratch->getTransaction())); } ; %type signed_short_integer signed_short_integer : nonneg_short_integer | '-' neg_short_integer { $$ = -$2; } ; %type nonneg_short_integer nonneg_short_integer : NUMBER32BIT { if ($1 > SHRT_POS_MAX) yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected $$ = $1; } ; %type neg_short_integer neg_short_integer : NUMBER32BIT { if ($1 > SHRT_NEG_MAX) yyabandon(YYPOSNARG(1), -842, isc_expec_short); // Short integer expected $$ = $1; } ; %type pos_short_integer pos_short_integer : nonneg_short_integer { if ($1 == 0) yyabandon(YYPOSNARG(1), -842, isc_expec_positive); // Positive number expected $$ = $1; } ; %type unsigned_short_integer unsigned_short_integer : NUMBER32BIT { if ($1 > SHRT_UNSIGNED_MAX) yyabandon(YYPOSNARG(1), -842, isc_expec_ushort); // Unsigned short integer expected $$ = $1; } ; %type signed_long_integer signed_long_integer : long_integer | '-' long_integer { $$ = -$2; } ; %type long_integer long_integer : NUMBER32BIT { $$ = $1;} ; // functions %type function function : aggregate_function { $$ = $1; } | non_aggregate_function | over_clause ; %type non_aggregate_function non_aggregate_function : numeric_value_function | string_value_function | system_function_expression ; %type aggregate_function aggregate_function : aggregate_function_prefix | aggregate_function_prefix FILTER '(' WHERE search_condition ')' { $$ = $1; if ($$->aggInfo.blr == blr_agg_count2 && !$$->arg) // count(*) $$->arg = newNode($5, MAKE_const_slong(1), NullNode::instance()); else { fb_assert($$->arg); $$->arg = newNode($5, $$->arg, NullNode::instance()); } } ; %type aggregate_function_prefix aggregate_function_prefix : COUNT '(' '*' ')' { $$ = newNode(false, (client_dialect < SQL_DIALECT_V6_TRANSITION)); } | COUNT '(' all_noise value ')' { $$ = newNode(false, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | COUNT '(' DISTINCT value ')' { $$ = newNode(true, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | SUM '(' all_noise value ')' { $$ = newNode(false, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | SUM '(' DISTINCT value ')' { $$ = newNode(true, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | AVG '(' all_noise value ')' { $$ = newNode(false, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | AVG '(' DISTINCT value ')' { $$ = newNode(true, (client_dialect < SQL_DIALECT_V6_TRANSITION), $4); } | MINIMUM '(' all_noise value ')' { $$ = newNode(MaxMinAggNode::TYPE_MIN, $4); } | MINIMUM '(' DISTINCT value ')' { $$ = newNode(MaxMinAggNode::TYPE_MIN, $4); } | MAXIMUM '(' all_noise value ')' { $$ = newNode(MaxMinAggNode::TYPE_MAX, $4); } | MAXIMUM '(' DISTINCT value ')' { $$ = newNode(MaxMinAggNode::TYPE_MAX, $4); } | LIST '(' all_noise value delimiter_opt ')' { $$ = newNode(false, $4, $5); } | LIST '(' DISTINCT value delimiter_opt ')' { $$ = newNode(true, $4, $5); } | STDDEV_SAMP '(' value ')' { $$ = newNode(StdDevAggNode::TYPE_STDDEV_SAMP, $3); } | STDDEV_POP '(' value ')' { $$ = newNode(StdDevAggNode::TYPE_STDDEV_POP, $3); } | VAR_SAMP '(' value ')' { $$ = newNode(StdDevAggNode::TYPE_VAR_SAMP, $3); } | VAR_POP '(' value ')' { $$ = newNode(StdDevAggNode::TYPE_VAR_POP, $3); } | COVAR_SAMP '(' value ',' value ')' { $$ = newNode(CorrAggNode::TYPE_COVAR_SAMP, $3, $5); } | COVAR_POP '(' value ',' value ')' { $$ = newNode(CorrAggNode::TYPE_COVAR_POP, $3, $5); } | CORR '(' value ',' value ')' { $$ = newNode(CorrAggNode::TYPE_CORR, $3, $5); } | REGR_AVGX '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_AVGX, $3, $5); } | REGR_AVGY '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_AVGY, $3, $5); } | REGR_COUNT '(' value ',' value ')' { $$ = newNode($3, $5); } | REGR_INTERCEPT '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_INTERCEPT, $3, $5); } | REGR_R2 '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_R2, $3, $5); } | REGR_SLOPE '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_SLOPE, $3, $5); } | REGR_SXX '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_SXX, $3, $5); } | REGR_SXY '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_SXY, $3, $5); } | REGR_SYY '(' value ',' value ')' { $$ = newNode(RegrAggNode::TYPE_REGR_SYY, $3, $5); } | ANY_VALUE '(' distinct_noise value ')' { $$ = newNode($4); } ; %type window_function window_function : DENSE_RANK '(' ')' { $$ = newNode(); } | RANK '(' ')' { $$ = newNode(); } | PERCENT_RANK '(' ')' { $$ = newNode(); } | CUME_DIST '(' ')' { $$ = newNode(); } | ROW_NUMBER '(' ')' { $$ = newNode(); } | FIRST_VALUE '(' value ')' { $$ = newNode($3); } | LAST_VALUE '(' value ')' { $$ = newNode($3); } | NTH_VALUE '(' value ',' value ')' nth_from { $$ = newNode($3, $5, $7); } | LAG '(' value ',' value ',' value ')' { $$ = newNode($3, $5, $7); } | LAG '(' value ',' value ')' { $$ = newNode($3, $5, NullNode::instance()); } | LAG '(' value ')' { $$ = newNode($3, MAKE_const_slong(1), NullNode::instance()); } | LEAD '(' value ',' value ',' value ')' { $$ = newNode($3, $5, $7); } | LEAD '(' value ',' value ')' { $$ = newNode($3, $5, NullNode::instance()); } | LEAD '(' value ')' { $$ = newNode($3, MAKE_const_slong(1), NullNode::instance()); } | NTILE '(' ntile_arg ')' { $$ = newNode($3); } ; %type nth_from nth_from : /* nothing */ { $$ = MAKE_const_slong(NthValueWinNode::FROM_FIRST); } | FROM FIRST { $$ = MAKE_const_slong(NthValueWinNode::FROM_FIRST); } | FROM LAST { $$ = MAKE_const_slong(NthValueWinNode::FROM_LAST); } ; %type ntile_arg ntile_arg : u_numeric_constant | variable | parameter ; %type aggregate_window_function aggregate_window_function : aggregate_function | window_function ; %type over_clause over_clause : aggregate_window_function OVER symbol_window_name { $$ = newNode($1, $3); } | aggregate_window_function OVER '(' window_clause ')' { $$ = newNode($1, $4); } ; %type window_clause window_clause : symbol_window_name_opt window_partition_opt order_clause_opt window_frame_extent window_frame_exclusion_opt { $$ = newNode($1, $2, $3, $4, $5); } ; %type window_partition_opt window_partition_opt : /* nothing */ { $$ = NULL; } | PARTITION BY value_list { $$ = $3; } ; %type window_frame_extent window_frame_extent : /* nothing */ { $$ = NULL; } | RANGE { $$ = newNode(WindowClause::FrameExtent::Unit::RANGE); } window_frame($2) { $$ = $2; } | ROWS { $$ = newNode(WindowClause::FrameExtent::Unit::ROWS); } window_frame($2) { $$ = $2; } ; %type window_frame() window_frame($frameExtent) : window_frame_start { $frameExtent->frame1 = $1; $frameExtent->frame2 = newNode(WindowClause::Frame::Bound::CURRENT_ROW); } | BETWEEN window_frame_between_bound1 AND window_frame_between_bound2 { $frameExtent->frame1 = $2; $frameExtent->frame2 = $4; } ; %type window_frame_start window_frame_start : UNBOUNDED PRECEDING { $$ = newNode(WindowClause::Frame::Bound::PRECEDING); } | CURRENT ROW { $$ = newNode(WindowClause::Frame::Bound::CURRENT_ROW); } | value PRECEDING { $$ = newNode(WindowClause::Frame::Bound::PRECEDING, $1); } ; %type window_frame_between_bound1 window_frame_between_bound1 : UNBOUNDED PRECEDING { $$ = newNode(WindowClause::Frame::Bound::PRECEDING); } | CURRENT ROW { $$ = newNode(WindowClause::Frame::Bound::CURRENT_ROW); } | value PRECEDING { $$ = newNode(WindowClause::Frame::Bound::PRECEDING, $1); } | value FOLLOWING { $$ = newNode(WindowClause::Frame::Bound::FOLLOWING, $1); } ; %type window_frame_between_bound2 window_frame_between_bound2 : UNBOUNDED FOLLOWING { $$ = newNode(WindowClause::Frame::Bound::FOLLOWING); } | CURRENT ROW { $$ = newNode(WindowClause::Frame::Bound::CURRENT_ROW); } | value PRECEDING { $$ = newNode(WindowClause::Frame::Bound::PRECEDING, $1); } | value FOLLOWING { $$ = newNode(WindowClause::Frame::Bound::FOLLOWING, $1); } ; %type window_frame_exclusion_opt window_frame_exclusion_opt : /* nothing */ { $$ = WindowClause::Exclusion::NO_OTHERS; } | EXCLUDE NO OTHERS { $$ = WindowClause::Exclusion::NO_OTHERS; } | EXCLUDE CURRENT ROW { $$ = WindowClause::Exclusion::CURRENT_ROW; } | EXCLUDE GROUP { $$ = WindowClause::Exclusion::GROUP; } | EXCLUDE TIES { $$ = WindowClause::Exclusion::TIES; } ; %type delimiter_opt delimiter_opt : /* nothing */ { $$ = MAKE_str_constant(newIntlString(","), lex.charSetId); } | ',' value { $$ = $2; } ; %type numeric_value_function numeric_value_function : extract_expression | length_expression ; %type extract_expression extract_expression : EXTRACT '(' timestamp_part FROM value ')' { $$ = newNode($3, $5); } ; %type length_expression length_expression : bit_length_expression | char_length_expression | octet_length_expression ; %type bit_length_expression bit_length_expression : BIT_LENGTH '(' value ')' { $$ = newNode(blr_strlen_bit, $3); } ; %type char_length_expression char_length_expression : CHAR_LENGTH '(' value ')' { $$ = newNode(blr_strlen_char, $3); } | CHARACTER_LENGTH '(' value ')' { $$ = newNode(blr_strlen_char, $3); } ; %type octet_length_expression octet_length_expression : OCTET_LENGTH '(' value ')' { $$ = newNode(blr_strlen_octet, $3); } ; %type system_function_expression system_function_expression : system_function_std_syntax '(' value_list_opt ')' { $$ = newNode(*$1, $3); } | system_function_special_syntax { $$ = $1; } ; %type system_function_std_syntax system_function_std_syntax : ABS | ACOS | ACOSH | ASCII_CHAR | ASCII_VAL | ASIN | ASINH | ATAN | ATAN2 | ATANH | BASE64_DECODE | BASE64_ENCODE | BIN_AND | BIN_NOT | BIN_OR | BIN_SHL | BIN_SHR | BIN_XOR | BLOB_APPEND | CEIL | CHAR_TO_UUID | COS | COSH | COT | EXP | FLOOR | GEN_UUID | HEX_DECODE | HEX_ENCODE | LEFT | LN | LOG | LOG10 | LPAD | MAKE_DBKEY | MAXVALUE | MINVALUE | MOD | PI | POWER | RAND | RDB_GET_CONTEXT | RDB_GET_TRANSACTION_CN | RDB_ROLE_IN_USE | RDB_SET_CONTEXT | REPLACE | REVERSE | RIGHT | ROUND | RPAD | RSA_PRIVATE | RSA_PUBLIC | SIGN | SIN | SINH | SQRT | TAN | TANH | TRUNC | UNICODE_CHAR | UNICODE_VAL | UUID_TO_CHAR | QUANTIZE | TOTALORDER | NORMALIZE_DECFLOAT | COMPARE_DECFLOAT ; %type system_function_special_syntax system_function_special_syntax : DATEADD '(' value timestamp_part TO value ')' { $$ = newNode(*$1, newNode($3)->add(MAKE_const_slong($4))->add($6)); $$->dsqlSpecialSyntax = true; } | DATEADD '(' timestamp_part ',' value ',' value ')' { $$ = newNode(*$1, newNode($5)->add(MAKE_const_slong($3))->add($7)); $$->dsqlSpecialSyntax = true; } | DATEDIFF '(' timestamp_part FROM value TO value ')' { $$ = newNode(*$1, newNode(MAKE_const_slong($3))->add($5)->add($7)); $$->dsqlSpecialSyntax = true; } | DATEDIFF '(' timestamp_part ',' value ',' value ')' { $$ = newNode(*$1, newNode(MAKE_const_slong($3))->add($5)->add($7)); $$->dsqlSpecialSyntax = true; } | encrypt_decrypt '(' value USING valid_symbol_name crypt_opt_mode KEY value crypt_opt_iv crypt_opt_counter_type crypt_opt_counter ')' { $$ = newNode(*$1, newNode($3)->add(MAKE_str_constant(newIntlString($5->c_str()), CS_ASCII))-> add(MAKE_str_constant(newIntlString($6->c_str()), CS_ASCII))->add($8)->add($9)-> add(MAKE_str_constant(newIntlString($10->c_str()), CS_ASCII))->add($11)); $$->dsqlSpecialSyntax = true; } | FIRST_DAY '(' of_first_last_day_part FROM value ')' { $$ = newNode(*$1, newNode(MAKE_const_slong($3))->add($5)); $$->dsqlSpecialSyntax = true; } | HASH '(' value ')' { $$ = newNode(*$1, newNode($3)); } | hash_func '(' value USING valid_symbol_name ')' { $$ = newNode(*$1, newNode($3)->add(MAKE_str_constant(newIntlString($5->c_str()), CS_ASCII))); $$->dsqlSpecialSyntax = true; } | LAST_DAY '(' of_first_last_day_part FROM value ')' { $$ = newNode(*$1, newNode(MAKE_const_slong($3))->add($5)); $$->dsqlSpecialSyntax = true; } | OVERLAY '(' value PLACING value FROM value FOR value ')' { $$ = newNode(*$1, newNode($3)->add($5)->add($7)->add($9)); $$->dsqlSpecialSyntax = true; } | OVERLAY '(' value PLACING value FROM value ')' { $$ = newNode(*$1, newNode($3)->add($5)->add($7)); $$->dsqlSpecialSyntax = true; } | POSITION '(' value IN value ')' { $$ = newNode(*$1, newNode($3)->add($5)); $$->dsqlSpecialSyntax = true; } | POSITION '(' value_list_opt ')' { $$ = newNode(*$1, $3); } | rsa_encrypt_decrypt '(' value KEY value crypt_opt_lparam crypt_opt_hash crypt_opt_pkcs')' { $$ = newNode(*$1, newNode($3)->add($5)->add($6)-> add(MAKE_str_constant(newIntlString($7->c_str()), CS_ASCII))->add($8)); $$->dsqlSpecialSyntax = true; } | RSA_SIGN_HASH '(' value KEY value crypt_opt_hash crypt_opt_saltlen crypt_opt_pkcs ')' { $$ = newNode(*$1, newNode($3)->add($5)-> add(MAKE_str_constant(newIntlString($6->c_str()), CS_ASCII))->add($7)->add($8)); $$->dsqlSpecialSyntax = true; } | RSA_VERIFY_HASH '(' value SIGNATURE value KEY value crypt_opt_hash crypt_opt_saltlen crypt_opt_pkcs ')' { $$ = newNode(*$1, newNode($3)->add($5)->add($7)-> add(MAKE_str_constant(newIntlString($8->c_str()), CS_ASCII))->add($9)->add($10)); $$->dsqlSpecialSyntax = true; } | RDB_SYSTEM_PRIVILEGE '(' valid_symbol_name ')' { ValueExprNode* v = MAKE_system_privilege($3->c_str()); $$ = newNode(*$1, newNode(v)); } ; %type hash_func hash_func : HASH | CRYPT_HASH ; %type rsa_encrypt_decrypt rsa_encrypt_decrypt : RSA_DECRYPT | RSA_ENCRYPT ; %type crypt_opt_lparam crypt_opt_lparam : // nothing { $$ = MAKE_str_constant(newIntlString(""), CS_ASCII); } | LPARAM value { $$ = $2; } ; %type crypt_opt_pkcs crypt_opt_pkcs : // nothing { $$ = MAKE_const_slong(0); } | PKCS_1_5 { $$ = MAKE_const_slong(1); } ; %type crypt_opt_hash crypt_opt_hash : // nothing { $$ = newNode(""); } | HASH valid_symbol_name { $$ = $2; } ; %type crypt_opt_saltlen crypt_opt_saltlen : // nothing { $$ = MAKE_str_constant(newIntlString(""), CS_ASCII); } | SALT_LENGTH value { $$ = $2; } ; %type crypt_opt_mode crypt_opt_mode : // nothing { $$ = newNode(""); } | MODE valid_symbol_name { $$ = $2; } ; %type crypt_opt_iv crypt_opt_iv : // nothing { $$ = MAKE_str_constant(newIntlString(""), CS_ASCII); } | IV value { $$ = $2; } ; %type crypt_opt_counter_type crypt_opt_counter_type : // nothing { $$ = newNode(""); } | crypt_counter_type { $$ = $1; } ; %type crypt_counter_type crypt_counter_type : CTR_BIG_ENDIAN | CTR_LITTLE_ENDIAN ; %type crypt_opt_counter crypt_opt_counter : // nothing { $$ = MAKE_str_constant(newIntlString(""), CS_ASCII); } | crypt_counter_name value { $$ = $2; } ; %type crypt_counter_name crypt_counter_name : COUNTER | CTR_LENGTH ; %type encrypt_decrypt encrypt_decrypt : ENCRYPT | DECRYPT ; %type of_first_last_day_part of_first_last_day_part : OF YEAR { $$ = blr_extract_year; } | OF QUARTER { $$ = blr_extract_quarter; } | OF MONTH { $$ = blr_extract_month; } | OF WEEK { $$ = blr_extract_week; } ; %type string_value_function string_value_function : substring_function | trim_function | btrim_function | ltrim_function | rtrim_function | UPPER '(' value ')' { $$ = newNode(blr_upcase, $3); } | LOWER '(' value ')' { $$ = newNode(blr_lowcase, $3); } ; %type substring_function 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 ArithmeticNode* subtractNode = newNode( blr_subtract, true, $5, MAKE_const_slong(1)); $$ = newNode($3, subtractNode, $6); } | SUBSTRING '(' value SIMILAR value ESCAPE value ')' { $$ = newNode($3, $5, $7); } ; %type string_length_opt string_length_opt : /* nothing */ { $$ = NULL; } | FOR value { $$ = $2; } ; %type trim_function trim_function : TRIM '(' trim_specification value FROM value ')' { $$ = newNode($3, blr_trim_characters, $6, $4); } | TRIM '(' value FROM value ')' { $$ = newNode(blr_trim_both, blr_trim_characters, $5, $3); } | TRIM '(' trim_specification FROM value ')' { $$ = newNode($3, blr_trim_spaces, $5); } | TRIM '(' value ')' { $$ = newNode(blr_trim_both, blr_trim_spaces, $3); } ; %type trim_specification trim_specification : BOTH { $$ = blr_trim_both; } | TRAILING { $$ = blr_trim_trailing; } | LEADING { $$ = blr_trim_leading; } ; %type btrim_function btrim_function : BTRIM '(' value ',' value ')' { $$ = newNode(blr_trim_both, blr_trim_multi_characters, $3, $5); } | BTRIM '(' value ')' { $$ = newNode(blr_trim_both, blr_trim_spaces, $3); } ; %type ltrim_function ltrim_function : LTRIM '(' value ',' value ')' { $$ = newNode(blr_trim_leading, blr_trim_multi_characters, $3, $5); } | LTRIM '(' value ')' { $$ = newNode(blr_trim_leading, blr_trim_spaces, $3); } ; %type rtrim_function rtrim_function : RTRIM '(' value ',' value ')' { $$ = newNode(blr_trim_trailing, blr_trim_multi_characters, $3, $5); } | RTRIM '(' value ')' { $$ = newNode(blr_trim_trailing, blr_trim_spaces, $3); } ; %type udf udf : symbol_UDF_call_name '(' argument_list_opt ')' { $$ = newNode(QualifiedName(*$1, ""), $3->second, $3->first); } | symbol_package_name '.' symbol_UDF_name '(' argument_list_opt ')' { $$ = newNode(QualifiedName(*$3, *$1), $5->second, $5->first); } ; %type argument_list_opt argument_list_opt : // nothing { $$ = newNode*, ValueListNode*>>(); $$->second = newNode(); } | argument_list ; %type argument_list argument_list : named_argument_list | value_or_default_list { $$ = newNode*, ValueListNode*>>(); $$->second = $1; } | value_or_default_list ',' named_argument_list { $$ = $3; for (auto item : $$->second->items) $1->add(item); delete $$->second; $$->second = $1; } ; %type named_argument_list named_argument_list : named_argument { $$ = newNode*, ValueListNode*>>(); $$->first = newNode>(); $$->first->add(*$1->first); $$->second = newNode(); $$->second->add($1->second); } | named_argument_list ',' named_argument { $$ = $1; $$->first->add(*$3->first); $$->second->add($3->second); } ; %type named_argument named_argument : symbol_column_name NAMED_ARG_ASSIGN value_or_default { $$ = newNode>($1, $3); } ; %type cast_specification cast_specification : CAST '(' value AS data_type_descriptor ')' { $$ = newNode($3, $5); } | CAST '(' value AS cast_format_type cast_format_clause utf_string ')' { $$ = newNode($3, $5, *$7); } ; %type cast_format_clause cast_format_clause : FORMAT ; %type date_time_type date_time_type : DATE { $$ = newNode(); stmt_ambiguous = true; if (client_dialect <= SQL_DIALECT_V5) { // Post warning saying that DATE is equivalent to TIMESTAMP ERRD_post_warning(Arg::Warning(isc_sqlwarn) << Arg::Num(301) << Arg::Warning(isc_dtype_renamed)); $$->dtype = dtype_timestamp; $$->length = sizeof(GDS_TIMESTAMP); } else if (client_dialect == SQL_DIALECT_V6_TRANSITION) yyabandon(YYPOSNARG(1), -104, isc_transitional_date); else { $$->dtype = dtype_sql_date; $$->length = sizeof(ULONG); } $$->flags |= FLD_has_prec; } | TIME without_time_zone_opt { $$ = newNode(); checkTimeDialect(); $$->dtype = dtype_sql_time; $$->length = sizeof(SLONG); $$->flags |= FLD_has_prec; } | TIME WITH TIME ZONE { $$ = newNode(); checkTimeDialect(); $$->dtype = dtype_sql_time_tz; $$->length = sizeof(ISC_TIME_TZ); $$->flags |= FLD_has_prec; } | TIMESTAMP without_time_zone_opt { $$ = newNode(); $$->dtype = dtype_timestamp; $$->length = sizeof(GDS_TIMESTAMP); $$->flags |= FLD_has_prec; } | TIMESTAMP WITH TIME ZONE { $$ = newNode(); $$->dtype = dtype_timestamp_tz; $$->length = sizeof(ISC_TIMESTAMP_TZ); $$->flags |= FLD_has_prec; } ; %type cast_format_type cast_format_type : character_type | date_time_type ; // case expressions %type case_expression case_expression : case_abbreviation | case_specification ; %type case_abbreviation case_abbreviation : NULLIF '(' value ',' value ')' { ComparativeBoolNode* condition = newNode(blr_eql, $3, $5); $$ = newNode(condition, NullNode::instance(), $3); } | IIF '(' search_condition ',' value ',' value ')' { $$ = newNode($3, $5, $7); } | COALESCE '(' value ',' value_list ')' { $$ = newNode($5->addFront($3)); } | DECODE '(' value ',' decode_pairs ')' { ValueListNode* list = $5; ValueListNode* conditions = newNode(list->items.getCount() / 2); ValueListNode* values = newNode(list->items.getCount() / 2); for (FB_SIZE_T i = 0; i < list->items.getCount(); i += 2) { conditions->items[i / 2] = list->items[i]; values->items[i / 2] = list->items[i + 1]; } $$ = newNode($3, conditions, values); } | DECODE '(' value ',' decode_pairs ',' value ')' { ValueListNode* list = $5; ValueListNode* conditions = newNode(list->items.getCount() / 2); ValueListNode* values = newNode(list->items.getCount() / 2 + 1); for (FB_SIZE_T i = 0; i < list->items.getCount(); i += 2) { conditions->items[i / 2] = list->items[i]; values->items[i / 2] = list->items[i + 1]; } values->items[list->items.getCount() / 2] = $7; $$ = newNode($3, conditions, values); } ; %type case_specification case_specification : simple_case { $$ = $1; } | searched_case { $$ = $1; } ; %type simple_case simple_case : CASE case_operand { $$ = newNode($2, newNode(0u), newNode(0u)); } simple_when_clause(NOTRIAL($3->conditions), NOTRIAL($3->values)) else_case_result_opt END { DecodeNode* node = $$ = $3; node->label = "CASE"; if ($5) node->values->add($5); } ; %type simple_when_clause(, ) simple_when_clause($conditions, $values) : WHEN when_operand THEN case_result { $conditions->add($2); $values->add($4); } | simple_when_clause WHEN when_operand THEN case_result { $conditions->add($3); $values->add($5); } ; %type else_case_result_opt else_case_result_opt : /* nothing */ { $$ = NULL; } | ELSE case_result { $$ = $2; } %type searched_case searched_case : CASE searched_when_clause END { $$ = $2; } | CASE searched_when_clause ELSE case_result END { ValueIfNode* last = $2; ValueIfNode* next; while ((next = nodeAs(last->falseValue))) last = next; fb_assert(nodeIs(last->falseValue)); last->falseValue = $4; $$ = $2; } ; %type searched_when_clause searched_when_clause : WHEN search_condition THEN case_result { $$ = newNode($2, $4, NullNode::instance()); } | searched_when_clause WHEN search_condition THEN case_result { ValueIfNode* cond = newNode($3, $5, NullNode::instance()); cond->dsqlGenCast = false; ValueIfNode* last = $1; ValueIfNode* next; while ((next = nodeAs(last->falseValue))) last = next; fb_assert(nodeIs(last->falseValue)); last->falseValue = cond; $$ = $1; } ; %type when_operand when_operand : value ; %type case_operand case_operand : value ; %type case_result case_result : value ; %type decode_pairs decode_pairs : value ',' value { $$ = newNode(0u)->add($1)->add($3); } | decode_pairs ',' value ',' value { $$ = $1->add($3)->add($5); } ; // next value expression %type next_value_expression next_value_expression : NEXT VALUE FOR symbol_generator_name { $$ = newNode((client_dialect < SQL_DIALECT_V6_TRANSITION), *$4, ((Jrd::ValueExprNode*) NULL), true, false); } | GEN_ID '(' symbol_generator_name ',' value ')' { $$ = newNode((client_dialect < SQL_DIALECT_V6_TRANSITION), *$3, $5, false, false); } ; %type timestamp_part timestamp_part : YEAR { $$ = blr_extract_year; } | QUARTER { $$ = blr_extract_quarter; } | MONTH { $$ = blr_extract_month; } | DAY { $$ = blr_extract_day; } | HOUR { $$ = blr_extract_hour; } | MINUTE { $$ = blr_extract_minute; } | SECOND { $$ = blr_extract_second; } | MILLISECOND { $$ = blr_extract_millisecond; } | TIMEZONE_HOUR { $$ = blr_extract_timezone_hour; } | TIMEZONE_MINUTE { $$ = blr_extract_timezone_minute; } | TIMEZONE_NAME { $$ = blr_extract_timezone_name; } | WEEK { $$ = blr_extract_week; } | WEEKDAY { $$ = blr_extract_weekday; } | YEARDAY { $$ = blr_extract_yearday; } ; all_noise : | ALL ; distinct_noise : | DISTINCT ; %type null_value null_value : NULL { $$ = NullNode::instance(); } | UNKNOWN { dsql_fld* field = newNode(); field->dtype = dtype_boolean; field->length = sizeof(UCHAR); CastNode* castNode = newNode(NullNode::instance(), field); castNode->dsqlAlias = "CONSTANT"; $$ = castNode; } ; // Performs special mapping of keywords into symbols %type symbol_UDF_call_name symbol_UDF_call_name : SYMBOL ; %type symbol_UDF_name symbol_UDF_name : valid_symbol_name ; %type symbol_blob_subtype_name symbol_blob_subtype_name : valid_symbol_name | BINARY ; %type symbol_character_set_name symbol_character_set_name : valid_symbol_name | BINARY ; %type symbol_collation_name symbol_collation_name : valid_symbol_name ; %type symbol_column_name symbol_column_name : valid_symbol_name ; %type symbol_constraint_name symbol_constraint_name : valid_symbol_name ; %type symbol_cursor_name symbol_cursor_name : valid_symbol_name ; %type symbol_domain_name symbol_domain_name : valid_symbol_name ; %type symbol_exception_name symbol_exception_name : valid_symbol_name ; %type symbol_filter_name symbol_filter_name : valid_symbol_name ; %type symbol_gdscode_name symbol_gdscode_name : valid_symbol_name ; %type symbol_generator_name symbol_generator_name : valid_symbol_name ; %type symbol_index_name symbol_index_name : valid_symbol_name ; %type symbol_item_alias_name symbol_item_alias_name : valid_symbol_name ; %type symbol_label_name symbol_label_name : valid_symbol_name ; %type symbol_ddl_name symbol_ddl_name : valid_symbol_name ; %type symbol_procedure_name symbol_procedure_name : valid_symbol_name ; %type symbol_role_name symbol_role_name : valid_symbol_name ; %type symbol_table_alias_name symbol_table_alias_name : valid_symbol_name ; %type symbol_table_name symbol_table_name : valid_symbol_name ; %type symbol_trigger_name symbol_trigger_name : valid_symbol_name ; %type symbol_user_name symbol_user_name : valid_symbol_name ; %type symbol_variable_name symbol_variable_name : valid_symbol_name ; %type symbol_view_name symbol_view_name : valid_symbol_name ; %type symbol_savepoint_name symbol_savepoint_name : valid_symbol_name ; %type symbol_package_name symbol_package_name : valid_symbol_name ; %type symbol_window_name symbol_window_name : valid_symbol_name ; // symbols %type valid_symbol_name valid_symbol_name : SYMBOL | non_reserved_word ; // list of non-reserved words %type non_reserved_word non_reserved_word : ACTION // added in IB 5.0/ | CASCADE | FREE_IT | RESTRICT | ROLE | TYPE // added in IB 6.0 | BREAK // added in FB 1.0 | DESCRIPTOR | SUBSTRING | COALESCE // added in FB 1.5 | LAST | LEAVE | LOCK | NULLIF | NULLS | STATEMENT | FIRST | SKIP | BLOCK // added in FB 2.0 | BACKUP | DIFFERENCE | IIF | SCALAR_ARRAY | WEEKDAY | YEARDAY | SEQUENCE | NEXT | RESTART | COLLATION | RETURNING | 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 | AUTONOMOUS // added in FB 2.5 | CHAR_TO_UUID | FIRSTNAME | MIDDLENAME | LASTNAME | MAPPING | OS_NAME | UUID_TO_CHAR | GRANTED | CALLER // new execute statement | COMMON | DATA | SOURCE | TWO_PHASE | BIN_NOT | ACTIVE // old keywords, that were reserved pre-Firebird.2.5 // | ADD // words commented it this list remain reserved due to conflicts | AFTER | ASC | AUTO | BEFORE | COMMITTED | COMPUTED | CONDITIONAL | CONTAINING | CSTRING | DATABASE | DESC | DO | DOMAIN | ENTRY_POINT | EXCEPTION | EXIT | FILE // | GDSCODE | GENERATOR | GEN_ID | IF | INACTIVE // | INDEX | INPUT_TYPE | ISOLATION | KEY | LENGTH | LEVEL // | LONG | MANUAL | MODULE_NAME | NAMES | OPTION | OUTPUT_TYPE | OVERFLOW | PAGE | PAGES | PAGE_SIZE | PASSWORD // | PLAN // | POST_EVENT | PRIVILEGES | PROTECTED | READ | RESERVING | RETAIN // | RETURNING_VALUES | SEGMENT | SHADOW | SHARED | SINGULAR | SIZE | SNAPSHOT | SORT // | SQLCODE | STABILITY | STARTING | STATISTICS | SUB_TYPE | SUSPEND | TRANSACTION | UNCOMMITTED // | VARIABLE // | VIEW | WAIT | WEEK // | WHILE | WORK | WRITE // end of old keywords, that were reserved pre-Firebird.2.5 | ABSOLUTE // added in FB 3.0 | ACOSH | ASINH | ATANH | BODY | CONTINUE | DDL | DECRYPT | ENCRYPT | ENGINE | IDENTITY | NAME | PACKAGE | PARTITION | PRIOR | RELATIVE | DENSE_RANK | FIRST_VALUE | NTH_VALUE | LAST_VALUE | LAG | LEAD | RANK | ROW_NUMBER | USAGE | LINGER | TAGS | PLUGIN | SERVERWIDE | INCREMENT | TRUSTED // added in FB 4.0 | BASE64_DECODE | BASE64_ENCODE | BIND | CLEAR | COUNTER | COMPARE_DECFLOAT | CONNECTIONS | CONSISTENCY | CRYPT_HASH | CTR_BIG_ENDIAN | CTR_LENGTH | CTR_LITTLE_ENDIAN | CUME_DIST | DEFINER | DISABLE | ENABLE | EXCESS | EXCLUDE | EXTENDED | FIRST_DAY | FOLLOWING | HEX_DECODE | HEX_ENCODE | IDLE | INCLUDE | INVOKER | IV | LAST_DAY | LEGACY | LIFETIME | LPARAM | MAKE_DBKEY | MESSAGE | MODE | NATIVE | NORMALIZE_DECFLOAT | NTILE | NUMBER | OLDEST | OTHERS | OVERRIDING | PERCENT_RANK | POOL | PRECEDING | PRIVILEGE | QUANTIZE | RANGE | RESET | RSA_DECRYPT | RSA_ENCRYPT | RSA_PRIVATE | RSA_PUBLIC | RSA_SIGN_HASH | RSA_VERIFY_HASH | SALT_LENGTH | SECURITY | SESSION | SIGNATURE | SQL | SYSTEM | TIES | TOTALORDER | TRAPS | ZONE // added in FB 4.0.1 | DEBUG | PKCS_1_5 // added in FB 4.0.2 | BLOB_APPEND // added in FB 5.0 | BLOBID | LOCKED | OPTIMIZE | QUARTER | TARGET | TEMP | TIMEZONE_NAME | UNICODE_CHAR | UNICODE_VAL // added in FB 6.0 | ANY_VALUE | FORMAT | OWNER ; %%