From 6df2b4cb5c49879dd70ba617f3de899dbe1df2aa Mon Sep 17 00:00:00 2001 From: TotaJ Date: Thu, 28 Oct 2021 17:51:48 +0800 Subject: [PATCH] Fix for openGauss 2.1.0. --- contrib/db_b_parser/Makefile | 3 +- contrib/db_b_parser/db_b_gram.y | 1559 +++- contrib/db_b_parser/db_b_hint_gram.y | 159 +- contrib/db_b_parser/db_b_hint_scan.l | 10 +- contrib/db_b_parser/db_b_keywords.h | 16 +- contrib/db_b_parser/db_b_scan.l | 90 +- contrib/db_b_parser/expected/db_b_parser.out | 1991 ++++ contrib/db_b_parser/pl/pl_b_gram.cpp | 8634 ------------------ contrib/db_b_parser/pl/pl_b_gram.hpp | 282 - contrib/db_b_parser/pl/pl_b_gram.y | 593 +- contrib/db_b_parser/pl/pl_b_scanner.cpp | 115 +- contrib/db_b_parser/pl/pl_b_sql.h | 409 +- contrib/db_b_parser/sql/db_b_parser.sql | 572 ++ 13 files changed, 5208 insertions(+), 9225 deletions(-) create mode 100644 contrib/db_b_parser/expected/db_b_parser.out delete mode 100644 contrib/db_b_parser/pl/pl_b_gram.cpp delete mode 100644 contrib/db_b_parser/pl/pl_b_gram.hpp create mode 100644 contrib/db_b_parser/sql/db_b_parser.sql diff --git a/contrib/db_b_parser/Makefile b/contrib/db_b_parser/Makefile index 1acd6186a..dbdb90e95 100644 --- a/contrib/db_b_parser/Makefile +++ b/contrib/db_b_parser/Makefile @@ -58,7 +58,8 @@ pl/pl_b_gram.cpp: pl/pl_b_gram.y $(top_builddir)/$(subdir)/pl/tool/mtlocal.pl $(PERL) $(top_builddir)/$(subdir)/pl/tool/mtlocal.pl $(top_builddir)/$(subdir)/pl/pl_b_gram.cpp $(PERL) $(top_builddir)/$(subdir)/pl/tool/mtlocal.pl $(top_builddir)/$(subdir)/pl/pl_b_gram.hpp - +REGRESS = db_b_parser +REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress -c 0 -d 1 --single_node EXTENSION = db_b_parser DATA = db_b_parser--1.0.sql diff --git a/contrib/db_b_parser/db_b_gram.y b/contrib/db_b_parser/db_b_gram.y index 93df74b46..1d02d1961 100644 --- a/contrib/db_b_parser/db_b_gram.y +++ b/contrib/db_b_parser/db_b_gram.y @@ -56,6 +56,7 @@ #include "catalog/index.h" #include "catalog/namespace.h" #include "catalog/pg_proc.h" +#include "catalog/gs_package.h" #include "catalog/pg_trigger.h" #include "commands/defrem.h" #ifdef ENABLE_MULTIPLE_NODES @@ -68,12 +69,15 @@ #include "parser/scanner.h" #include "db_b_gram.hpp" #include "parser/gramparse.h" +#include "parser/parse_type.h" #include "parser/parse_hint.h" +#include "parser/scansup.h" #include "pgxc/pgxc.h" #include "nodes/nodes.h" #include "pgxc/poolmgr.h" #include "parser/parser.h" #include "storage/lmgr.h" +#include "storage/tcap.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/datetime.h" @@ -215,14 +219,23 @@ static void SplitColQualList(List *qualList, static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); +static void getPkgName(char* pkgname); static Expr *makeNodeDecodeCondtion(Expr* firstCond,Expr* secondCond); static List *make_action_func(List *arguments); static List *get_func_args(char *sid); static char *pg_strsep(char **stringp, const char *delim); static long long get_pid(const char *strsid); static Node *MakeAnonyBlockFuncStmt(int flag, const char * str); +#define TYPE_LEN 4 /* strlen("TYPE") */ +#define DATE_LEN 4 /* strlen("DATE") */ #define DECLARE_LEN 9 /* strlen(" DECLARE ") */ #define DECLARE_STR " DECLARE " +#define PACKAGE_STR " PACKAGE " +#define PACKAGE_LEN 9 /* strlen(" PACKAGE ") */ +#define INSTANTIATION_STR " INSTANTIATION " +#define INSTANTIATION_LEN 15 +#define END_STR "\nEND\n" +#define END_LEN 6 static int get_outarg_num(List *fun_args); static int get_table_modes(int nargs, const char *p_argmodes); static void get_arg_mode_by_name(const char *argname, const char * const *argnames, @@ -238,7 +251,12 @@ bool IsValidIdent(char *input); bool IsValidGroupname(const char *input); static bool checkNlssortArgs(const char *argname); static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yyscan_t yyscanner); +static char *GetTargetFuncArgTypeName(char *typeString, TypeName* t); +static char *FormatFuncArgType(core_yyscan_t yyscanner, char *argsString, List* parameters); +static char *ParseFunctionArgSrc(core_yyscan_t yyscanner); static void parameter_check_execute_direct(const char* query); +static Node *make_node_from_scanbuf(int start_pos, int end_pos, core_yyscan_t yyscanner); + static const char* replace_data_type(char* input); static TypeName* parseFloatTypeByPrecision(int ival, int location, core_yyscan_t yyscanner); static TypeName* transferFloat4TypeInBFormat(char *typnam, List* list, int location, core_yyscan_t yyscanner); @@ -271,6 +289,7 @@ static char* mapping_func_name(char* old_name, bool free_old); Value *value; ObjectType objtype; TypeName *typnam; + FunctionSources *fun_src; FunctionParameter *fun_param; FunctionParameterMode fun_param_mode; FuncWithArgs *funwithargs; @@ -301,7 +320,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type stmt schema_stmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDataSourceStmt AlterDomainStmt AlterEnumStmt - AlterFdwStmt AlterForeignServerStmt AlterGroupStmt + AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterSchemaStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt @@ -324,10 +343,10 @@ static char* mapping_func_name(char* old_name, bool free_old); DropForeignServerStmt DropUserMappingStmt ExplainStmt ExecDirectStmt FetchStmt GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt - CreateFunctionStmt CreateProcedureStmt AlterFunctionStmt AlterProcedureStmt ReindexStmt RemoveAggrStmt - RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt + CreateFunctionStmt CreateProcedureStmt CreatePackageStmt CreatePackageBodyStmt AlterFunctionStmt AlterProcedureStmt ReindexStmt RemoveAggrStmt + RemoveFuncStmt RemoveOperStmt RemovePackageStmt RenameStmt RevokeStmt RevokeRoleStmt RuleActionStmt RuleActionStmtOrEmpty RuleStmt - SecLabelStmt SelectStmt TransactionStmt TruncateStmt CallFuncStmt + SecLabelStmt SelectStmt TimeCapsuleStmt TransactionStmt TruncateStmt CallFuncStmt UnlistenStmt UpdateStmt VacuumStmt VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt ShutdownStmt ViewStmt CheckPointStmt CreateConversionStmt @@ -338,14 +357,21 @@ static char* mapping_func_name(char* old_name, bool free_old); CreateNodeGroupStmt AlterNodeGroupStmt DropNodeGroupStmt CreatePolicyLabelStmt AlterPolicyLabelStmt DropPolicyLabelStmt CreateAuditPolicyStmt AlterAuditPolicyStmt DropAuditPolicyStmt - CreateMaskingPolicyStmt AlterMaskingPolicyStmt DropMaskingPolicyStmt + CreateMaskingPolicyStmt AlterMaskingPolicyStmt DropMaskingPolicyStmt CreateResourcePoolStmt AlterResourcePoolStmt DropResourcePoolStmt CreateWorkloadGroupStmt AlterWorkloadGroupStmt DropWorkloadGroupStmt CreateAppWorkloadGroupMappingStmt AlterAppWorkloadGroupMappingStmt DropAppWorkloadGroupMappingStmt - MergeStmt CreateMatViewStmt RefreshMatViewStmt + MergeStmt PurgeStmt CreateMatViewStmt RefreshMatViewStmt CreateWeakPasswordDictionaryStmt DropWeakPasswordDictionaryStmt /* */ +/* SNAPSHOTS */ +%type SnapshotStmt +%type AlterSnapshotCmdOrEmpty AlterSnapshotCmdList AlterSnapshotCmdListNoParens +%type AlterSnapshotCmdListWithParens SnapshotSample SnapshotSampleList OptSnapshotStratify +%type SnapshotVersion OptSnapshotVersion OptSnapshotComment +%type OptSnapshotAlias AlterSnapshotDdl AlterSnapshotDdlList +%type OptAlterUpdateSnapshot OptInsertIntoSnapshot OptDeleteFromSnapshot /* TRAIN MODEL */ %type CreateModelStmt hyperparameter_name_value DropModelStmt @@ -388,10 +414,11 @@ static char* mapping_func_name(char* old_name, bool free_old); %type foreign_server_version opt_foreign_server_version %type data_source_version opt_data_source_version data_source_type opt_data_source_type %type auth_ident -%type opt_in_database +%type opt_in_database opt_rename %type OptSchemaName %type OptSchemaEltList +%type OptBlockchainWith OptAlterToBlockchain %type TriggerForSpec TriggerForType ForeignTblWritable %type TriggerActionTime @@ -405,7 +432,7 @@ static char* mapping_func_name(char* old_name, bool free_old); index_name cluster_index_specification pgxcnode_name pgxcgroup_name resource_pool_name workload_group_name application_name password_string hint_string -%type func_name func_name_opt_arg handler_name qual_Op qual_all_Op subquery_Op +%type func_name func_name_opt_arg pkg_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_inline_handler opt_validator validator_clause opt_collate @@ -460,6 +487,7 @@ static char* mapping_func_name(char* old_name, bool free_old); create_generic_options alter_generic_options relation_expr_list dostmt_opt_list merge_values_clause + invoker_rights %type group_by_list %type group_by_item empty_grouping_set rollup_clause cube_clause @@ -476,7 +504,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type arg_class %type func_return func_type -%type opt_trusted opt_restart_seqs +%type opt_trusted opt_restart_seqs opt_purge %type OptTemp OptKind %type OnCommitOption @@ -551,7 +579,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type relation_expr %type relation_expr_opt_alias %type target_el single_set_clause set_target insert_column_item -%type tablesample_clause opt_repeatable_clause +%type tablesample_clause timecapsule_clause opt_timecapsule_clause opt_repeatable_clause %type generic_option_name %type generic_option_arg @@ -572,7 +600,7 @@ static char* mapping_func_name(char* old_name, bool free_old); CharacterWithLength CharacterWithoutLength ConstDatetime ConstInterval Bit ConstBit BitWithLength BitWithoutLength client_logic_type - datatypecl + datatypecl OptCopyColTypename %type character %type extract_arg %type timestamp_units @@ -619,7 +647,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type with_clause opt_with_clause %type cte_list -%type within_group_clause +%type within_group_clause pkg_subprogram pkg_body_subprogram %type window_clause window_definition_list opt_partition_clause %type window_definition over_clause window_specification opt_frame_clause frame_extent frame_bound @@ -628,7 +656,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type OptCompress %type KVType %type ColCmprsMode -%type subprogram_body +%type subprogram_body %type as_is %type column_item opt_table_partitioning_clause opt_partition_index_def range_partition_index_item range_partition_index_list @@ -655,10 +683,10 @@ static char* mapping_func_name(char* old_name, bool free_old); /* PGXC_END */ %type OptPartitionElement -%type OptForeignTableLogError OptForeignTableLogRemote -%type ForeignPosition ForeignColDef copy_col_format_def +%type OptForeignTableLogError OptForeignTableLogRemote OptCopyColExpr +%type ForeignPosition ForeignColDef copy_col_format_def copy_column_expr_item %type OptPerNodeRejectLimit -%type copy_foramtter_opt +%type copy_foramtter_opt copy_column_expr_list /* FOREIGN_PARTITION */ %type OptForeignPartBy OptForeignPartAuto @@ -669,6 +697,8 @@ static char* mapping_func_name(char* old_name, bool free_old); %type opt_vcgroup opt_to_elastic_group %type opt_set_vcgroup %type opt_redistributed opt_internal_data internal_data_body +%type bucket_cnt +%type pgxcgroup_parent /* MERGE INTO */ %type merge_when_clause opt_merge_where_condition @@ -704,7 +734,7 @@ static char* mapping_func_name(char* old_name, bool free_old); %type alter_policy_action_clause policy_comments_alter_clause /* MASKING POLICY */ -%type masking_func masking_policy_target_type alter_masking_policy_action_clause +%type masking_func masking_func_nsp masking_policy_target_type alter_masking_policy_action_clause masking_policy_condition_operator %type masking_clause masking_func_params_opt masking_func_params_list alter_masking_policy_func_items_list @@ -738,17 +768,17 @@ static char* mapping_func_name(char* old_name, bool free_old); /* PGXC - added DISTRIBUTE, DIRECT, COORDINATOR, CLEAN, NODE, BARRIER, SLICE, DATANODE */ %token ABORT_P ABSOLUTE_P ACCESS ACCOUNT ACTION ADD_P ADMIN AFTER AGGREGATE ALGORITHM ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY APP ARCHIVE ARRAY AS ASC - ASSERTION ASSIGNMENT ASYMMETRIC AT ATTRIBUTE AUDIT AUTHID AUTHORIZATION AUTOEXTEND AUTOMAPPED AUTOML + ASSERTION ASSIGNMENT ASYMMETRIC AT ATTRIBUTE AUDIT AUTHID AUTHORIZATION AUTOEXTEND AUTOMAPPED - BACKWARD BARRIER BEFORE BEGIN_NON_ANOYBLOCK BEGIN_P BETWEEN BIGINT BINARY BINARY_DOUBLE BINARY_INTEGER BIT BLOB_P BOGUS - BOOLEAN_P BOTH BUCKETS BY BYTEAWITHOUTORDER BYTEAWITHOUTORDERWITHEQUAL + BACKWARD BARRIER BEFORE BEGIN_NON_ANOYBLOCK BEGIN_P BETWEEN BIGINT BINARY BINARY_DOUBLE BINARY_FLOAT BINARY_INTEGER BIT BLOB_P + BLOCKCHAIN BODY_P BOGUS BOOLEAN_P BOTH BUCKETCNT BUCKETS BY BYTEAWITHOUTORDER BYTEAWITHOUTORDERWITHEQUAL CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLEAN CLIENT CLIENT_MASTER_KEY CLIENT_MASTER_KEYS CLOB CLOSE CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMN_ARGS COLUMN_ENCRYPTION_KEY COLUMN_ENCRYPTION_KEYS COLUMN_FUNCTION COMMENT COMMENTS COMMIT COMMITTED COMPACT COMPATIBLE_ILLEGAL_CHARS COMPLETE COMPRESS CONCURRENTLY CONDITION CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS CONTENT_P CONTINUE_P CONTVIEW CONVERSION_P COORDINATOR COORDINATORS COPY COST CREATE - CROSS CSV CUBE CURRENT_P + CROSS CSN CSV CUBE CURRENT_P CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE @@ -767,7 +797,7 @@ static char* mapping_func_name(char* old_name, bool free_old); FEATURES // DB4AI FREEZE FROM FULL FUNCTION FUNCTIONS - GENERATED GLOBAL GLOBAL_FUNCTION GRANT GRANTED GREATEST GROUP_P GROUPING_P + GENERATED GLOBAL GLOBAL_FUNCTION GRANT GRANTED GREATEST GROUP_P GROUPING_P GROUPPARENT HANDLER HAVING HDFSDIRECTORY HEADER_P HOLD HOUR_P @@ -804,10 +834,10 @@ static char* mapping_func_name(char* old_name, bool free_old); QUARTER QUERY QUOTE - RANDOMIZED RANGE RATIO RAW READ REAL REASSIGN REBUILD RECHECK RECURSIVE REDISANYVALUE REF REFERENCES REFRESH REINDEX REJECT_P + RANDOMIZED RANGE RATIO RAW READ REAL REASSIGN REBUILD RECHECK RECURSIVE RECYCLEBIN REDISANYVALUE REF REFERENCES REFRESH REINDEX REJECT_P RELATIVE_P RELEASE RELOPTIONS REMOTE_P REMOVE RENAME REPEATABLE REPLACE REPLICA REGEXP RESET RESIZE RESOURCE RESTART RESTRICT RETURN RETURNING RETURNS REUSE REVOKE RIGHT RLIKE ROLE ROLES ROLLBACK ROLLUP - ROW ROWNUM ROWS RULE + ROTATION ROW ROWNUM ROWS RULE SAMPLE SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHIPPABLE SHOW SHUTDOWN @@ -815,14 +845,14 @@ static char* mapping_func_name(char* old_name, bool free_old); STATEMENT STATEMENT_ID STATISTICS STDIN STDOUT STORAGE STORE_P STORED STRATIFY STREAM STRICT_P STRIP_P SUBSTRING SYMMETRIC SYNONYM SYSDATE SYSID SYSTEM_P SYS_REFCURSOR - TABLE TABLES TABLESAMPLE TABLESPACE TARGET TEMP TEMPLATE TEMPORARY TEXT_P THAN THEN TIME TIME_FORMAT_P TIMESTAMP TIMESTAMP_FORMAT_P TIMESTAMPDIFF TINYINT - TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P + TABLE TABLES TABLESAMPLE TABLESPACE TARGET TEMP TEMPLATE TEMPORARY TEXT_P THAN THEN TIME TIME_FORMAT_P TIMECAPSULE TIMESTAMP TIMESTAMP_FORMAT_P TIMESTAMPDIFF TINYINT + TO TRAILING TRANSACTION TRANSFORM TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TSFIELD TSTAG TSTIME TYPE_P TYPES_P UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLIMITED UNLISTEN UNLOCK UNLOGGED UNTIL UNUSABLE UPDATE USER USING - VACUUM VALID VALIDATE VALIDATION VALIDATOR VALUE_P VALUES VARCHAR VARCHAR2 VARIABLES VARIADIC VARRAY VARYING VCGROUP + VACUUM VALID VALIDATE VALIDATION VALIDATOR VALUE_P VALUES VARCHAR VARCHAR2 VARIADIC VARRAY VARYING VCGROUP VERBOSE VERIFY VERSION_P VIEW VOLATILE WEAK WEEKDAY WEEKOFYEAR WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WORKLOAD WRAPPER WRITE @@ -992,6 +1022,7 @@ stmt : | AlterRlsPolicyStmt | AlterResourcePoolStmt | AlterSeqStmt + | AlterSchemaStmt | AlterTableStmt | AlterSystemStmt | AlterCompositeTypeStmt @@ -1030,6 +1061,8 @@ stmt : | CreateForeignTableStmt | CreateDataSourceStmt | CreateFunctionStmt + | CreatePackageStmt + | CreatePackageBodyStmt | CreateGroupStmt | CreateMatViewStmt | CreateModelStmt // DB4AI @@ -1113,10 +1146,12 @@ stmt : | MergeStmt | NotifyStmt | PrepareStmt + | PurgeStmt | ReassignOwnedStmt | ReindexStmt | RemoveAggrStmt | RemoveFuncStmt + | RemovePackageStmt | RemoveOperStmt | RenameStmt | RevokeStmt @@ -1124,7 +1159,9 @@ stmt : | RuleStmt | SecLabelStmt | SelectStmt - | ShutdownStmt + | ShutdownStmt + | TimeCapsuleStmt + | SnapshotStmt | TransactionStmt | TruncateStmt | UnlistenStmt @@ -1722,10 +1759,10 @@ AlterSystemStmt: | ALTER SYSTEM_P SET generic_set { -#ifdef ENABLE_MULTIPLE_NODES +#if defined(ENABLE_MULTIPLE_NODES) || defined (ENABLE_PRIVATEGAUSS) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ALTER SYSTEM SET is not supported in distributed mode."))); + errmsg("ALTER SYSTEM SET is not supported."))); #else AlterSystemStmt *n = makeNode(AlterSystemStmt); n->setstmt = $4; @@ -1771,7 +1808,7 @@ DropGroupStmt: *****************************************************************************/ CreateSchemaStmt: - CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList + CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptBlockchainWith OptSchemaEltList { CreateSchemaStmt *n = makeNode(CreateSchemaStmt); /* One can omit the schema name or the authorization id. */ @@ -1780,16 +1817,18 @@ CreateSchemaStmt: else n->schemaname = $5; n->authid = $5; - n->schemaElts = $6; + n->hasBlockChain = $6; + n->schemaElts = $7; $$ = (Node *)n; } - | CREATE SCHEMA ColId OptSchemaEltList + | CREATE SCHEMA ColId OptBlockchainWith OptSchemaEltList { CreateSchemaStmt *n = makeNode(CreateSchemaStmt); /* ...but not both */ n->schemaname = $3; n->authid = NULL; - n->schemaElts = $4; + n->hasBlockChain = $4; + n->schemaElts = $5; $$ = (Node *)n; } ; @@ -1804,13 +1843,39 @@ OptSchemaEltList: | /* EMPTY */ { $$ = NIL; } ; +OptBlockchainWith: + WITH BLOCKCHAIN { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + +/***************************************************************************** + * + * ALTER SCHEMA WITH BLOCKCHAIN + * alter blockchain property of a schema. + * + *****************************************************************************/ +AlterSchemaStmt: + ALTER SCHEMA ColId OptAlterToBlockchain + { + AlterSchemaStmt *n = makeNode(AlterSchemaStmt); + n->schemaname = $3; + n->authid = NULL; + n->hasBlockChain = $4; + $$ = (Node *)n; + } + ; + +OptAlterToBlockchain: + WITH BLOCKCHAIN { $$ = true; } + | WITHOUT BLOCKCHAIN { $$ = false; } + ; + /* * schema_stmt are the ones that can show up inside a CREATE SCHEMA * statement (in addition to by themselves). */ schema_stmt: CreateStmt - | CreateKeyStmt | IndexStmt | CreateSeqStmt | CreateTrigStmt @@ -2255,13 +2320,6 @@ VariableShowStmt: n->name = "session_authorization"; $$ = (Node *) n; } - | SHOW VARIABLES LIKE var_name - { - VariableShowStmt *n = makeNode(VariableShowStmt); - n->name = "all"; - n->likename = $4; - $$ = (Node *) n; - } | SHOW ALL { VariableShowStmt *n = makeNode(VariableShowStmt); @@ -3114,6 +3172,15 @@ alter_table_cmd: n->def = $3; $$ = (Node *)n; } + | ADD_P TABLE qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + AddTableIntoCBIState *s = makeNode(AddTableIntoCBIState); + s->relation = $3; + n->def = (Node *)s; + n->subtype = AT_AddIntoCBI; + $$ = (Node *)n; + } /* ALTER TABLE ALTER [COLUMN] {SET DEFAULT |DROP DEFAULT} */ | ALTER opt_column ColId alter_column_default { @@ -3538,6 +3605,14 @@ alter_table_cmd: n->def = (Node *)$3; $$ = (Node *)n; } + /* ALTER TABLE UPDATE SLICE LIKE (reftalbename), only used for redis range/list distribution table */ + | UPDATE SLICE LIKE qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_UpdateSliceLike; + n->exchange_with_rel = $4; + $$ = (Node *)n; + } /* ALTER TABLE ENABLE ROW LEVEL SECURITY */ | ENABLE_P ROW LEVEL SECURITY { @@ -3566,6 +3641,13 @@ alter_table_cmd: n->subtype = AT_NoForceRls; $$ = (Node *)n; } + /* ALTER TABLE ENCRYPTION KEY ROTATION */ + | ENCRYPTION KEY ROTATION + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EncryptionKeyRotation; + $$ = (Node *)n; + } /* PGXC_END */ ; @@ -3978,9 +4060,13 @@ copy_opt_item: $$ = makeDefElem("compatible_illegal_chars", (Node *)makeInteger(TRUE)); } | FILL_MISSING_FIELDS - { + { $$ = makeDefElem("fill_missing_fields", (Node *)makeInteger(TRUE)); - } + } + | TRANSFORM '(' copy_column_expr_list ')' + { + $$ = MakeDefElemWithLoc("transform", (Node *)$3, @1, @4); + } ; /* The following exist for backward compatibility with very old versions */ @@ -4106,6 +4192,42 @@ copy_col_format_def: $$ = (Node*)arg; } ; + +copy_column_expr_list: + copy_column_expr_item + { + $$ = list_make1($1); + } + | copy_column_expr_list ',' copy_column_expr_item + { + $$ = lappend($1, $3); + } + ; +copy_column_expr_item: + ColId OptCopyColTypename OptCopyColExpr + { + CopyColExpr* n = makeNode(CopyColExpr); + n->colname = $1; + if ($2 != NULL) + n->typname = $2; + else + n->typname = NULL; + if ($3 != NULL) + n->colexpr = $3; + else + n->colexpr = NULL; + $$ = (Node*)n; + } + ; +OptCopyColTypename: + Typename { $$ = $1; } + | /*EMPTY*/ { $$ = NULL; } + ; +OptCopyColExpr: + AS b_expr { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; } + ; + /***************************************************************************** * * QUERY : @@ -4138,6 +4260,105 @@ CreateStreamStmt: } ; +/***************************************************************************** + * + * PURGE : + * PURGE TABLE [schema_name.]table_name + * PURGE INDEX [schema_name.]index_name + * PURGE TABLESPACE tablespace_name + * PURGE RECYCLEBIN + * + *****************************************************************************/ +PurgeStmt: + PURGE TABLE qualified_name + { + TcapFeatureEnsure(); + PurgeStmt *n = makeNode(PurgeStmt); + n->purtype = PURGE_TABLE; + n->purobj = $3; + $$ = (Node *)n; + } + + | PURGE INDEX qualified_name + { + TcapFeatureEnsure(); + PurgeStmt *n = makeNode(PurgeStmt); + n->purtype = PURGE_INDEX; + n->purobj = $3; + $$ = (Node *)n; + } + + | PURGE TABLESPACE name + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PURGE TABLESPACE is not yet supported."))); + TcapFeatureEnsure(); + PurgeStmt *n = makeNode(PurgeStmt); + n->purtype = PURGE_TABLESPACE; + n->purobj = makeRangeVar(NULL, $3, @3); + $$ = (Node *) n; + } + + | PURGE RECYCLEBIN + { + TcapFeatureEnsure(); + PurgeStmt *n = makeNode(PurgeStmt); + n->purtype = PURGE_RECYCLEBIN; + n->purobj = makeRangeVar(NULL, NULL, @2); + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * TIMECAPSULE : + * TIMECAPSULE TABLE { table_name } TO { TIMESTAMP | CSN } expression + * TIMECAPSULE TABLE { table_name } TO BEFORE DROP [RENAME TO new_tablename] + * TIMECAPSULE TABLE { table_name } TO BEFORE TRUNCATE [ FORCE ] + * + *****************************************************************************/ + +TimeCapsuleStmt: + TIMECAPSULE TABLE qualified_name TO opt_timecapsule_clause + { + TcapFeatureEnsure(); + TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt); + + n->relation = $3; + n->tcaptype = TIMECAPSULE_VERSION; + + n->tvtype = ((RangeTimeCapsule *)$5)->tvtype; + n->tvver = ((RangeTimeCapsule *)$5)->tvver; + + $$ = (Node *) n; + } + + | TIMECAPSULE TABLE qualified_name TO BEFORE DROP opt_rename + { + TcapFeatureEnsure(); + TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt); + n->relation = $3; + n->tcaptype = TIMECAPSULE_DROP; + n->new_relname = $7; + $$ = (Node *) n; + } + + | TIMECAPSULE TABLE qualified_name TO BEFORE TRUNCATE + { + TcapFeatureEnsure(); + TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt); + n->relation = $3; + n->tcaptype = TIMECAPSULE_TRUNCATE; + $$ = (Node *) n; + } + ; + +opt_rename: + RENAME TO name { $$ = $3; } + | /* EMPTY */ { $$ = NULL; } + ; + /***************************************************************************** * * QUERY : @@ -4749,8 +4970,13 @@ columnDef: ColId Typename KVType ColCmprsMode create_generic_options ColQualList n->cooked_default = NULL; n->collOid = InvalidOid; n->fdwoptions = $5; - SplitColQualList($6, &n->constraints, &n->collClause, &n->clientLogicColumnRef, + if ($3 == ATT_KV_UNDEFINED) { + SplitColQualList($6, &n->constraints, &n->collClause, &n->clientLogicColumnRef, yyscanner); + } else { + SplitColQualList($6, &n->constraints, &n->collClause, + yyscanner); + } $$ = (Node *)n; } ; @@ -6109,8 +6335,330 @@ opt_with_data: /***************************************************************************** * - * QUERY : - * CREATE MATERIALIZED VIEW relname AS SelectStmt + * QUERY : + * CREATE SNAPSHOT relname AS SelectStmt + * CREATE SNAPSHOT relname FROM @ version USING (AlterAndDMLStmts) + * SAMPLE SNAPSHOT relname AS postfix AT RATIO FCONST + * PUBLISH SNAPSHOT relname @ version + * ARCHIVE SNAPSHOT relname @ version + * PURGE SNAPSHOT relname @ version + * + *****************************************************************************/ + +SnapshotStmt: + CREATE OptTemp SNAPSHOT qualified_name OptSnapshotVersion +/* PGXC_BEGIN */ + OptDistributeBy OptSubCluster +/* PGXC_END */ + OptSnapshotComment + AS SelectStmt + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE SNAPSHOT is not yet supported."))); +#endif + + if ($2 != RELPERSISTENCE_PERMANENT) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Temporary snapshots are not supported."))); + } + + if ($7 != NULL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Clustered snapshots are not supported."))); + } + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("create_snapshot")), + lcons(makeStringConst($4->schemaname, @4), list_make4(makeStringConst($4->relname, @4), + makeAArrayExpr(list_make1(make_node_from_scanbuf(@10, yylloc , yyscanner)), @10), + makeStringConst($5, @5),makeStringConst($8, @8)))); + } + | CREATE OptTemp SNAPSHOT qualified_name OptSnapshotVersion +/* PGXC_BEGIN */ + OptDistributeBy OptSubCluster +/* PGXC_END */ + FROM SnapshotVersion + OptSnapshotComment + USING '(' AlterSnapshotCmdList ')' + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE SNAPSHOT is not yet supported."))); +#endif + + if ($2 != RELPERSISTENCE_PERMANENT) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Temporary snapshots are not supported."))); + } + + if ($6 != NULL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("illegal DISTRIBUTE BY clause in CREATE SNAPSHOT ... FROM"), + errhint("DISTRIBUTE BY is inherited from parent snapshot."), + parser_errposition(@6))); + } + + if ($7 != NULL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Clustered snapshots are not supported."), + parser_errposition(@7))); + } + + if ($13 == NIL) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("List of snapshot modifications is empty."), + parser_errposition(@13))); + } + + char *snapshot_name = (char *)palloc0(strlen($4->relname) + 1 + strlen($9) + 1); + sprintf(snapshot_name, "%s%c%s", $4->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $9); + $4->relname = snapshot_name; + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("prepare_snapshot")), + lcons(makeStringConst($4->schemaname, @4), list_make4(makeStringConst($4->relname, @4), + makeAArrayExpr($13, @13), makeStringConst($5, @5), makeStringConst($10, @10)))); + } + | SAMPLE SNAPSHOT qualified_name SnapshotVersion OptSnapshotStratify SnapshotSampleList + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SAMPLE SNAPSHOT is not yet supported."))); +#endif + + char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1); + sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4); + $3->relname = snapshot_name; + + List *stratify = NIL; + foreach_cell (c, $5) { + ColumnRef *r = (ColumnRef*)lfirst(c); + stratify = lappend(stratify, makeStringConst(((Value *)llast(r->fields))->val.str, @5)); + } + + List *names = NIL, *ratios = NIL, *comments = NIL; + foreach_cell (c, $6) { + names = lappend(names, lfirst(c)); + c = lnext(c); + ratios = lappend(ratios, lfirst(c)); + c = lnext(c); + comments = lappend(comments, lfirst(c)); + } + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("sample_snapshot")), + lcons(makeStringConst($3->schemaname, @3), + lcons(makeStringConst($3->relname, @3), + list_make4(makeAArrayExpr(names, -1), makeAArrayExpr(ratios, -1), + (stratify == NIL) ? makeNullAConst(-1) : makeAArrayExpr(stratify, @5), + makeAArrayExpr(comments, -1))))); + } + | ARCHIVE SNAPSHOT qualified_name SnapshotVersion + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ARCHIVE SNAPSHOT is not yet supported."))); +#endif + + char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1); + sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4); + $3->relname = snapshot_name; + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("archive_snapshot")), + list_make2(makeStringConst($3->schemaname, @3), makeStringConst($3->relname, @3))); + } + | PUBLISH SNAPSHOT qualified_name SnapshotVersion + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PUBLISH SNAPSHOT is not yet supported."))); +#endif + + char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1); + sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4); + $3->relname = snapshot_name; + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("publish_snapshot")), + list_make2(makeStringConst($3->schemaname, @3), makeStringConst($3->relname, @3))); + } + | PURGE SNAPSHOT qualified_name SnapshotVersion {} + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PURGE SNAPSHOT is not yet supported."))); +#endif + + char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1); + sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4); + $3->relname = snapshot_name; + + $$ = makeCallFuncStmt( + list_make2(makeString("db4ai"), makeString("purge_snapshot")), + list_make2(makeStringConst($3->schemaname, @3), makeStringConst($3->relname, @3))); + } + ; + +SnapshotVersion: + '@' Iconst + { + char buf[64]; + snprintf(buf, sizeof(buf), "%d", $2); + $$ = pstrdup(buf); + } + | '@' FCONST + { for (int i = strlen($2) - 1; i >= 0; i--) + { + if ($2[i] == '.') + { + $2[i] = DB4AI_SNAPSHOT_VERSION_SEPARATOR; + } + } + $$ = $2; + } + | '@' VCONST { $$ = $2; } + | '@' ColId_or_Sconst { $$ = $2; } + ; + +OptSnapshotVersion: + SnapshotVersion + { +#ifdef ENABLE_MULTIPLE_NODES + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SNAPSHOT VERSION syntax is not yet supported."))); +#endif + $$ = $1; + } + | /*EMPTY*/ { $$ = NULL; } + ; + +OptSnapshotComment: + COMMENT IS comment_text { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + +AlterSnapshotCmdList: AlterSnapshotCmdListNoParens + | AlterSnapshotCmdListWithParens + ; + +AlterSnapshotCmdListWithParens: + '(' AlterSnapshotCmdListNoParens ')' { $$ = $2; } + | '(' AlterSnapshotCmdListWithParens ')' { $$ = $2; } + ; + +AlterSnapshotCmdListNoParens: + AlterSnapshotCmdOrEmpty { $$ = $1; } + | AlterSnapshotCmdListNoParens ';' AlterSnapshotCmdOrEmpty { $$ = list_concat($1, $3); } + ; + +AlterSnapshotCmdOrEmpty: + INSERT OptInsertIntoSnapshot insert_rest + { + $$ = list_make2(make_node_from_scanbuf(@1, ($2) ? @2 : @3, yyscanner), + make_node_from_scanbuf(@3, yylloc, yyscanner)); + } + | UPDATE OptAlterUpdateSnapshot OptSnapshotAlias SET set_clause_list from_clause where_clause + { + $$ = list_make1(make_node_from_scanbuf(@1, ($2) ? @2 : ($3) ? @3 : @4, yyscanner)); + if ($3) + $$ = lappend($$, make_node_from_scanbuf(@3, @4, yyscanner)); + $$ = lappend($$, make_node_from_scanbuf(@4, (@5 == @6) ? ((@5 == @7) ? yylloc : @7) : @6, yyscanner)); + if ($6 != NIL) + $$ = lappend($$, make_node_from_scanbuf(@6, (@6 == @7) ? yylloc : @7, yyscanner)); + if ($7 != NULL) + $$ = lappend($$, make_node_from_scanbuf(@7, yylloc, yyscanner)); + } + | DELETE_P OptDeleteFromSnapshot OptSnapshotAlias using_clause where_clause + { + $$ = list_make1(make_node_from_scanbuf(@1, ($2) ? @2 : ($3) ? @3 : (@1 == @4) ? ((@1 == @5) ? yylloc : @5) : @4, yyscanner)); + if ($3) + $$ = lappend($$, make_node_from_scanbuf(@3, (@3 == @4) ? ((@3 == @5) ? yylloc : @5) : @4, yyscanner)); + if ($4 != NIL) + $$ = lappend($$, make_node_from_scanbuf(@4, (@4 == @5) ? yylloc : @5, yyscanner)); + if ($5 != NULL) + $$ = lappend($$, make_node_from_scanbuf(@5, yylloc, yyscanner)); + } + | ALTER OptAlterUpdateSnapshot AlterSnapshotDdlList + { + $$ = list_make2(make_node_from_scanbuf(@1, ($2) ? @2 : @3, yyscanner), + make_node_from_scanbuf(@3, yylloc, yyscanner)); + } + | /*EMPTY*/ { $$ = NIL; } + ; + +OptAlterUpdateSnapshot: + SNAPSHOT { $$ = TRUE; } + | /*EMPTY*/ { $$ = FALSE; } + ; + +OptInsertIntoSnapshot: + INTO SNAPSHOT { $$ = TRUE; } + | /*EMPTY*/ { $$ = FALSE; } + ; + +OptDeleteFromSnapshot: + FROM SNAPSHOT { $$ = TRUE; } + | /*EMPTY*/ { $$ = FALSE; } + ; + +OptSnapshotAlias: + AS ColId { $$ = TRUE; } + | /*EMPTY*/ { $$ = FALSE; } + ; + +AlterSnapshotDdlList: // parse and ignore + AlterSnapshotDdl { $$ = FALSE; } + | AlterSnapshotDdlList ',' AlterSnapshotDdl { $$ = FALSE; } + ; + +AlterSnapshotDdl: // parse and ignore + ADD_P opt_column columnDef { $$ = FALSE; } + | DROP opt_column IF_P EXISTS ColId { $$ = FALSE; } + | DROP opt_column ColId { $$ = FALSE; } + ; + +SnapshotSample: + AS ColLabel AT RATIO FCONST OptSnapshotComment + { + $$ = list_make3(makeStringConst($2, @2), makeStringConst($5, @5), makeStringConst($6, @6)); + } + ; + +SnapshotSampleList: + SnapshotSample { $$ = $1; } + | SnapshotSampleList ',' SnapshotSample { $$ = list_concat($1, $3); } + ; + +OptSnapshotStratify: + STRATIFY BY column_item_list { $$ = $3; } + | /*EMPTY*/ { $$ = NIL; } + ; + + /***************************************************************************** + * + * QUERY : + * CREATE MATERIALIZED VIEW relname AS SelectStmt * *****************************************************************************/ @@ -8902,7 +9450,7 @@ ReassignOwnedStmt: * *****************************************************************************/ -DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior +DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior opt_purge { DropStmt *n = makeNode(DropStmt); n->removeType = $2; @@ -8911,9 +9459,17 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior n->arguments = NIL; n->behavior = $6; n->concurrent = false; + n->purge = $7; + if (n->removeType != OBJECT_TABLE && n->purge) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("PURGE clause only allowed in \"DROP TABLE\" statement"), + parser_errposition(@7))); + } + $$ = (Node *)n; } - | DROP drop_type any_name_list opt_drop_behavior + | DROP drop_type any_name_list opt_drop_behavior opt_purge { DropStmt *n = makeNode(DropStmt); n->removeType = $2; @@ -8922,6 +9478,13 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior n->arguments = NIL; n->behavior = $4; n->concurrent = false; + n->purge = $5; + if (n->removeType != OBJECT_TABLE && n->purge) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("PURGE clause only allowed in \"DROP TABLE\" statement"), + parser_errposition(@5))); + } $$ = (Node *)n; } | DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior @@ -8948,6 +9511,11 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior } ; +opt_purge: + PURGE { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + drop_type: TABLE { $$ = OBJECT_TABLE; } | CONTVIEW { $$ = OBJECT_CONTQUERY; } @@ -8995,12 +9563,13 @@ attrs: '.' attr_name *****************************************************************************/ TruncateStmt: - TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior + TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior opt_purge { TruncateStmt *n = makeNode(TruncateStmt); n->relations = $3; n->restart_seqs = $4; n->behavior = $5; + n->purge = $6; $$ = (Node *)n; } ; @@ -9023,7 +9592,7 @@ opt_restart_seqs: * TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE | * TEXT SEARCH CONFIGURATION | FOREIGN TABLE | * FOREIGN DATA WRAPPER | SERVER | EVENT TRIGGER | - MATERIALIZED VIEW] | + * MATERIALIZED VIEW | SNAPSHOT] | * AGGREGATE (arg1, ...) | * FUNCTION (arg1, arg2, ...) | * OPERATOR (leftoperand_typ, rightoperand_typ) | @@ -9198,6 +9767,7 @@ comment_type: | TYPE_P { $$ = OBJECT_TYPE; } | VIEW { $$ = OBJECT_VIEW; } | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } + | SNAPSHOT { $$ = OBJECT_VIEW; } | COLLATION { $$ = OBJECT_COLLATION; } | CONVERSION_P { $$ = OBJECT_CONVERSION; } | TABLESPACE { $$ = OBJECT_TABLESPACE; } @@ -9656,11 +10226,19 @@ privilege_target: n->objs = $2; $$ = n; } - | PROCEDURE function_with_argtypes_list + | PROCEDURE function_with_argtypes_list + { + PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); + n->targtype = ACL_TARGET_OBJECT; + n->objtype = ACL_OBJECT_FUNCTION; + n->objs = $2; + $$ = n; + } + | PACKAGE any_name_list { PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); n->targtype = ACL_TARGET_OBJECT; - n->objtype = ACL_OBJECT_FUNCTION; + n->objtype = ACL_OBJECT_PACKAGE; n->objs = $2; $$ = n; } @@ -10249,6 +10827,7 @@ CreateFunctionStmt: { CreateFunctionStmt *n = makeNode(CreateFunctionStmt); n->isOraStyle = false; + n->isPrivate = false; n->replace = $2; n->funcname = $4; n->parameters = $5; @@ -10263,6 +10842,7 @@ CreateFunctionStmt: { CreateFunctionStmt *n = makeNode(CreateFunctionStmt); n->isOraStyle = false; + n->isPrivate = false; n->replace = $2; n->funcname = $4; n->parameters = mergeTableFuncParameters($5, $9); @@ -10278,6 +10858,7 @@ CreateFunctionStmt: { CreateFunctionStmt *n = makeNode(CreateFunctionStmt); n->isOraStyle = false; + n->isPrivate = false; n->replace = $2; n->funcname = $4; n->parameters = $5; @@ -10288,17 +10869,24 @@ CreateFunctionStmt: $$ = (Node *)n; } | CREATE opt_or_replace FUNCTION func_name_opt_arg proc_args - RETURN func_return opt_createproc_opt_list as_is {u_sess->parser_cxt.eaten_declare = false; u_sess->parser_cxt.eaten_begin = false;} subprogram_body + RETURN func_return opt_createproc_opt_list as_is { + u_sess->parser_cxt.eaten_declare = false; + u_sess->parser_cxt.eaten_begin = false; + pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true; + } subprogram_body { CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + FunctionSources *funSource = (FunctionSources *)$11; n->isOraStyle = true; + n->isPrivate = false; n->replace = $2; n->funcname = $4; n->parameters = $5; + n->inputHeaderSrc = FormatFuncArgType(yyscanner, funSource->headerSrc, n->parameters); n->returnType = $7; n->options = $8; n->options = lappend(n->options, makeDefElem("as", - (Node *)list_make1(makeString($11)))); + (Node *)list_make1(makeString(funSource->bodySrc)))); n->options = lappend(n->options, makeDefElem("language", (Node *)makeString("plpgsql"))); @@ -10307,54 +10895,443 @@ CreateFunctionStmt: n->isProcedure = false; $$ = (Node *)n; } - ; -CallFuncStmt: CALL func_name '(' ')' + ; +CallFuncStmt: CALL func_name '(' ')' + { + $$ = makeCallFuncStmt($2,NULL); + } + | CALL func_name '(' callfunc_args ')' + { + $$ = makeCallFuncStmt($2,$4); + } + ; +callfunc_args: func_arg_expr + { + $$ = list_make1($1); + } + | callfunc_args ',' func_arg_expr + { + $$ = lappend($1, $3); + } + ; +CreateProcedureStmt: + CREATE opt_or_replace PROCEDURE func_name_opt_arg proc_args + opt_createproc_opt_list as_is { + u_sess->parser_cxt.eaten_declare = false; + u_sess->parser_cxt.eaten_begin = false; + pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true; + } subprogram_body + { + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + FunctionSources *funSource = (FunctionSources *)$9; + int count = get_outarg_num($5); + + n->isOraStyle = true; + n->isPrivate = false; + n->replace = $2; + n->funcname = $4; + n->parameters = $5; + n->inputHeaderSrc = FormatFuncArgType(yyscanner, funSource->headerSrc, n->parameters); + n->returnType = NULL; + n->isProcedure = true; + if (0 == count) + { + n->returnType = makeTypeName("void"); + n->returnType->typmods = NULL; + n->returnType->arrayBounds = NULL; + } + n->options = $6; + n->options = lappend(n->options, makeDefElem("as", + (Node *)list_make1(makeString(funSource->bodySrc)))); + n->options = lappend(n->options, makeDefElem("language", + (Node *)makeString("plpgsql"))); + n->withClause = NIL; + $$ = (Node *)n; + } + + ; + +CreatePackageStmt: + CREATE opt_or_replace PACKAGE pkg_name invoker_rights as_is {pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;} pkg_subprogram + { + char *pkgNameBegin = NULL; + char *pkgNameEnd = NULL; + char *pkgName = NULL; + DefElem *def = NULL; + switch (list_length($4)) { + case 1: + pkgName = strVal(linitial($4)); + break; + case 2: + pkgName = strVal(lsecond($4)); + break; + case 3: + pkgName = strVal(lthird($4)); + break; + default: + parser_yyerror("package name is invalid!"); + break; + } + pkgNameBegin = (char *)palloc(strlen(pkgName) + 1); + strcpy(pkgNameBegin, pkgName); + pkgNameBegin = pg_strtolower(pkgNameBegin); + def = (DefElem *)lsecond($8); + if (strcmp(def->defname,"name") != 0) + { + parser_yyerror("internal grammer error!"); + } + pkgNameEnd = strVal(def->arg); + getPkgName(pkgNameEnd); + if (strcmp(pkgNameBegin, pkgNameEnd) != 0) + { + parser_yyerror("package name end is not match the one begin!"); + } + CreatePackageStmt *n = makeNode(CreatePackageStmt); + n->replace = $2; + n->pkgname = $4; + n->options = $5; + def = (DefElem *)linitial($8); + if (strcmp(def->defname,"decl") != 0) + { + parser_yyerror("internal grammer error!"); + } + n->pkgspec = strVal(def->arg); + $$ = (Node *)n; + } + ; +pkg_name: ColId + { $$ = list_make1(makeString($1)); } + | ColId indirection + { + $$ = check_func_name(lcons(makeString($1), $2), + yyscanner); + } + ; +invoker_rights: AUTHID DEFINER + { + $$ = list_make1(makeDefElem("security", (Node *)makeInteger(TRUE))); + } + | AUTHID CURRENT_USER + { + $$ = list_make1(makeDefElem("security", (Node *)makeInteger(FALSE))); + } + | + { + $$ = list_make1(makeDefElem("security", (Node *)makeInteger(TRUE))); + } + ; +pkg_subprogram: { + int proc_b = 0; + int proc_e = 0; + char *pkg_spec_str = NULL; + char *pkg_name_str = NULL; + int pkg_spec_len = 0; + int tok = YYEMPTY; + int pre_tok = 0; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + yyextra->core_yy_extra.in_slash_proc_body = true; + /* the token BEGIN_P have been parsed */ + if (yychar == YYEOF || yychar == YYEMPTY) + tok = YYLEX; + else + { + tok = yychar; + yychar = YYEMPTY; + } + proc_b = yylloc; + while(true) + { + if (tok == YYEOF) + parser_yyerror("package spec is not ended correctly"); + + if (tok == END_P) + { + pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = false; + tok = YYLEX; + proc_e = yylloc; + + if (tok == ';') + { + continue; + } + + tok = YYLEX; + if (tok != ';') + { + parser_yyerror("variable declare in package spec is not ended correctly"); + } + + if (proc_e == 0) { + parser_yyerror("variable declare in package spec is not ended correctly"); + } + + pkg_spec_len = proc_e - proc_b + 1; + pkg_spec_str = (char *)palloc0(pkg_spec_len + DECLARE_LEN + PACKAGE_LEN + 1); + strncpy_s(pkg_spec_str, PACKAGE_LEN + 1, PACKAGE_STR, PACKAGE_LEN); + strncpy_s(pkg_spec_str + PACKAGE_LEN, DECLARE_LEN + 1, DECLARE_STR, DECLARE_LEN); + strncpy_s(pkg_spec_str + DECLARE_LEN + PACKAGE_LEN, pkg_spec_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_spec_len); + pkg_spec_str[pkg_spec_len + DECLARE_LEN + PACKAGE_LEN] = '\0'; + proc_b = proc_e; + proc_e = yylloc; + if (proc_e == 0) + { + parser_yyerror("variable declare in package spec is not ended correctly"); + } + pkg_spec_len = proc_e - proc_b + 1 ; + pkg_name_str = (char *)palloc0(pkg_spec_len + 1); + strncpy_s(pkg_name_str, pkg_spec_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_spec_len); + pkg_name_str[pkg_spec_len] = '\0'; + while (isspace((unsigned char)*pkg_name_str)) { + pkg_name_str++; + } + truncate_identifier(pkg_name_str, strlen(pkg_name_str), false); + break; + } + tok = YYLEX; + } + pkg_name_str = pg_strtolower(pkg_name_str); + if (yyextra->lookahead_num != 0) + parser_yyerror("package spec is not ended correctly"); + else + { + yyextra->lookahead_token[0] = tok; + yyextra->lookahead_num = 1; + } + /* Reset the flag which mark whether we are in slash proc. */ + yyextra->core_yy_extra.in_slash_proc_body = false; + yyextra->core_yy_extra.dolqstart = NULL; + /* + * Add the end location of slash proc to the locationlist for the multi-query + * processed. + */ + yyextra->core_yy_extra.query_string_locationlist = + lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc); + $$ = list_concat(list_make1(makeDefElem("decl", (Node *)makeString(pkg_spec_str))), + list_make1(makeDefElem("name", (Node *)makeString(pkg_name_str)))); + } + ; + + +pkg_body_subprogram: { + int proc_b = 0; + int proc_e = 0; + char *pkg_body_str = NULL; + char *pkg_name_str = NULL; + int pkg_name_len = 0; + int pkg_body_len = 0; + int instantiation_start = 0; + int instantiation_end = 0; + int block_level = 0; + int tok = YYEMPTY; + int pre_tok_loc = 0; + bool pkg_end = true; + char* instantiation_str = NULL; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + bool in_procedure = false; + yyextra->core_yy_extra.in_slash_proc_body = true; + /* the token BEGIN_P have been parsed */ + List* result_list = NULL; + if (yychar == YYEOF || yychar == YYEMPTY) + { + tok = YYLEX; + } + else + { + tok = yychar; + yychar = YYEMPTY; + } + proc_b = yylloc; + while(true) + { + if (tok == YYEOF) { + parser_yyerror("package is not ended correctly"); + } + if (tok == PROCEDURE || tok == FUNCTION) { + in_procedure = true; + } + + if (tok == BEGIN_P) { + block_level = block_level + 1; + if (in_procedure == false) { + instantiation_start = yylloc; + } + } + + if (tok == END_P) + { + pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = false; + tok = YYLEX; + proc_e = yylloc; + if (tok == ';') + { + block_level = block_level - 1; + if (block_level == 0) + { + in_procedure = false; + } + continue; + } + if (tok == LOOP || tok == IF_P || tok == CASE) + { + continue; + } + tok = YYLEX; + if (tok != ';' && tok != 0) { + continue; + } else if (tok == 0){ + parser_yyerror("package is not ended correctly"); + } + if (proc_e == 0) + parser_yyerror("variable declare in package is not ended correctly"); + if (instantiation_start == 0) { + pkg_body_len = proc_e - proc_b + 1; + pkg_body_str = (char *)palloc0(pkg_body_len + DECLARE_LEN + PACKAGE_LEN + 1); + strncpy_s(pkg_body_str, PACKAGE_LEN + 1, PACKAGE_STR, PACKAGE_LEN); + strncpy_s(pkg_body_str + PACKAGE_LEN, DECLARE_LEN + 1, DECLARE_STR, DECLARE_LEN); + strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN, pkg_body_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_body_len); + pkg_body_str[pkg_body_len + DECLARE_LEN + PACKAGE_LEN] = '\0'; + proc_b = proc_e; + proc_e = yylloc; + if (proc_e == 0) + parser_yyerror("variable declare in package spec is not ended correctly"); + pkg_name_len = proc_e - proc_b + 1 ; + pkg_name_str = (char *)palloc0(pkg_name_len + 1); + strncpy_s(pkg_name_str, pkg_name_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_name_len); + pkg_name_str[pkg_name_len] = '\0'; + while (isspace((unsigned char)*pkg_name_str)) { + pkg_name_str++; + } + truncate_identifier(pkg_name_str, strlen(pkg_name_str), false); + break; + } else { + int proc_end_all = proc_e; + proc_e = instantiation_start; + pkg_body_len = proc_e - proc_b + 1; + pkg_body_str = (char *)palloc0(pkg_body_len + DECLARE_LEN + PACKAGE_LEN + END_LEN + 2); + strncpy_s(pkg_body_str, PACKAGE_LEN + 1, PACKAGE_STR, PACKAGE_LEN); + strncpy_s(pkg_body_str + PACKAGE_LEN, DECLARE_LEN + 1, DECLARE_STR, DECLARE_LEN); + strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN, pkg_body_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_body_len); + strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN + pkg_body_len, END_LEN + 1, + END_STR, END_LEN); + pkg_body_str[pkg_body_len + DECLARE_LEN + PACKAGE_LEN + END_LEN] = '\0'; + proc_b = proc_end_all; + proc_e = yylloc; + if (proc_e == 0) + parser_yyerror("variable declare in package spec is not ended correctly"); + pkg_name_len = proc_e - proc_b + 1 ; + pkg_name_str = (char *)palloc0(pkg_name_len + 1); + strncpy_s(pkg_name_str, pkg_name_len + 1, + yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_name_len); + pkg_name_str[pkg_name_len] = '\0'; + while (isspace((unsigned char)*pkg_name_str)) { + pkg_name_str++; + } + truncate_identifier(pkg_name_str, strlen(pkg_name_str), false); + instantiation_end = pre_tok_loc; + int pkg_instantiation_len = instantiation_end - instantiation_start; + instantiation_str = (char *)palloc0(INSTANTIATION_LEN + pkg_instantiation_len + END_LEN + 2); + strncpy_s(instantiation_str, INSTANTIATION_LEN + 1, INSTANTIATION_STR, INSTANTIATION_LEN); + strncpy_s(instantiation_str + INSTANTIATION_LEN, pkg_instantiation_len + 1, + yyextra->core_yy_extra.scanbuf + instantiation_start - 1, pkg_instantiation_len); + strncpy_s(instantiation_str + INSTANTIATION_LEN + pkg_instantiation_len, END_LEN + 1 , END_STR, END_LEN); + instantiation_str[INSTANTIATION_LEN + pkg_instantiation_len + END_LEN] = '\0'; + break; + } + } + tok = YYLEX; + pre_tok_loc = yylloc; + } + pkg_name_str = pg_strtolower(pkg_name_str); + if (yyextra->lookahead_num != 0) + parser_yyerror("package spec is not ended correctly"); + else + { + yyextra->lookahead_token[0] = tok; + yyextra->lookahead_num = 1; + } + /* Reset the flag which mark whether we are in slash proc. */ + yyextra->core_yy_extra.in_slash_proc_body = false; + yyextra->core_yy_extra.dolqstart = NULL; + /* + * Add the end location of slash proc to the locationlist for the multi-query + * processed. + */ + yyextra->core_yy_extra.query_string_locationlist = + lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc); + + result_list = list_concat(list_make1(makeDefElem("decl", (Node *)makeString(pkg_body_str))), + list_make1(makeDefElem("name", (Node *)makeString(pkg_name_str)))); + if (instantiation_start != 0) { + result_list = list_concat(result_list,list_make1(makeDefElem(("init"), (Node *)makeString(instantiation_str)))); + } else { + result_list = list_concat(result_list,list_make1(makeDefElem(("init"), NULL))); + } + $$ = result_list; + } + ; +CreatePackageBodyStmt: + CREATE opt_or_replace PACKAGE BODY_P pkg_name as_is {pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;} pkg_body_subprogram + { + char *pkgNameBegin = NULL; + char *pkgNameEnd = NULL; + char *pkgName = NULL; + DefElem *def = NULL; + switch (list_length($5)) { + case 1: + pkgName = strVal(linitial($5)); + break; + case 2: + pkgName = strVal(lsecond($5)); + break; + case 3: + pkgName = strVal(lthird($5)); + break; + default: + parser_yyerror("package name is invalid!"); + break; + } + pkgNameBegin = (char *)palloc(strlen(pkgName) + 1); + strcpy(pkgNameBegin, pkgName); + pkgNameBegin = pg_strtolower(pkgNameBegin); + int length = list_length($8); + def = (DefElem *)lsecond($8); + if (strcmp(def->defname,"name") != 0) { - $$ = makeCallFuncStmt($2,NULL); + parser_yyerror("internal grammer error!"); } - | CALL func_name '(' callfunc_args ')' + pkgNameEnd = strVal(def->arg); + getPkgName(pkgNameEnd); + if (strcmp(pkgNameBegin, pkgNameEnd) != 0) { - $$ = makeCallFuncStmt($2,$4); + parser_yyerror("package name end is not match the one begin!"); } - ; -callfunc_args: func_arg_expr - { - $$ = list_make1($1); - } - | callfunc_args ',' func_arg_expr - { - $$ = lappend($1, $3); - } - ; -CreateProcedureStmt: - CREATE opt_or_replace PROCEDURE func_name_opt_arg proc_args - opt_createproc_opt_list as_is {u_sess->parser_cxt.eaten_declare = false; u_sess->parser_cxt.eaten_begin = false;} subprogram_body - { - CreateFunctionStmt *n = makeNode(CreateFunctionStmt); - int count = get_outarg_num($5); - n->isOraStyle = true; + CreatePackageBodyStmt *n = makeNode(CreatePackageBodyStmt); n->replace = $2; - n->funcname = $4; - n->parameters = $5; - n->returnType = NULL; - n->isProcedure = true; - if (0 == count) + n->pkgname = $5; + def = (DefElem *)linitial($8); + if (strcmp(def->defname,"decl") != 0) { - n->returnType = makeTypeName("void"); - n->returnType->typmods = NULL; - n->returnType->arrayBounds = NULL; + parser_yyerror("internal grammer error!"); } - n->options = $6; - n->options = lappend(n->options, makeDefElem("as", - (Node *)list_make1(makeString($9)))); - n->options = lappend(n->options, makeDefElem("language", - (Node *)makeString("plpgsql"))); - n->withClause = NIL; + n->pkgbody = strVal(def->arg); + def = (DefElem *)lthird($8); + if (strcmp(def->defname,"init") != 0) + { + parser_yyerror("internal grammer error!"); + } + if (def->arg) { + n->pkginit = strVal(def->arg); + } else { + n->pkginit = NULL; + } $$ = (Node *)n; } - ; - opt_or_replace: OR REPLACE { $$ = TRUE; } | /*EMPTY*/ { $$ = FALSE; } @@ -10364,7 +11341,9 @@ func_args: '(' func_args_list ')' { $$ = $2; } | '(' ')' { $$ = NIL; } ; -proc_args: func_args_with_defaults { $$ = $1; } +proc_args: { + pg_yyget_extra(yyscanner)->core_yy_extra.func_param_begin = yylloc; + } func_args_with_defaults { pg_yyget_extra(yyscanner)->core_yy_extra.func_param_end = yylloc; $$ = $2; } |/*EMPTY*/ { $$ = NIL; } ; @@ -10491,6 +11470,7 @@ func_type: Typename { $$ = $1; } $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); $$->pct_type = true; $$->location = @1; + $$->end_location = @4 + TYPE_LEN; } | SETOF type_function_name attrs '%' TYPE_P { @@ -10498,6 +11478,7 @@ func_type: Typename { $$ = $1; } $$->pct_type = true; $$->setof = TRUE; $$->location = @2; + $$->end_location = @5 + TYPE_LEN; } ; @@ -10623,13 +11604,6 @@ common_func_opt_item: } | FENCED { - if (IS_SINGLE_NODE) - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("FENCED mode function is not yet supported in current version."))); - } - $$ = makeDefElem("fenced", (Node *)makeInteger(TRUE)); } | NOT FENCED @@ -10682,6 +11656,8 @@ subprogram_body: { int proc_body_len = 0; int blocklevel = 0; bool add_declare = true; /* Mark if need to add a DECLARE */ + FunctionSources *funSrc = NULL; + char *proc_header_str = NULL; int tok = YYEMPTY; int pre_tok = 0; @@ -10703,8 +11679,13 @@ subprogram_body: { if (u_sess->parser_cxt.eaten_declare || DECLARE == tok) add_declare = false; + /* Save procedure header str,start with param exclude brackets */ + proc_header_str = ParseFunctionArgSrc(yyscanner); + /* Save the beginning of procedure body. */ proc_b = yylloc; + + /* start procedure body scan */ while(true) { if (tok == YYEOF) @@ -10804,7 +11785,11 @@ subprogram_body: { yyextra->core_yy_extra.query_string_locationlist = lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc); - $$ = proc_body_str; + funSrc = (FunctionSources*)palloc0(sizeof(FunctionSources)); + funSrc->bodySrc = proc_body_str; + funSrc->headerSrc = proc_header_str; + + $$ = funSrc; } ; opt_definition: @@ -10842,6 +11827,57 @@ table_func_column_list: * only be applied to functions. * *****************************************************************************/ + + RemovePackageStmt: + DROP PACKAGE pkg_name + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PACKAGE; + n->objects = list_make1($3); + n->arguments = NULL; + n->behavior = DROP_CASCADE; + n->missing_ok = false; + n->concurrent = false; + n->isProcedure = false; + $$ = (Node *)n; + } + | DROP PACKAGE IF_P EXISTS pkg_name + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PACKAGE; + n->objects = list_make1($5); + n->arguments = NULL; + n->behavior = DROP_CASCADE; + n->missing_ok = true; + n->concurrent = false; + n->isProcedure = false; + $$ = (Node *)n; + } + | DROP PACKAGE BODY_P pkg_name + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PACKAGE_BODY; + n->objects = list_make1($4); + n->arguments = NULL; + n->behavior = DROP_CASCADE; + n->missing_ok = false; + n->concurrent = false; + n->isProcedure = false; + $$ = (Node *)n; + } + | DROP PACKAGE BODY_P IF_P EXISTS pkg_name + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_PACKAGE_BODY; + n->objects = list_make1($6); + n->arguments = NULL; + n->behavior = DROP_CASCADE; + n->missing_ok = true; + n->concurrent = false; + n->isProcedure = false; + $$ = (Node *)n; + } + AlterFunctionStmt: ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict { @@ -11094,11 +12130,11 @@ dostmt_opt_item: AnonyBlockStmt: DECLARE { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = false; } subprogram_body { - $$ = (Node *)MakeAnonyBlockFuncStmt(DECLARE, $3); + $$ = (Node *)MakeAnonyBlockFuncStmt(DECLARE, ((FunctionSources*)$3)->bodySrc); } | BEGIN_P { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = true; } subprogram_body { - $$ = (Node *)MakeAnonyBlockFuncStmt(BEGIN_P, $3); + $$ = (Node *)MakeAnonyBlockFuncStmt(BEGIN_P, ((FunctionSources*)$3)->bodySrc); } ; /***************************************************************************** @@ -13572,6 +14608,16 @@ bucket_list: | Iconst { $$ = list_make1(makeInteger($1)); } ; +bucket_cnt: + BUCKETCNT Iconst { $$ = $2; } + | /*EMPTY*/ { $$ = -1; } + ; + +pgxcgroup_parent: + GROUPPARENT pgxcnode_name { $$ = $2; } + | /*EMPTY*/ { $$ = NULL;} + ; + opt_vcgroup: VCGROUP {$$ = TRUE;} | /* EMPTY */ {$$ = FALSE;} @@ -13583,7 +14629,7 @@ opt_to_elastic_group: ; opt_redistributed: - DISTRIBUTE FROM ColId {$$ = $3;} + DISTRIBUTE FROM ColId {$$ = $3;} | /* EMPTY */ {$$ = NULL;} ; @@ -13677,15 +14723,17 @@ opt_pgxcnodes: WITH pgxcnodes * *****************************************************************************/ -CreateNodeGroupStmt: CREATE NODE GROUP_P pgxcgroup_name WITH pgxcnodes bucket_maps opt_vcgroup opt_redistributed +CreateNodeGroupStmt: CREATE NODE GROUP_P pgxcgroup_name opt_pgxcnodes bucket_maps opt_vcgroup opt_redistributed bucket_cnt pgxcgroup_parent { CreateGroupStmt *n = makeNode(CreateGroupStmt); IsValidGroupname($4); n->group_name = $4; - n->nodes = $6; - n->buckets = $7; - n->vcgroup = $8; - n->src_group_name = $9; + n->nodes = $5; + n->buckets = $6; + n->vcgroup = $7; + n->src_group_name = $8; + n->bucketcnt = $9; + n->group_parent = $10; $$ = (Node *)n; } ; @@ -14267,6 +15315,14 @@ masking_clause_elem: { $$ = makeDefElem($1, (Node *)lappend(list_make1($2) , $4)); } + | masking_func_nsp '.' masking_func masking_func_params_opt ON masking_target + { + $$ = makeDefElemExtended($1, $3, (Node *)lappend(list_make1($4) , $6), DEFELEM_UNSPEC); + } + ; + +masking_func_nsp: + ColLabel { IsValidIdent($1); $$ = $1; } ; masking_func: @@ -14346,6 +15402,7 @@ masking_policy_condition_operator: | '<' { $$ = "<"; } | '>' { $$ = ">"; } | '=' { $$ = "="; } + | '@' { $$ = "@"; } ; masking_policy_condition_value: @@ -14998,6 +16055,7 @@ ExplainableStmt: | DeclareCursorStmt | CreateAsStmt | CreateModelStmt + | SnapshotStmt | ExecuteStmt /* by default all are $$=$1 */ ; @@ -16508,7 +17566,20 @@ table_ref: relation_expr n->relation = (Node *) $1; $$ = (Node *) n; } + | relation_expr opt_alias_clause timecapsule_clause + { + RangeTimeCapsule *n = (RangeTimeCapsule *) $3; + $1->alias = $2; + /* relation_expr goes inside the RangeTimeCapsule node */ + n->relation = (Node *) $1; + + if (IsA($1, RangeVar)) { + RangeVar *rv = (RangeVar *)$1; + rv->withVerExpr = true; + } + $$ = (Node *) n; + } | relation_expr PARTITION '(' name ')' { $1->partitionname = $4; @@ -16784,10 +17855,16 @@ join_qual: USING '(' name_list ')' { $$ = (Node *) $3; } relation_expr: - qualified_name + qualified_name OptSnapshotVersion { /* default inheritance */ $$ = $1; + if ($2 != NULL) + { + char *snapshot_name = (char *)palloc0(strlen($1->relname) + 1 + strlen($2) + 1); + sprintf(snapshot_name, "%s%c%s", $1->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $2); + $$->relname = snapshot_name; + } $$->inhOpt = INH_DEFAULT; $$->alias = NULL; } @@ -16866,6 +17943,33 @@ tablesample_clause: } ; +/* + * TIMECAPSULE decoration in a FROM item + */ +timecapsule_clause: + TIMECAPSULE opt_timecapsule_clause { $$ = $2; } + +opt_timecapsule_clause: + CSN a_expr + { + TcapFeatureEnsure(); + RangeTimeCapsule *n = makeNode(RangeTimeCapsule); + n->tvtype = TV_VERSION_CSN; + n->tvver = (Node *)$2; + n->location = @2; + $$ = (Node *) n; + } + | TIMESTAMP a_expr + { + TcapFeatureEnsure(); + RangeTimeCapsule *n = makeNode(RangeTimeCapsule); + n->tvtype = TV_VERSION_TIMESTAMP; + n->tvver = (Node *)$2; + n->location = @2; + $$ = (Node *) n; + } + ; + opt_repeatable_clause: REPEATABLE '(' a_expr ')' { $$ = (Node *) $3; } | /*EMPTY*/ { $$ = NULL; } @@ -17123,6 +18227,11 @@ Numeric: INT_P $$ = SystemTypeName("float8"); $$->location = @1; } + | BINARY_FLOAT + { + $$ = SystemTypeName("float4"); + $$->location = @1; + } | BINARY_INTEGER { $$ = SystemTypeName("int4"); @@ -17405,6 +18514,7 @@ ConstDatetime: else $$ = SystemTypeName("date"); $$->location = @1; + $$->end_location = @1 + DATE_LEN; } | SMALLDATETIME { @@ -17623,6 +18733,8 @@ a_expr: c_expr { $$ = $1; } { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } | '-' a_expr %prec UMINUS { $$ = doNegate($2, @1); } + | '@' a_expr + { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", NULL, $2, @1); } | a_expr '+' a_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); } | a_expr '-' a_expr @@ -17641,6 +18753,8 @@ a_expr: c_expr { $$ = $1; } { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); } | a_expr '=' a_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); } + | a_expr '@' a_expr + { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", $1, $3, @2); } | a_expr CmpOp a_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, $2, $1, $3, @2); } | a_expr qual_Op a_expr %prec Op @@ -18146,6 +19260,8 @@ b_expr: c_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } | '-' b_expr %prec UMINUS { $$ = doNegate($2, @1); } + | '@' b_expr + { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", NULL, $2, @1); } | b_expr '+' b_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); } | b_expr '-' b_expr @@ -18164,6 +19280,8 @@ b_expr: c_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); } | b_expr '=' b_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); } + | b_expr '@' b_expr + { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", $1, $3, @2); } | b_expr CmpOp b_expr { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, $2, $1, $3, @2); } | b_expr qual_Op b_expr %prec Op @@ -19754,6 +20872,7 @@ MathOp: '+' { $$ = "+"; } | '<' { $$ = "<"; } | '>' { $$ = ">"; } | '=' { $$ = "="; } + | '@' { $$ = "@"; } ; qual_Op: Op @@ -20577,6 +21696,7 @@ unreserved_keyword: | ALTER | ALWAYS | APP + | ARCHIVE | ASSERTION | ASSIGNMENT | AT @@ -20592,6 +21712,8 @@ unreserved_keyword: | BEGIN_NON_ANOYBLOCK | BEGIN_P | BLOB_P + | BLOCKCHAIN + | BODY_P | BY | CACHE | CALL @@ -20838,6 +21960,8 @@ unreserved_keyword: | PRIVILEGES | PROCEDURAL | PROFILE + | PUBLISH + | PURGE | QUERY | QUOTE | RANDOMIZED @@ -20876,6 +22000,7 @@ unreserved_keyword: | ROLES | ROLLBACK | ROLLUP + | ROTATION | ROWS | RULE | SAMPLE @@ -20934,6 +22059,7 @@ unreserved_keyword: | TIME_FORMAT_P | TIMESTAMP_FORMAT_P | TRANSACTION + | TRANSFORM | TRIGGER | TRUNCATE | TRUSTED @@ -20959,7 +22085,6 @@ unreserved_keyword: | VALIDATION | VALIDATOR | VALUE_P - | VARIABLES | VARYING | VERSION_P | VIEW @@ -20991,9 +22116,11 @@ col_name_keyword: BETWEEN | BIGINT | BINARY_DOUBLE + | BINARY_FLOAT | BINARY_INTEGER | BIT | BOOLEAN_P + | BUCKETCNT | BYTEAWITHOUTORDER | BYTEAWITHOUTORDERWITHEQUAL | CHAR_P @@ -21082,6 +22209,7 @@ type_func_name_keyword: | COMPACT | CONCURRENTLY | CROSS + | CSN | CURRENT_SCHEMA | DELTAMERGE | DIV @@ -21097,11 +22225,13 @@ type_func_name_keyword: | NOTNULL | OUTER_P | OVERLAPS + | RECYCLEBIN | REGEXP | RIGHT | RLIKE | SIMILAR | TABLESAMPLE + | TIMECAPSULE | VERBOSE | XOR ; @@ -21154,6 +22284,7 @@ reserved_keyword: | FROM | GRANT | GROUP_P + | GROUPPARENT | HAVING | IN_P | INITIALLY @@ -21285,6 +22416,19 @@ makeTypeCast(Node *arg, TypeName *typname, int location) return (Node *) n; } +static void +getPkgName(char* pkgname) { + while (isspace((unsigned char)*pkgname) && (unsigned char)*pkgname != '\0') { + pkgname++; + } + while (!isspace((unsigned char)*pkgname) && (unsigned char)*pkgname != '\0') { + pkgname++; + } + if (isspace((unsigned char)*pkgname)) { + *pkgname = '\0'; + } +} + static Node * makeStringConst(char *str, int location) { @@ -21834,6 +22978,13 @@ SplitColQualList(List *qualList, parser_errposition(c->location))); *collClause = c; } + else if (IsA(n, ClientLogicColumnRef)) + { + ereport(ERROR, (errmodule(MOD_SEC), errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unsupported syntax: ENCRYPTED WITH in this operation"), errdetail("N/A"), + errcause("client encryption feature is not supported this operation."), + erraction("Check client encryption feature whether supported this operation."))); + } else ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), @@ -22391,6 +23542,8 @@ makeCallFuncStmt(List* funcname,List* parameters) RangeFunction *rangeFunction = NULL; char *schemaname = NULL; char *name = NULL; + char *pkgname = NULL; + Oid pkgoid = InvalidOid; FuncCandidateList clist = NULL; HeapTuple proctup = NULL; Form_pg_proc procStruct; @@ -22405,9 +23558,9 @@ makeCallFuncStmt(List* funcname,List* parameters) int ntable_colums = 0; bool *have_assigend = NULL; bool has_overload_func = false; - + Datum package_oid_datum; /* deconstruct the name list */ - DeconstructQualifiedName(funcname, &schemaname, &name); + DeconstructQualifiedName(funcname, &schemaname, &name, &pkgname); /* search the function */ clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false); @@ -22431,23 +23584,21 @@ makeCallFuncStmt(List* funcname,List* parameters) } } + proctup = SearchSysCache(PROCOID, + ObjectIdGetDatum(clist->oid), + 0, 0, 0); + /* + * function may be deleted after clist be searched. + */ + if (!HeapTupleIsValid(proctup)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function \"%s\" doesn't exist ", name))); + return NULL; + } if (!has_overload_func) { - proctup = SearchSysCache(PROCOID, - ObjectIdGetDatum(clist->oid), - 0, 0, 0); - - /* - * function may be deleted after clist be searched. - */ - if (!HeapTupleIsValid(proctup)) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", name))); - return NULL; - } - /* get the all args informations, only "in" parameters if p_argmodes is null */ narg = get_func_arg_info(proctup,&p_argtypes,&p_argnames,&p_argmodes); @@ -22457,7 +23608,6 @@ makeCallFuncStmt(List* funcname,List* parameters) procStruct = (Form_pg_proc) GETSTRUCT(proctup); ndefaultargs = procStruct->pronargdefaults; - ReleaseSysCache(proctup); /* check the parameters' count*/ if (narg - ndefaultargs > (parameters ? parameters->length : 0) ) @@ -22511,7 +23661,7 @@ makeCallFuncStmt(List* funcname,List* parameters) { in_parameters = parameters; } - + ReleaseSysCache(proctup); column = makeNode(ColumnRef); column->fields = list_make1(makeNode(A_Star)); @@ -22532,6 +23682,7 @@ makeCallFuncStmt(List* funcname,List* parameters) funcCall->agg_order = NIL; funcCall->over = NULL; funcCall->location = -1; + /*funcCall->pkgoid = pkgoid;*/ if (has_overload_func) funcCall->call_func = true; else @@ -22548,7 +23699,7 @@ makeCallFuncStmt(List* funcname,List* parameters) newm->fromClause = list_make1(rangeFunction); newm->whereClause = NULL; newm->havingClause= NULL; - newm->groupClause = NIL; + newm->groupClause = NIL; return (Node*)newm; } @@ -22701,6 +23852,134 @@ static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yy pfree_ext(buf.data); } +/* get proc header sting len and start pos in scanbuffer */ +static int GetProcHeaderLen(core_yyscan_t yyscanner, int *startPos) +{ + int param_pos_b = 0; + int param_pos_e = 0; + int proc_header_len = 0; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + + param_pos_b = yyextra->core_yy_extra.func_param_begin; + param_pos_e = yyextra->core_yy_extra.func_param_end; + /* exclude left parenthesis at beginning of param */ + param_pos_b++; + /* exclude right parenthesis at end of param */ + proc_header_len = param_pos_e - param_pos_b; + + *startPos = param_pos_b; + + return proc_header_len; +} + +/* get pg_dump type name by input name */ +static char *GetTargetFuncArgTypeName(char *typeString, TypeName* t) +{ + char *target = NULL; + + if (t->pct_type) + { + Type typtup; + Oid toid; + typtup = LookupTypeName(NULL, t, NULL, false); + if (typtup) + { + toid = typeTypeId(typtup); + target = format_type_be(toid); + ReleaseSysCache(typtup); + } + } + else + { + if (t->end_location - t->location == DATE_LEN + && (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT) + && pg_strncasecmp(typeString, "date", DATE_LEN) == 0) + { + target = pstrdup("timestamp without time zone"); + } + } + + return target; +} + +/* covert input type name into pg_dump type name */ +static char *FormatFuncArgType(core_yyscan_t yyscanner, char *argsString, List* parameters) +{ + ListCell* x = NULL; + char *tmp_pos = argsString; + int param_pos_b = 0; + int proc_header_len = 0; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + StringInfoData buf; + char *target = NULL; + int token_offset = 0; + + if (argsString == NULL) + { + return NULL; + } + + proc_header_len = GetProcHeaderLen(yyscanner, ¶m_pos_b); + initStringInfo(&buf); + + foreach (x, parameters) + { + FunctionParameter* fp = (FunctionParameter*)lfirst(x); + TypeName* t = fp->argType; + + if (t->end_location > 0) + { + token_offset = t->location - param_pos_b; + target = GetTargetFuncArgTypeName(argsString + token_offset, t); + if (target != NULL) + { + *(argsString + token_offset) = '\0'; + appendStringInfoString(&buf, tmp_pos); + appendStringInfoString(&buf, target); + tmp_pos = argsString + (t->end_location - param_pos_b); + pfree(target); + } + } + } + appendStringInfoString(&buf, tmp_pos); + pfree(argsString); + proc_header_len = proc_header_len; + + yyextra->core_yy_extra.func_param_begin = 0; + yyextra->core_yy_extra.func_param_end = 0; + + return buf.data; +} + +/* + * get function and procedure args input string + */ +static char *ParseFunctionArgSrc(core_yyscan_t yyscanner) +{ + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + int param_pos_b = 0; + int proc_header_len = 0; + char *proc_header_str = NULL; + + if (yyextra->core_yy_extra.include_ora_comment == false) + { + return NULL; + } + + /* exclude right parenthesis at end of param */ + proc_header_len = GetProcHeaderLen(yyscanner, ¶m_pos_b); + if (proc_header_len > 0) + { + proc_header_str = (char *)palloc0(proc_header_len + 1); + strncpy_s(proc_header_str, (proc_header_len + 1), yyextra->core_yy_extra.scanbuf + param_pos_b, proc_header_len); + proc_header_str[proc_header_len] = '\0'; + } + + yyextra->core_yy_extra.include_ora_comment = false; + + return proc_header_str; +} + static void parameter_check_execute_direct(const char* query) { #ifndef ENABLE_MULTIPLE_NODES @@ -22722,6 +24001,22 @@ static void parameter_check_execute_direct(const char* query) errmsg("must be system admin or monitor admin to use EXECUTE DIRECT"))); } +static Node *make_node_from_scanbuf(int start_pos, int end_pos, core_yyscan_t yyscanner) +{ + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + int len = end_pos - 1; + + /* trim trailing blanks */ + while (yyextra->core_yy_extra.scanbuf[len] == ' ') + len--; + + len = len - start_pos + 1; + char *str = (char *)palloc0(len + 1); + strncpy(str, yyextra->core_yy_extra.scanbuf + start_pos, len); + str[len] = '\0'; + return makeStringConst(str, start_pos); +} + static const char* replace_data_type(char* input) { int rc; diff --git a/contrib/db_b_parser/db_b_hint_gram.y b/contrib/db_b_parser/db_b_hint_gram.y index e01bced6a..8bd3b0e64 100644 --- a/contrib/db_b_parser/db_b_hint_gram.y +++ b/contrib/db_b_parser/db_b_hint_gram.y @@ -22,6 +22,9 @@ static Value *makeNullValue(); static Value *makeBoolValue(bool state); +static void doNegateFloat(Value *v); +static Value* integerToString(Value *v); + #define YYMALLOC palloc #define YYFREE pfree @@ -48,14 +51,16 @@ static double convert_to_numeric(Node *value); -%type join_hint_item join_order_hint join_method_hint stream_hint row_hint scan_hint skew_hint expr_const pred_push_hint rewrite_hint +%type join_hint_item join_order_hint join_method_hint stream_hint row_hint scan_hint skew_hint expr_const + pred_push_hint rewrite_hint gather_hint set_hint plancache_hint guc_value no_expand_hint no_gpc_hint %type relation_list join_hint_list relation_item relation_list_with_p ident_list skew_relist column_list_p column_list value_list_p value_list value_list_item value_type value_list_with_bracket %token IDENT FCONST SCONST BCONST XCONST %token ICONST -%token NestLoop_P MergeJoin_P HashJoin_P No_P Leading_P Rows_P Broadcast_P - Redistribute_P BlockName_P TableScan_P IndexScan_P IndexOnlyScan_P Skew_P HINT_MULTI_NODE_P NULL_P TRUE_P FALSE_P Predpush_P Rewrite_P +%token NestLoop_P MergeJoin_P HashJoin_P No_P Leading_P Rows_P Broadcast_P Redistribute_P BlockName_P + TableScan_P IndexScan_P IndexOnlyScan_P Skew_P HINT_MULTI_NODE_P NULL_P TRUE_P FALSE_P Predpush_P Rewrite_P + Gather_P Set_P USE_CPLAN_P USE_GPLAN_P ON_P OFF_P No_expand_P NO_GPC_P %nonassoc IDENT NULL_P @@ -134,6 +139,123 @@ join_hint_item: { $$ = $2; } + | gather_hint + { + $$ = $1; + } + | set_hint + { + $$ = $1; + } + | plancache_hint + { + $$ = $1; + } + | no_expand_hint + { + $$ = $1; + } + | no_gpc_hint + { + $$ = $1; + } + +gather_hint: + Gather_P '(' IDENT ')' + { + GatherHint *gatherHint = makeNode(GatherHint); + gatherHint->base.hint_keyword = HINT_KEYWORD_GATHER; + gatherHint->base.state = HINT_STATE_NOTUSED; + if (pg_strcasecmp($3, "REL") == 0) { + gatherHint->source = HINT_GATHER_REL; + } else if (pg_strcasecmp($3, "JOIN") == 0) { + gatherHint->source = HINT_GATHER_JOIN; + } else if (pg_strcasecmp($3, "ALL") == 0) { + gatherHint->source = HINT_GATHER_ALL; + } else { + gatherHint->source = HINT_GATHER_UNKNOWN; + } + $$ = (Node *) gatherHint; + } + +no_gpc_hint: + NO_GPC_P + { + NoGPCHint *noGPCHint = makeNode(NoGPCHint); + noGPCHint->base.hint_keyword = HINT_KEYWORD_NO_GPC; + noGPCHint->base.state = HINT_STATE_NOTUSED; + $$ = (Node *) noGPCHint; + } + +no_expand_hint: + No_expand_P + { + NoExpandHint *noExpandHint = makeNode(NoExpandHint); + noExpandHint->base.hint_keyword = HINT_KEYWORD_NO_EXPAND; + noExpandHint->base.state = HINT_STATE_NOTUSED; + $$ = (Node *) noExpandHint; + } + +guc_value: + IDENT { $$ = (Node*)makeStringValue($1); } + | SCONST { $$ = (Node*)makeStringValue($1); } + | TRUE_P { $$ = (Node*)makeBoolValue(TRUE); } + | FALSE_P { $$ = (Node*)makeBoolValue(FALSE); } + | ON_P { $$ = (Node*)makeBoolValue(TRUE); } + | OFF_P { $$ = (Node*)makeBoolValue(FALSE); } + | ICONST { $$ = (Node*)makeInteger($1); } + | '+' ICONST { $$ = (Node*)makeInteger($2); } + | '-' ICONST { $$ = (Node*)makeInteger(-$2); } + | FCONST { $$ = (Node*)makeFloat($1); } + | '+' FCONST { $$ = (Node*)makeFloat($2); } + | '-' FCONST + { + Value *fvalue = makeFloat($2); + doNegateFloat(fvalue); + $$ = (Node*)fvalue; + } + ; + +set_hint: + Set_P '(' IDENT guc_value ')' + { + char* name = $3; + if (!check_set_hint_in_white_list(name)) { + ereport(WARNING, (errmsg("SetHint is invalid. Parameter [%s] is not in whitelist.", name))); + $$ = NULL; + } else { + Value* guc_val = NULL; + if (IsA($4, Integer)) { + guc_val = integerToString((Value*)$4); + } else { + guc_val = (Value*)$4; + } + SetHint *setHint = makeNode(SetHint); + setHint->base.hint_keyword = HINT_KEYWORD_SET; + setHint->base.state = HINT_STATE_NOTUSED; + setHint->name = name; + setHint->value = strVal(guc_val); + $$ = (Node *) setHint; + } + } + +plancache_hint: + USE_CPLAN_P + { + PlanCacheHint *planCacheHint = makeNode(PlanCacheHint); + planCacheHint->base.hint_keyword = HINT_KEYWORD_CPLAN; + planCacheHint->base.state = HINT_STATE_NOTUSED; + planCacheHint->chooseCustomPlan = true; + $$ = (Node *) planCacheHint; + } + | USE_GPLAN_P + { + PlanCacheHint *planCacheHint = makeNode(PlanCacheHint); + planCacheHint->base.hint_keyword = HINT_KEYWORD_GPLAN; + planCacheHint->base.state = HINT_STATE_NOTUSED; + planCacheHint->chooseCustomPlan = false; + $$ = (Node *) planCacheHint; + } rewrite_hint: Rewrite_P '(' ident_list ')' @@ -521,6 +643,37 @@ makeBoolValue(bool state) return val; } +static void +doNegateFloat(Value *v) +{ + char *oldval = v->val.str; + Assert(IsA(v, Float)); + if (*oldval == '+') + oldval++; + if (*oldval == '-') + v->val.str = oldval + 1; /* just strip the '-' */ + else + { + char *newval = (char *) palloc(strlen(oldval) + 2); + + *newval = '-'; + strcpy(newval + 1, oldval); + v->val.str = newval; + } +} + +static Value* integerToString(Value *v) +{ + Assert(IsA(v, Integer)); + long num = intVal(v); + const int max_len_long_type = 11; + char* str = (char*)palloc0(sizeof(char) * (max_len_long_type + 1)); + errno_t rc = sprintf_s(str, max_len_long_type + 1, "%ld", num); + securec_check_ss(rc, "\0", "\0"); + Value* ret = makeString(str); + pfree(v); + return ret; +} #include "db_b_hint_scan.inc" diff --git a/contrib/db_b_parser/db_b_hint_scan.l b/contrib/db_b_parser/db_b_hint_scan.l index fcbed6f6c..2444fdfec 100644 --- a/contrib/db_b_parser/db_b_hint_scan.l +++ b/contrib/db_b_parser/db_b_hint_scan.l @@ -39,9 +39,15 @@ static const hintKeyword parsers[] = {HINT_MULTI_NODE, HINT_MULTI_NODE_P}, {HINT_NULL, NULL_P}, {HINT_TRUE, TRUE_P}, - {HINT_FALSE, FALSE_P}, - {HINT_PRED_PUSH, Predpush_P}, + {HINT_FALSE, FALSE_P}, + {HINT_PRED_PUSH, Predpush_P}, {HINT_REWRITE, Rewrite_P}, + {HINT_GATHER, Gather_P}, + {HINT_SET, Set_P}, + {HINT_CPLAN, USE_CPLAN_P}, + {HINT_GPLAN, USE_GPLAN_P}, + {HINT_NO_EXPAND, No_expand_P}, + {HINT_NO_GPC, NO_GPC_P}, }; static const hintKeyword* HintKeywordLookup(const char *str); diff --git a/contrib/db_b_parser/db_b_keywords.h b/contrib/db_b_parser/db_b_keywords.h index c04538ef8..a6f344805 100644 --- a/contrib/db_b_parser/db_b_keywords.h +++ b/contrib/db_b_parser/db_b_keywords.h @@ -26,6 +26,7 @@ PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD) PG_KEYWORD("and", AND, RESERVED_KEYWORD) PG_KEYWORD("any", ANY, RESERVED_KEYWORD) PG_KEYWORD("app", APP, UNRESERVED_KEYWORD) +PG_KEYWORD("archive", ARCHIVE, UNRESERVED_KEYWORD) PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD) PG_KEYWORD("as", AS, RESERVED_KEYWORD) PG_KEYWORD("asc", ASC, RESERVED_KEYWORD) @@ -50,11 +51,15 @@ PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD) PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD) PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("binary_double", BINARY_DOUBLE, COL_NAME_KEYWORD) +PG_KEYWORD("binary_float", BINARY_FLOAT, COL_NAME_KEYWORD) PG_KEYWORD("binary_integer", BINARY_INTEGER, COL_NAME_KEYWORD) PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD) PG_KEYWORD("blob", BLOB_P, UNRESERVED_KEYWORD) +PG_KEYWORD("blockchain", BLOCKCHAIN, UNRESERVED_KEYWORD) +PG_KEYWORD("body", BODY_P, UNRESERVED_KEYWORD) PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD) PG_KEYWORD("both", BOTH, RESERVED_KEYWORD) +PG_KEYWORD("bucketcnt", BUCKETCNT, COL_NAME_KEYWORD) PG_KEYWORD("buckets", BUCKETS, RESERVED_KEYWORD) PG_KEYWORD("by", BY, UNRESERVED_KEYWORD) PG_KEYWORD("byteawithoutorder", BYTEAWITHOUTORDER, COL_NAME_KEYWORD) @@ -115,6 +120,7 @@ PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD) PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD) PG_KEYWORD("create", CREATE, RESERVED_KEYWORD) PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD) +PG_KEYWORD("csn", CSN, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD) PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD) PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD) @@ -428,6 +434,8 @@ PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD) PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD) PG_KEYWORD("procedure", PROCEDURE, RESERVED_KEYWORD) PG_KEYWORD("profile", PROFILE, UNRESERVED_KEYWORD) +PG_KEYWORD("publish", PUBLISH, UNRESERVED_KEYWORD) +PG_KEYWORD("purge", PURGE, UNRESERVED_KEYWORD) PG_KEYWORD("quarter", QUARTER, COL_NAME_KEYWORD) PG_KEYWORD("query", QUERY, UNRESERVED_KEYWORD) PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD) @@ -441,6 +449,7 @@ PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD) PG_KEYWORD("rebuild", REBUILD, UNRESERVED_KEYWORD) PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD) PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD) +PG_KEYWORD("recyclebin", RECYCLEBIN, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("redisanyvalue", REDISANYVALUE, UNRESERVED_KEYWORD) PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD) PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD) @@ -473,6 +482,7 @@ PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD) PG_KEYWORD("roles", ROLES, UNRESERVED_KEYWORD) PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD) PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD) +PG_KEYWORD("rotation", ROTATION, UNRESERVED_KEYWORD) PG_KEYWORD("row", ROW, COL_NAME_KEYWORD) #ifndef ENABLE_MULTIPLE_NODES PG_KEYWORD("rownum", ROWNUM, RESERVED_KEYWORD) @@ -524,6 +534,7 @@ PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD) PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD) PG_KEYWORD("store", STORE_P, UNRESERVED_KEYWORD) PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD) +PG_KEYWORD("stratify", STRATIFY, UNRESERVED_KEYWORD) PG_KEYWORD("stream", STREAM, UNRESERVED_KEYWORD) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD) @@ -547,6 +558,7 @@ PG_KEYWORD("than", THAN, UNRESERVED_KEYWORD) PG_KEYWORD("then", THEN, RESERVED_KEYWORD) PG_KEYWORD("time", TIME, COL_NAME_KEYWORD) PG_KEYWORD("time_format", TIME_FORMAT_P, UNRESERVED_KEYWORD) +PG_KEYWORD("timecapsule", TIMECAPSULE, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD) PG_KEYWORD("timestamp_format", TIMESTAMP_FORMAT_P, UNRESERVED_KEYWORD) PG_KEYWORD("timestampdiff", TIMESTAMPDIFF, COL_NAME_KEYWORD) @@ -554,6 +566,7 @@ PG_KEYWORD("tinyint", TINYINT, COL_NAME_KEYWORD) PG_KEYWORD("to", TO, RESERVED_KEYWORD) PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD) PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD) +PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD) PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD) PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD) PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD) @@ -589,7 +602,6 @@ PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD) PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD) PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD) PG_KEYWORD("varchar2", VARCHAR2, COL_NAME_KEYWORD) -PG_KEYWORD("variables", VARIABLES, UNRESERVED_KEYWORD) PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD) PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD) PG_KEYWORD("vcgroup", VCGROUP, UNRESERVED_KEYWORD) @@ -628,4 +640,4 @@ PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD) PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD) }; -const int DbBNumScanKeywords = lengthof(DbBScanKeywords); \ No newline at end of file +const int DbBNumScanKeywords = lengthof(DbBScanKeywords); diff --git a/contrib/db_b_parser/db_b_scan.l b/contrib/db_b_parser/db_b_scan.l index 84a6f68dc..287a8c902 100644 --- a/contrib/db_b_parser/db_b_scan.l +++ b/contrib/db_b_parser/db_b_scan.l @@ -67,6 +67,8 @@ long getDynaParamSeq(const char *string, bool initflag, bool placeholder, core_y */ #define SET_YYLLOC() (*(yylloc) = yytext - yyextra->scanbuf) +#define COMMENT_NOT_IGNORED() (yyextra->is_hint_str || yyextra->include_ora_comment) + /* * Advance yylloc by the given number of bytes. */ @@ -177,6 +179,7 @@ non_newline [^\n\r] comment ("--"{non_newline}*) whitespace ({space}+|{comment}) +whitespace_only ({space}+) /* * SQL requires at least one newline in the whitespace separating @@ -325,8 +328,8 @@ para_equals "=>" * If you change either set, adjust the character lists appearing in the * rule for "operator"! */ -self [,()\[\].;\:\+\-\*\/\%\^\<\>\=] -op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=] +self [,()\[\].;\:\+\-\*\/\%\^\<\>\=\@] +op_chars [\~\!\#\^\&\|\`\?\+\-\*\/\%\<\>\=\@] operator {op_chars}+ /* we no longer allow unary minus in numbers. @@ -345,6 +348,7 @@ decimalfail {digit}+\.\. real ({integer}|{decimal})[Ee][-+]?{digit}+ realfail1 ({integer}|{decimal})[Ee] realfail2 ({integer}|{decimal})[Ee][-+] +snapvers ({digit}+(\.{digit}+)*) param \${integer} @@ -369,7 +373,18 @@ other . %% -{whitespace} { +{whitespace_only} { + /* ignore */ + } + +{comment} { + if (yyextra->include_ora_comment) + { + SET_YYLLOC(); + addlit(yytext, yyleng, yyscanner); + yylval->str = litbufdup(yyscanner); + return COMMENTSTRING; + } /* ignore */ } @@ -380,7 +395,7 @@ other . BEGIN(xc); /* Put back any characters past slash-star; see above */ yyless(2); - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { startlit(); addlit(yytext, yyleng, yyscanner); @@ -391,7 +406,7 @@ other . (yyextra->xcdepth)++; /* Put back any characters past slash-star; see above */ yyless(2); - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { addlit(yytext, yyleng, yyscanner); } @@ -403,7 +418,7 @@ other . else (yyextra->xcdepth)--; - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { addlit(yytext, yyleng, yyscanner); yylval->str = litbufdup(yyscanner); @@ -413,21 +428,21 @@ other . } {xcinside} { - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { addlit(yytext, yyleng, yyscanner); } } {op_chars} { - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { addlit(yytext, yyleng, yyscanner); } } \*+ { - if (yyextra->is_hint_str) + if (COMMENT_NOT_IGNORED()) { addlit(yytext, yyleng, yyscanner); } @@ -875,7 +890,7 @@ other . for (ic = nchars-2; ic >= 0; ic--) { - if (strchr("~!@#^&|`?%", yytext[ic])) + if (strchr("~!#^&|`?%", yytext[ic])) break; } if (ic >= 0) @@ -896,7 +911,7 @@ other . * that the "self" rule would have. */ if (nchars == 1 && - strchr(",()[].;:+-*/%^<>=", yytext[0])) + strchr(",()[].;:+-*/%^<>=@", yytext[0])) { yyextra->is_hint_str = false; return yytext[0]; @@ -992,6 +1007,19 @@ other . yyextra->is_hint_str = false; return FCONST; } +{snapvers} { + SET_YYLLOC(); + yylval->str = pstrdup(yytext); + for (int i = strlen(yylval->str) - 1; i > 0; i--) + { + if (yylval->str[i] == '.') + { + yylval->str[i] = DB4AI_SNAPSHOT_VERSION_SEPARATOR; + } + } + yyextra->is_hint_str = false; + return VCONST; + } {identifier} { @@ -1131,21 +1159,44 @@ db_b_scanner_yyerror(const char *message, core_yyscan_t yyscanner) { const char *loc = yyextra->scanbuf + *yylloc; - if (*loc == YY_END_OF_BUFFER_CHAR) - { - ereport(ERROR, + if (u_sess->plsql_cxt.plpgsql_curr_compile != NULL && + u_sess->plsql_cxt.plpgsql_curr_compile_package != NULL) { + PLpgSQL_function* func = u_sess->plsql_cxt.plpgsql_curr_compile; + if (*loc == YY_END_OF_BUFFER_CHAR) + { + ereport(ERROR, + (errmodule(MOD_PLSQL), errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s at end of input when compile function %s", _(message), func->fn_signature), + errdetail("syntax error"), + errcause("The package declaration contains a character string error."), + erraction("Check character string"))); + } + else + { + ereport(ERROR, + (errmodule(MOD_PLSQL), errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s at or near \"%s\" when compile function %s", _(message), loc, func->fn_signature), + errdetail("syntax error"), + errcause("The package declaration contains a character string error."), + erraction("Check character string"))); + } + } else { + if (*loc == YY_END_OF_BUFFER_CHAR) + { + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is typically the translation of "syntax error" */ errmsg("%s at end of input", _(message)), lexer_errposition())); - } - else - { - ereport(ERROR, + } + else + { + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: first %s is typically the translation of "syntax error" */ errmsg("%s at or near \"%s\"", _(message), loc), lexer_errposition())); + } } } @@ -1178,6 +1229,9 @@ db_b_scanner_init(const char *str, yyext->dolqstart = NULL; yyext->is_hint_str = false; yyext->parameter_list = NIL; + yyext->include_ora_comment = false; + yyext->func_param_begin = 0; + yyext->func_param_end = 0; /* * Make a scan buffer with special termination needed by flex. diff --git a/contrib/db_b_parser/expected/db_b_parser.out b/contrib/db_b_parser/expected/db_b_parser.out new file mode 100644 index 000000000..1352b9d8b --- /dev/null +++ b/contrib/db_b_parser/expected/db_b_parser.out @@ -0,0 +1,1991 @@ +create database db_b_parser_test_db dbcompatibility 'B'; +\c db_b_parser_test_db + +create extension db_b_parser; +WARNING: could not open file for reading: db_b_parser.conf + +INFO: db_b parser extension init, this parser is not enabled until enable_custom_parser is to true +INFO: db_b_extension init + +-- test with parser disabled +set enable_custom_parser to off; + +--text(n), tinytext, mediumtext, longtext, failed +create table t1(a text(10)); +ERROR: type modifier is not allowed for type "text" +LINE 1: create table t1(a text(10)); + ^ +create table t2(a tinytext); +ERROR: type "tinytext" does not exist +LINE 1: create table t2(a tinytext); + ^ +create table t3(a mediumtext); +ERROR: type "mediumtext" does not exist +LINE 1: create table t3(a mediumtext); + ^ +create table t4(a longtext); +ERROR: type "longtext" does not exist +LINE 1: create table t4(a longtext); + ^ + +drop table if exists t1; +NOTICE: table "t1" does not exist, skipping +drop table if exists t2; +NOTICE: table "t2" does not exist, skipping +drop table if exists t3; +NOTICE: table "t3" does not exist, skipping +drop table if exists t4; +NOTICE: table "t4" does not exist, skipping + +--default presicion of decimal/number/dec/numeric +create table t_default_decimal(a decimal, b number, c dec, d numeric); +\d t_default_decimal +Table "public.t_default_decimal" + Column | Type | Modifiers +--------+---------+----------- + a | numeric | + b | numeric | + c | numeric | + d | numeric | + +drop table t_default_decimal; + +--failed +create table t_default_float1(a float4(10)); +ERROR: type modifier is not allowed for type "float4" +LINE 1: create table t_default_float1(a float4(10)); + ^ +create table t_default_float2(a double); +ERROR: type "double" does not exist +LINE 1: create table t_default_float2(a double); + ^ + +drop table if exists t_default_float1; +NOTICE: table "t_default_float1" does not exist, skipping +drop table if exists t_default_float2; +NOTICE: table "t_default_float2" does not exist, skipping + +--real is single presicion, float is double presicion +create table t_default_float3(a real, b float); +\d t_default_float3 + Table "public.t_default_float3" + Column | Type | Modifiers +--------+------------------+----------- + a | real | + b | double precision | + +drop table if exists t_default_float3; + +-- := +-- only support +-- update set clause +-- set stmt\alter system set +---------------------------- +create table a(a1 int, a2 int); +insert into a select generate_series(1,5); +update a set a1 := 11; +ERROR: syntax error at or near ":=" +LINE 1: update a set a1 := 11; + ^ +select a1 from a; + a1 +---- + 1 + 2 + 3 + 4 + 5 +(5 rows) + +update a set (a1, a2) := (12,13); +ERROR: syntax error at or near ":=" +LINE 1: update a set (a1, a2) := (12,13); + ^ +set io_limits := 100; +ERROR: syntax error at or near ":=" +LINE 1: set io_limits := 100; + ^ +set io_limits := default; +ERROR: syntax error at or near ":=" +LINE 1: set io_limits := default; + ^ + +drop table if exists a; + +-- DIV\MOD\REGEXP\NOT REGEXP\RLIKE\XOR gram test +Select 8div3; + div3 +------ + 8 +(1 row) + +Select 8 div3; + div3 +------ + 8 +(1 row) + +Select 8div 3, 8div 3div2, 8div 3div 2; +ERROR: syntax error at or near "3" +LINE 1: Select 8div 3, 8div 3div2, 8div 3div 2; + ^ +Select 8mod; + mod +----- + 8 +(1 row) + +Select 8 div; + div +----- + 8 +(1 row) + +Select 8 as div; + div +----- + 8 +(1 row) + +Select xor1; +ERROR: column "xor1" does not exist +LINE 1: Select xor1; + ^ +CONTEXT: referenced column: xor1 +Select div 1; +ERROR: syntax error at or near "1" +LINE 1: Select div 1; + ^ + +create schema xor; +create table xor(a int); +create table opr_test2(regexp int); +create type regexp; +create type regexpp as (regexp int); +CREATE FUNCTION regexp(int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +CREATE FUNCTION regexp2(regexp int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +create procedure mod(int,int) +as +begin + select $1 + $2; +end; +/ +create procedure mod2(mod int, xxx int) +as +begin + select $1 + $2; +end; +/ + +drop schema xor; +drop table xor; +drop table opr_test2; +drop type regexp; +drop type regexpp; +drop function regexp; +ERROR: function regexp asks parameters +drop function regexp2; +drop procedure mod(int,int); +drop procedure mod2; + +SELECT '-12.3abc' div NULL; +ERROR: syntax error at or near "NULL" +LINE 1: SELECT '-12.3abc' div NULL; + ^ +SELECT '-12.3abc' div -100.1; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' div -100.1; + ^ +SELECT '-12.3abc' div 0; +ERROR: syntax error at or near "0" +LINE 1: SELECT '-12.3abc' div 0; + ^ +SELECT '-12.3abc' div 5; +ERROR: syntax error at or near "5" +LINE 1: SELECT '-12.3abc' div 5; + ^ +SELECT '-12.3abc' div 158.3; +ERROR: syntax error at or near "158.3" +LINE 1: SELECT '-12.3abc' div 158.3; + ^ +SELECT '-12.3abc' div -8.222e4; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' div -8.222e4; + ^ +SELECT '-12.3abc' div true; +ERROR: syntax error at or near "true" +LINE 1: SELECT '-12.3abc' div true; + ^ +SELECT '-12.3abc' div false; +ERROR: syntax error at or near "false" +LINE 1: SELECT '-12.3abc' div false; + ^ +SELECT '-12.3abc' div 'NULL'; +ERROR: syntax error at or near "'NULL'" +LINE 1: SELECT '-12.3abc' div 'NULL'; + ^ + +select 123456 div 5 div 4; +ERROR: syntax error at or near "5" +LINE 1: select 123456 div 5 div 4; + ^ +select 8 div 1 where 100 div 3 div 4 = 0; +ERROR: syntax error at or near "1" +LINE 1: select 8 div 1 where 100 div 3 div 4 = 0; + ^ +select 8 div 3 where 100 div 3 div 4 > 0; +ERROR: syntax error at or near "3" +LINE 1: select 8 div 3 where 100 div 3 div 4 > 0; + ^ +SELECT '-12.3abc' mod NULL; +ERROR: syntax error at or near "NULL" +LINE 1: SELECT '-12.3abc' mod NULL; + ^ +SELECT '-12.3abc' mod -100.1; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' mod -100.1; + ^ +SELECT '-12.3abc' mod 0; +ERROR: syntax error at or near "0" +LINE 1: SELECT '-12.3abc' mod 0; + ^ +SELECT '-12.3abc' mod 5; +ERROR: syntax error at or near "5" +LINE 1: SELECT '-12.3abc' mod 5; + ^ +SELECT '-12.3abc' mod 158.3; +ERROR: syntax error at or near "158.3" +LINE 1: SELECT '-12.3abc' mod 158.3; + ^ +SELECT '-12.3abc' mod -8.222e4; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' mod -8.222e4; + ^ +SELECT '-12.3abc' mod true; +ERROR: syntax error at or near "true" +LINE 1: SELECT '-12.3abc' mod true; + ^ +SELECT '-12.3abc' mod false; +ERROR: syntax error at or near "false" +LINE 1: SELECT '-12.3abc' mod false; + ^ +SELECT '-12.3abc' mod 'NULL'; +ERROR: syntax error at or near "'NULL'" +LINE 1: SELECT '-12.3abc' mod 'NULL'; + ^ +select 123456 mod 5 mod 4; +ERROR: syntax error at or near "5" +LINE 1: select 123456 mod 5 mod 4; + ^ +select 8 mod 1 where 100 mod 3 mod 4 = 0; +ERROR: syntax error at or near "1" +LINE 1: select 8 mod 1 where 100 mod 3 mod 4 = 0; + ^ +select 8 mod 3 where 100 mod 3 mod 4 > 0; +ERROR: syntax error at or near "3" +LINE 1: select 8 mod 3 where 100 mod 3 mod 4 > 0; + ^ +SELECT '-12.3abc' regexp NULL; +ERROR: syntax error at or near "NULL" +LINE 1: SELECT '-12.3abc' regexp NULL; + ^ +SELECT '-12.3abc' regexp -100.1; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' regexp -100.1; + ^ +SELECT '-12.3abc' regexp 0; +ERROR: syntax error at or near "0" +LINE 1: SELECT '-12.3abc' regexp 0; + ^ +SELECT '-12.3abc' regexp 5; +ERROR: syntax error at or near "5" +LINE 1: SELECT '-12.3abc' regexp 5; + ^ +SELECT '-12.3abc' regexp 158.3; +ERROR: syntax error at or near "158.3" +LINE 1: SELECT '-12.3abc' regexp 158.3; + ^ +SELECT '-12.3abc' regexp -8.222e4; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' regexp -8.222e4; + ^ +SELECT '-12.3abc' regexp true; +ERROR: syntax error at or near "true" +LINE 1: SELECT '-12.3abc' regexp true; + ^ +SELECT '-12.3abc' regexp false; +ERROR: syntax error at or near "false" +LINE 1: SELECT '-12.3abc' regexp false; + ^ +SELECT '-12.3abc' regexp 'NULL'; +ERROR: syntax error at or near "'NULL'" +LINE 1: SELECT '-12.3abc' regexp 'NULL'; + ^ +SELECT '-12.3abc' not regexp NULL; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp NULL; + ^ +SELECT '-12.3abc' not regexp -100.1; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp -100.1; + ^ +SELECT '-12.3abc' not regexp 0; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp 0; + ^ +SELECT '-12.3abc' not regexp 5; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp 5; + ^ +SELECT '-12.3abc' not regexp 158.3; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp 158.3; + ^ +SELECT '-12.3abc' not regexp -8.222e4; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp -8.222e4; + ^ +SELECT '-12.3abc' not regexp true; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp true; + ^ +SELECT '-12.3abc' not regexp false; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp false; + ^ +SELECT '-12.3abc' not regexp 'NULL'; +ERROR: syntax error at or near "regexp" +LINE 1: SELECT '-12.3abc' not regexp 'NULL'; + ^ +SELECT '-12.3abc' xor NULL; +ERROR: syntax error at or near "NULL" +LINE 1: SELECT '-12.3abc' xor NULL; + ^ +SELECT '-12.3abc' xor -100.1; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' xor -100.1; + ^ +SELECT '-12.3abc' xor 0; +ERROR: syntax error at or near "0" +LINE 1: SELECT '-12.3abc' xor 0; + ^ +SELECT '-12.3abc' xor 5; +ERROR: syntax error at or near "5" +LINE 1: SELECT '-12.3abc' xor 5; + ^ +SELECT '-12.3abc' xor 158.3; +ERROR: syntax error at or near "158.3" +LINE 1: SELECT '-12.3abc' xor 158.3; + ^ +SELECT '-12.3abc' xor -8.222e4; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' xor -8.222e4; + ^ +SELECT '-12.3abc' xor true; +ERROR: syntax error at or near "true" +LINE 1: SELECT '-12.3abc' xor true; + ^ +SELECT '-12.3abc' xor false; +ERROR: syntax error at or near "false" +LINE 1: SELECT '-12.3abc' xor false; + ^ +SELECT '-12.3abc' xor 'NULL'; +ERROR: syntax error at or near "'NULL'" +LINE 1: SELECT '-12.3abc' xor 'NULL'; + ^ +SELECT '-12.3abc' rlike NULL; +ERROR: syntax error at or near "NULL" +LINE 1: SELECT '-12.3abc' rlike NULL; + ^ +SELECT '-12.3abc' rlike -100.1; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' rlike -100.1; + ^ +SELECT '-12.3abc' rlike 0; +ERROR: syntax error at or near "0" +LINE 1: SELECT '-12.3abc' rlike 0; + ^ +SELECT '-12.3abc' rlike 5; +ERROR: syntax error at or near "5" +LINE 1: SELECT '-12.3abc' rlike 5; + ^ +SELECT '-12.3abc' rlike 158.3; +ERROR: syntax error at or near "158.3" +LINE 1: SELECT '-12.3abc' rlike 158.3; + ^ +SELECT '-12.3abc' rlike -8.222e4; +ERROR: syntax error at or near "-" +LINE 1: SELECT '-12.3abc' rlike -8.222e4; + ^ +SELECT '-12.3abc' rlike true; +ERROR: syntax error at or near "true" +LINE 1: SELECT '-12.3abc' rlike true; + ^ +SELECT '-12.3abc' rlike false; +ERROR: syntax error at or near "false" +LINE 1: SELECT '-12.3abc' rlike false; + ^ +SELECT '-12.3abc' rlike 'NULL'; +ERROR: syntax error at or near "'NULL'" +LINE 1: SELECT '-12.3abc' rlike 'NULL'; + ^ +---------------------------------------- +-- copy from regex.sql of fastcheck +---------------------------------------- +set enable_bitmapscan = off; +set standard_conforming_strings = on; +select 'bbbbb' regexp '^([bc])\1*$' as t, 'bbbbb' not regexp '^([bc])\1*$' as t2, 'bbbbb' rlike '^([bc])\1*$' as t; +ERROR: syntax error at or near "'^([bc])\1*$'" +LINE 1: select 'bbbbb' regexp '^([bc])\1*$' as t, 'bbbbb' not regexp... + ^ +select 'ccc' regexp '^([bc])\1*$' as t, 'ccc' not regexp '^([bc])\1*$' as t2, 'ccc' rlike '^([bc])\1*$' as t; +ERROR: syntax error at or near "'^([bc])\1*$'" +LINE 1: select 'ccc' regexp '^([bc])\1*$' as t, 'ccc' not regexp '^(... + ^ +select 'xxx' regexp '^([bc])\1*$' as f, 'xxx' not regexp '^([bc])\1*$' as f2, 'xxx' rlike '^([bc])\1*$' as f; +ERROR: syntax error at or near "'^([bc])\1*$'" +LINE 1: select 'xxx' regexp '^([bc])\1*$' as f, 'xxx' not regexp '^(... + ^ +select 'bbc' regexp '^([bc])\1*$' as f, 'bbc' not regexp '^([bc])\1*$' as f2, 'bbc' rlike '^([bc])\1*$' as f; +ERROR: syntax error at or near "'^([bc])\1*$'" +LINE 1: select 'bbc' regexp '^([bc])\1*$' as f, 'bbc' not regexp '^(... + ^ +select 'b' regexp '^([bc])\1*$' as t, 'b' not regexp '^([bc])\1*$' as t2, 'b' rlike '^([bc])\1*$' as t; +ERROR: syntax error at or near "'^([bc])\1*$'" +LINE 1: select 'b' regexp '^([bc])\1*$' as t, 'b' not regexp '^([bc]... + ^ +select 'abc abc abc' regexp '^(\w+)( \1)+$' as t, 'abc abc abc' not regexp '^(\w+)( \1)+$' as t, 'abc abc abc' rlike '^(\w+)( \1)+$' as t; +ERROR: syntax error at or near "'^(\w+)( \1)+$'" +LINE 1: select 'abc abc abc' regexp '^(\w+)( \1)+$' as t, 'abc abc a... + ^ +select 'abc abd abc' regexp '^(\w+)( \1)+$' as f, 'abc abd abc' not regexp '^(\w+)( \1)+$' as f, 'abc abd abc' rlike '^(\w+)( \1)+$' as f; +ERROR: syntax error at or near "'^(\w+)( \1)+$'" +LINE 1: select 'abc abd abc' regexp '^(\w+)( \1)+$' as f, 'abc abd a... + ^ +select 'abc abc abd' regexp '^(\w+)( \1)+$' as f, 'abc abc abd' not regexp '^(\w+)( \1)+$' as f, 'abc abc abd' rlike '^(\w+)( \1)+$' as f; +ERROR: syntax error at or near "'^(\w+)( \1)+$'" +LINE 1: select 'abc abc abd' regexp '^(\w+)( \1)+$' as f, 'abc abc a... + ^ +select 'abc abc abc' regexp '^(.+)( \1)+$' as t, 'abc abc abc' not regexp '^(.+)( \1)+$' as t, 'abc abc abc' rlike '^(.+)( \1)+$' as t; +ERROR: syntax error at or near "'^(.+)( \1)+$'" +LINE 1: select 'abc abc abc' regexp '^(.+)( \1)+$' as t, 'abc abc ab... + ^ +select 'abc abd abc' regexp '^(.+)( \1)+$' as f, 'abc abd abc' not regexp '^(.+)( \1)+$' as f, 'abc abd abc' rlike '^(.+)( \1)+$' as f; +ERROR: syntax error at or near "'^(.+)( \1)+$'" +LINE 1: select 'abc abd abc' regexp '^(.+)( \1)+$' as f, 'abc abd ab... + ^ +select 'abc abc abd' regexp '^(.+)( \1)+$' as f, 'abc abc abd' not regexp '^(.+)( \1)+$' as f, 'abc abc abd' rlike '^(.+)( \1)+$' as f; +ERROR: syntax error at or near "'^(.+)( \1)+$'" +LINE 1: select 'abc abc abd' regexp '^(.+)( \1)+$' as f, 'abc abc ab... + ^ +select 'a' regexp '($|^)*', 'a' not regexp '($|^)*', 'a' rlike '($|^)*'; +ERROR: syntax error at or near "'($|^)*'" +LINE 1: select 'a' regexp '($|^)*', 'a' not regexp '($|^)*', 'a' rli... + ^ +select 'a' regexp '(^)+^', 'a' not regexp '(^)+^', 'a' rlike '(^)+^'; +ERROR: syntax error at or near "'(^)+^'" +LINE 1: select 'a' regexp '(^)+^', 'a' not regexp '(^)+^', 'a' rlike... + ^ +select 'a' regexp '$($$)+', 'a' not regexp '$($$)+', 'a' rlike '$($$)+'; +ERROR: syntax error at or near "'$($$)+'" +LINE 1: select 'a' regexp '$($$)+', 'a' not regexp '$($$)+', 'a' rli... + ^ +select 'a' regexp '($^)+', 'a' not regexp '($^)+', 'a' rlike '($^)+'; +ERROR: syntax error at or near "'($^)+'" +LINE 1: select 'a' regexp '($^)+', 'a' not regexp '($^)+', 'a' rlike... + ^ +select 'a' regexp '(^$)*', 'a' not regexp '(^$)*', 'a' rlike '(^$)*'; +ERROR: syntax error at or near "'(^$)*'" +LINE 1: select 'a' regexp '(^$)*', 'a' not regexp '(^$)*', 'a' rlike... + ^ +select 'aa bb cc' regexp '(^(?!aa))+', 'aa bb cc' not regexp '(^(?!aa))+', 'aa bb cc' rlike '(^(?!aa))+'; +ERROR: syntax error at or near "'(^(?!aa))+'" +LINE 1: select 'aa bb cc' regexp '(^(?!aa))+', 'aa bb cc' not regexp... + ^ +select 'aa x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +ERROR: syntax error at or near "'(^(?!aa)(?!bb)(?!cc))+'" +LINE 1: select 'aa x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' not re... + ^ +select 'bb x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +ERROR: syntax error at or near "'(^(?!aa)(?!bb)(?!cc))+'" +LINE 1: select 'bb x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' not re... + ^ +select 'cc x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +ERROR: syntax error at or near "'(^(?!aa)(?!bb)(?!cc))+'" +LINE 1: select 'cc x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' not re... + ^ +select 'dd x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +ERROR: syntax error at or near "'(^(?!aa)(?!bb)(?!cc))+'" +LINE 1: select 'dd x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' not re... + ^ +select 'x' regexp 'abcd(\m)+xyz', 'x' not regexp 'abcd(\m)+xyz', 'x' rlike 'abcd(\m)+xyz'; +ERROR: syntax error at or near "'abcd(\m)+xyz'" +LINE 1: select 'x' regexp 'abcd(\m)+xyz', 'x' not regexp 'abcd(\m)+x... + ^ +select 'x' regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' not regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' rlike 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'; +ERROR: syntax error at or near "'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'" +LINE 1: select 'x' regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'... + ^ +select 'a' regexp '((((((a)*)*)*)*)*)*', 'a' not regexp '((((((a)*)*)*)*)*)*', 'a' rlike '((((((a)*)*)*)*)*)*'; +ERROR: syntax error at or near "'((((((a)*)*)*)*)*)*'" +LINE 1: select 'a' regexp '((((((a)*)*)*)*)*)*', 'a' not regexp '(((... + ^ +select 'a' regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' not regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' rlike '((((((a+|)+|)+|)+|)+|)+|)'; +ERROR: syntax error at or near "'((((((a+|)+|)+|)+|)+|)+|)'" +LINE 1: select 'a' regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' not regex... + ^ +select 'a' regexp '\x7fffffff', 'a' not regexp '\x7fffffff', 'a' rlike '\x7fffffff'; +ERROR: syntax error at or near "'\x7fffffff'" +LINE 1: select 'a' regexp '\x7fffffff', 'a' not regexp '\x7fffffff',... + ^ +select 'a' regexp '$()|^\1', 'a' not regexp '$()|^\1', 'a' rlike '$()|^\1'; +ERROR: syntax error at or near "'$()|^\1'" +LINE 1: select 'a' regexp '$()|^\1', 'a' not regexp '$()|^\1', 'a' r... + ^ +select 'a' regexp '.. ()|\1', 'a' not regexp '.. ()|\1', 'a' rlike '.. ()|\1'; +ERROR: syntax error at or near "'.. ()|\1'" +LINE 1: select 'a' regexp '.. ()|\1', 'a' not regexp '.. ()|\1', 'a'... + ^ +select 'a' regexp '()*\1', 'a' not regexp '()*\1', 'a' rlike '()*\1'; +ERROR: syntax error at or near "'()*\1'" +LINE 1: select 'a' regexp '()*\1', 'a' not regexp '()*\1', 'a' rlike... + ^ +select 'a' regexp '()+\1', 'a' not regexp '()+\1', 'a' rlike '()+\1'; +ERROR: syntax error at or near "'()+\1'" +LINE 1: select 'a' regexp '()+\1', 'a' not regexp '()+\1', 'a' rlike... + ^ +explain (costs off) select * from pg_proc where proname regexp 'abc'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp 'ab... + ^ +explain (costs off) select * from pg_proc where proname regexp '^abc'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname regexp '^abc$'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname regexp '^abcd*e'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname regexp '^abc+d'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname regexp '^(abc)(def)'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname regexp '^(abc)$'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname regexp '^(abc)?d'; +ERROR: syntax error at or near "regexp" +LINE 1: ...n (costs off) select * from pg_proc where proname regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname not regexp 'abc'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp 'ab... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^abc'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^abc$'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^abcd*e'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^abc+d'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^a... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^(abc)(def)'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^(abc)$'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname not regexp '^(abc)?d'; +ERROR: syntax error at or near "regexp" +LINE 1: ...osts off) select * from pg_proc where proname not regexp '^(... + ^ +explain (costs off) select * from pg_proc where proname rlike 'abc'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike 'abc... + ^ +explain (costs off) select * from pg_proc where proname rlike '^abc'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^ab... + ^ +explain (costs off) select * from pg_proc where proname rlike '^abc$'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^ab... + ^ +explain (costs off) select * from pg_proc where proname rlike '^abcd*e'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^ab... + ^ +explain (costs off) select * from pg_proc where proname rlike '^abc+d'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^ab... + ^ +explain (costs off) select * from pg_proc where proname rlike '^(abc)(def)'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^(a... + ^ +explain (costs off) select * from pg_proc where proname rlike '^(abc)$'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^(a... + ^ +explain (costs off) select * from pg_proc where proname rlike '^(abc)?d'; +ERROR: syntax error at or near "rlike" +LINE 1: ...n (costs off) select * from pg_proc where proname rlike '^(a... + ^ +set enable_bitmapscan = default; +set standard_conforming_strings = default; +------DAYOFMONTH() DAYOFWEEK() DAYOFYEAR() HOUR() MICROSECOND() MINUTE() QUARTER() SECOND() WEEKDAY() WEEKOFYEAR() YEAR() +select DAYOFMONTH(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function dayofmonth(timestamp without time zone) does not exist +LINE 1: select DAYOFMONTH(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: dayofmonth +select DAYOFWEEK(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function dayofweek(timestamp without time zone) does not exist +LINE 1: select DAYOFWEEK(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: dayofweek +select DAYOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function dayofyear(timestamp without time zone) does not exist +LINE 1: select DAYOFYEAR(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: dayofyear +select HOUR(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function hour(timestamp without time zone) does not exist +LINE 1: select HOUR(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: hour +select MICROSECOND(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function microsecond(timestamp without time zone) does not exist +LINE 1: select MICROSECOND(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: microsecond +select MINUTE(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function minute(timestamp without time zone) does not exist +LINE 1: select MINUTE(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: minute +select QUARTER(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function quarter(timestamp without time zone) does not exist +LINE 1: select QUARTER(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: quarter +select SECOND(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function second(timestamp without time zone) does not exist +LINE 1: select SECOND(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: second +select WEEKDAY(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function weekday(timestamp without time zone) does not exist +LINE 1: select WEEKDAY(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: weekday +select WEEKOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function weekofyear(timestamp without time zone) does not exist +LINE 1: select WEEKOFYEAR(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: weekofyear +select YEAR(timestamp '2021-05-26 16:30:44.341191'); +ERROR: function year(timestamp without time zone) does not exist +LINE 1: select YEAR(timestamp '2021-05-26 16:30:44.341191'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: year +--- LOCATE +select locate('test','testgood'); +ERROR: function locate(unknown, unknown) does not exist +LINE 1: select locate('test','testgood'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: locate +select locate('test','11testgood',5); +ERROR: function locate(unknown, unknown, integer) does not exist +LINE 1: select locate('test','11testgood',5); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: locate +select locate('test','11testgood',3); +ERROR: function locate(unknown, unknown, integer) does not exist +LINE 1: select locate('test','11testgood',3); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: locate +-- IFNULL +SELECT IFNULL(NULL, 'test'); +ERROR: function ifnull(unknown, unknown) does not exist +LINE 1: SELECT IFNULL(NULL, 'test'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: ifnull +-- IF +SELECT IF(TRUE,'A','B'); +ERROR: function if(boolean, unknown, unknown) does not exist +LINE 1: SELECT IF(TRUE,'A','B'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: if +SELECT IF(FALSE,'A','B'); +ERROR: function if(boolean, unknown, unknown) does not exist +LINE 1: SELECT IF(FALSE,'A','B'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: if +------------------------------------------------------------------------------------------------------------------------ +---------------------------- +-- bit_length\octet_length\length +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length'); + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+--------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+--------------------- +(0 rows) + +select bit_length(b'1'), bit_length(b'101'), bit_length(b'1011111111'); + bit_length | bit_length | bit_length +------------+------------+------------ + 1 | 3 | 10 +(1 row) + +select bit_length( '1'), bit_length( '101'), bit_length( '1011111111'); + bit_length | bit_length | bit_length +------------+------------+------------ + 8 | 24 | 80 +(1 row) + +select bit_length( '哈1哈\n'),bit_length( '\n'),bit_length( '\\n'); + bit_length | bit_length | bit_length +------------+------------+------------ + 72 | 16 | 24 +(1 row) + +select octet_length(b'1'), octet_length(b'101'), octet_length(b'1011111111'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 1 | 1 | 2 +(1 row) + +select octet_length( '1'), octet_length( '101'), octet_length( '1011111111'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 1 | 3 | 10 +(1 row) + +select octet_length( '哈1哈\n'),octet_length( '\n'),octet_length( '\\n'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 9 | 2 | 3 +(1 row) + +select length(b'1'), length(b'101'), length(b'1011111111'); + length | length | length +--------+--------+-------- + 1 | 3 | 10 +(1 row) + +select length( '1'), length( '101'), length( '1011111111'); + length | length | length +--------+--------+-------- + 1 | 3 | 10 +(1 row) + +select length( '哈1哈\n'),length( '\n'),length( '\\n'); + length | length | length +--------+--------+-------- + 5 | 2 | 3 +(1 row) + +---------------------------- +-- \lcase\ucase\rand\truncate\current_date() +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length', 'lower', 'upper', 'random', 'trunc') order by oid; + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+---------------------------------------------------------------------------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+--------------------- + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 829 | 829 | | | | | macaddr_trunc | | | | | f | | f | f | | 0 | f | | + lower | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 25 | 25 | | | | | lower | | | | | f | | f | f | | 0 | f | | + upper | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 25 | 25 | | | | | upper | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 701 | 701 | | | | | dtrunc | | | | | f | | f | f | | 0 | f | | + random | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | v | 0 | 0 | 701 | | | | | | drandom | | | | | f | t | f | f | | 0 | f | | + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 1700 | 1700 23 | | | | | numeric_trunc | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 14 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 1700 | 1700 | | | | | select pg_catalog.trunc($1,0) | | | | | f | | f | f | | 0 | f | | + lower | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 2283 | 3831 | | | | | range_lower | | | | | f | | f | f | | 0 | f | | + upper | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 2283 | 3831 | | | | | range_upper | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 14 | 100 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 1114 | 1184 | | | | | +| | | | | f | f | f | f | | 0 | f | | + | | | | | | | | | | | | | | | | | | | | | | | SELECT CAST(DATE_TRUNC('day',$1) AS TIMESTAMP WITHOUT TIME ZONE);+| | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +(10 rows) + +select lcase('ABc'), lcase('哈哈'), lcase('123456'); +ERROR: function lcase(unknown) does not exist +LINE 1: select lcase('ABc'), lcase('哈哈'), lcase('123456'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: lcase +select lower('ABc'), lower('哈哈'), lower('123456'); + lower | lower | lower +-------+-------+-------- + abc | 哈哈 | 123456 +(1 row) + +select ucase('ABc'), ucase('哈哈'), ucase('123456'); +ERROR: function ucase(unknown) does not exist +LINE 1: select ucase('ABc'), ucase('哈哈'), ucase('123456'); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: ucase +select upper('ABc'), upper('哈哈'), upper('123456'); + upper | upper | upper +-------+-------+-------- + ABC | 哈哈 | 123456 +(1 row) + +select rand(), random(); +ERROR: function rand() does not exist +LINE 1: select rand(), random(); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: rand +select truncate(111.28), truncate(111.28,1), truncate(111.28,5), truncate(111.28,500), truncate(111.28,-1), truncate(111.28,-4); +ERROR: function truncate(numeric) does not exist +LINE 1: select truncate(111.28), truncate(111.28,1), truncate(111.28... + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: truncate +select trunc(111.28), trunc(111.28,1), trunc(111.28,5), trunc(111.28,500), trunc(111.28,-1), trunc(111.28,-4); + trunc | trunc | trunc | trunc | trunc | trunc +-------+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------- + 111 | 111.2 | 111.28000 | 111.28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | 110 | 0 +(1 row) + +truncate a; +ERROR: relation "a" does not exist +select current_date(), current_date; +ERROR: syntax error at or near "(" +LINE 1: select current_date(), current_date; + ^ +---------------------------------------------- +-- test with parser enabled, same testcases -- +---------------------------------------------- +set enable_custom_parser to on; +--text(n), tinytext, mediumtext, longtext, failed +create table t1(a text(10)); +create table t2(a tinytext); +create table t3(a mediumtext); +create table t4(a longtext); + +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +drop table if exists t4; +--default presicion of decimal/number/dec/numeric +create table t_default_decimal(a decimal, b number, c dec, d numeric); +\d t_default_decimal + Table "public.t_default_decimal" + Column | Type | Modifiers +--------+---------------+----------- + a | numeric(10,0) | + b | numeric(10,0) | + c | numeric(10,0) | + d | numeric(10,0) | + +drop table t_default_decimal; +--failed +create table t_default_float1(a float4(10)); +create table t_default_float2(a double); + +drop table if exists t_default_float1; +drop table if exists t_default_float2; +--real is single presicion, float is double presicion +create table t_default_float3(a real, b float); +\d t_default_float3 + Table "public.t_default_float3" + Column | Type | Modifiers +--------+------------------+----------- + a | double precision | + b | real | + +drop table t_default_float3; +-- := +-- only support +-- update set clause +-- set stmt\alter system set +---------------------------- +create table a(a1 int, a2 int); +insert into a select generate_series(1,5); +update a set a1 := 11; +select a1 from a; + a1 +---- + 11 + 11 + 11 + 11 + 11 +(5 rows) + +update a set (a1, a2) := (12,13); +set io_limits := 100; +set io_limits := default; + +drop table if exists a; +-- DIV\MOD\REGEXP\NOT REGEXP\RLIKE\XOR gram test +Select 8div3; + div3 +------ + 8 +(1 row) + +Select 8 div3; + div3 +------ + 8 +(1 row) + +Select 8div 3, 8div 3div2, 8div 3div 2; + div | div2 | div +-----+------+----- + 2 | 2 | 1 +(1 row) + +Select 8mod; +ERROR: syntax error at or near ";" +LINE 1: Select 8mod; + ^ +Select 8 div; +ERROR: syntax error at or near ";" +LINE 1: Select 8 div; + ^ +Select 8 as div; + div +----- + 8 +(1 row) + +Select xor1; +ERROR: column "xor1" does not exist +LINE 1: Select xor1; + ^ +CONTEXT: referenced column: xor1 +Select div 1; +ERROR: syntax error at or near "1" +LINE 1: Select div 1; + ^ +create schema xor; +ERROR: syntax error at or near "xor" +LINE 1: create schema xor; + ^ +create table xor(a int); +ERROR: syntax error at or near "xor" +LINE 1: create table xor(a int); + ^ +create table opr_test2(regexp int); +ERROR: syntax error at or near "regexp" +LINE 1: create table opr_test2(regexp int); + ^ +create type regexp; +ERROR: syntax error at or near "regexp" +LINE 1: create type regexp; + ^ +create type regexpp as (regexp int); +ERROR: syntax error at or near "regexp" +LINE 1: create type regexpp as (regexp int); + ^ +CREATE FUNCTION regexp(int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +ERROR: function "regexp" already exists with same argument types +CREATE FUNCTION regexp2(regexp int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +create procedure mod(int,int) +as +begin + select $1 + $2; +end; +/ +create procedure mod2(mod int, xxx int) +as +begin + select $1 + $2; +end; +/ +drop schema xor; +ERROR: syntax error at or near "xor" +LINE 1: drop schema xor; + ^ +drop table xor; +ERROR: syntax error at or near "xor" +LINE 1: drop table xor; + ^ +drop table opr_test2; +ERROR: table "opr_test2" does not exist +drop type regexp; +ERROR: syntax error at or near "regexp" +LINE 1: drop type regexp; + ^ +drop type regexpp; +ERROR: type "regexpp" does not exist +drop function regexp; +ERROR: function regexp asks parameters +drop function regexp2; +drop procedure mod(int,int); +drop procedure mod2; +SELECT '-12.3abc' div NULL; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div NULL; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div -100.1; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div -100.1; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div 0; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div 0; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div 5; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div 5; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div 158.3; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div 158.3; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div -8.222e4; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div -8.222e4; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div true; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div true; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div false; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div false; + ^ +CONTEXT: referenced column: div +SELECT '-12.3abc' div 'NULL'; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' div 'NULL'; + ^ +CONTEXT: referenced column: div +select 123456 div 5 div 4; + div +------ + 6172 +(1 row) + +select 8 div 1 where 100 div 3 div 4 = 0; + div +----- +(0 rows) + +select 8 div 3 where 100 div 3 div 4 > 0; + div +----- + 2 +(1 row) + +SELECT '-12.3abc' mod NULL; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod NULL; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod -100.1; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod -100.1; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod 0; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod 0; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod 5; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod 5; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod 158.3; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod 158.3; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod -8.222e4; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod -8.222e4; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod true; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod true; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod false; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod false; + ^ +CONTEXT: referenced column: b_mod +SELECT '-12.3abc' mod 'NULL'; +ERROR: invalid input syntax for type numeric: "-12.3abc" +LINE 1: SELECT '-12.3abc' mod 'NULL'; + ^ +CONTEXT: referenced column: b_mod +select 123456 mod 5 mod 4; + b_mod +------- + 1 +(1 row) + +select 8 mod 1 where 100 mod 3 mod 4 = 0; + b_mod +------- +(0 rows) + +select 8 mod 3 where 100 mod 3 mod 4 > 0; + b_mod +------- + 2 +(1 row) + +SELECT '-12.3abc' regexp NULL; + regexp +-------- + +(1 row) + +SELECT '-12.3abc' regexp -100.1; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' regexp 0; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' regexp 5; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' regexp 158.3; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' regexp -8.222e4; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' regexp true; +ERROR: function pg_catalog.regexp(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' regexp true; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: regexp +SELECT '-12.3abc' regexp false; +ERROR: function pg_catalog.regexp(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' regexp false; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: regexp +SELECT '-12.3abc' regexp 'NULL'; + regexp +-------- + 0 +(1 row) + +SELECT '-12.3abc' not regexp NULL; + not_regexp +------------ + +(1 row) + +SELECT '-12.3abc' not regexp -100.1; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' not regexp 0; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' not regexp 5; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' not regexp 158.3; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' not regexp -8.222e4; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' not regexp true; +ERROR: function pg_catalog.not_regexp(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' not regexp true; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: not_regexp +SELECT '-12.3abc' not regexp false; +ERROR: function pg_catalog.not_regexp(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' not regexp false; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: not_regexp +SELECT '-12.3abc' not regexp 'NULL'; + not_regexp +------------ + 1 +(1 row) + +SELECT '-12.3abc' xor NULL; + xor +----- + +(1 row) + +SELECT '-12.3abc' xor -100.1; + xor +----- + 0 +(1 row) + +SELECT '-12.3abc' xor 0; + xor +----- + 1 +(1 row) + +SELECT '-12.3abc' xor 5; + xor +----- + 0 +(1 row) + +SELECT '-12.3abc' xor 158.3; + xor +----- + 0 +(1 row) + +SELECT '-12.3abc' xor -8.222e4; + xor +----- + 0 +(1 row) + +SELECT '-12.3abc' xor true; + xor +----- + 0 +(1 row) + +SELECT '-12.3abc' xor false; + xor +----- + 1 +(1 row) + +SELECT '-12.3abc' xor 'NULL'; + xor +----- + 1 +(1 row) + +SELECT '-12.3abc' rlike NULL; + rlike +------- + +(1 row) + +SELECT '-12.3abc' rlike -100.1; + rlike +------- + 0 +(1 row) + +SELECT '-12.3abc' rlike 0; + rlike +------- + 0 +(1 row) + +SELECT '-12.3abc' rlike 5; + rlike +------- + 0 +(1 row) + +SELECT '-12.3abc' rlike 158.3; + rlike +------- + 0 +(1 row) + +SELECT '-12.3abc' rlike -8.222e4; + rlike +------- + 0 +(1 row) + +SELECT '-12.3abc' rlike true; +ERROR: function pg_catalog.rlike(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' rlike true; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: rlike +SELECT '-12.3abc' rlike false; +ERROR: function pg_catalog.rlike(unknown, boolean) does not exist +LINE 1: SELECT '-12.3abc' rlike false; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: rlike +SELECT '-12.3abc' rlike 'NULL'; + rlike +------- + 0 +(1 row) + +---------------------------------------- +-- copy from regex.sql of fastcheck +---------------------------------------- +set enable_bitmapscan = off; +set standard_conforming_strings = on; +select 'bbbbb' regexp '^([bc])\1*$' as t, 'bbbbb' not regexp '^([bc])\1*$' as t2, 'bbbbb' rlike '^([bc])\1*$' as t; + t | t2 | t +---+----+--- + 1 | 0 | 1 +(1 row) + +select 'ccc' regexp '^([bc])\1*$' as t, 'ccc' not regexp '^([bc])\1*$' as t2, 'ccc' rlike '^([bc])\1*$' as t; + t | t2 | t +---+----+--- + 1 | 0 | 1 +(1 row) + +select 'xxx' regexp '^([bc])\1*$' as f, 'xxx' not regexp '^([bc])\1*$' as f2, 'xxx' rlike '^([bc])\1*$' as f; + f | f2 | f +---+----+--- + 0 | 1 | 0 +(1 row) + +select 'bbc' regexp '^([bc])\1*$' as f, 'bbc' not regexp '^([bc])\1*$' as f2, 'bbc' rlike '^([bc])\1*$' as f; + f | f2 | f +---+----+--- + 0 | 1 | 0 +(1 row) + +select 'b' regexp '^([bc])\1*$' as t, 'b' not regexp '^([bc])\1*$' as t2, 'b' rlike '^([bc])\1*$' as t; + t | t2 | t +---+----+--- + 1 | 0 | 1 +(1 row) + +select 'abc abc abc' regexp '^(\w+)( \1)+$' as t, 'abc abc abc' not regexp '^(\w+)( \1)+$' as t, 'abc abc abc' rlike '^(\w+)( \1)+$' as t; + t | t | t +---+---+--- + 1 | 0 | 1 +(1 row) + +select 'abc abd abc' regexp '^(\w+)( \1)+$' as f, 'abc abd abc' not regexp '^(\w+)( \1)+$' as f, 'abc abd abc' rlike '^(\w+)( \1)+$' as f; + f | f | f +---+---+--- + 0 | 1 | 0 +(1 row) + +select 'abc abc abd' regexp '^(\w+)( \1)+$' as f, 'abc abc abd' not regexp '^(\w+)( \1)+$' as f, 'abc abc abd' rlike '^(\w+)( \1)+$' as f; + f | f | f +---+---+--- + 0 | 1 | 0 +(1 row) + +select 'abc abc abc' regexp '^(.+)( \1)+$' as t, 'abc abc abc' not regexp '^(.+)( \1)+$' as t, 'abc abc abc' rlike '^(.+)( \1)+$' as t; + t | t | t +---+---+--- + 1 | 0 | 1 +(1 row) + +select 'abc abd abc' regexp '^(.+)( \1)+$' as f, 'abc abd abc' not regexp '^(.+)( \1)+$' as f, 'abc abd abc' rlike '^(.+)( \1)+$' as f; + f | f | f +---+---+--- + 0 | 1 | 0 +(1 row) + +select 'abc abc abd' regexp '^(.+)( \1)+$' as f, 'abc abc abd' not regexp '^(.+)( \1)+$' as f, 'abc abc abd' rlike '^(.+)( \1)+$' as f; + f | f | f +---+---+--- + 0 | 1 | 0 +(1 row) + +select 'a' regexp '($|^)*', 'a' not regexp '($|^)*', 'a' rlike '($|^)*'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '(^)+^', 'a' not regexp '(^)+^', 'a' rlike '(^)+^'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '$($$)+', 'a' not regexp '$($$)+', 'a' rlike '$($$)+'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '($^)+', 'a' not regexp '($^)+', 'a' rlike '($^)+'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'a' regexp '(^$)*', 'a' not regexp '(^$)*', 'a' rlike '(^$)*'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'aa bb cc' regexp '(^(?!aa))+', 'aa bb cc' not regexp '(^(?!aa))+', 'aa bb cc' rlike '(^(?!aa))+'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'aa x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' rlike '(^(?!aa)(?!bb)(?!cc))+'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'bb x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' rlike '(^(?!aa)(?!bb)(?!cc))+'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'cc x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' rlike '(^(?!aa)(?!bb)(?!cc))+'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'dd x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' rlike '(^(?!aa)(?!bb)(?!cc))+'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'x' regexp 'abcd(\m)+xyz', 'x' not regexp 'abcd(\m)+xyz', 'x' rlike 'abcd(\m)+xyz'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'x' regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' not regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' rlike 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'a' regexp '((((((a)*)*)*)*)*)*', 'a' not regexp '((((((a)*)*)*)*)*)*', 'a' rlike '((((((a)*)*)*)*)*)*'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' not regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' rlike '((((((a+|)+|)+|)+|)+|)+|)'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '\x7fffffff', 'a' not regexp '\x7fffffff', 'a' rlike '\x7fffffff'; +ERROR: invalid regular expression: invalid escape \ sequence +CONTEXT: referenced column: int4 +SQL statement "SELECT (select lower(a)~ lower(b))::integer" +PL/pgSQL function regexp(text,text) line 6 at RETURN +referenced column: regexp +select 'a' regexp '$()|^\1', 'a' not regexp '$()|^\1', 'a' rlike '$()|^\1'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'a' regexp '.. ()|\1', 'a' not regexp '.. ()|\1', 'a' rlike '.. ()|\1'; + regexp | not_regexp | rlike +--------+------------+------- + 0 | 1 | 0 +(1 row) + +select 'a' regexp '()*\1', 'a' not regexp '()*\1', 'a' rlike '()*\1'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +select 'a' regexp '()+\1', 'a' not regexp '()+\1', 'a' rlike '()+\1'; + regexp | not_regexp | rlike +--------+------------+------- + 1 | 0 | 1 +(1 row) + +explain (costs off) select * from pg_proc where proname regexp 'abc'; + QUERY PLAN +------------------------------------------------ + Seq Scan on pg_proc + Filter: regexp((proname)::text, 'abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^abc'; + QUERY PLAN +------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^abc$'; + QUERY PLAN +-------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^abc$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^abcd*e'; + QUERY PLAN +---------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^abcd*e'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^abc+d'; + QUERY PLAN +--------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^abc+d'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^(abc)(def)'; + QUERY PLAN +-------------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^(abc)(def)'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^(abc)$'; + QUERY PLAN +---------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^(abc)$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname regexp '^(abc)?d'; + QUERY PLAN +----------------------------------------------------- + Seq Scan on pg_proc + Filter: regexp((proname)::text, '^(abc)?d'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp 'abc'; + QUERY PLAN +---------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, 'abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^abc'; + QUERY PLAN +----------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^abc$'; + QUERY PLAN +------------------------------------------------------ + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^abc$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^abcd*e'; + QUERY PLAN +-------------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^abcd*e'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^abc+d'; + QUERY PLAN +------------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^abc+d'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^(abc)(def)'; + QUERY PLAN +------------------------------------------------------------ + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^(abc)(def)'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^(abc)$'; + QUERY PLAN +-------------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^(abc)$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname not regexp '^(abc)?d'; + QUERY PLAN +--------------------------------------------------------- + Seq Scan on pg_proc + Filter: not_regexp((proname)::text, '^(abc)?d'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike 'abc'; + QUERY PLAN +----------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, 'abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^abc'; + QUERY PLAN +------------------------------------------------ + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^abc'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^abc$'; + QUERY PLAN +------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^abc$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^abcd*e'; + QUERY PLAN +--------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^abcd*e'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^abc+d'; + QUERY PLAN +-------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^abc+d'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^(abc)(def)'; + QUERY PLAN +------------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^(abc)(def)'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^(abc)$'; + QUERY PLAN +--------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^(abc)$'::text) +(2 rows) + +explain (costs off) select * from pg_proc where proname rlike '^(abc)?d'; + QUERY PLAN +---------------------------------------------------- + Seq Scan on pg_proc + Filter: rlike((proname)::text, '^(abc)?d'::text) +(2 rows) + +set enable_bitmapscan = default; +set standard_conforming_strings = default; +------DAYOFMONTH() DAYOFWEEK() DAYOFYEAR() HOUR() MICROSECOND() MINUTE() QUARTER() SECOND() WEEKDAY() WEEKOFYEAR() YEAR() +select DAYOFMONTH(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 26 +(1 row) + +select DAYOFWEEK(timestamp '2021-05-26 16:30:44.341191'); + ?column? +---------- + 4 +(1 row) + +select DAYOFYEAR(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 146 +(1 row) + +select HOUR(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 16 +(1 row) + +select MICROSECOND(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 44341191 +(1 row) + +select MINUTE(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 30 +(1 row) + +select QUARTER(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 2 +(1 row) + +select SECOND(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 44.341191 +(1 row) + +select WEEKDAY(timestamp '2021-05-26 16:30:44.341191'); + ?column? +---------- + 2 +(1 row) + +select WEEKOFYEAR(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 21 +(1 row) + +select YEAR(timestamp '2021-05-26 16:30:44.341191'); + date_part +----------- + 2021 +(1 row) + +--- LOCATE +select locate('test','testgood'); + position +---------- + 1 +(1 row) + +select locate('test','11testgood',5); + instr +------- + 0 +(1 row) + +select locate('test','11testgood',3); + instr +------- + 3 +(1 row) + +-- IFNULL +SELECT IFNULL(NULL, 'test'); + nvl +------ + test +(1 row) + +-- IF +SELECT IF(TRUE,'A','B'); + case +------ + A +(1 row) + +SELECT IF(FALSE,'A','B'); + case +------ + B +(1 row) + +------------------------------------------------------------------------------------------------------------------------ +---------------------------- +-- bit_length\octet_length\length +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length'); + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+--------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+--------------------- +(0 rows) + +select bit_length(b'1'), bit_length(b'101'), bit_length(b'1011111111'); + mysql_parser_bit_length | mysql_parser_bit_length | mysql_parser_bit_length +-------------------------+-------------------------+------------------------- + 8 | 8 | 16 +(1 row) + +select bit_length( '1'), bit_length( '101'), bit_length( '1011111111'); + mysql_parser_bit_length | mysql_parser_bit_length | mysql_parser_bit_length +-------------------------+-------------------------+------------------------- + 8 | 24 | 80 +(1 row) + +select bit_length( '哈1哈\n'),bit_length( '\n'),bit_length( '\\n'); + mysql_parser_bit_length | mysql_parser_bit_length | mysql_parser_bit_length +-------------------------+-------------------------+------------------------- + 72 | 16 | 24 +(1 row) + +select octet_length(b'1'), octet_length(b'101'), octet_length(b'1011111111'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 1 | 1 | 2 +(1 row) + +select octet_length( '1'), octet_length( '101'), octet_length( '1011111111'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 1 | 3 | 10 +(1 row) + +select octet_length( '哈1哈\n'),octet_length( '\n'),octet_length( '\\n'); + octet_length | octet_length | octet_length +--------------+--------------+-------------- + 9 | 2 | 3 +(1 row) + +select length(b'1'), length(b'101'), length(b'1011111111'); + length | length | length +--------+--------+-------- + 1 | 3 | 10 +(1 row) + +select length( '1'), length( '101'), length( '1011111111'); + length | length | length +--------+--------+-------- + 1 | 3 | 10 +(1 row) + +select length( '哈1哈\n'),length( '\n'),length( '\\n'); + length | length | length +--------+--------+-------- + 5 | 2 | 3 +(1 row) + +---------------------------- +-- \lcase\ucase\rand\truncate\current_date() +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length', 'lower', 'upper', 'random', 'trunc') order by oid; + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+---------------------------------------------------------------------------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+--------------------- + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 829 | 829 | | | | | macaddr_trunc | | | | | f | | f | f | | 0 | f | | + lower | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 25 | 25 | | | | | lower | | | | | f | | f | f | | 0 | f | | + upper | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 25 | 25 | | | | | upper | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 701 | 701 | | | | | dtrunc | | | | | f | | f | f | | 0 | f | | + random | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | v | 0 | 0 | 701 | | | | | | drandom | | | | | f | t | f | f | | 0 | f | | + trunc | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 1700 | 1700 23 | | | | | numeric_trunc | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 14 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 1700 | 1700 | | | | | select pg_catalog.trunc($1,0) | | | | | f | | f | f | | 0 | f | | + lower | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 2283 | 3831 | | | | | range_lower | | | | | f | | f | f | | 0 | f | | + upper | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 2283 | 3831 | | | | | range_upper | | | | | f | | f | f | | 0 | f | | + trunc | 11 | 10 | 14 | 100 | 0 | 0 | - | f | f | f | f | t | f | i | 1 | 0 | 1114 | 1184 | | | | | +| | | | | f | f | f | f | | 0 | f | | + | | | | | | | | | | | | | | | | | | | | | | | SELECT CAST(DATE_TRUNC('day',$1) AS TIMESTAMP WITHOUT TIME ZONE);+| | | | | | | | | | | | | + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +(10 rows) + +select lcase('ABc'), lcase('哈哈'), lcase('123456'); + lower | lower | lower +-------+-------+-------- + abc | 哈哈 | 123456 +(1 row) + +select lower('ABc'), lower('哈哈'), lower('123456'); + lower | lower | lower +-------+-------+-------- + abc | 哈哈 | 123456 +(1 row) + +select ucase('ABc'), ucase('哈哈'), ucase('123456'); + upper | upper | upper +-------+-------+-------- + ABC | 哈哈 | 123456 +(1 row) + +select upper('ABc'), upper('哈哈'), upper('123456'); + upper | upper | upper +-------+-------+-------- + ABC | 哈哈 | 123456 +(1 row) + +select rand(), random(); + random | random +------------------+------------------ + .901107039768249 | .417141783051193 +(1 row) + +select truncate(111.28), truncate(111.28,1), truncate(111.28,5), truncate(111.28,500), truncate(111.28,-1), truncate(111.28,-4); + trunc | trunc | trunc | trunc | trunc | trunc +-------+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------- + 111 | 111.2 | 111.28000 | 111.28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | 110 | 0 +(1 row) + +select trunc(111.28), trunc(111.28,1), trunc(111.28,5), trunc(111.28,500), trunc(111.28,-1), trunc(111.28,-4); + trunc | trunc | trunc | trunc | trunc | trunc +-------+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------- + 111 | 111.2 | 111.28000 | 111.28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | 110 | 0 +(1 row) + +truncate a; +ERROR: relation "a" does not exist +select current_date(), current_date; + date | date +------------+------------ + 10-28-2021 | 10-28-2021 +(1 row) + +------------------------------------------------------------------------------------------------------------------------ +\c contrib_regression +drop database db_b_parser_test_db; diff --git a/contrib/db_b_parser/pl/pl_b_gram.cpp b/contrib/db_b_parser/pl/pl_b_gram.cpp deleted file mode 100644 index f4d145703..000000000 --- a/contrib/db_b_parser/pl/pl_b_gram.cpp +++ /dev/null @@ -1,8634 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.5. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Undocumented macros, especially those whose name start with YY_, - are private implementation details. Do not rely on them. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "3.5" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - -/* Substitute the variable and function names. */ -#define yyparse plbsql_yyparse -#define yylex plbsql_yylex -#define yyerror plbsql_yyerror -#define yydebug plbsql_yydebug -#define yynerrs plbsql_yynerrs -#define yylval plbsql_yylval -#define yychar plbsql_yychar -#define yylloc plbsql_yylloc - -/* First part of user prologue. */ -#line 1 "pl/pl_b_gram.y" - -/* ------------------------------------------------------------------------- - * - * gram.y - Parser for the PL/pgSQL procedural language - * - * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/pl/plpgsql/src/gram.y - * - * ------------------------------------------------------------------------- - */ - -#include "pl_b_sql.h" - -#include "catalog/namespace.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_type.h" -#include "funcapi.h" -#include "nodes/makefuncs.h" -#include "parser/analyze.h" -#include "parser/keywords.h" -#include "parser/parser.h" -#include "parser/parse_coerce.h" -#include "parser/parse_expr.h" -#include "parser/parse_func.h" -#include "parser/parse_type.h" -#include "parser/scanner.h" -#include "parser/scansup.h" -#include "utils/builtins.h" -#include "utils/memutils.h" -#include "utils/syscache.h" - -#include - - -/* Location tracking support --- simpler than bison's default */ -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do { \ - if (N) \ - (Current) = (Rhs)[1]; \ - else \ - (Current) = (Rhs)[0]; \ - } while (0) - -extern List* db_b_raw_parser(const char* str, List** query_string_locationlist = NULL); - -/* - * Helper function to record statements label so that GOTO statements could reach - * there. - */ -static inline void -record_stmt_label(char * label, PLpgSQL_stmt *stmt) -{ - /* - * Note, we do plpgsql parsing under "PL/pgSQL Function" memory context, - * so palloc memory for goto-lable element and the global array under it. - */ - PLpgSQL_gotoLabel *gl = - (PLpgSQL_gotoLabel *)palloc0(sizeof(PLpgSQL_gotoLabel)); - gl->label = label; - gl->stmt = stmt; - u_sess->plsql_cxt.goto_labels = lappend(u_sess->plsql_cxt.goto_labels, (void *)gl); -} - -/* - * Bison doesn't allocate anything that needs to live across parser calls, - * so we can easily have it use palloc instead of malloc. This prevents - * memory leaks if we error out during parsing. Note this only works with - * bison >= 2.0. However, in bison 1.875 the default is to use alloca() - * if possible, so there's not really much problem anyhow, at least if - * you're building with gcc. - */ -#define YYMALLOC palloc -#define YYFREE pfree - - -typedef struct -{ - int location; - int leaderlen; -} sql_error_callback_arg; - -#define parser_errposition(pos) plpgsql_scanner_errposition(pos) - -union YYSTYPE; /* need forward reference for tok_is_keyword */ - -static bool tok_is_keyword(int token, union YYSTYPE *lval, - int kw_token, const char *kw_str); -static void word_is_not_variable(PLword *word, int location); -static void cword_is_not_variable(PLcword *cword, int location); -static void current_token_is_not_variable(int tok); -static void yylex_inparam(StringInfoData* func_inparam, - int *params, - int * tok); -static void yylex_outparam(char** fieldnames, - int *varnos, - int nfields, - PLpgSQL_row **row, - PLpgSQL_rec **rec, - int *token, - bool overload = false); - -static bool is_function(const char *name, bool is_assign, bool no_parenthesis); -static void plpgsql_parser_funcname(const char *s, char **output, - int numidents); -static PLpgSQL_stmt *make_callfunc_stmt(const char *sqlstart, - int location, bool is_assign); -static PLpgSQL_stmt *make_callfunc_stmt_no_arg(const char *sqlstart, int location); -static PLpgSQL_expr *read_sql_construct5(int until, - int until2, - int until3, - int until4, - int until5, - const char *expected, - const char *sqlstart, - bool isexpression, - bool valid_sql, - bool trim, - int *startloc, - int *endtoken); - -static PLpgSQL_expr *read_sql_construct(int until, - int until2, - int until3, - const char *expected, - const char *sqlstart, - bool isexpression, - bool valid_sql, - bool trim, - int *startloc, - int *endtoken); -static PLpgSQL_expr *read_sql_expression(int until, - const char *expected); -static PLpgSQL_expr *read_sql_expression2(int until, int until2, - const char *expected, - int *endtoken); -static PLpgSQL_expr *read_sql_stmt(const char *sqlstart); -static PLpgSQL_type *read_datatype(int tok); -static PLpgSQL_stmt *parse_lob_open_close(int location); -static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location); -static PLpgSQL_stmt_fetch *read_fetch_direction(void); -static void complete_direction(PLpgSQL_stmt_fetch *fetch, - bool *check_FROM); -static PLpgSQL_stmt *make_return_stmt(int location); -static PLpgSQL_stmt *make_return_next_stmt(int location); -static PLpgSQL_stmt *make_return_query_stmt(int location); -static PLpgSQL_stmt *make_case(int location, PLpgSQL_expr *t_expr, - List *case_when_list, List *else_stmts); -static char *NameOfDatum(PLwdatum *wdatum); -static void check_assignable(PLpgSQL_datum *datum, int location); -static void read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, - bool *strict); -static PLpgSQL_row *read_into_scalar_list(char *initial_name, - PLpgSQL_datum *initial_datum, - int initial_location); -static PLpgSQL_row *read_into_array_scalar_list(char *initial_name, - PLpgSQL_datum *initial_datum, - int initial_location); -static void read_using_target(List **in_expr, PLpgSQL_row **out_row); - -static PLpgSQL_row *read_into_placeholder_scalar_list(char *initial_name, - int initial_location); - -static PLpgSQL_row *make_scalar_list1(char *initial_name, - PLpgSQL_datum *initial_datum, - int lineno, int location); -static void check_sql_expr(const char *stmt, int location, - int leaderlen); -static void plpgsql_sql_error_callback(void *arg); -static PLpgSQL_type *parse_datatype(const char *string, int location); -static void check_labels(const char *start_label, - const char *end_label, - int end_location); -static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, - int until, const char *expected); -static List *read_raise_options(void); -static bool last_pragma; - - -#line 261 "pl/pl_b_gram.cpp" - -# ifndef YY_CAST -# ifdef __cplusplus -# define YY_CAST(Type, Val) static_cast (Val) -# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) -# else -# define YY_CAST(Type, Val) ((Type) (Val)) -# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) -# endif -# endif -# ifndef YY_NULLPTR -# if defined __cplusplus -# if 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# else -# define YY_NULLPTR ((void*)0) -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Use api.header.include to #include this header - instead of duplicating it here. */ -#ifndef YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED -# define YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int plbsql_yydebug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - IDENT = 258, - FCONST = 259, - SCONST = 260, - BCONST = 261, - VCONST = 262, - XCONST = 263, - Op = 264, - CmpOp = 265, - COMMENTSTRING = 266, - ICONST = 267, - PARAM = 268, - TYPECAST = 269, - ORA_JOINOP = 270, - DOT_DOT = 271, - COLON_EQUALS = 272, - PARA_EQUALS = 273, - T_WORD = 274, - T_CWORD = 275, - T_DATUM = 276, - T_PLACEHOLDER = 277, - T_VARRAY = 278, - T_ARRAY_FIRST = 279, - T_ARRAY_LAST = 280, - T_ARRAY_COUNT = 281, - T_ARRAY_EXTEND = 282, - T_VARRAY_VAR = 283, - T_RECORD = 284, - LESS_LESS = 285, - GREATER_GREATER = 286, - T_REFCURSOR = 287, - T_SQL_ISOPEN = 288, - T_SQL_FOUND = 289, - T_SQL_NOTFOUND = 290, - T_SQL_ROWCOUNT = 291, - T_CURSOR_ISOPEN = 292, - T_CURSOR_FOUND = 293, - T_CURSOR_NOTFOUND = 294, - T_CURSOR_ROWCOUNT = 295, - K_ABSOLUTE = 296, - K_ALIAS = 297, - K_ALL = 298, - K_ALTER = 299, - K_ARRAY = 300, - K_BACKWARD = 301, - K_BEGIN = 302, - K_BY = 303, - K_CASE = 304, - K_CLOSE = 305, - K_COLLATE = 306, - K_COMMIT = 307, - K_CONSTANT = 308, - K_CONTINUE = 309, - K_CURRENT = 310, - K_CURSOR = 311, - K_DEBUG = 312, - K_DECLARE = 313, - K_DEFAULT = 314, - K_DELETE = 315, - K_DETAIL = 316, - K_DIAGNOSTICS = 317, - K_DUMP = 318, - K_ELSE = 319, - K_ELSIF = 320, - K_END = 321, - K_ERRCODE = 322, - K_ERROR = 323, - K_EXCEPTION = 324, - K_EXECUTE = 325, - K_EXIT = 326, - K_FETCH = 327, - K_FIRST = 328, - K_FOR = 329, - K_FORALL = 330, - K_FOREACH = 331, - K_FORWARD = 332, - K_FROM = 333, - K_GET = 334, - K_GOTO = 335, - K_HINT = 336, - K_IF = 337, - K_IMMEDIATE = 338, - K_IN = 339, - K_INFO = 340, - K_INSERT = 341, - K_INTO = 342, - K_IS = 343, - K_LAST = 344, - K_LOG = 345, - K_LOOP = 346, - K_MERGE = 347, - K_MESSAGE = 348, - K_MESSAGE_TEXT = 349, - K_MOVE = 350, - K_NEXT = 351, - K_NO = 352, - K_NOT = 353, - K_NOTICE = 354, - K_NULL = 355, - K_OF = 356, - K_OPEN = 357, - K_OPTION = 358, - K_OR = 359, - K_OUT = 360, - K_PERFORM = 361, - K_PG_EXCEPTION_CONTEXT = 362, - K_PG_EXCEPTION_DETAIL = 363, - K_PG_EXCEPTION_HINT = 364, - K_PRAGMA = 365, - K_PRIOR = 366, - K_QUERY = 367, - K_RAISE = 368, - K_RECORD = 369, - K_REF = 370, - K_RELATIVE = 371, - K_RESULT_OID = 372, - K_RETURN = 373, - K_RETURNED_SQLSTATE = 374, - K_REVERSE = 375, - K_ROLLBACK = 376, - K_ROWTYPE = 377, - K_ROW_COUNT = 378, - K_SAVEPOINT = 379, - K_SELECT = 380, - K_SCROLL = 381, - K_SLICE = 382, - K_SQLSTATE = 383, - K_STACKED = 384, - K_STRICT = 385, - K_SYS_REFCURSOR = 386, - K_THEN = 387, - K_TO = 388, - K_TYPE = 389, - K_UPDATE = 390, - K_USE_COLUMN = 391, - K_USE_VARIABLE = 392, - K_USING = 393, - K_VARIABLE_CONFLICT = 394, - K_VARRAY = 395, - K_WARNING = 396, - K_WHEN = 397, - K_WHILE = 398, - K_WITH = 399 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -union YYSTYPE -{ -#line 188 "pl/pl_b_gram.y" - - core_YYSTYPE core_yystype; - /* these fields must match core_YYSTYPE: */ - int ival; - char *str; - const char *keyword; - - PLword word; - PLcword cword; - PLwdatum wdatum; - bool boolean; - Oid oid; - struct - { - char *name; - int lineno; - } varname; - struct - { - char *name; - int lineno; - PLpgSQL_datum *scalar; - PLpgSQL_rec *rec; - PLpgSQL_row *row; - } forvariable; - struct - { - char *label; - int n_initvars; - int *initvarnos; - bool autonomous; - } declhdr; - struct - { - List *stmts; - char *end_label; - int end_label_location; - } loop_body; - List *list; - PLpgSQL_type *dtype; - PLpgSQL_datum *datum; - PLpgSQL_var *var; - PLpgSQL_expr *expr; - PLpgSQL_stmt *stmt; - PLpgSQL_condition *condition; - PLpgSQL_exception *exception; - PLpgSQL_exception_block *exception_block; - PLpgSQL_nsitem *nsitem; - PLpgSQL_diag_item *diagitem; - PLpgSQL_stmt_fetch *fetch; - PLpgSQL_case_when *casewhen; - PLpgSQL_rec_attr *recattr; - -#line 512 "pl/pl_b_gram.cpp" - -}; -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - -/* Location type. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - -extern THR_LOCAL YYSTYPE plbsql_yylval; -extern THR_LOCAL YYLTYPE plbsql_yylloc; -int plbsql_yyparse (void); - -#endif /* !YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED */ - - - -#ifdef short -# undef short -#endif - -/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure - and (if available) are included - so that the code can choose integer types of a good width. */ - -#ifndef __PTRDIFF_MAX__ -# include /* INFRINGES ON USER NAME SPACE */ -# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_STDINT_H -# endif -#endif - -/* Narrow types that promote to a signed type and that can represent a - signed or unsigned integer of at least N bits. In tables they can - save space and decrease cache pressure. Promoting to a signed type - helps avoid bugs in integer arithmetic. */ - -#ifdef __INT_LEAST8_MAX__ -typedef __INT_LEAST8_TYPE__ yytype_int8; -#elif defined YY_STDINT_H -typedef int_least8_t yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef __INT_LEAST16_MAX__ -typedef __INT_LEAST16_TYPE__ yytype_int16; -#elif defined YY_STDINT_H -typedef int_least16_t yytype_int16; -#else -typedef short yytype_int16; -#endif - -#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST8_TYPE__ yytype_uint8; -#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST8_MAX <= INT_MAX) -typedef uint_least8_t yytype_uint8; -#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX -typedef unsigned char yytype_uint8; -#else -typedef short yytype_uint8; -#endif - -#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST16_TYPE__ yytype_uint16; -#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST16_MAX <= INT_MAX) -typedef uint_least16_t yytype_uint16; -#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX -typedef unsigned short yytype_uint16; -#else -typedef int yytype_uint16; -#endif - -#ifndef YYPTRDIFF_T -# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ -# define YYPTRDIFF_T __PTRDIFF_TYPE__ -# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ -# elif defined PTRDIFF_MAX -# ifndef ptrdiff_t -# include /* INFRINGES ON USER NAME SPACE */ -# endif -# define YYPTRDIFF_T ptrdiff_t -# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX -# else -# define YYPTRDIFF_T long -# define YYPTRDIFF_MAXIMUM LONG_MAX -# endif -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned -# endif -#endif - -#define YYSIZE_MAXIMUM \ - YY_CAST (YYPTRDIFF_T, \ - (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ - ? YYPTRDIFF_MAXIMUM \ - : YY_CAST (YYSIZE_T, -1))) - -#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) - -/* Stored state numbers (used for stacks). */ -typedef yytype_int16 yy_state_t; - -/* State numbers in computations. */ -typedef int yy_state_fast_t; - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef YY_ATTRIBUTE_PURE -# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) -# else -# define YY_ATTRIBUTE_PURE -# endif -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -# else -# define YY_ATTRIBUTE_UNUSED -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) -#else -# define YYUSE(E) /* empty */ -#endif - -#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - -#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ -# define YY_IGNORE_USELESS_CAST_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") -# define YY_IGNORE_USELESS_CAST_END \ - _Pragma ("GCC diagnostic pop") -#endif -#ifndef YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_END -#endif - - -#define YY_ASSERT(E) ((void) (0 && (E))) - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yy_state_t yyss_alloc; - YYSTYPE yyvs_alloc; - YYLTYPE yyls_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ - + YYSIZEOF (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYPTRDIFF_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / YYSIZEOF (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYPTRDIFF_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 3 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 669 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 152 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 99 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 252 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 363 - -#define YYUNDEFTOK 2 -#define YYMAXUTOK 399 - - -/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, with out-of-bounds checking. */ -#define YYTRANSLATE(YYX) \ - (0 <= (YYX) && (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 145, 2, 2, 2, 2, - 147, 148, 2, 2, 149, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 146, - 2, 150, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 151, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 -}; - -#if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_int16 yyrline[] = -{ - 0, 443, 443, 449, 450, 453, 457, 461, 465, 471, - 472, 475, 503, 512, 520, 531, 544, 545, 548, 549, - 553, 566, 623, 630, 629, 654, 660, 670, 684, 689, - 711, 722, 735, 751, 755, 761, 793, 796, 800, 807, - 820, 823, 852, 856, 862, 870, 871, 871, 875, 876, - 878, 893, 924, 937, 953, 954, 959, 970, 971, 976, - 983, 984, 988, 990, 997, 1000, 1010, 1011, 1014, 1015, - 1019, 1020, 1024, 1031, 1044, 1046, 1048, 1050, 1052, 1054, - 1056, 1058, 1064, 1067, 1075, 1085, 1087, 1089, 1091, 1093, - 1095, 1097, 1099, 1101, 1103, 1105, 1107, 1109, 1111, 1113, - 1115, 1119, 1132, 1146, 1201, 1204, 1208, 1214, 1218, 1224, - 1237, 1266, 1278, 1283, 1290, 1296, 1302, 1307, 1312, 1317, - 1333, 1347, 1359, 1365, 1382, 1385, 1399, 1402, 1408, 1415, - 1429, 1433, 1439, 1451, 1454, 1469, 1489, 1510, 1550, 1578, - 1824, 1932, 1970, 2002, 2017, 2024, 2070, 2073, 2078, 2080, - 2084, 2099, 2103, 2109, 2135, 2305, 2323, 2327, 2331, 2340, - 2348, 2356, 2360, 2366, 2370, 2420, 2468, 2483, 2556, 2641, - 2673, 2686, 2691, 2704, 2717, 2731, 2745, 2761, 2766, 2774, - 2776, 2775, 2815, 2819, 2825, 2838, 2847, 2853, 2912, 2956, - 2960, 2964, 2968, 2972, 2976, 2984, 2987, 2997, 2999, 3006, - 3010, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, - 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, - 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, - 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, - 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, - 3068, 3069, 3070 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || 0 -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "IDENT", "FCONST", "SCONST", "BCONST", - "VCONST", "XCONST", "Op", "CmpOp", "COMMENTSTRING", "ICONST", "PARAM", - "TYPECAST", "ORA_JOINOP", "DOT_DOT", "COLON_EQUALS", "PARA_EQUALS", - "T_WORD", "T_CWORD", "T_DATUM", "T_PLACEHOLDER", "T_VARRAY", - "T_ARRAY_FIRST", "T_ARRAY_LAST", "T_ARRAY_COUNT", "T_ARRAY_EXTEND", - "T_VARRAY_VAR", "T_RECORD", "LESS_LESS", "GREATER_GREATER", - "T_REFCURSOR", "T_SQL_ISOPEN", "T_SQL_FOUND", "T_SQL_NOTFOUND", - "T_SQL_ROWCOUNT", "T_CURSOR_ISOPEN", "T_CURSOR_FOUND", - "T_CURSOR_NOTFOUND", "T_CURSOR_ROWCOUNT", "K_ABSOLUTE", "K_ALIAS", - "K_ALL", "K_ALTER", "K_ARRAY", "K_BACKWARD", "K_BEGIN", "K_BY", "K_CASE", - "K_CLOSE", "K_COLLATE", "K_COMMIT", "K_CONSTANT", "K_CONTINUE", - "K_CURRENT", "K_CURSOR", "K_DEBUG", "K_DECLARE", "K_DEFAULT", "K_DELETE", - "K_DETAIL", "K_DIAGNOSTICS", "K_DUMP", "K_ELSE", "K_ELSIF", "K_END", - "K_ERRCODE", "K_ERROR", "K_EXCEPTION", "K_EXECUTE", "K_EXIT", "K_FETCH", - "K_FIRST", "K_FOR", "K_FORALL", "K_FOREACH", "K_FORWARD", "K_FROM", - "K_GET", "K_GOTO", "K_HINT", "K_IF", "K_IMMEDIATE", "K_IN", "K_INFO", - "K_INSERT", "K_INTO", "K_IS", "K_LAST", "K_LOG", "K_LOOP", "K_MERGE", - "K_MESSAGE", "K_MESSAGE_TEXT", "K_MOVE", "K_NEXT", "K_NO", "K_NOT", - "K_NOTICE", "K_NULL", "K_OF", "K_OPEN", "K_OPTION", "K_OR", "K_OUT", - "K_PERFORM", "K_PG_EXCEPTION_CONTEXT", "K_PG_EXCEPTION_DETAIL", - "K_PG_EXCEPTION_HINT", "K_PRAGMA", "K_PRIOR", "K_QUERY", "K_RAISE", - "K_RECORD", "K_REF", "K_RELATIVE", "K_RESULT_OID", "K_RETURN", - "K_RETURNED_SQLSTATE", "K_REVERSE", "K_ROLLBACK", "K_ROWTYPE", - "K_ROW_COUNT", "K_SAVEPOINT", "K_SELECT", "K_SCROLL", "K_SLICE", - "K_SQLSTATE", "K_STACKED", "K_STRICT", "K_SYS_REFCURSOR", "K_THEN", - "K_TO", "K_TYPE", "K_UPDATE", "K_USE_COLUMN", "K_USE_VARIABLE", - "K_USING", "K_VARIABLE_CONFLICT", "K_VARRAY", "K_WARNING", "K_WHEN", - "K_WHILE", "K_WITH", "'#'", "';'", "'('", "')'", "','", "'='", "'['", - "$accept", "pl_function", "comp_options", "comp_option", "opt_semi", - "pl_block", "decl_sect", "decl_start", "decl_stmts", "decl_stmt", - "decl_statement", "$@1", "record_attr_list", "record_attr", - "opt_scrollable", "decl_cursor_query", "decl_cursor_args", - "decl_cursor_arglist", "decl_cursor_arg", "cursor_in_out_option", - "decl_is_for", "decl_aliasitem", "decl_varname", "decl_const", - "decl_datatype", "decl_collate", "decl_notnull", "decl_defval", - "decl_rec_defval", "decl_defkey", "assign_operator", "proc_sect", - "proc_stmts", "proc_stmt", "goto_block_label", "label_stmts", - "label_stmt", "stmt_perform", "stmt_assign", "stmt_getdiag", - "getdiag_area_opt", "getdiag_list", "getdiag_list_item", "getdiag_item", - "getdiag_target", "varray_var", "record_var", "assign_var", "stmt_goto", - "label_name", "stmt_if", "stmt_elsifs", "stmt_else", "stmt_case", - "opt_expr_until_when", "case_when_list", "case_when", "opt_case_else", - "stmt_loop", "stmt_while", "stmt_for", "for_control", "forall_control", - "for_variable", "stmt_foreach_a", "foreach_slice", "forall_body", - "stmt_exit", "exit_type", "stmt_return", "stmt_raise", "loop_body", - "stmt_execsql", "stmt_dynexecute", "stmt_open", "stmt_fetch", - "stmt_move", "opt_fetch_direction", "stmt_close", "stmt_null", - "stmt_commit", "stmt_rollback", "cursor_variable", "exception_sect", - "@2", "proc_exceptions", "proc_exception", "proc_conditions", - "proc_condition", "expr_until_semi", "expr_until_rightbracket", - "expr_until_parenthesis", "expr_until_then", "expr_until_loop", - "opt_block_label", "opt_label", "opt_exitcond", "any_identifier", - "unreserved_keyword", YY_NULLPTR -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[NUM] -- (External) token number corresponding to the - (internal) symbol number NUM (which must be that of a token). */ -static const yytype_int16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 35, 59, 40, 41, 44, - 61, 91 -}; -# endif - -#define YYPACT_NINF (-298) - -#define yypact_value_is_default(Yyn) \ - ((Yyn) == YYPACT_NINF) - -#define YYTABLE_NINF (-195) - -#define yytable_value_is_error(Yyn) \ - 0 - - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - -298, 35, -25, -298, 42, -83, -298, -102, 3, -1, - -298, -298, 39, 14, -37, -298, -298, 473, -298, 266, - -298, -298, -298, -298, -298, 42, -80, 18, 28, -298, - 392, -298, -298, -298, -298, -298, -298, -298, 7, -298, - 42, -298, -298, -298, -298, -298, -298, -298, -298, -298, - 111, -298, -298, -298, -298, -298, -298, -298, -298, -298, - -298, -298, -298, -298, -298, -298, -298, -298, -298, -298, - -298, -298, -298, -298, 42, -298, -298, -298, -298, -298, - -298, -298, -298, -298, -298, -298, -298, -298, -298, -298, - 111, -298, -298, -298, -298, -298, -298, 266, -298, -298, - 1, -298, 64, -298, -298, 45, -298, -298, -298, -298, - -298, -298, -298, -298, -298, 86, -298, -298, -298, -298, - -298, -38, 82, -298, -298, -298, -298, -31, 86, -298, - -298, -298, -298, -298, -298, -298, -298, -298, -298, -298, - -13, -298, -298, -298, -298, 42, -298, -298, -298, -298, - -298, -298, -298, -298, -298, -28, 48, 48, 48, 526, - -15, -298, 90, -79, 5, 66, -298, -298, -298, 12, - 73, -298, 15, -298, -11, 16, 38, 25, 42, 27, - -298, -298, -298, 29, 86, -298, -298, 71, 30, -298, - 379, 86, -298, -298, -298, -298, -298, -298, -298, -298, - -108, -298, -298, -298, -298, -298, -298, 526, 76, -8, - 93, 53, 116, -298, -298, 526, -298, 57, -298, -298, - -298, -87, -298, 20, -298, 134, -298, -298, -298, -298, - -298, -298, 42, 25, -298, -298, -298, -54, -298, -298, - 99, 89, -298, -298, 41, -298, -298, -298, -298, -298, - -298, -298, -298, -298, -298, -298, -298, 177, 106, 100, - -298, -298, 46, 47, 139, 50, -298, -298, 52, 54, - 104, -81, -298, -298, -298, 438, 526, -298, 140, -298, - -298, -298, -298, -117, -298, -9, 59, -298, -298, -298, - 164, 42, 111, -33, 111, 65, 200, -298, -298, -298, - 113, -11, 42, 494, -298, -298, 166, -298, 89, -298, - 526, -298, 150, -298, 75, -23, -298, -59, -298, -298, - -298, -5, -298, -298, -298, 69, -298, -298, -298, -298, - 78, -298, -298, -298, 379, 144, 526, -298, -298, 111, - -298, -298, -298, -298, 95, 111, 104, 135, -298, -298, - 97, -298, -298, -298, -298, -298, -10, -298, -298, -298, - -298, 103, -298 -}; - - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 3, 0, 193, 1, 0, 0, 4, 9, 0, 12, - 199, 200, 0, 0, 0, 10, 2, 82, 15, 13, - 194, 5, 6, 8, 7, 0, 0, 179, 82, 73, - 0, 81, 75, 76, 77, 78, 79, 80, 12, 52, - 0, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 0, 210, 19, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 0, 232, 233, 234, 235, 236, - 237, 238, 239, 241, 240, 242, 243, 244, 245, 246, - 0, 247, 248, 249, 250, 251, 252, 14, 17, 18, - 54, 53, 0, 74, 180, 0, 72, 164, 165, 116, - 166, 118, 117, 156, 129, 0, 152, 160, 167, 151, - 171, 104, 0, 191, 157, 163, 171, 0, 0, 188, - 154, 153, 162, 158, 159, 161, 84, 93, 85, 94, - 0, 95, 86, 87, 88, 195, 89, 90, 91, 92, - 96, 97, 98, 99, 100, 0, 0, 0, 0, 82, - 0, 192, 0, 36, 0, 0, 16, 114, 115, 0, - 0, 55, 0, 56, 0, 0, 83, 0, 195, 0, - 177, 178, 176, 0, 0, 105, 106, 0, 0, 121, - 82, 0, 173, 168, 101, 69, 190, 68, 189, 188, - 0, 196, 174, 143, 144, 141, 142, 82, 0, 0, - 0, 146, 0, 135, 175, 82, 20, 0, 38, 23, - 32, 0, 26, 0, 27, 57, 67, 62, 29, 63, - 66, 31, 0, 181, 183, 11, 191, 133, 131, 172, - 0, 0, 122, 124, 0, 120, 119, 102, 188, 197, - 150, 137, 139, 138, 149, 148, 140, 0, 0, 0, - 136, 37, 40, 0, 0, 0, 50, 51, 0, 0, - 60, 0, 186, 187, 182, 82, 82, 130, 0, 169, - 112, 113, 111, 0, 108, 0, 126, 170, 198, 147, - 0, 195, 0, 0, 0, 0, 0, 22, 58, 59, - 0, 0, 0, 82, 132, 134, 0, 103, 0, 110, - 82, 191, 0, 192, 0, 0, 42, 47, 49, 48, - 39, 0, 33, 56, 25, 0, 61, 21, 185, 184, - 0, 107, 109, 127, 82, 0, 82, 155, 41, 0, - 45, 46, 56, 24, 0, 0, 60, 0, 128, 125, - 0, 145, 43, 44, 30, 34, 64, 56, 123, 35, - 65, 0, 28 -}; - - /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -298, -298, -298, -298, -298, 233, -298, -298, -298, 148, - -298, -298, -298, -92, -298, -298, -298, -298, -85, -298, - -298, -298, -48, -298, -297, -298, -90, -44, -298, -96, - -137, -17, -298, 234, -298, -298, -298, -298, -298, -298, - -298, -298, -47, -298, -298, -298, -298, -298, -298, -298, - -298, -298, -298, -298, -298, -298, 26, -298, -298, -298, - -298, -298, -298, -12, -298, -298, -298, -298, -298, -298, - -298, -194, 55, 56, -298, -298, -298, 141, -298, -298, - -298, -298, -112, -298, -298, -298, 33, -298, -34, -184, - -298, -298, -222, -43, 267, -169, -298, -3, -298 -}; - - /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 2, 6, 16, 26, 8, 19, 97, 98, - 99, 262, 321, 322, 219, 343, 293, 315, 316, 342, - 320, 268, 100, 173, 225, 270, 301, 228, 359, 229, - 230, 212, 28, 29, 30, 31, 136, 137, 138, 139, - 187, 283, 284, 332, 285, 174, 175, 140, 141, 189, - 142, 286, 312, 143, 179, 237, 238, 278, 32, 33, - 34, 207, 209, 208, 35, 258, 253, 144, 145, 146, - 147, 213, 148, 149, 150, 151, 152, 184, 153, 154, - 36, 37, 183, 105, 177, 233, 234, 271, 272, 194, - 246, 245, 190, 215, 38, 200, 250, 201, 101 -}; - - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int16 yytable[] = -{ - 27, 12, 163, 199, 195, 4, 195, 195, 195, 235, - 276, 107, 108, 251, 275, 247, 193, 185, 217, 110, - 13, 260, 102, 302, 167, 340, 346, 263, 264, 307, - 168, 22, 308, 169, 248, 3, 113, 162, 249, 266, - 267, 318, 165, 170, 15, 353, 341, 218, 226, 226, - 17, 303, 117, 265, 171, 319, 14, 18, 25, 155, - 361, 10, 118, 11, 288, 18, 103, 203, 204, 205, - 20, 164, 240, 298, 299, -193, 206, 21, 124, 244, - -193, 156, 157, 158, 125, -194, -193, 104, 236, 334, - -194, 186, -71, -71, -71, 176, -194, -71, 159, 23, - 24, 188, -193, -193, -193, 180, 181, 182, 280, 281, - 282, 178, -194, -194, -194, 192, 132, 133, 202, -193, - 5, 216, 314, 310, 311, 338, 339, 134, 160, -194, - 39, 214, 172, 241, 196, 227, 135, 197, 198, 197, - 197, 197, 351, 344, 345, 210, 211, 223, 309, -193, - 161, 220, 41, 42, 221, 43, 44, 45, 222, -194, - 252, 224, 231, 46, 47, 48, 49, 232, 51, 236, - -71, -193, 53, 243, 54, 239, 242, 256, 55, 56, - 257, -194, 259, 261, 57, 269, 279, 287, 58, 289, - 290, 291, 59, 292, 294, 295, 60, 296, 297, 61, - 62, 63, 300, 64, 65, 66, 306, 67, 68, 313, - 69, 324, 325, 326, 70, 330, 335, 347, 71, 72, - 73, 337, 75, 76, 348, 77, 350, 78, 79, 273, - 80, 81, 82, 83, 84, 7, 357, 85, 86, 87, - 88, 354, 89, 358, 317, 166, 323, 91, 92, 362, - 93, 94, 95, 355, 352, 96, 356, 327, 304, 305, - 360, 331, 106, 277, 254, 255, 274, 191, 328, 9, - 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 39, 329, 0, 0, 0, - 0, 317, 0, 333, 0, 0, 40, 323, 0, 273, - 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, - 43, 44, 45, 0, 0, 0, 0, 349, 46, 47, - 48, 49, 50, 51, 52, 0, 0, 53, 0, 54, - 0, 0, 0, 55, 56, 0, 0, 0, 0, 57, - 0, 0, 0, 58, 0, 0, 0, 59, 0, 0, - 0, 60, 0, 0, 61, 62, 63, 0, 64, 65, - 66, 0, 67, 68, 0, 69, 0, 0, 0, 70, - 0, 0, 0, 71, 72, 73, 74, 75, 76, 0, - 77, 0, 78, 79, 0, 80, 81, 82, 83, 84, - 0, 0, 85, 86, 87, 88, 0, 89, 0, 0, - 90, 0, 91, 92, 0, 93, 94, 95, 0, 25, - 96, 107, 108, 109, 0, 0, 0, 0, 0, 110, - 111, 112, 0, 0, 0, 0, -193, 0, 0, 0, - 0, -193, 0, 0, 0, 0, 113, -193, 0, 0, - 0, 114, 115, -70, -70, -70, 116, 0, 0, 0, - 0, 0, 117, -193, -193, -193, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 0, 0, 0, 25, 0, - -193, 121, 122, 0, 123, 0, 0, 0, 124, 0, - 0, 0, 0, 0, 125, -193, 0, 126, 0, 0, - -193, 0, 127, 0, 128, 0, -193, 0, 129, 0, - -193, 0, -70, 25, -70, 130, 0, 0, 0, 0, - 131, 0, -193, -193, -193, 0, 132, 133, 0, 0, - -193, 0, -193, 0, 25, -193, 0, 134, 0, -193, - 0, -193, 0, 0, 0, 0, 135, 0, 0, -70, - 0, -193, -70, 0, 0, 0, -193, -193, -193, -193, - 0, 0, -193, 0, 0, 0, 25, 0, 0, -193, - -70, 0, 0, 0, -193, 0, 0, 0, -193, -193, - -193, 0, 0, -193, 0, 0, 0, 0, -193, 0, - -70, -193, 0, 0, -193, -193, 0, 0, 0, 0, - 0, 0, -70, 0, -193, 0, 0, 0, 0, 0, - -193, -193, -193, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -193, -193, -193, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -70, -193, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -193, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -193 -}; - -static const yytype_int16 yycheck[] = -{ - 17, 4, 50, 140, 17, 30, 17, 17, 17, 178, - 64, 19, 20, 207, 236, 199, 128, 55, 97, 27, - 103, 215, 25, 104, 23, 84, 323, 114, 115, 146, - 29, 68, 149, 32, 142, 0, 44, 40, 146, 19, - 20, 74, 90, 42, 146, 342, 105, 126, 59, 59, - 47, 132, 60, 140, 53, 88, 139, 58, 30, 52, - 357, 19, 70, 21, 248, 58, 146, 19, 20, 21, - 31, 74, 184, 19, 20, 47, 28, 63, 86, 191, - 52, 74, 75, 76, 92, 47, 58, 69, 142, 311, - 52, 129, 64, 65, 66, 31, 58, 69, 91, 136, - 137, 19, 74, 75, 76, 19, 20, 21, 19, 20, - 21, 66, 74, 75, 76, 146, 124, 125, 146, 91, - 145, 31, 291, 64, 65, 148, 149, 135, 121, 91, - 19, 146, 131, 62, 147, 146, 144, 150, 151, 150, - 150, 150, 336, 148, 149, 157, 158, 74, 285, 121, - 143, 146, 41, 42, 88, 44, 45, 46, 146, 121, - 84, 146, 146, 52, 53, 54, 55, 142, 57, 142, - 142, 143, 61, 190, 63, 146, 146, 84, 67, 68, - 127, 143, 66, 126, 73, 51, 87, 146, 77, 12, - 84, 91, 81, 147, 147, 56, 85, 147, 146, 88, - 89, 90, 98, 92, 93, 94, 66, 96, 97, 45, - 99, 146, 12, 100, 103, 49, 66, 148, 107, 108, - 109, 146, 111, 112, 146, 114, 82, 116, 117, 232, - 119, 120, 121, 122, 123, 2, 101, 126, 127, 128, - 129, 146, 131, 146, 292, 97, 294, 136, 137, 146, - 139, 140, 141, 345, 339, 144, 346, 301, 275, 276, - 356, 308, 28, 237, 209, 209, 233, 126, 302, 2, - 313, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 19, 303, -1, -1, -1, - -1, 339, -1, 310, -1, -1, 30, 345, -1, 302, - -1, -1, -1, -1, -1, -1, -1, 41, 42, -1, - 44, 45, 46, -1, -1, -1, -1, 334, 52, 53, - 54, 55, 56, 57, 58, -1, -1, 61, -1, 63, - -1, -1, -1, 67, 68, -1, -1, -1, -1, 73, - -1, -1, -1, 77, -1, -1, -1, 81, -1, -1, - -1, 85, -1, -1, 88, 89, 90, -1, 92, 93, - 94, -1, 96, 97, -1, 99, -1, -1, -1, 103, - -1, -1, -1, 107, 108, 109, 110, 111, 112, -1, - 114, -1, 116, 117, -1, 119, 120, 121, 122, 123, - -1, -1, 126, 127, 128, 129, -1, 131, -1, -1, - 134, -1, 136, 137, -1, 139, 140, 141, -1, 30, - 144, 19, 20, 21, -1, -1, -1, -1, -1, 27, - 28, 29, -1, -1, -1, -1, 47, -1, -1, -1, - -1, 52, -1, -1, -1, -1, 44, 58, -1, -1, - -1, 49, 50, 64, 65, 66, 54, -1, -1, -1, - -1, -1, 60, 74, 75, 76, -1, -1, -1, -1, - -1, -1, 70, 71, 72, -1, -1, -1, 30, -1, - 91, 79, 80, -1, 82, -1, -1, -1, 86, -1, - -1, -1, -1, -1, 92, 47, -1, 95, -1, -1, - 52, -1, 100, -1, 102, -1, 58, -1, 106, -1, - 121, -1, 64, 30, 66, 113, -1, -1, -1, -1, - 118, -1, 74, 75, 76, -1, 124, 125, -1, -1, - 47, -1, 143, -1, 30, 52, -1, 135, -1, 91, - -1, 58, -1, -1, -1, -1, 144, -1, -1, 66, - -1, 47, 69, -1, -1, -1, 52, 74, 75, 76, - -1, -1, 58, -1, -1, -1, 30, -1, -1, 121, - 66, -1, -1, -1, 91, -1, -1, -1, 74, 75, - 76, -1, -1, 47, -1, -1, -1, -1, 52, -1, - 142, 143, -1, -1, 58, 91, -1, -1, -1, -1, - -1, -1, 66, -1, 121, -1, -1, -1, -1, -1, - 74, 75, 76, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 121, 143, 91, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 142, 143, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 121, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 143 -}; - - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 153, 154, 0, 30, 145, 155, 157, 158, 246, - 19, 21, 249, 103, 139, 146, 156, 47, 58, 159, - 31, 63, 68, 136, 137, 30, 157, 183, 184, 185, - 186, 187, 210, 211, 212, 216, 232, 233, 246, 19, - 30, 41, 42, 44, 45, 46, 52, 53, 54, 55, - 56, 57, 58, 61, 63, 67, 68, 73, 77, 81, - 85, 88, 89, 90, 92, 93, 94, 96, 97, 99, - 103, 107, 108, 109, 110, 111, 112, 114, 116, 117, - 119, 120, 121, 122, 123, 126, 127, 128, 129, 131, - 134, 136, 137, 139, 140, 141, 144, 160, 161, 162, - 174, 250, 249, 146, 69, 235, 185, 19, 20, 21, - 27, 28, 29, 44, 49, 50, 54, 60, 70, 71, - 72, 79, 80, 82, 86, 92, 95, 100, 102, 106, - 113, 118, 124, 125, 135, 144, 188, 189, 190, 191, - 199, 200, 202, 205, 219, 220, 221, 222, 224, 225, - 226, 227, 228, 230, 231, 52, 74, 75, 76, 91, - 121, 143, 249, 174, 249, 174, 161, 23, 29, 32, - 42, 53, 131, 175, 197, 198, 31, 236, 66, 206, - 19, 20, 21, 234, 229, 55, 129, 192, 19, 201, - 244, 229, 146, 234, 241, 17, 147, 150, 151, 182, - 247, 249, 146, 19, 20, 21, 28, 213, 215, 214, - 215, 215, 183, 223, 146, 245, 31, 97, 126, 166, - 146, 88, 146, 74, 146, 176, 59, 146, 179, 181, - 182, 146, 142, 237, 238, 247, 142, 207, 208, 146, - 234, 62, 146, 183, 234, 243, 242, 241, 142, 146, - 248, 223, 84, 218, 224, 225, 84, 127, 217, 66, - 223, 126, 163, 114, 115, 140, 19, 20, 173, 51, - 177, 239, 240, 249, 238, 244, 64, 208, 209, 87, - 19, 20, 21, 193, 194, 196, 203, 146, 241, 12, - 84, 91, 147, 168, 147, 56, 147, 146, 19, 20, - 98, 178, 104, 132, 183, 183, 66, 146, 149, 182, - 64, 65, 204, 45, 247, 169, 170, 174, 74, 88, - 172, 164, 165, 174, 146, 12, 100, 179, 240, 183, - 49, 194, 195, 183, 244, 66, 245, 146, 148, 149, - 84, 105, 171, 167, 148, 149, 176, 148, 146, 183, - 82, 223, 170, 176, 146, 165, 178, 101, 146, 180, - 181, 176, 146 -}; - - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 152, 153, 154, 154, 155, 155, 155, 155, 156, - 156, 157, 158, 158, 158, 159, 160, 160, 161, 161, - 161, 162, 162, 163, 162, 162, 162, 162, 162, 162, - 162, 162, 162, 164, 164, 165, 166, 166, 166, 167, - 168, 168, 169, 169, 170, 171, 171, 171, 172, 172, - 173, 173, 174, 174, 175, 175, 176, 177, 177, 177, - 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, - 183, 183, 184, 184, 185, 185, 185, 185, 185, 185, - 185, 185, 186, 186, 187, 188, 188, 188, 188, 188, - 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, - 188, 189, 190, 191, 192, 192, 192, 193, 193, 194, - 195, 196, 196, 196, 197, 198, 199, 199, 199, 199, - 199, 200, 201, 202, 203, 203, 204, 204, 205, 206, - 207, 207, 208, 209, 209, 210, 211, 212, 212, 213, - 214, 215, 215, 215, 215, 216, 217, 217, 218, 218, - 219, 220, 220, 221, 222, 223, 224, 224, 224, 224, - 224, 224, 224, 224, 224, 224, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 234, 234, 235, - 236, 235, 237, 237, 238, 239, 239, 240, 241, 242, - 243, 244, 245, 246, 246, 247, 247, 248, 248, 249, - 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 250, 250 -}; - - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_int8 yyr2[] = -{ - 0, 2, 3, 0, 2, 3, 3, 3, 3, 0, - 1, 6, 1, 2, 3, 1, 2, 1, 1, 1, - 3, 6, 5, 0, 7, 6, 3, 3, 10, 3, - 8, 3, 3, 1, 3, 4, 0, 2, 1, 0, - 0, 3, 1, 3, 3, 1, 1, 0, 1, 1, - 1, 1, 1, 1, 0, 1, 0, 0, 2, 2, - 0, 2, 1, 1, 0, 1, 1, 1, 1, 1, - 0, 1, 2, 1, 2, 1, 1, 1, 1, 1, - 1, 1, 0, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 3, 5, 0, 1, 1, 3, 1, 3, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, - 3, 2, 2, 8, 0, 4, 0, 2, 7, 0, - 2, 1, 3, 0, 2, 3, 4, 4, 4, 2, - 2, 1, 1, 1, 1, 8, 0, 2, 1, 1, - 3, 1, 1, 1, 1, 5, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, - 4, 0, 3, 2, 3, 3, 1, 1, 1, 0, - 0, 3, 2, 1, 4, 3, 1, 1, 0, 0, - 0, 0, 0, 0, 3, 0, 1, 1, 2, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1 -}; - - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ - do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ - while (0) - -/* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (N) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (0) -#endif - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - -/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ - -YY_ATTRIBUTE_UNUSED -static int -yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) -{ - int res = 0; - int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; - if (0 <= yylocp->first_line) - { - res += YYFPRINTF (yyo, "%d", yylocp->first_line); - if (0 <= yylocp->first_column) - res += YYFPRINTF (yyo, ".%d", yylocp->first_column); - } - if (0 <= yylocp->last_line) - { - if (yylocp->first_line < yylocp->last_line) - { - res += YYFPRINTF (yyo, "-%d", yylocp->last_line); - if (0 <= end_col) - res += YYFPRINTF (yyo, ".%d", end_col); - } - else if (0 <= end_col && yylocp->first_column < end_col) - res += YYFPRINTF (yyo, "-%d", end_col); - } - return res; - } - -# define YY_LOCATION_PRINT(File, Loc) \ - yy_location_print_ (File, &(Loc)) - -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, Location); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*-----------------------------------. -| Print this symbol's value on YYO. | -`-----------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -{ - FILE *yyoutput = yyo; - YYUSE (yyoutput); - YYUSE (yylocationp); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyo, yytoknum[yytype], *yyvaluep); -# endif - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - -/*---------------------------. -| Print this symbol on YYO. | -`---------------------------*/ - -static void -yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -{ - YYFPRINTF (yyo, "%s %s (", - yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - - YY_LOCATION_PRINT (yyo, *yylocationp); - YYFPRINTF (yyo, ": "); - yy_symbol_value_print (yyo, yytype, yyvaluep, yylocationp); - YYFPRINTF (yyo, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) -{ - int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - yystos[yyssp[yyi + 1 - yynrhs]], - &yyvsp[(yyi + 1) - (yynrhs)] - , &(yylsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -THR_LOCAL int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) -# else -/* Return the length of YYSTR. */ -static YYPTRDIFF_T -yystrlen (const char *yystr) -{ - YYPTRDIFF_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -yystpcpy (char *yydest, const char *yysrc) -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYPTRDIFF_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYPTRDIFF_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - else - goto append; - - append: - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (yyres) - return yystpcpy (yyres, yystr) - yyres; - else - return yystrlen (yystr); -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, - yy_state_t *yyssp, int yytoken) -{ - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat: reported tokens (one for the "unexpected", - one per "expected"). */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Actual size of YYARG. */ - int yycount = 0; - /* Cumulated lengths of YYARG. */ - YYPTRDIFF_T yysize = 0; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - YYPTRDIFF_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - yysize = yysize0; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYPTRDIFF_T yysize1 - = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) - yysize = yysize1; - else - return 2; - } - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - default: /* Avoid compiler warnings. */ - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - /* Don't count the "%s"s in the final size, but reserve room for - the terminator. */ - YYPTRDIFF_T yysize1 = yysize + (yystrlen (yyformat) - 2 * yycount) + 1; - if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) - yysize = yysize1; - else - return 2; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - ++yyp; - ++yyformat; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) -{ - YYUSE (yyvaluep); - YYUSE (yylocationp); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - -/* The lookahead symbol. */ -THR_LOCAL int yychar; - -/* The semantic value of the lookahead symbol. */ -THR_LOCAL YYSTYPE yylval; -/* Location data for the lookahead symbol. */ -THR_LOCAL YYLTYPE yylloc -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - = { 1, 1, 1, 1 } -# endif -; -/* Number of syntax errors so far. */ -THR_LOCAL int yynerrs; - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (void) -{ - yy_state_fast_t yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - 'yyls': related to locations. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yy_state_t yyssa[YYINITDEPTH]; - yy_state_t *yyss; - yy_state_t *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls; - YYLTYPE *yylsp; - - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[3]; - - YYPTRDIFF_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - YYLTYPE yyloc; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yylsp = yyls = yylsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - yylsp[0] = yylloc; - goto yysetstate; - - -/*------------------------------------------------------------. -| yynewstate -- push a new state, which is found in yystate. | -`------------------------------------------------------------*/ -yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - -/*--------------------------------------------------------------------. -| yysetstate -- set current state (the top of the stack) to yystate. | -`--------------------------------------------------------------------*/ -yysetstate: - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - YY_ASSERT (0 <= yystate && yystate < YYNSTATES); - YY_IGNORE_USELESS_CAST_BEGIN - *yyssp = YY_CAST (yy_state_t, yystate); - YY_IGNORE_USELESS_CAST_END - - if (yyss + yystacksize - 1 <= yyssp) -#if !defined yyoverflow && !defined YYSTACK_RELOCATE - goto yyexhaustedlab; -#else - { - /* Get the current used size of the three stacks, in elements. */ - YYPTRDIFF_T yysize = yyssp - yyss + 1; - -# if defined yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - yy_state_t *yyss1 = yyss; - YYSTYPE *yyvs1 = yyvs; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * YYSIZEOF (*yyssp), - &yyvs1, yysize * YYSIZEOF (*yyvsp), - &yyls1, yysize * YYSIZEOF (*yylsp), - &yystacksize); - yyss = yyss1; - yyvs = yyvs1; - yyls = yyls1; - } -# else /* defined YYSTACK_RELOCATE */ - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yy_state_t *yyss1 = yyss; - union yyalloc *yyptr = - YY_CAST (union yyalloc *, - YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - yylsp = yyls + yysize - 1; - - YY_IGNORE_USELESS_CAST_BEGIN - YYDPRINTF ((stderr, "Stack size increased to %ld\n", - YY_CAST (long, yystacksize))); - YY_IGNORE_USELESS_CAST_END - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } -#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = yylex (); - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - *++yylsp = yylloc; - - /* Discard the shifted token. */ - yychar = YYEMPTY; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - /* Default location. */ - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); - yyerror_range[1] = yyloc; - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 444 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_parse_result = (PLpgSQL_stmt_block *) (yyvsp[-1].stmt); - } -#line 2201 "pl/pl_b_gram.cpp" - break; - - case 5: -#line 454 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_DumpExecTree = true; - } -#line 2209 "pl/pl_b_gram.cpp" - break; - - case 6: -#line 458 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_ERROR; - } -#line 2217 "pl/pl_b_gram.cpp" - break; - - case 7: -#line 462 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_VARIABLE; - } -#line 2225 "pl/pl_b_gram.cpp" - break; - - case 8: -#line 466 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_COLUMN; - } -#line 2233 "pl/pl_b_gram.cpp" - break; - - case 11: -#line 476 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_block *newp; - - newp = (PLpgSQL_stmt_block *)palloc0(sizeof(PLpgSQL_stmt_block)); - - newp->cmd_type = PLPGSQL_STMT_BLOCK; - newp->lineno = plpgsql_location_to_lineno((yylsp[-4])); - newp->label = (yyvsp[-5].declhdr).label; -#ifndef ENABLE_MULTIPLE_NODES - newp->autonomous = (yyvsp[-5].declhdr).autonomous; -#endif - newp->n_initvars = (yyvsp[-5].declhdr).n_initvars; - newp->initvarnos = (yyvsp[-5].declhdr).initvarnos; - newp->body = (yyvsp[-3].list); - newp->exceptions = (yyvsp[-2].exception_block); - - check_labels((yyvsp[-5].declhdr).label, (yyvsp[0].str), (yylsp[0])); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-5].declhdr).label, (PLpgSQL_stmt *)newp); - } -#line 2262 "pl/pl_b_gram.cpp" - break; - - case 12: -#line 504 "pl/pl_b_gram.y" - { - /* done with decls, so resume identifier lookup */ - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - (yyval.declhdr).label = (yyvsp[0].str); - (yyval.declhdr).n_initvars = 0; - (yyval.declhdr).initvarnos = NULL; - (yyval.declhdr).autonomous = false; - } -#line 2275 "pl/pl_b_gram.cpp" - break; - - case 13: -#line 513 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - (yyval.declhdr).label = (yyvsp[-1].str); - (yyval.declhdr).n_initvars = 0; - (yyval.declhdr).initvarnos = NULL; - (yyval.declhdr).autonomous = false; - } -#line 2287 "pl/pl_b_gram.cpp" - break; - - case 14: -#line 521 "pl/pl_b_gram.y" - { - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - (yyval.declhdr).label = (yyvsp[-2].str); - /* Remember variables declared in decl_stmts */ - (yyval.declhdr).n_initvars = plpgsql_add_initdatums(&((yyval.declhdr).initvarnos)); - (yyval.declhdr).autonomous = last_pragma; - last_pragma = false; - } -#line 2300 "pl/pl_b_gram.cpp" - break; - - case 15: -#line 532 "pl/pl_b_gram.y" - { - /* Forget any variables created before block */ - plpgsql_add_initdatums(NULL); - last_pragma = false; - /* - * Disable scanner lookup of identifiers while - * we process the decl_stmts - */ - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE; - } -#line 2315 "pl/pl_b_gram.cpp" - break; - - case 19: -#line 550 "pl/pl_b_gram.y" - { - /* We allow useless extra DECLAREs */ - } -#line 2323 "pl/pl_b_gram.cpp" - break; - - case 20: -#line 554 "pl/pl_b_gram.y" - { - /* - * Throw a helpful error if user tries to put block - * label just before BEGIN, instead of before DECLARE. - */ - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("block label must be placed before DECLARE, not after"), - parser_errposition((yylsp[-2])))); - } -#line 2338 "pl/pl_b_gram.cpp" - break; - - case 21: -#line 567 "pl/pl_b_gram.y" - { - PLpgSQL_variable *var; - - /* - * If a collation is supplied, insert it into the - * datatype. We assume decl_datatype always returns - * a freshly built struct not shared with other - * variables. - */ - if (OidIsValid((yyvsp[-2].oid))) - { - if (!OidIsValid((yyvsp[-3].dtype)->collation)) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("collations are not supported by type %s", - format_type_be((yyvsp[-3].dtype)->typoid)), - parser_errposition((yylsp[-2])))); - (yyvsp[-3].dtype)->collation = (yyvsp[-2].oid); - } - - var = plpgsql_build_variable((yyvsp[-5].varname).name, (yyvsp[-5].varname).lineno, - (yyvsp[-3].dtype), true); - if ((yyvsp[-4].boolean)) - { - if (var->dtype == PLPGSQL_DTYPE_VAR) - ((PLpgSQL_var *) var)->isconst = (yyvsp[-4].boolean); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("row or record variable cannot be CONSTANT"), - parser_errposition((yylsp[-4])))); - } - if ((yyvsp[-1].boolean)) - { - if (var->dtype == PLPGSQL_DTYPE_VAR) - ((PLpgSQL_var *) var)->notnull = (yyvsp[-1].boolean); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("row or record variable cannot be NOT NULL"), - parser_errposition((yylsp[-2])))); - - } - if ((yyvsp[0].expr) != NULL) - { - if (var->dtype == PLPGSQL_DTYPE_VAR) - ((PLpgSQL_var *) var)->default_val = (yyvsp[0].expr); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("default value for row or record variable is not supported"), - parser_errposition((yylsp[-1])))); - } - - pfree_ext((yyvsp[-5].varname).name); - } -#line 2399 "pl/pl_b_gram.cpp" - break; - - case 22: -#line 624 "pl/pl_b_gram.y" - { - plpgsql_ns_additem((yyvsp[-1].nsitem)->itemtype, - (yyvsp[-1].nsitem)->itemno, (yyvsp[-4].varname).name); - pfree_ext((yyvsp[-4].varname).name); - } -#line 2409 "pl/pl_b_gram.cpp" - break; - - case 23: -#line 630 "pl/pl_b_gram.y" - { plpgsql_ns_push((yyvsp[-1].varname).name); } -#line 2415 "pl/pl_b_gram.cpp" - break; - - case 24: -#line 632 "pl/pl_b_gram.y" - { - PLpgSQL_var *newp; - - /* pop local namespace for cursor args */ - plpgsql_ns_pop(); - - newp = (PLpgSQL_var *) - plpgsql_build_variable((yyvsp[-5].varname).name, (yyvsp[-5].varname).lineno, - plpgsql_build_datatype(REFCURSOROID, - -1, - InvalidOid), - true); - - newp->cursor_explicit_expr = (yyvsp[0].expr); - if ((yyvsp[-2].datum) == NULL) - newp->cursor_explicit_argrow = -1; - else - newp->cursor_explicit_argrow = (yyvsp[-2].datum)->dno; - newp->cursor_options = CURSOR_OPT_FAST_PLAN | (yyvsp[-4].ival); - - pfree_ext((yyvsp[-5].varname).name); - } -#line 2442 "pl/pl_b_gram.cpp" - break; - - case 25: -#line 655 "pl/pl_b_gram.y" - { - /* add name of cursor type to PLPGSQL_NSTYPE_REFCURSOR */ - plpgsql_ns_additem(PLPGSQL_NSTYPE_REFCURSOR,0,(yyvsp[-4].varname).name); - pfree_ext((yyvsp[-4].varname).name); - } -#line 2452 "pl/pl_b_gram.cpp" - break; - - case 26: -#line 661 "pl/pl_b_gram.y" - { - plpgsql_build_variable( - (yyvsp[-2].varname).name, - (yyvsp[-2].varname).lineno, - plpgsql_build_datatype(REFCURSOROID,-1,InvalidOid), - true); - pfree_ext((yyvsp[-2].varname).name); - } -#line 2465 "pl/pl_b_gram.cpp" - break; - - case 27: -#line 671 "pl/pl_b_gram.y" - { - plpgsql_build_variable( - (yyvsp[-2].varname).name, - (yyvsp[-2].varname).lineno, - plpgsql_build_datatype(REFCURSOROID,-1,InvalidOid), - true); - pfree_ext((yyvsp[-2].varname).name); - } -#line 2478 "pl/pl_b_gram.cpp" - break; - - case 28: -#line 685 "pl/pl_b_gram.y" - { - plpgsql_build_varrayType((yyvsp[-8].varname).name, (yyvsp[-8].varname).lineno, (yyvsp[-1].dtype), true); - pfree_ext((yyvsp[-8].varname).name); - } -#line 2487 "pl/pl_b_gram.cpp" - break; - - case 29: -#line 690 "pl/pl_b_gram.y" - { - char *type_name; - errno_t ret; - PLpgSQL_type * var_type = ((PLpgSQL_var *)u_sess->plsql_cxt.plpgsql_Datums[(yyvsp[-1].ival)])->datatype; - PLpgSQL_var *newp; - int len = strlen(var_type->typname) + 3; - type_name = (char *)palloc0(len); - ret = strcpy_s(type_name, len, var_type->typname); - securec_check(ret, "", ""); - ret = strcat_s(type_name, len, "[]"); - securec_check(ret, "", ""); - var_type = parse_datatype(type_name, yylloc); - - newp = (PLpgSQL_var *)plpgsql_build_variable((yyvsp[-2].varname).name, (yyvsp[-2].varname).lineno,var_type,true); - if (NULL == newp) - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), - errmsg("build variable failed"))); - pfree_ext((yyvsp[-2].varname).name); - pfree_ext(type_name); - } -#line 2513 "pl/pl_b_gram.cpp" - break; - - case 30: -#line 712 "pl/pl_b_gram.y" - { - PLpgSQL_rec_type *newp = NULL; - - newp = plpgsql_build_rec_type((yyvsp[-6].varname).name, (yyvsp[-6].varname).lineno, (yyvsp[-2].list), true); - if (NULL == newp) - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), - errmsg("build variable failed"))); - pfree_ext((yyvsp[-6].varname).name); - } -#line 2528 "pl/pl_b_gram.cpp" - break; - - case 31: -#line 723 "pl/pl_b_gram.y" - { - PLpgSQL_var *newp = NULL; - PLpgSQL_type * var_type = (PLpgSQL_type *)u_sess->plsql_cxt.plpgsql_Datums[(yyvsp[-1].ival)]; - - newp = (PLpgSQL_var *)plpgsql_build_variable((yyvsp[-2].varname).name,(yyvsp[-2].varname).lineno, - var_type,true); - if (NULL == newp) - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), - errmsg("build variable failed"))); - pfree_ext((yyvsp[-2].varname).name); - } -#line 2545 "pl/pl_b_gram.cpp" - break; - - case 32: -#line 736 "pl/pl_b_gram.y" - { - if (pg_strcasecmp((yyvsp[-1].str), "autonomous_transaction") == 0) -#ifndef ENABLE_MULTIPLE_NODES - last_pragma = true; -#else - - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("autonomous transaction is not yet supported."))); -#endif - else - elog(ERROR, "invalid pragma"); - } -#line 2563 "pl/pl_b_gram.cpp" - break; - - case 33: -#line 752 "pl/pl_b_gram.y" - { - (yyval.list) = list_make1((yyvsp[0].recattr)); - } -#line 2571 "pl/pl_b_gram.cpp" - break; - - case 34: -#line 756 "pl/pl_b_gram.y" - { - (yyval.list) = lappend((yyvsp[-2].list), (yyvsp[0].recattr)); - } -#line 2579 "pl/pl_b_gram.cpp" - break; - - case 35: -#line 762 "pl/pl_b_gram.y" - { - PLpgSQL_rec_attr *attr = NULL; - - attr = (PLpgSQL_rec_attr*)palloc0(sizeof(PLpgSQL_rec_attr)); - - attr->attrname = (yyvsp[-3].varname).name; - attr->type = (yyvsp[-2].dtype); - - attr->notnull = (yyvsp[-1].boolean); - if ((yyvsp[0].expr) != NULL) - { - if (attr->type->ttype == PLPGSQL_TTYPE_SCALAR) - attr->defaultvalue = (yyvsp[0].expr); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("default value for row or record variable is not supported"), - parser_errposition((yylsp[-1])))); - } - - if ((yyvsp[-1].boolean) && (yyvsp[0].expr) == NULL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("variables declared as NOT NULL must have " - "a default value."))); - - (yyval.recattr) = attr; - } -#line 2612 "pl/pl_b_gram.cpp" - break; - - case 36: -#line 793 "pl/pl_b_gram.y" - { - (yyval.ival) = 0; - } -#line 2620 "pl/pl_b_gram.cpp" - break; - - case 37: -#line 797 "pl/pl_b_gram.y" - { - (yyval.ival) = CURSOR_OPT_NO_SCROLL; - } -#line 2628 "pl/pl_b_gram.cpp" - break; - - case 38: -#line 801 "pl/pl_b_gram.y" - { - (yyval.ival) = CURSOR_OPT_SCROLL; - } -#line 2636 "pl/pl_b_gram.cpp" - break; - - case 39: -#line 807 "pl/pl_b_gram.y" - { - int tok; - tok = yylex(); - plbsql_push_back_token(tok); - - /* check cursor syntax, cursor query only accept select query */ - { - (yyval.expr) = read_sql_stmt(""); - } - } -#line 2651 "pl/pl_b_gram.cpp" - break; - - case 40: -#line 820 "pl/pl_b_gram.y" - { - (yyval.datum) = NULL; - } -#line 2659 "pl/pl_b_gram.cpp" - break; - - case 41: -#line 824 "pl/pl_b_gram.y" - { - PLpgSQL_row *newp; - int i; - ListCell *l; - - newp = (PLpgSQL_row *)palloc0(sizeof(PLpgSQL_row)); - newp->dtype = PLPGSQL_DTYPE_ROW; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->rowtupdesc = NULL; - newp->nfields = list_length((yyvsp[-1].list)); - newp->fieldnames = (char **)palloc(newp->nfields * sizeof(char *)); - newp->varnos = (int *)palloc(newp->nfields * sizeof(int)); - - i = 0; - foreach (l, (yyvsp[-1].list)) - { - PLpgSQL_variable *arg = (PLpgSQL_variable *) lfirst(l); - newp->fieldnames[i] = arg->refname; - newp->varnos[i] = arg->dno; - i++; - } - list_free_ext((yyvsp[-1].list)); - - plpgsql_adddatum((PLpgSQL_datum *) newp); - (yyval.datum) = (PLpgSQL_datum *) newp; - } -#line 2690 "pl/pl_b_gram.cpp" - break; - - case 42: -#line 853 "pl/pl_b_gram.y" - { - (yyval.list) = list_make1((yyvsp[0].datum)); - } -#line 2698 "pl/pl_b_gram.cpp" - break; - - case 43: -#line 857 "pl/pl_b_gram.y" - { - (yyval.list) = lappend((yyvsp[-2].list), (yyvsp[0].datum)); - } -#line 2706 "pl/pl_b_gram.cpp" - break; - - case 44: -#line 863 "pl/pl_b_gram.y" - { - (yyval.datum) = (PLpgSQL_datum *) - plpgsql_build_variable((yyvsp[-2].varname).name, (yyvsp[-2].varname).lineno, - (yyvsp[0].dtype), true); - pfree_ext((yyvsp[-2].varname).name); - } -#line 2717 "pl/pl_b_gram.cpp" - break; - - case 50: -#line 879 "pl/pl_b_gram.y" - { - PLpgSQL_nsitem *nsi; - - nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, - (yyvsp[0].word).ident, NULL, NULL, - NULL); - if (nsi == NULL) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("variable \"%s\" does not exist", - (yyvsp[0].word).ident), - parser_errposition((yylsp[0])))); - (yyval.nsitem) = nsi; - } -#line 2736 "pl/pl_b_gram.cpp" - break; - - case 51: -#line 894 "pl/pl_b_gram.y" - { - PLpgSQL_nsitem *nsi; - - if (list_length((yyvsp[0].cword).idents) == 2) - nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, - strVal(linitial((yyvsp[0].cword).idents)), - strVal(lsecond((yyvsp[0].cword).idents)), - NULL, - NULL); - else if (list_length((yyvsp[0].cword).idents) == 3) - nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false, - strVal(linitial((yyvsp[0].cword).idents)), - strVal(lsecond((yyvsp[0].cword).idents)), - strVal(lthird((yyvsp[0].cword).idents)), - NULL); - else - nsi = NULL; - if (nsi == NULL) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("variable \"%s\" does not exist", - NameListToString((yyvsp[0].cword).idents)), - parser_errposition((yylsp[0])))); - (yyval.nsitem) = nsi; - } -#line 2766 "pl/pl_b_gram.cpp" - break; - - case 52: -#line 925 "pl/pl_b_gram.y" - { - (yyval.varname).name = (yyvsp[0].word).ident; - (yyval.varname).lineno = plpgsql_location_to_lineno((yylsp[0])); - /* - * Check to make sure name isn't already declared - * in the current block. - */ - if (plpgsql_ns_lookup(plpgsql_ns_top(), true, - (yyvsp[0].word).ident, NULL, NULL, - NULL) != NULL) - yyerror("duplicate declaration"); - } -#line 2783 "pl/pl_b_gram.cpp" - break; - - case 53: -#line 938 "pl/pl_b_gram.y" - { - (yyval.varname).name = pstrdup((yyvsp[0].keyword)); - (yyval.varname).lineno = plpgsql_location_to_lineno((yylsp[0])); - /* - * Check to make sure name isn't already declared - * in the current block. - */ - if (plpgsql_ns_lookup(plpgsql_ns_top(), true, - (yyvsp[0].keyword), NULL, NULL, - NULL) != NULL) - yyerror("duplicate declaration"); - } -#line 2800 "pl/pl_b_gram.cpp" - break; - - case 54: -#line 953 "pl/pl_b_gram.y" - { (yyval.boolean) = false; } -#line 2806 "pl/pl_b_gram.cpp" - break; - - case 55: -#line 955 "pl/pl_b_gram.y" - { (yyval.boolean) = true; } -#line 2812 "pl/pl_b_gram.cpp" - break; - - case 56: -#line 959 "pl/pl_b_gram.y" - { - /* - * If there's a lookahead token, read_datatype - * should consume it. - */ - (yyval.dtype) = read_datatype(yychar); - yyclearin; - } -#line 2825 "pl/pl_b_gram.cpp" - break; - - case 57: -#line 970 "pl/pl_b_gram.y" - { (yyval.oid) = InvalidOid; } -#line 2831 "pl/pl_b_gram.cpp" - break; - - case 58: -#line 972 "pl/pl_b_gram.y" - { - (yyval.oid) = get_collation_oid(list_make1(makeString((yyvsp[0].word).ident)), - false); - } -#line 2840 "pl/pl_b_gram.cpp" - break; - - case 59: -#line 977 "pl/pl_b_gram.y" - { - (yyval.oid) = get_collation_oid((yyvsp[0].cword).idents, false); - } -#line 2848 "pl/pl_b_gram.cpp" - break; - - case 60: -#line 983 "pl/pl_b_gram.y" - { (yyval.boolean) = false; } -#line 2854 "pl/pl_b_gram.cpp" - break; - - case 61: -#line 985 "pl/pl_b_gram.y" - { (yyval.boolean) = true; } -#line 2860 "pl/pl_b_gram.cpp" - break; - - case 62: -#line 989 "pl/pl_b_gram.y" - { (yyval.expr) = NULL; } -#line 2866 "pl/pl_b_gram.cpp" - break; - - case 63: -#line 991 "pl/pl_b_gram.y" - { - (yyval.expr) = read_sql_expression(';', ";"); - } -#line 2874 "pl/pl_b_gram.cpp" - break; - - case 64: -#line 997 "pl/pl_b_gram.y" - { - (yyval.expr) = NULL; - } -#line 2882 "pl/pl_b_gram.cpp" - break; - - case 65: -#line 1001 "pl/pl_b_gram.y" - { - int tok; - - (yyval.expr) = read_sql_expression2(',', ')', ")", &tok); - - plbsql_push_back_token(tok); - } -#line 2894 "pl/pl_b_gram.cpp" - break; - - case 70: -#line 1019 "pl/pl_b_gram.y" - { (yyval.list) = NIL; } -#line 2900 "pl/pl_b_gram.cpp" - break; - - case 71: -#line 1021 "pl/pl_b_gram.y" - { (yyval.list) = (yyvsp[0].list); } -#line 2906 "pl/pl_b_gram.cpp" - break; - - case 72: -#line 1025 "pl/pl_b_gram.y" - { - if ((yyvsp[0].stmt) == NULL) - (yyval.list) = (yyvsp[-1].list); - else - (yyval.list) = lappend((yyvsp[-1].list), (yyvsp[0].stmt)); - } -#line 2917 "pl/pl_b_gram.cpp" - break; - - case 73: -#line 1032 "pl/pl_b_gram.y" - { - if ((yyvsp[0].stmt) == NULL) - (yyval.list) = NIL; - else - (yyval.list) = list_make1((yyvsp[0].stmt)); - } -#line 2928 "pl/pl_b_gram.cpp" - break; - - case 74: -#line 1045 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[-1].stmt); } -#line 2934 "pl/pl_b_gram.cpp" - break; - - case 75: -#line 1047 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2940 "pl/pl_b_gram.cpp" - break; - - case 76: -#line 1049 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2946 "pl/pl_b_gram.cpp" - break; - - case 77: -#line 1051 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2952 "pl/pl_b_gram.cpp" - break; - - case 78: -#line 1053 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2958 "pl/pl_b_gram.cpp" - break; - - case 79: -#line 1055 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2964 "pl/pl_b_gram.cpp" - break; - - case 80: -#line 1057 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2970 "pl/pl_b_gram.cpp" - break; - - case 81: -#line 1059 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 2976 "pl/pl_b_gram.cpp" - break; - - case 82: -#line 1064 "pl/pl_b_gram.y" - { - (yyval.str) = NULL; - } -#line 2984 "pl/pl_b_gram.cpp" - break; - - case 83: -#line 1068 "pl/pl_b_gram.y" - { - plpgsql_ns_push((yyvsp[-1].str)); - (yyval.str) = (yyvsp[-1].str); - } -#line 2993 "pl/pl_b_gram.cpp" - break; - - case 84: -#line 1076 "pl/pl_b_gram.y" - { - /* - * If label is not null, we record it in current execution - * block so that the later or former GOTO can redirect the plpgsql execution steps - */ - record_stmt_label((yyvsp[-1].str), (yyvsp[0].stmt)); - (yyval.stmt) = (yyvsp[0].stmt); - } -#line 3006 "pl/pl_b_gram.cpp" - break; - - case 85: -#line 1086 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3012 "pl/pl_b_gram.cpp" - break; - - case 86: -#line 1088 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3018 "pl/pl_b_gram.cpp" - break; - - case 87: -#line 1090 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3024 "pl/pl_b_gram.cpp" - break; - - case 88: -#line 1092 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3030 "pl/pl_b_gram.cpp" - break; - - case 89: -#line 1094 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3036 "pl/pl_b_gram.cpp" - break; - - case 90: -#line 1096 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3042 "pl/pl_b_gram.cpp" - break; - - case 91: -#line 1098 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3048 "pl/pl_b_gram.cpp" - break; - - case 92: -#line 1100 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3054 "pl/pl_b_gram.cpp" - break; - - case 93: -#line 1102 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3060 "pl/pl_b_gram.cpp" - break; - - case 94: -#line 1104 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3066 "pl/pl_b_gram.cpp" - break; - - case 95: -#line 1106 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3072 "pl/pl_b_gram.cpp" - break; - - case 96: -#line 1108 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3078 "pl/pl_b_gram.cpp" - break; - - case 97: -#line 1110 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3084 "pl/pl_b_gram.cpp" - break; - - case 98: -#line 1112 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3090 "pl/pl_b_gram.cpp" - break; - - case 99: -#line 1114 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3096 "pl/pl_b_gram.cpp" - break; - - case 100: -#line 1116 "pl/pl_b_gram.y" - { (yyval.stmt) = (yyvsp[0].stmt); } -#line 3102 "pl/pl_b_gram.cpp" - break; - - case 101: -#line 1120 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_perform *newp; - - newp = (PLpgSQL_stmt_perform *)palloc0(sizeof(PLpgSQL_stmt_perform)); - newp->cmd_type = PLPGSQL_STMT_PERFORM; - newp->lineno = plpgsql_location_to_lineno((yylsp[-1])); - newp->expr = (yyvsp[0].expr); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 3117 "pl/pl_b_gram.cpp" - break; - - case 102: -#line 1133 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_assign *newp; - - newp = (PLpgSQL_stmt_assign *)palloc0(sizeof(PLpgSQL_stmt_assign)); - newp->cmd_type = PLPGSQL_STMT_ASSIGN; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->varno = (yyvsp[-2].ival); - newp->expr = (yyvsp[0].expr); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 3133 "pl/pl_b_gram.cpp" - break; - - case 103: -#line 1147 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_getdiag *newp; - ListCell *lc; - - newp = (PLpgSQL_stmt_getdiag *)palloc0(sizeof(PLpgSQL_stmt_getdiag)); - newp->cmd_type = PLPGSQL_STMT_GETDIAG; - newp->lineno = plpgsql_location_to_lineno((yylsp[-4])); - newp->is_stacked = (yyvsp[-3].boolean); - newp->diag_items = (yyvsp[-1].list); - - /* - * Check information items are valid for area option. - */ - foreach(lc, newp->diag_items) - { - PLpgSQL_diag_item *ditem = (PLpgSQL_diag_item *) lfirst(lc); - - switch (ditem->kind) - { - /* these fields are disallowed in stacked case */ - case PLPGSQL_GETDIAG_ROW_COUNT: - case PLPGSQL_GETDIAG_RESULT_OID: - if (newp->is_stacked) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("diagnostics item %s is not allowed in GET STACKED DIAGNOSTICS", - plpgsql_getdiag_kindname(ditem->kind)), - parser_errposition((yylsp[-4])))); - break; - /* these fields are disallowed in current case */ - case PLPGSQL_GETDIAG_ERROR_CONTEXT: - case PLPGSQL_GETDIAG_ERROR_DETAIL: - case PLPGSQL_GETDIAG_ERROR_HINT: - case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: - case PLPGSQL_GETDIAG_MESSAGE_TEXT: - if (!newp->is_stacked) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("diagnostics item %s is not allowed in GET CURRENT DIAGNOSTICS", - plpgsql_getdiag_kindname(ditem->kind)), - parser_errposition((yylsp[-4])))); - break; - default: - elog(ERROR, "unrecognized diagnostic item kind: %d", - ditem->kind); - break; - } - } - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 3189 "pl/pl_b_gram.cpp" - break; - - case 104: -#line 1201 "pl/pl_b_gram.y" - { - (yyval.boolean) = false; - } -#line 3197 "pl/pl_b_gram.cpp" - break; - - case 105: -#line 1205 "pl/pl_b_gram.y" - { - (yyval.boolean) = false; - } -#line 3205 "pl/pl_b_gram.cpp" - break; - - case 106: -#line 1209 "pl/pl_b_gram.y" - { - (yyval.boolean) = true; - } -#line 3213 "pl/pl_b_gram.cpp" - break; - - case 107: -#line 1215 "pl/pl_b_gram.y" - { - (yyval.list) = lappend((yyvsp[-2].list), (yyvsp[0].diagitem)); - } -#line 3221 "pl/pl_b_gram.cpp" - break; - - case 108: -#line 1219 "pl/pl_b_gram.y" - { - (yyval.list) = list_make1((yyvsp[0].diagitem)); - } -#line 3229 "pl/pl_b_gram.cpp" - break; - - case 109: -#line 1225 "pl/pl_b_gram.y" - { - PLpgSQL_diag_item *newp; - - newp = (PLpgSQL_diag_item *)palloc(sizeof(PLpgSQL_diag_item)); - newp->target = (yyvsp[-2].ival); - newp->kind = (yyvsp[0].ival); - - (yyval.diagitem) = newp; - } -#line 3243 "pl/pl_b_gram.cpp" - break; - - case 110: -#line 1237 "pl/pl_b_gram.y" - { - int tok = yylex(); - - if (tok_is_keyword(tok, &yylval, - K_ROW_COUNT, "row_count")) - (yyval.ival) = PLPGSQL_GETDIAG_ROW_COUNT; - else if (tok_is_keyword(tok, &yylval, - K_RESULT_OID, "result_oid")) - (yyval.ival) = PLPGSQL_GETDIAG_RESULT_OID; - else if (tok_is_keyword(tok, &yylval, - K_PG_EXCEPTION_DETAIL, "pg_exception_detail")) - (yyval.ival) = PLPGSQL_GETDIAG_ERROR_DETAIL; - else if (tok_is_keyword(tok, &yylval, - K_PG_EXCEPTION_HINT, "pg_exception_hint")) - (yyval.ival) = PLPGSQL_GETDIAG_ERROR_HINT; - else if (tok_is_keyword(tok, &yylval, - K_PG_EXCEPTION_CONTEXT, "pg_exception_context")) - (yyval.ival) = PLPGSQL_GETDIAG_ERROR_CONTEXT; - else if (tok_is_keyword(tok, &yylval, - K_MESSAGE_TEXT, "message_text")) - (yyval.ival) = PLPGSQL_GETDIAG_MESSAGE_TEXT; - else if (tok_is_keyword(tok, &yylval, - K_RETURNED_SQLSTATE, "returned_sqlstate")) - (yyval.ival) = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; - else - yyerror("unrecognized GET DIAGNOSTICS item"); - } -#line 3275 "pl/pl_b_gram.cpp" - break; - - case 111: -#line 1267 "pl/pl_b_gram.y" - { - check_assignable((yyvsp[0].wdatum).datum, (yylsp[0])); - if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_ROW || - (yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_REC) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&((yyvsp[0].wdatum)))), - parser_errposition((yylsp[0])))); - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3291 "pl/pl_b_gram.cpp" - break; - - case 112: -#line 1279 "pl/pl_b_gram.y" - { - /* just to give a better message than "syntax error" */ - word_is_not_variable(&((yyvsp[0].word)), (yylsp[0])); - } -#line 3300 "pl/pl_b_gram.cpp" - break; - - case 113: -#line 1284 "pl/pl_b_gram.y" - { - /* just to give a better message than "syntax error" */ - cword_is_not_variable(&((yyvsp[0].cword)), (yylsp[0])); - } -#line 3309 "pl/pl_b_gram.cpp" - break; - - case 114: -#line 1291 "pl/pl_b_gram.y" - { - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3317 "pl/pl_b_gram.cpp" - break; - - case 115: -#line 1297 "pl/pl_b_gram.y" - { - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3325 "pl/pl_b_gram.cpp" - break; - - case 116: -#line 1303 "pl/pl_b_gram.y" - { - check_assignable((yyvsp[0].wdatum).datum, (yylsp[0])); - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3334 "pl/pl_b_gram.cpp" - break; - - case 117: -#line 1308 "pl/pl_b_gram.y" - { - check_assignable((yyvsp[0].wdatum).datum, (yylsp[0])); - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3343 "pl/pl_b_gram.cpp" - break; - - case 118: -#line 1313 "pl/pl_b_gram.y" - { - check_assignable((yyvsp[0].wdatum).datum, (yylsp[0])); - (yyval.ival) = (yyvsp[0].wdatum).datum->dno; - } -#line 3352 "pl/pl_b_gram.cpp" - break; - - case 119: -#line 1318 "pl/pl_b_gram.y" - { - PLpgSQL_arrayelem *newp; - - newp = (PLpgSQL_arrayelem *)palloc0(sizeof(PLpgSQL_arrayelem)); - newp->dtype = PLPGSQL_DTYPE_ARRAYELEM; - newp->subscript = (yyvsp[0].expr); - newp->arrayparentno = (yyvsp[-2].ival); - /* initialize cached type data to "not valid" */ - newp->parenttypoid = InvalidOid; - - plpgsql_adddatum((PLpgSQL_datum *) newp); - - (yyval.ival) = newp->dno; - } -#line 3371 "pl/pl_b_gram.cpp" - break; - - case 120: -#line 1334 "pl/pl_b_gram.y" - { - PLpgSQL_arrayelem *newp; - newp = (PLpgSQL_arrayelem *)palloc0(sizeof(PLpgSQL_arrayelem)); - newp->dtype = PLPGSQL_DTYPE_ARRAYELEM; - newp->subscript = (yyvsp[0].expr); - newp->arrayparentno = (yyvsp[-2].ival); - /* initialize cached type data to "not valid" */ - newp->parenttypoid = InvalidOid; - plpgsql_adddatum((PLpgSQL_datum *)newp); - (yyval.ival) = newp->dno; - } -#line 3387 "pl/pl_b_gram.cpp" - break; - - case 121: -#line 1348 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_goto *newp; - - newp = (PLpgSQL_stmt_goto *)palloc0(sizeof(PLpgSQL_stmt_goto)); - newp->cmd_type = PLPGSQL_STMT_GOTO; - newp->lineno = plpgsql_location_to_lineno((yylsp[-1])); - newp->label = (yyvsp[0].str); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 3402 "pl/pl_b_gram.cpp" - break; - - case 122: -#line 1360 "pl/pl_b_gram.y" - { - (yyval.str) = (yyvsp[-1].word).ident; - } -#line 3410 "pl/pl_b_gram.cpp" - break; - - case 123: -#line 1366 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_if *newp; - - newp = (PLpgSQL_stmt_if *)palloc0(sizeof(PLpgSQL_stmt_if)); - newp->cmd_type = PLPGSQL_STMT_IF; - newp->lineno = plpgsql_location_to_lineno((yylsp[-7])); - newp->cond = (yyvsp[-6].expr); - newp->then_body = (yyvsp[-5].list); - newp->elsif_list = (yyvsp[-4].list); - newp->else_body = (yyvsp[-3].list); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 3428 "pl/pl_b_gram.cpp" - break; - - case 124: -#line 1382 "pl/pl_b_gram.y" - { - (yyval.list) = NIL; - } -#line 3436 "pl/pl_b_gram.cpp" - break; - - case 125: -#line 1386 "pl/pl_b_gram.y" - { - PLpgSQL_if_elsif *newp; - - newp = (PLpgSQL_if_elsif *)palloc0(sizeof(PLpgSQL_if_elsif)); - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->cond = (yyvsp[-1].expr); - newp->stmts = (yyvsp[0].list); - - (yyval.list) = lappend((yyvsp[-3].list), newp); - } -#line 3451 "pl/pl_b_gram.cpp" - break; - - case 126: -#line 1399 "pl/pl_b_gram.y" - { - (yyval.list) = NIL; - } -#line 3459 "pl/pl_b_gram.cpp" - break; - - case 127: -#line 1403 "pl/pl_b_gram.y" - { - (yyval.list) = (yyvsp[0].list); - } -#line 3467 "pl/pl_b_gram.cpp" - break; - - case 128: -#line 1409 "pl/pl_b_gram.y" - { - (yyval.stmt) = make_case((yylsp[-6]), (yyvsp[-5].expr), (yyvsp[-4].list), (yyvsp[-3].list)); - } -#line 3475 "pl/pl_b_gram.cpp" - break; - - case 129: -#line 1415 "pl/pl_b_gram.y" - { - PLpgSQL_expr *expr = NULL; - int tok = yylex(); - - if (tok != K_WHEN) - { - plbsql_push_back_token(tok); - expr = read_sql_expression(K_WHEN, "WHEN"); - } - plbsql_push_back_token(K_WHEN); - (yyval.expr) = expr; - } -#line 3492 "pl/pl_b_gram.cpp" - break; - - case 130: -#line 1430 "pl/pl_b_gram.y" - { - (yyval.list) = lappend((yyvsp[-1].list), (yyvsp[0].casewhen)); - } -#line 3500 "pl/pl_b_gram.cpp" - break; - - case 131: -#line 1434 "pl/pl_b_gram.y" - { - (yyval.list) = list_make1((yyvsp[0].casewhen)); - } -#line 3508 "pl/pl_b_gram.cpp" - break; - - case 132: -#line 1440 "pl/pl_b_gram.y" - { - PLpgSQL_case_when *newp = (PLpgSQL_case_when *)palloc(sizeof(PLpgSQL_case_when)); - - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->expr = (yyvsp[-1].expr); - newp->stmts = (yyvsp[0].list); - (yyval.casewhen) = newp; - } -#line 3521 "pl/pl_b_gram.cpp" - break; - - case 133: -#line 1451 "pl/pl_b_gram.y" - { - (yyval.list) = NIL; - } -#line 3529 "pl/pl_b_gram.cpp" - break; - - case 134: -#line 1455 "pl/pl_b_gram.y" - { - /* - * proc_sect could return an empty list, but we - * must distinguish that from not having ELSE at all. - * Simplest fix is to return a list with one NULL - * pointer, which make_case() must take care of. - */ - if ((yyvsp[0].list) != NIL) - (yyval.list) = (yyvsp[0].list); - else - (yyval.list) = list_make1(NULL); - } -#line 3546 "pl/pl_b_gram.cpp" - break; - - case 135: -#line 1470 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_loop *newp; - - newp = (PLpgSQL_stmt_loop *)palloc0(sizeof(PLpgSQL_stmt_loop)); - newp->cmd_type = PLPGSQL_STMT_LOOP; - newp->lineno = plpgsql_location_to_lineno((yylsp[-1])); - newp->label = (yyvsp[-2].str); - newp->body = (yyvsp[0].loop_body).stmts; - - check_labels((yyvsp[-2].str), (yyvsp[0].loop_body).end_label, (yyvsp[0].loop_body).end_label_location); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-2].str), (PLpgSQL_stmt *)newp); - } -#line 3568 "pl/pl_b_gram.cpp" - break; - - case 136: -#line 1490 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_while *newp; - - newp = (PLpgSQL_stmt_while *)palloc0(sizeof(PLpgSQL_stmt_while)); - newp->cmd_type = PLPGSQL_STMT_WHILE; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->label = (yyvsp[-3].str); - newp->cond = (yyvsp[-1].expr); - newp->body = (yyvsp[0].loop_body).stmts; - - check_labels((yyvsp[-3].str), (yyvsp[0].loop_body).end_label, (yyvsp[0].loop_body).end_label_location); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-3].str), (PLpgSQL_stmt *)newp); - } -#line 3591 "pl/pl_b_gram.cpp" - break; - - case 137: -#line 1511 "pl/pl_b_gram.y" - { - /* This runs after we've scanned the loop body */ - if ((yyvsp[-1].stmt)->cmd_type == PLPGSQL_STMT_FORI) - { - PLpgSQL_stmt_fori *newp; - - newp = (PLpgSQL_stmt_fori *) (yyvsp[-1].stmt); - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->label = (yyvsp[-3].str); - newp->body = (yyvsp[0].loop_body).stmts; - (yyval.stmt) = (PLpgSQL_stmt *) newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-3].str), (PLpgSQL_stmt *)newp); - } - else - { - PLpgSQL_stmt_forq *newp; - - AssertEreport((yyvsp[-1].stmt)->cmd_type == PLPGSQL_STMT_FORS || - (yyvsp[-1].stmt)->cmd_type == PLPGSQL_STMT_FORC || - (yyvsp[-1].stmt)->cmd_type == PLPGSQL_STMT_DYNFORS, - MOD_PLSQL, - "unexpected node type."); - /* forq is the common supertype of all three */ - newp = (PLpgSQL_stmt_forq *) (yyvsp[-1].stmt); - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->label = (yyvsp[-3].str); - newp->body = (yyvsp[0].loop_body).stmts; - (yyval.stmt) = (PLpgSQL_stmt *) newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-3].str), (PLpgSQL_stmt *)newp); - } - - check_labels((yyvsp[-3].str), (yyvsp[0].loop_body).end_label, (yyvsp[0].loop_body).end_label_location); - /* close namespace started in opt_block_label */ - plpgsql_ns_pop(); - } -#line 3635 "pl/pl_b_gram.cpp" - break; - - case 138: -#line 1551 "pl/pl_b_gram.y" - { - /* This runs after we've scanned the loop body */ - /* A db FORALL support 3 types like below. We implemented the first one. - * FORALL index_name IN lower_bound .. upper_bound - * FORALL index_name IN INDICES OF collection between lower_bound and upper_bound - * FORALL index_name IN VALUES OF index_collection - * forall_body can only have one statement. - */ - if ((yyvsp[-1].stmt)->cmd_type == PLPGSQL_STMT_FORI) - { - PLpgSQL_stmt_fori *newm; - - newm = (PLpgSQL_stmt_fori *) (yyvsp[-1].stmt); - newm->label = NULL; - newm->body = (yyvsp[0].list); - (yyval.stmt) = (PLpgSQL_stmt *) newm; - } - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("please use \'FORALL index_name IN lower_bound .. upper_bound\'"))); - - /* close namespace started in opt_block_label */ - plpgsql_ns_pop(); - } -#line 3665 "pl/pl_b_gram.cpp" - break; - - case 139: -#line 1579 "pl/pl_b_gram.y" - { - int tok = yylex(); - int tokloc = yylloc; - - if (tok == K_EXECUTE) - { - /* EXECUTE means it's a dynamic FOR loop */ - PLpgSQL_stmt_dynfors *newp; - PLpgSQL_expr *expr; - int term; - - expr = read_sql_expression2(K_LOOP, K_USING, - "LOOP or USING", - &term); - - newp = (PLpgSQL_stmt_dynfors *)palloc0(sizeof(PLpgSQL_stmt_dynfors)); - newp->cmd_type = PLPGSQL_STMT_DYNFORS; - if ((yyvsp[-1].forvariable).rec) - { - newp->rec = (yyvsp[-1].forvariable).rec; - check_assignable((PLpgSQL_datum *) newp->rec, (yylsp[-1])); - } - else if ((yyvsp[-1].forvariable).row) - { - newp->row = (yyvsp[-1].forvariable).row; - check_assignable((PLpgSQL_datum *) newp->row, (yylsp[-1])); - } - else if ((yyvsp[-1].forvariable).scalar) - { - /* convert single scalar to list */ - newp->row = make_scalar_list1((yyvsp[-1].forvariable).name, (yyvsp[-1].forvariable).scalar, - (yyvsp[-1].forvariable).lineno, (yylsp[-1])); - /* no need for check_assignable */ - } - else - { - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"), - parser_errposition((yylsp[-1])))); - } - newp->query = expr; - - if (term == K_USING) - { - do - { - expr = read_sql_expression2(',', K_LOOP, - ", or LOOP", - &term); - newp->params = lappend(newp->params, expr); - } while (term == ','); - } - - (yyval.stmt) = (PLpgSQL_stmt *) newp; - } - else if (tok == T_DATUM && - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR && - ((PLpgSQL_var *) yylval.wdatum.datum)->datatype->typoid == REFCURSOROID) - { - /* It's FOR var IN cursor */ - PLpgSQL_stmt_forc *newp; - PLpgSQL_var *cursor = (PLpgSQL_var *) yylval.wdatum.datum; - - newp = (PLpgSQL_stmt_forc *) palloc0(sizeof(PLpgSQL_stmt_forc)); - newp->cmd_type = PLPGSQL_STMT_FORC; - newp->curvar = cursor->dno; - - /* Should have had a single variable name */ - if ((yyvsp[-1].forvariable).scalar && (yyvsp[-1].forvariable).row) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cursor FOR loop must have only one target variable"), - parser_errposition((yylsp[-1])))); - - /* can't use an unbound cursor this way */ - if (cursor->cursor_explicit_expr == NULL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cursor FOR loop must use a bound cursor variable"), - parser_errposition(tokloc))); - - /* collect cursor's parameters if any */ - newp->argquery = read_cursor_args(cursor, - K_LOOP, - "LOOP"); - - /* create loop's private RECORD variable */ - newp->rec = plpgsql_build_record((yyvsp[-1].forvariable).name, - (yyvsp[-1].forvariable).lineno, - true); - - (yyval.stmt) = (PLpgSQL_stmt *) newp; - } - else - { - PLpgSQL_expr *expr1; - int expr1loc; - bool reverse = false; - - /* - * We have to distinguish between two - * alternatives: FOR var IN a .. b and FOR - * var IN query. Unfortunately this is - * tricky, since the query in the second - * form needn't start with a SELECT - * keyword. We use the ugly hack of - * looking for two periods after the first - * token. We also check for the REVERSE - * keyword, which means it must be an - * integer loop. - */ - if (tok_is_keyword(tok, &yylval, - K_REVERSE, "reverse")) - reverse = true; - else - plbsql_push_back_token(tok); - - /* - * Read tokens until we see either a ".." - * or a LOOP. The text we read may not - * necessarily be a well-formed SQL - * statement, so we need to invoke - * read_sql_construct directly. - */ - expr1 = read_sql_construct(DOT_DOT, - K_LOOP, - 0, - "LOOP", - "SELECT ", - true, - false, - true, - &expr1loc, - &tok); - - if (tok == DOT_DOT) - { - /* Saw "..", so it must be an integer loop */ - PLpgSQL_expr *expr2; - PLpgSQL_expr *expr_by; - PLpgSQL_var *fvar; - PLpgSQL_stmt_fori *newp; - - /* Check first expression is well-formed */ - check_sql_expr(expr1->query, expr1loc, 7); - - /* Read and check the second one */ - expr2 = read_sql_expression2(K_LOOP, K_BY, - "LOOP", - &tok); - - /* Get the BY clause if any */ - if (tok == K_BY) - expr_by = read_sql_expression(K_LOOP, - "LOOP"); - else - expr_by = NULL; - - /* Should have had a single variable name */ - if ((yyvsp[-1].forvariable).scalar && (yyvsp[-1].forvariable).row) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("integer FOR loop must have only one target variable"), - parser_errposition((yylsp[-1])))); - - /* create loop's private variable */ - fvar = (PLpgSQL_var *) - plpgsql_build_variable((yyvsp[-1].forvariable).name, - (yyvsp[-1].forvariable).lineno, - plpgsql_build_datatype(INT4OID, - -1, - InvalidOid), - true); - - newp = (PLpgSQL_stmt_fori *)palloc0(sizeof(PLpgSQL_stmt_fori)); - newp->cmd_type = PLPGSQL_STMT_FORI; - newp->var = fvar; - newp->reverse = reverse; - newp->lower = expr1; - newp->upper = expr2; - newp->step = expr_by; - - (yyval.stmt) = (PLpgSQL_stmt *) newp; - } - else - { - /* - * No "..", so it must be a query loop. We've - * prefixed an extra SELECT to the query text, - * so we need to remove that before performing - * syntax checking. - */ - char *tmp_query; - PLpgSQL_stmt_fors *newp; - - if (reverse) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cannot specify REVERSE in query FOR loop"), - parser_errposition(tokloc))); - - AssertEreport(strncmp(expr1->query, "SELECT ", 7) == 0, - MOD_PLSQL, - "It should be SELECT"); - tmp_query = pstrdup(expr1->query + 7); - pfree_ext(expr1->query); - expr1->query = tmp_query; - - check_sql_expr(expr1->query, expr1loc, 0); - - newp = (PLpgSQL_stmt_fors *)palloc0(sizeof(PLpgSQL_stmt_fors)); - newp->cmd_type = PLPGSQL_STMT_FORS; - if ((yyvsp[-1].forvariable).rec) - { - newp->rec = (yyvsp[-1].forvariable).rec; - check_assignable((PLpgSQL_datum *) newp->rec, (yylsp[-1])); - } - else if ((yyvsp[-1].forvariable).row) - { - newp->row = (yyvsp[-1].forvariable).row; - check_assignable((PLpgSQL_datum *) newp->row, (yylsp[-1])); - } - else if ((yyvsp[-1].forvariable).scalar) - { - /* convert single scalar to list */ - newp->row = make_scalar_list1((yyvsp[-1].forvariable).name, (yyvsp[-1].forvariable).scalar, - (yyvsp[-1].forvariable).lineno, (yylsp[-1])); - /* no need for check_assignable */ - } - else - { - PLpgSQL_type dtype; - dtype.ttype = PLPGSQL_TTYPE_REC; - newp->rec = (PLpgSQL_rec *) - plpgsql_build_variable((yyvsp[-1].forvariable).name,(yyvsp[-1].forvariable).lineno, &dtype, true); - check_assignable((PLpgSQL_datum *) newp->rec, (yylsp[-1])); - } - - newp->query = expr1; - (yyval.stmt) = (PLpgSQL_stmt *) newp; - } - } - } -#line 3914 "pl/pl_b_gram.cpp" - break; - - case 140: -#line 1825 "pl/pl_b_gram.y" - { - int tok; - int expr1loc; - PLpgSQL_expr *expr1; - - /* - * Read tokens until we see either a ".." - * or a LOOP. The text we read may not - * necessarily be a well-formed SQL - * statement, so we need to invoke - * read_sql_construct directly. - */ - expr1 = read_sql_construct(DOT_DOT, - 0, - 0, - "..", - "SELECT ", - true, - false, - true, - &expr1loc, - &tok); - - if (DOT_DOT == tok) - { - /* Saw "..", so it must be an integer loop */ - PLpgSQL_expr *expr2 = NULL; - PLpgSQL_var *fvar = NULL; - PLpgSQL_stmt_fori *newm = NULL; - - /* Check first expression is well-formed */ - check_sql_expr(expr1->query, expr1loc, 7); - - /* Read and check the second one */ - expr2 = read_sql_construct5(K_MERGE, - K_INSERT, - K_SELECT, - K_UPDATE, - K_DELETE, - "DML", - "SELECT ", - true, - false, - true, - NULL, - &tok); - - plbsql_push_back_token(tok); - - if (';' == tok) - ereport(ERROR, - (errcode(ERRCODE_FORALL_NEED_DML), - errmsg("FORALL must follow DML statement."))); - - /* should follow DML statement */ - if (tok != K_INSERT && tok != K_UPDATE && tok != K_DELETE && tok != K_SELECT && tok != K_MERGE) - ereport(ERROR, - (errcode(ERRCODE_FORALL_NEED_DML), - errmsg("FORALL must follow DML statement."))); - - /* Should have had a single variable name */ - if ((yyvsp[-1].forvariable).scalar && (yyvsp[-1].forvariable).row) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("integer FORALL must have just one target variable"))); - - /* create loop's private variable */ - fvar = (PLpgSQL_var *) - plpgsql_build_variable((yyvsp[-1].forvariable).name, - (yyvsp[-1].forvariable).lineno, - plpgsql_build_datatype(INT4OID, -1, InvalidOid), - true); - - newm = (PLpgSQL_stmt_fori *)palloc0(sizeof(PLpgSQL_stmt_fori)); - newm->cmd_type = PLPGSQL_STMT_FORI; - newm->var = fvar; - newm->reverse = false; - newm->lower = expr1; - newm->upper = expr2; - newm->step = NULL; - - (yyval.stmt) = (PLpgSQL_stmt *) newm; - } - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("please use \'FORALL index_name IN lower_bound .. upper_bound\'"))); - } -#line 4007 "pl/pl_b_gram.cpp" - break; - - case 141: -#line 1933 "pl/pl_b_gram.y" - { - (yyval.forvariable).name = NameOfDatum(&((yyvsp[0].wdatum))); - (yyval.forvariable).lineno = plpgsql_location_to_lineno((yylsp[0])); - if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_ROW) - { - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = (PLpgSQL_row *) (yyvsp[0].wdatum).datum; - } - else if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_RECORD) - { - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = (PLpgSQL_row *) (yyvsp[0].wdatum).datum; - } - else if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_REC) - { - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = (PLpgSQL_rec *) (yyvsp[0].wdatum).datum; - (yyval.forvariable).row = NULL; - } - else - { - int tok; - - (yyval.forvariable).scalar = (yyvsp[0].wdatum).datum; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = NULL; - /* check for comma-separated list */ - tok = yylex(); - plbsql_push_back_token(tok); - if (tok == ',') - (yyval.forvariable).row = read_into_scalar_list((yyval.forvariable).name, - (yyval.forvariable).scalar, - (yylsp[0])); - } - } -#line 4049 "pl/pl_b_gram.cpp" - break; - - case 142: -#line 1971 "pl/pl_b_gram.y" - { - (yyval.forvariable).name = NameOfDatum(&((yyvsp[0].wdatum))); - (yyval.forvariable).lineno = plpgsql_location_to_lineno((yylsp[0])); - if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_ROW) - { - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = (PLpgSQL_row *) (yyvsp[0].wdatum).datum; - } - else if ((yyvsp[0].wdatum).datum->dtype == PLPGSQL_DTYPE_REC) - { - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = (PLpgSQL_rec *) (yyvsp[0].wdatum).datum; - (yyval.forvariable).row = NULL; - } - else - { - int tok; - - (yyval.forvariable).scalar = (yyvsp[0].wdatum).datum; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = NULL; - /* check for comma-separated list */ - tok = yylex(); - plbsql_push_back_token(tok); - if (tok == ',') - (yyval.forvariable).row = read_into_scalar_list((yyval.forvariable).name, - (yyval.forvariable).scalar, - (yylsp[0])); - } - } -#line 4085 "pl/pl_b_gram.cpp" - break; - - case 143: -#line 2003 "pl/pl_b_gram.y" - { - int tok; - - (yyval.forvariable).name = (yyvsp[0].word).ident; - (yyval.forvariable).lineno = plpgsql_location_to_lineno((yylsp[0])); - (yyval.forvariable).scalar = NULL; - (yyval.forvariable).rec = NULL; - (yyval.forvariable).row = NULL; - /* check for comma-separated list */ - tok = yylex(); - plbsql_push_back_token(tok); - if (tok == ',') - word_is_not_variable(&((yyvsp[0].word)), (yylsp[0])); - } -#line 4104 "pl/pl_b_gram.cpp" - break; - - case 144: -#line 2018 "pl/pl_b_gram.y" - { - /* just to give a better message than "syntax error" */ - cword_is_not_variable(&((yyvsp[0].cword)), (yylsp[0])); - } -#line 4113 "pl/pl_b_gram.cpp" - break; - - case 145: -#line 2025 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_foreach_a *newp; - - newp = (PLpgSQL_stmt_foreach_a *)palloc0(sizeof(PLpgSQL_stmt_foreach_a)); - newp->cmd_type = PLPGSQL_STMT_FOREACH_A; - newp->lineno = plpgsql_location_to_lineno((yylsp[-6])); - newp->label = (yyvsp[-7].str); - newp->slice = (yyvsp[-4].ival); - newp->expr = (yyvsp[-1].expr); - newp->body = (yyvsp[0].loop_body).stmts; - - if ((yyvsp[-5].forvariable).rec) - { - newp->varno = (yyvsp[-5].forvariable).rec->dno; - check_assignable((PLpgSQL_datum *) (yyvsp[-5].forvariable).rec, (yylsp[-5])); - } - else if ((yyvsp[-5].forvariable).row) - { - newp->varno = (yyvsp[-5].forvariable).row->dno; - check_assignable((PLpgSQL_datum *) (yyvsp[-5].forvariable).row, (yylsp[-5])); - } - else if ((yyvsp[-5].forvariable).scalar) - { - newp->varno = (yyvsp[-5].forvariable).scalar->dno; - check_assignable((yyvsp[-5].forvariable).scalar, (yylsp[-5])); - } - else - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("loop variable of FOREACH must be a known variable or list of variables"), - parser_errposition((yylsp[-5])))); - } - - check_labels((yyvsp[-7].str), (yyvsp[0].loop_body).end_label, (yyvsp[0].loop_body).end_label_location); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *) newp; - - /* register the stmt if it is labeled */ - record_stmt_label((yyvsp[-7].str), (PLpgSQL_stmt *)newp); - } -#line 4160 "pl/pl_b_gram.cpp" - break; - - case 146: -#line 2070 "pl/pl_b_gram.y" - { - (yyval.ival) = 0; - } -#line 4168 "pl/pl_b_gram.cpp" - break; - - case 147: -#line 2074 "pl/pl_b_gram.y" - { - (yyval.ival) = (yyvsp[0].ival); - } -#line 4176 "pl/pl_b_gram.cpp" - break; - - case 148: -#line 2079 "pl/pl_b_gram.y" - { (yyval.list) = list_make1((yyvsp[0].stmt)); } -#line 4182 "pl/pl_b_gram.cpp" - break; - - case 149: -#line 2081 "pl/pl_b_gram.y" - { (yyval.list) = list_make1((yyvsp[0].stmt)); } -#line 4188 "pl/pl_b_gram.cpp" - break; - - case 150: -#line 2085 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_exit *newp; - - newp = (PLpgSQL_stmt_exit *)palloc0(sizeof(PLpgSQL_stmt_exit)); - newp->cmd_type = PLPGSQL_STMT_EXIT; - newp->is_exit = (yyvsp[-2].boolean); - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->label = (yyvsp[-1].str); - newp->cond = (yyvsp[0].expr); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4205 "pl/pl_b_gram.cpp" - break; - - case 151: -#line 2100 "pl/pl_b_gram.y" - { - (yyval.boolean) = true; - } -#line 4213 "pl/pl_b_gram.cpp" - break; - - case 152: -#line 2104 "pl/pl_b_gram.y" - { - (yyval.boolean) = false; - } -#line 4221 "pl/pl_b_gram.cpp" - break; - - case 153: -#line 2110 "pl/pl_b_gram.y" - { - int tok; - - tok = yylex(); - if (tok == 0) - yyerror("unexpected end of function definition"); - - if (tok_is_keyword(tok, &yylval, - K_NEXT, "next")) - { - (yyval.stmt) = make_return_next_stmt((yylsp[0])); - } - else if (tok_is_keyword(tok, &yylval, - K_QUERY, "query")) - { - (yyval.stmt) = make_return_query_stmt((yylsp[0])); - } - else - { - plbsql_push_back_token(tok); - (yyval.stmt) = make_return_stmt((yylsp[0])); - } - } -#line 4249 "pl/pl_b_gram.cpp" - break; - - case 154: -#line 2136 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_raise *newp; - int tok; - - PLpgSQL_row * row = NULL; - char message[32] = ""; - StringInfoData ds; - initStringInfo(&ds); - - newp = (PLpgSQL_stmt_raise *)palloc(sizeof(PLpgSQL_stmt_raise)); - - newp->cmd_type = PLPGSQL_STMT_RAISE; - newp->lineno = plpgsql_location_to_lineno((yylsp[0])); - newp->elog_level = ERROR; /* default */ - newp->condname = NULL; - newp->message = NULL; - newp->params = NIL; - newp->options = NIL; - - tok = yylex(); - if (tok == 0) - yyerror("unexpected end of function definition"); - - /* - * We could have just RAISE, meaning to re-throw - * the current error. - */ - if (tok != ';') - { - if (T_DATUM == tok && PLPGSQL_DTYPE_ROW == yylval.wdatum.datum->dtype) - { - PLpgSQL_expr *expr = NULL; - - sprintf(message, "line:%d ", plpgsql_location_to_lineno((yylsp[0]))); - appendStringInfoString(&ds, message); - appendStringInfoString(&ds,"%"); - - row = (PLpgSQL_row *)yylval.wdatum.datum; - - /* condname is system embedded error name, so it is still null in this case. */ - newp->condname = pstrdup(unpack_sql_state(row->customErrorCode)); - newp->message = pstrdup(ds.data); - plbsql_push_back_token(tok); - expr = read_sql_construct(';', 0, 0, ";", - "SELECT ", true, true, true, NULL, &tok); - - if (tok != ';') - yyerror("syntax error"); - - newp->params = lappend(newp->params, expr); - } - else - { - /* - * First is an optional elog severity level. - */ - if (tok_is_keyword(tok, &yylval, - K_EXCEPTION, "exception")) - { - newp->elog_level = ERROR; - tok = yylex(); - } - else if (tok_is_keyword(tok, &yylval, - K_WARNING, "warning")) - { - newp->elog_level = WARNING; - tok = yylex(); - } - else if (tok_is_keyword(tok, &yylval, - K_NOTICE, "notice")) - { - newp->elog_level = NOTICE; - tok = yylex(); - } - else if (tok_is_keyword(tok, &yylval, - K_INFO, "info")) - { - newp->elog_level = INFO; - tok = yylex(); - } - else if (tok_is_keyword(tok, &yylval, - K_LOG, "log")) - { - newp->elog_level = LOG; - tok = yylex(); - } - else if (tok_is_keyword(tok, &yylval, - K_DEBUG, "debug")) - { - newp->elog_level = DEBUG1; - tok = yylex(); - } - - if (tok == 0) - yyerror("unexpected end of function definition"); - - /* - * Next we can have a condition name, or - * equivalently SQLSTATE 'xxxxx', or a string - * literal that is the old-style message format, - * or USING to start the option list immediately. - */ - if (tok == SCONST) - { - /* old style message and parameters */ - newp->message = yylval.str; - /* - * We expect either a semi-colon, which - * indicates no parameters, or a comma that - * begins the list of parameter expressions, - * or USING to begin the options list. - */ - tok = yylex(); - if (tok != ',' && tok != ';' && tok != K_USING) - yyerror("syntax error"); - - while (tok == ',') - { - PLpgSQL_expr *expr; - - expr = read_sql_construct(',', ';', K_USING, - ", or ; or USING", - "SELECT ", - true, true, true, - NULL, &tok); - newp->params = lappend(newp->params, expr); - } - } - else if (tok != K_USING) - { - /* must be condition name or SQLSTATE */ - if (tok_is_keyword(tok, &yylval, - K_SQLSTATE, "sqlstate")) - { - /* next token should be a string literal */ - char *sqlstatestr; - - if (yylex() != SCONST) - yyerror("syntax error"); - sqlstatestr = yylval.str; - - if (strlen(sqlstatestr) != 5) - yyerror("invalid SQLSTATE code"); - if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror("invalid SQLSTATE code"); - newp->condname = sqlstatestr; - } - else - { - if (tok != T_WORD) - yyerror("syntax error"); - newp->condname = yylval.word.ident; - plpgsql_recognize_err_condition(newp->condname, - false); - } - tok = yylex(); - if (tok != ';' && tok != K_USING) - yyerror("syntax error"); - } - - if (tok == K_USING) - newp->options = read_raise_options(); - } - } - pfree_ext(ds.data); - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4421 "pl/pl_b_gram.cpp" - break; - - case 155: -#line 2306 "pl/pl_b_gram.y" - { - (yyval.loop_body).stmts = (yyvsp[-4].list); - (yyval.loop_body).end_label = (yyvsp[-1].str); - (yyval.loop_body).end_label_location = (yylsp[-1]); - } -#line 4431 "pl/pl_b_gram.cpp" - break; - - case 156: -#line 2324 "pl/pl_b_gram.y" - { - (yyval.stmt) = make_execsql_stmt(K_ALTER, (yylsp[0])); - } -#line 4439 "pl/pl_b_gram.cpp" - break; - - case 157: -#line 2328 "pl/pl_b_gram.y" - { - (yyval.stmt) = make_execsql_stmt(K_INSERT, (yylsp[0])); - } -#line 4447 "pl/pl_b_gram.cpp" - break; - - case 158: -#line 2332 "pl/pl_b_gram.y" - { - int tok = -1; - - tok = yylex(); - plbsql_push_back_token(tok); - (yyval.stmt) = make_execsql_stmt(K_SELECT, (yylsp[0])); - } -#line 4459 "pl/pl_b_gram.cpp" - break; - - case 159: -#line 2341 "pl/pl_b_gram.y" - { - int tok = -1; - - tok = yylex(); - plbsql_push_back_token(tok); - (yyval.stmt) = make_execsql_stmt(K_UPDATE, (yylsp[0])); - } -#line 4471 "pl/pl_b_gram.cpp" - break; - - case 160: -#line 2349 "pl/pl_b_gram.y" - { - int tok = -1; - - tok = yylex(); - plbsql_push_back_token(tok); - (yyval.stmt) = make_execsql_stmt(K_DELETE, (yylsp[0])); - } -#line 4483 "pl/pl_b_gram.cpp" - break; - - case 161: -#line 2357 "pl/pl_b_gram.y" - { - (yyval.stmt) = make_execsql_stmt(K_WITH, (yylsp[0])); - } -#line 4491 "pl/pl_b_gram.cpp" - break; - - case 162: -#line 2361 "pl/pl_b_gram.y" - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("SAVEPOINT in function/procedure is not yet supported."))); - } -#line 4501 "pl/pl_b_gram.cpp" - break; - - case 163: -#line 2367 "pl/pl_b_gram.y" - { - (yyval.stmt) = make_execsql_stmt(K_MERGE, (yylsp[0])); - } -#line 4509 "pl/pl_b_gram.cpp" - break; - - case 164: -#line 2371 "pl/pl_b_gram.y" - { - int tok = -1; - bool isCallFunc = false; - bool FuncNoarg = false; - - if (0 == strcasecmp((yyvsp[0].word).ident, "DBMS_LOB") - && (plpgsql_is_token_match2('.', K_OPEN) - || plpgsql_is_token_match2('.', K_CLOSE))) - (yyval.stmt) = parse_lob_open_close((yylsp[0])); - else - { - tok = yylex(); - if ('(' == tok) - isCallFunc = is_function((yyvsp[0].word).ident, false, false); - else if ('=' ==tok || COLON_EQUALS == tok || '[' == tok) - word_is_not_variable(&((yyvsp[0].word)), (yylsp[0])); - else if (';' == tok) - { - isCallFunc = is_function((yyvsp[0].word).ident, false, true); - FuncNoarg = true; - } - - plbsql_push_back_token(tok); - if(isCallFunc) - { - if (FuncNoarg) - { - (yyval.stmt) = make_callfunc_stmt_no_arg((yyvsp[0].word).ident, (yylsp[0])); - } - else - { - PLpgSQL_stmt *stmt = make_callfunc_stmt((yyvsp[0].word).ident, (yylsp[0]), false); - if (stmt->cmd_type == PLPGSQL_STMT_PERFORM) - { - ((PLpgSQL_stmt_perform *)stmt)->expr->is_funccall = true; - } - else if (stmt->cmd_type == PLPGSQL_STMT_EXECSQL) - { - ((PLpgSQL_stmt_execsql *)stmt)->sqlstmt->is_funccall = true; - } - (yyval.stmt) = stmt; - } - } - else - { - (yyval.stmt) = make_execsql_stmt(T_WORD, (yylsp[0])); - } - } - } -#line 4563 "pl/pl_b_gram.cpp" - break; - - case 165: -#line 2421 "pl/pl_b_gram.y" - { - int tok = yylex(); - char *name = NULL; - bool isCallFunc = false; - bool FuncNoarg = false; - - if ('(' == tok) - { - MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - name = NameListToString((yyvsp[0].cword).idents); - (void)MemoryContextSwitchTo(colCxt); - isCallFunc = is_function(name, false, false); - } - else if ('=' == tok || COLON_EQUALS == tok || '[' == tok) - cword_is_not_variable(&((yyvsp[0].cword)), (yylsp[0])); - else if (';' == tok) { - MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - name = NameListToString((yyvsp[0].cword).idents); - (void)MemoryContextSwitchTo(colCxt); - isCallFunc = is_function(name, false, true); - FuncNoarg = true; - } - - plbsql_push_back_token(tok); - if (isCallFunc) - { - if (FuncNoarg) - (yyval.stmt) = make_callfunc_stmt_no_arg(name, (yylsp[0])); - else - { - PLpgSQL_stmt *stmt = make_callfunc_stmt(name, (yylsp[0]), false); - if (stmt->cmd_type == PLPGSQL_STMT_PERFORM) - { - ((PLpgSQL_stmt_perform *)stmt)->expr->is_funccall = true; - } - else if (stmt->cmd_type == PLPGSQL_STMT_EXECSQL) - { - ((PLpgSQL_stmt_execsql *)stmt)->sqlstmt->is_funccall = true; - } - (yyval.stmt) = stmt; - } - } - else - { - (yyval.stmt) = make_execsql_stmt(T_CWORD, (yylsp[0])); - } - } -#line 4615 "pl/pl_b_gram.cpp" - break; - - case 166: -#line 2469 "pl/pl_b_gram.y" - { - int tok = yylex(); - if (';' == tok) - { - (yyval.stmt) = NULL; - } - else - { - plbsql_push_back_token(tok); - (yyval.stmt) = make_callfunc_stmt("array_extend", (yylsp[0]), false); - } - } -#line 4632 "pl/pl_b_gram.cpp" - break; - - case 167: -#line 2484 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_dynexecute *newp; - PLpgSQL_expr *expr; - int endtoken; - - - if((endtoken = yylex()) != K_IMMEDIATE) - { - plbsql_push_back_token(endtoken); - } - - expr = read_sql_construct(K_INTO, K_USING, ';', - "INTO or USING or ;", - "SELECT ", - true, true, true, - NULL, &endtoken); - newp = (PLpgSQL_stmt_dynexecute*)palloc0(sizeof(PLpgSQL_stmt_dynexecute)); - newp->cmd_type = PLPGSQL_STMT_DYNEXECUTE; - newp->lineno = plpgsql_location_to_lineno((yylsp[0])); - newp->query = expr; - newp->into = false; - newp->strict = false; - newp->rec = NULL; - newp->row = NULL; - newp->params = NIL; - newp->out_row = NULL; - newp->isinouttype = false; - newp->ppd = NULL; - newp->isanonymousblock = true; - - /* If we found "INTO", collect the argument */ - - if (endtoken == K_INTO) - { - if (newp->into) /* multiple INTO */ - yyerror("syntax error"); - newp->into = true; - read_into_target(&newp->rec, &newp->row, &newp->strict); - endtoken = yylex(); - } - /* If we found "USING", collect the argument */ - if(endtoken == K_USING) - { - PLpgSQL_row *out_row; - if (newp->params) /* multiple USING */ - yyerror("syntax error"); - - read_using_target(&(newp->params), &out_row ); - if(out_row) - { - newp->into = true; - newp->strict = true; - newp->isinouttype = true; - } - endtoken = yylex(); - if( out_row && newp->row ) - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("target into is conflicted with using out (inout)"), - errdetail("\"select clause\" can't has out parameters, can only use \"into\""))); - } - newp->out_row = newp->row ? newp->row:out_row; - - } - if (endtoken != ';') - yyerror("syntax error"); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4707 "pl/pl_b_gram.cpp" - break; - - case 168: -#line 2557 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_open *newp; - int tok; - int endtoken; - PLpgSQL_row *out_row = NULL; - - newp = (PLpgSQL_stmt_open *)palloc0(sizeof(PLpgSQL_stmt_open)); - newp->cmd_type = PLPGSQL_STMT_OPEN; - newp->lineno = plpgsql_location_to_lineno((yylsp[-1])); - newp->curvar = (yyvsp[0].var)->dno; - newp->cursor_options = CURSOR_OPT_FAST_PLAN; - - if ((yyvsp[0].var)->cursor_explicit_expr == NULL) - { - /* be nice if we could use opt_scrollable here */ - tok = yylex(); - if (tok_is_keyword(tok, &yylval, - K_NO, "no")) - { - tok = yylex(); - if (tok_is_keyword(tok, &yylval, - K_SCROLL, "scroll")) - { - newp->cursor_options |= CURSOR_OPT_NO_SCROLL; - tok = yylex(); - } - } - else if (tok_is_keyword(tok, &yylval, - K_SCROLL, "scroll")) - { - newp->cursor_options |= CURSOR_OPT_SCROLL; - tok = yylex(); - } - - if (tok != K_FOR) - yyerror("syntax error, expected \"FOR\""); - - tok = yylex(); - if (tok == K_EXECUTE) - { - newp->dynquery = read_sql_stmt("select "); - } - else - { - plbsql_push_back_token(tok); - - if (tok == K_SELECT || tok == K_WITH) - { - newp->query = read_sql_stmt(""); - } - else - { - newp->dynquery = - read_sql_expression2(K_USING, ';', - "USING or ;", - &endtoken); - - /* If we found "USING", collect argument(s) */ - if(K_USING == endtoken) - { - read_using_target(&(newp->params), &out_row); - if(NULL != out_row) - yyerror("syntax error"); - if(NULL == newp->params) - yyerror("syntax error"); - - endtoken = plbsql_yylex(); - } - - if(';' != endtoken ) - yyerror("syntax error"); - } - } - } - else - { - /* predefined cursor query, so read args */ - newp->argquery = read_cursor_args((yyvsp[0].var), ';', ";"); - } - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4794 "pl/pl_b_gram.cpp" - break; - - case 169: -#line 2642 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_fetch *fetch = (yyvsp[-2].fetch); - PLpgSQL_rec *rec; - PLpgSQL_row *row; - - /* We have already parsed everything through the INTO keyword */ - read_into_target(&rec, &row, NULL); - - if (yylex() != ';') - yyerror("syntax error"); - - /* - * We don't allow multiple rows in PL/pgSQL's FETCH - * statement, only in MOVE. - */ - if (fetch->returns_multiple_rows) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("FETCH statement cannot return multiple rows"), - parser_errposition((yylsp[-3])))); - - fetch->lineno = plpgsql_location_to_lineno((yylsp[-3])); - fetch->rec = rec; - fetch->row = row; - fetch->curvar = (yyvsp[-1].var)->dno; - fetch->is_move = false; - - (yyval.stmt) = (PLpgSQL_stmt *)fetch; - } -#line 4828 "pl/pl_b_gram.cpp" - break; - - case 170: -#line 2674 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_fetch *fetch = (yyvsp[-2].fetch); - - fetch->lineno = plpgsql_location_to_lineno((yylsp[-3])); - fetch->curvar = (yyvsp[-1].var)->dno; - fetch->is_move = true; - - (yyval.stmt) = (PLpgSQL_stmt *)fetch; - } -#line 4842 "pl/pl_b_gram.cpp" - break; - - case 171: -#line 2686 "pl/pl_b_gram.y" - { - (yyval.fetch) = read_fetch_direction(); - } -#line 4850 "pl/pl_b_gram.cpp" - break; - - case 172: -#line 2692 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_close *newp; - - newp = (PLpgSQL_stmt_close *)palloc(sizeof(PLpgSQL_stmt_close)); - newp->cmd_type = PLPGSQL_STMT_CLOSE; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - newp->curvar = (yyvsp[-1].var)->dno; - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4865 "pl/pl_b_gram.cpp" - break; - - case 173: -#line 2705 "pl/pl_b_gram.y" - { - /* We do building a node for NULL for GOTO */ - PLpgSQL_stmt *newp; - - newp = (PLpgSQL_stmt_null *)palloc(sizeof(PLpgSQL_stmt_null)); - newp->cmd_type = PLPGSQL_STMT_NULL; - newp->lineno = plpgsql_location_to_lineno((yylsp[-1])); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - } -#line 4880 "pl/pl_b_gram.cpp" - break; - - case 174: -#line 2718 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_commit *newp; - - newp = (PLpgSQL_stmt_commit *)palloc(sizeof(PLpgSQL_stmt_commit)); - newp->cmd_type = PLPGSQL_STMT_COMMIT; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - record_stmt_label((yyvsp[-2].str), (PLpgSQL_stmt *)newp); - } -#line 4896 "pl/pl_b_gram.cpp" - break; - - case 175: -#line 2732 "pl/pl_b_gram.y" - { - PLpgSQL_stmt_rollback *newp; - - newp = (PLpgSQL_stmt_rollback *) palloc(sizeof(PLpgSQL_stmt_rollback)); - newp->cmd_type = PLPGSQL_STMT_ROLLBACK; - newp->lineno = plpgsql_location_to_lineno((yylsp[-2])); - plpgsql_ns_pop(); - - (yyval.stmt) = (PLpgSQL_stmt *)newp; - record_stmt_label((yyvsp[-2].str), (PLpgSQL_stmt *)newp); - } -#line 4912 "pl/pl_b_gram.cpp" - break; - - case 176: -#line 2746 "pl/pl_b_gram.y" - { - if ((yyvsp[0].wdatum).datum->dtype != PLPGSQL_DTYPE_VAR) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cursor variable must be a simple variable"), - parser_errposition((yylsp[0])))); - - if (((PLpgSQL_var *) (yyvsp[0].wdatum).datum)->datatype->typoid != REFCURSOROID) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("variable \"%s\" must be of type cursor or refcursor", - ((PLpgSQL_var *) (yyvsp[0].wdatum).datum)->refname), - parser_errposition((yylsp[0])))); - (yyval.var) = (PLpgSQL_var *) (yyvsp[0].wdatum).datum; - } -#line 4932 "pl/pl_b_gram.cpp" - break; - - case 177: -#line 2762 "pl/pl_b_gram.y" - { - /* just to give a better message than "syntax error" */ - word_is_not_variable(&((yyvsp[0].word)), (yylsp[0])); - } -#line 4941 "pl/pl_b_gram.cpp" - break; - - case 178: -#line 2767 "pl/pl_b_gram.y" - { - /* just to give a better message than "syntax error" */ - cword_is_not_variable(&((yyvsp[0].cword)), (yylsp[0])); - } -#line 4950 "pl/pl_b_gram.cpp" - break; - - case 179: -#line 2774 "pl/pl_b_gram.y" - { (yyval.exception_block) = NULL; } -#line 4956 "pl/pl_b_gram.cpp" - break; - - case 180: -#line 2776 "pl/pl_b_gram.y" - { - /* - * We use a mid-rule action to add these - * special variables to the namespace before - * parsing the WHEN clauses themselves. The - * scope of the names extends to the end of the - * current block. - */ - int lineno = plpgsql_location_to_lineno((yylsp[0])); - PLpgSQL_exception_block *newp = (PLpgSQL_exception_block *)palloc(sizeof(PLpgSQL_exception_block)); - PLpgSQL_variable *var; - - var = plpgsql_build_variable("sqlstate", lineno, - plpgsql_build_datatype(TEXTOID, - -1, - u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation), - true); - ((PLpgSQL_var *) var)->isconst = true; - newp->sqlstate_varno = var->dno; - - var = plpgsql_build_variable("sqlerrm", lineno, - plpgsql_build_datatype(TEXTOID, - -1, - u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation), - true); - ((PLpgSQL_var *) var)->isconst = true; - newp->sqlerrm_varno = var->dno; - - (yyval.exception_block) = newp; - } -#line 4991 "pl/pl_b_gram.cpp" - break; - - case 181: -#line 2807 "pl/pl_b_gram.y" - { - PLpgSQL_exception_block *newp = (yyvsp[-1].exception_block); - newp->exc_list = (yyvsp[0].list); - - (yyval.exception_block) = newp; - } -#line 5002 "pl/pl_b_gram.cpp" - break; - - case 182: -#line 2816 "pl/pl_b_gram.y" - { - (yyval.list) = lappend((yyvsp[-1].list), (yyvsp[0].exception)); - } -#line 5010 "pl/pl_b_gram.cpp" - break; - - case 183: -#line 2820 "pl/pl_b_gram.y" - { - (yyval.list) = list_make1((yyvsp[0].exception)); - } -#line 5018 "pl/pl_b_gram.cpp" - break; - - case 184: -#line 2826 "pl/pl_b_gram.y" - { - PLpgSQL_exception *newp; - - newp = (PLpgSQL_exception *)palloc0(sizeof(PLpgSQL_exception)); - newp->lineno = plpgsql_location_to_lineno((yylsp[-3])); - newp->conditions = (yyvsp[-2].condition); - newp->action = (yyvsp[0].list); - - (yyval.exception) = newp; - } -#line 5033 "pl/pl_b_gram.cpp" - break; - - case 185: -#line 2839 "pl/pl_b_gram.y" - { - PLpgSQL_condition *old; - - for (old = (yyvsp[-2].condition); old->next != NULL; old = old->next) - /* skip */ ; - old->next = (yyvsp[0].condition); - (yyval.condition) = (yyvsp[-2].condition); - } -#line 5046 "pl/pl_b_gram.cpp" - break; - - case 186: -#line 2848 "pl/pl_b_gram.y" - { - (yyval.condition) = (yyvsp[0].condition); - } -#line 5054 "pl/pl_b_gram.cpp" - break; - - case 187: -#line 2854 "pl/pl_b_gram.y" - { - if (strcmp((yyvsp[0].str), "sqlstate") != 0) - { - if (PLPGSQL_DTYPE_ROW == yylval.wdatum.datum->dtype) - { - PLpgSQL_condition *newp = NULL; - PLpgSQL_row * row = ( PLpgSQL_row* ) u_sess->plsql_cxt.plpgsql_Datums[yylval.wdatum.datum->dno]; - TupleDesc rowtupdesc = row ? row->rowtupdesc : NULL; - - if(rowtupdesc && - 0 == strcmp(format_type_be(rowtupdesc->tdtypeid), "exception")) - { - newp = (PLpgSQL_condition *)palloc(sizeof(PLpgSQL_condition)); - newp->sqlerrstate = row->customErrorCode; - newp->condname = pstrdup(row->refname); - newp->next = NULL; - } - - if(NULL == newp) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unrecognized exception condition \"%s\"", - row? row->refname : "??"))); - (yyval.condition) = newp; - } - else - (yyval.condition) = plpgsql_parse_err_condition((yyvsp[0].str)); - } - else - { - PLpgSQL_condition *newp; - char *sqlstatestr; - - /* next token should be a string literal */ - if (yylex() != SCONST) - yyerror("syntax error"); - sqlstatestr = yylval.str; - - if (strlen(sqlstatestr) != 5) - yyerror("invalid SQLSTATE code"); - if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) - yyerror("invalid SQLSTATE code"); - - newp = (PLpgSQL_condition *)palloc(sizeof(PLpgSQL_condition)); - newp->sqlerrstate = - MAKE_SQLSTATE(sqlstatestr[0], - sqlstatestr[1], - sqlstatestr[2], - sqlstatestr[3], - sqlstatestr[4]); - newp->condname = sqlstatestr; - newp->next = NULL; - - (yyval.condition) = newp; - } - } -#line 5115 "pl/pl_b_gram.cpp" - break; - - case 188: -#line 2912 "pl/pl_b_gram.y" - { - /* - * support invoking function with out - * argument in a := expression - */ - PLpgSQL_stmt *stmt = NULL; - int tok = -1; - char *name = NULL; - bool isCallFunc = false; - PLpgSQL_expr* expr = NULL; - - if (plpgsql_is_token_match2(T_WORD, '(') || - plpgsql_is_token_match2(T_CWORD,'(')) - { - tok = yylex(); - if (T_WORD == tok) - name = yylval.word.ident; - else - name = NameListToString(yylval.cword.idents); - - isCallFunc = is_function(name, true, false); - } - - if (isCallFunc) - { - stmt = make_callfunc_stmt(name, yylloc, true); - if (PLPGSQL_STMT_EXECSQL == stmt->cmd_type) - expr = ((PLpgSQL_stmt_execsql*)stmt)->sqlstmt; - else if (PLPGSQL_STMT_PERFORM == stmt->cmd_type) - expr = ((PLpgSQL_stmt_perform*)stmt)->expr; - - expr->is_funccall = true; - (yyval.expr) = expr; - } - else - { - if (name != NULL) - plbsql_push_back_token(tok); - (yyval.expr) = read_sql_expression(';', ";"); - } - } -#line 5161 "pl/pl_b_gram.cpp" - break; - - case 189: -#line 2956 "pl/pl_b_gram.y" - { (yyval.expr) = read_sql_expression(']', "]"); } -#line 5167 "pl/pl_b_gram.cpp" - break; - - case 190: -#line 2960 "pl/pl_b_gram.y" - { (yyval.expr) = read_sql_expression(')', ")"); } -#line 5173 "pl/pl_b_gram.cpp" - break; - - case 191: -#line 2964 "pl/pl_b_gram.y" - { (yyval.expr) = read_sql_expression(K_THEN, "THEN"); } -#line 5179 "pl/pl_b_gram.cpp" - break; - - case 192: -#line 2968 "pl/pl_b_gram.y" - { (yyval.expr) = read_sql_expression(K_LOOP, "LOOP"); } -#line 5185 "pl/pl_b_gram.cpp" - break; - - case 193: -#line 2972 "pl/pl_b_gram.y" - { - plpgsql_ns_push(NULL); - (yyval.str) = NULL; - } -#line 5194 "pl/pl_b_gram.cpp" - break; - - case 194: -#line 2977 "pl/pl_b_gram.y" - { - plpgsql_ns_push((yyvsp[-1].str)); - (yyval.str) = (yyvsp[-1].str); - } -#line 5203 "pl/pl_b_gram.cpp" - break; - - case 195: -#line 2984 "pl/pl_b_gram.y" - { - (yyval.str) = NULL; - } -#line 5211 "pl/pl_b_gram.cpp" - break; - - case 196: -#line 2988 "pl/pl_b_gram.y" - { -#if 0 - if (plpgsql_ns_lookup_label(plpgsql_ns_top(), (yyvsp[0].str)) == NULL) - yyerror("label does not exist"); -#endif - (yyval.str) = (yyvsp[0].str); - } -#line 5223 "pl/pl_b_gram.cpp" - break; - - case 197: -#line 2998 "pl/pl_b_gram.y" - { (yyval.expr) = NULL; } -#line 5229 "pl/pl_b_gram.cpp" - break; - - case 198: -#line 3000 "pl/pl_b_gram.y" - { (yyval.expr) = (yyvsp[0].expr); } -#line 5235 "pl/pl_b_gram.cpp" - break; - - case 199: -#line 3007 "pl/pl_b_gram.y" - { - (yyval.str) = (yyvsp[0].word).ident; - } -#line 5243 "pl/pl_b_gram.cpp" - break; - - case 200: -#line 3011 "pl/pl_b_gram.y" - { - if ((yyvsp[0].wdatum).ident == NULL) /* composite name not OK */ - yyerror("syntax error"); - (yyval.str) = (yyvsp[0].wdatum).ident; - } -#line 5253 "pl/pl_b_gram.cpp" - break; - - -#line 5257 "pl/pl_b_gram.cpp" - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - *++yylsp = yyloc; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - { - const int yylhs = yyr1[yyn] - YYNTOKENS; - const int yyi = yypgoto[yylhs] + *yyssp; - yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp - ? yytable[yyi] - : yydefgoto[yylhs]); - } - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = YY_CAST (char *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - yyerror_range[1] = yylloc; - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - /* Pacify compilers when the user code never invokes YYERROR and the - label yyerrorlab therefore never appears in user code. */ - if (0) - YYERROR; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - yyerror_range[1] = *yylsp; - yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - yyerror_range[2] = yylloc; - /* Using YYLLOC is tempting, but would change the location of - the lookahead. YYLOC is available though. */ - YYLLOC_DEFAULT (yyloc, yyerror_range, 2); - *++yylsp = yyloc; - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - - -/*-----------------------------------------------------. -| yyreturn -- parsing is finished, return the result. | -`-----------------------------------------------------*/ -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - return yyresult; -} -#line 3073 "pl/pl_b_gram.y" - - -#define MAX_EXPR_PARAMS 1024 - -/* - * Check whether a token represents an "unreserved keyword". - * We have various places where we want to recognize a keyword in preference - * to a variable name, but not reserve that keyword in other contexts. - * Hence, this kluge. - */ -static bool -tok_is_keyword(int token, union YYSTYPE *lval, - int kw_token, const char *kw_str) -{ - if (token == kw_token) - { - /* Normal case, was recognized by scanner (no conflicting variable) */ - return true; - } - else if (token == T_DATUM) - { - /* - * It's a variable, so recheck the string name. Note we will not - * match composite names (hence an unreserved word followed by "." - * will not be recognized). - */ - if (!lval->wdatum.quoted && lval->wdatum.ident != NULL && - strcmp(lval->wdatum.ident, kw_str) == 0) - return true; - } - return false; /* not the keyword */ -} - -/* - * Convenience routine to complain when we expected T_DATUM and got T_WORD, - * ie, unrecognized variable. - */ -static void -word_is_not_variable(PLword *word, int location) -{ - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a known variable", - word->ident), - parser_errposition(location))); -} - -/* Same, for a CWORD */ -static void -cword_is_not_variable(PLcword *cword, int location) -{ - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a known variable", - NameListToString(cword->idents)), - parser_errposition(location))); -} - -/* - * Convenience routine to complain when we expected T_DATUM and got - * something else. "tok" must be the current token, since we also - * look at yylval and yylloc. - */ -static void -current_token_is_not_variable(int tok) -{ - if (tok == T_WORD) - word_is_not_variable(&(yylval.word), yylloc); - else if (tok == T_CWORD) - cword_is_not_variable(&(yylval.cword), yylloc); - else - yyerror("syntax error"); -} - -/* - * Brief : handle the C-style function IN arguments. - * Description : - * Notes : - */ -static void -yylex_inparam(StringInfoData* func_inparam, - int *nparams, - int * tok) -{ - PLpgSQL_expr * expr = NULL; - - if (*nparams) - appendStringInfoString(func_inparam, ","); - - /* - * handle the problem that the function - * arguments can only be variable. the argment validsql is set FALSE to - * ignore sql expression check to the "$n" type of arguments. - */ - expr = read_sql_construct(',', ')', 0, ",|)", "", true, false, false, NULL, tok); - - if (*nparams >= MAX_EXPR_PARAMS) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many variables specified in SQL statement ,more than %d", MAX_EXPR_PARAMS))); - - (*nparams)++; - - /* - * handle the problem that the function - * arguments can only be variable. After revising, the arguments can be any - * expression. - */ - appendStringInfoString(func_inparam, expr->query); -} - -/* - * Brief : handle the C-style function OUT arguments. - * Description : - * Notes : - */ -static void -yylex_outparam(char** fieldnames, - int *varnos, - int nfields, - PLpgSQL_row **row, - PLpgSQL_rec **rec, - int *token, - bool overload) -{ - *token = yylex(); - - if (T_DATUM == *token) - { - if (PLPGSQL_TTYPE_ROW == yylval.wdatum.datum->dtype) - { - check_assignable(yylval.wdatum.datum, yylloc); - fieldnames[nfields] = pstrdup(NameOfDatum(&yylval.wdatum)); - varnos[nfields] = yylval.wdatum.datum->dno; - *row = (PLpgSQL_row *)yylval.wdatum.datum; - } - else if (PLPGSQL_TTYPE_REC == yylval.wdatum.datum->dtype) - { - check_assignable(yylval.wdatum.datum, yylloc); - fieldnames[nfields] = pstrdup(NameOfDatum(&yylval.wdatum)); - varnos[nfields] = yylval.wdatum.datum->dno; - *rec = (PLpgSQL_rec *)yylval.wdatum.datum; - } - else if (PLPGSQL_TTYPE_SCALAR == yylval.wdatum.datum->dtype) - { - check_assignable(yylval.wdatum.datum, yylloc); - fieldnames[nfields] = pstrdup(NameOfDatum(&yylval.wdatum)); - varnos[nfields] = yylval.wdatum.datum->dno; - } - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&yylval.wdatum)))); - } - else if (overload) - { - fieldnames[nfields] = NULL; - varnos[nfields] = -1; - } -} - -/* - * Brief: passe the called function name and return it into output. - * Description: - * in s: original idents - * inout output: splited idents. - * in numidnets: max ident number. - * returns: void - * Notes : No need to consider double quoted ident because it has been handled in lex. - * Ident here has been downcase if no double quoted, and been without quote if it had double quote before. - */ -void -plpgsql_parser_funcname(const char *s, char **output, int numidents) -{ - int ident_num = 0; - char *outer_ptr = NULL; - char *p = NULL; - char delimiter[] = "."; - errno_t ret; - char *str = (char *)palloc0(sizeof(char) * (strlen(s) + 1)); - - for (int i = 0; i < numidents; i++) - output[i] = (char *)palloc0(sizeof(char) * NAMEDATALEN * 2); - - ret = strcpy_s(str, sizeof(char) * (strlen(s) + 1), s); - securec_check(ret, "\0", "\0"); - - p = strtok_s(str, delimiter, &outer_ptr); - - while (p != NULL) - { - ret = strcpy_s(output[ident_num++], sizeof(char) * NAMEDATALEN * 2, p); - securec_check(ret, "\0", "\0"); - p = strtok_s(NULL, delimiter, &outer_ptr); - } - - pfree_ext(str); -} - -/* - * Brief : handle A-style function call. - * Description : handle A-style function call. First read the function - * name, then read the arguments. At last assembing the function - * name and arguments into the postgresql-style function call. - * in sqlstart: the sql stmt string to be handle. - * in location: the location number to erreport. - * in is_assign: is an assign stmt or not. - * returns: the parsed stmt. - * Notes : - */ -static PLpgSQL_stmt * -make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) -{ - int nparams = 0; - int nfields = 0; - int narg = 0; - int inArgNum = 0; - int i= 0; - int tok = 0; - Oid *p_argtypes = NULL; - char *cp[3]; - char **p_argnames = NULL; - char *p_argmodes = NULL; - /* pos_outer is the postion got by matching the name. */ - int pos_outer = 0; - /* pos_inner is the position got by its real postion in function invoke */ - int pos_inner = -1; - int varnos[FUNC_MAX_ARGS]; - bool namedarg[FUNC_MAX_ARGS]; - char* namedargnamses[FUNC_MAX_ARGS]; - char *fieldnames[FUNC_MAX_ARGS]; - - List *funcname = NIL; - PLpgSQL_row *row = NULL; - PLpgSQL_rec *rec = NULL; - PLpgSQL_expr* expr = NULL; - HeapTuple proctup = NULL; - Form_pg_proc procStruct; - FuncCandidateList clist = NULL; - StringInfoData func_inparas; - bool noargs = FALSE; - int ndefaultargs = 0; - StringInfoData argname; - int j = 0; - int placeholders = 0; - char *quoted_sqlstart = NULL; - - MemoryContext oldCxt = NULL; - bool multi_func = false; - /*get the function's name*/ - cp[0] = NULL; - cp[1] = NULL; - cp[2] = NULL; - /* the function make_callfunc_stmt is only to assemble a sql statement, so the context is set to tmp context */ - oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - plpgsql_parser_funcname(sqlstart, cp, 3); - - if (cp[2] && cp[2][0] != '\0') - funcname = list_make3(makeString(cp[0]), makeString(cp[1]), makeString(cp[2])); - else if (cp[1] && cp[1][0] != '\0') - funcname = list_make2(makeString(cp[0]), makeString(cp[1])); - else - funcname = list_make1(makeString(cp[0])); - - - /* search the function */ - clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false); - if (!clist) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", sqlstart))); - return NULL; - } - - if (clist->next) - { - multi_func = true; - if (IsPackageFunction(funcname) == false) - { - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_FUNCTION), - errmsg("function \"%s\" isn't exclusive ", sqlstart))); - } - } - - if (multi_func == false) - { - proctup = SearchSysCache(PROCOID, - ObjectIdGetDatum(clist->oid), - 0, 0, 0); - - /* - * function may be deleted after clist be searched. - */ - if (!HeapTupleIsValid(proctup)) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", sqlstart))); - return NULL; - } - /* get the all args informations, only "in" parameters if p_argmodes is null */ - narg = get_func_arg_info(proctup,&p_argtypes, &p_argnames, &p_argmodes); - if (p_argmodes) - { - for (i = 0; i < narg; i++) - { - if (p_argmodes[i] == 'i' || p_argmodes[i] == 'b') - { - inArgNum++; - } - } - } - else - { - inArgNum = narg; - } - procStruct = (Form_pg_proc) GETSTRUCT(proctup); - ndefaultargs = procStruct->pronargdefaults; - ReleaseSysCache(proctup); - } - - initStringInfo(&func_inparas); - - tok = yylex(); - - /* check the format for the function without parameters */ - if ((tok = yylex()) == ')') - noargs = TRUE; - plbsql_push_back_token(tok); - - /* has any "out" parameters, user execsql stmt */ - if (is_assign) - { - appendStringInfoString(&func_inparas, "SELECT "); - } - else - { - appendStringInfoString(&func_inparas, "CALL "); - } - - /* - * Properly double-quote schema name and function name to handle uppercase - * and special characters when making 'CALL func_name;' statement. - */ - quoted_sqlstart = NameListToQuotedString(funcname); - appendStringInfoString(&func_inparas, quoted_sqlstart); - pfree_ext(quoted_sqlstart); - - appendStringInfoString(&func_inparas, "("); - - /* analyse all parameters */ - if (noargs) - { - i = 0; - tok = yylex(); - } - else if (!multi_func) - { - if (p_argmodes) - { - for ( i = 0; i < narg ; i++) - { - initStringInfo(&argname); - pos_outer = -1; - if ('o' == p_argmodes[i] || 'b' == p_argmodes[i]) - pos_inner++; - - /* - * see if an arg is 'defargname => realargname' type. - * if so, p_argnames must be searched to match the defined - * argument name. - */ - if (plpgsql_is_token_match2(T_DATUM, PARA_EQUALS) - || plpgsql_is_token_match2(T_WORD, PARA_EQUALS)) - { - tok = yylex(); - if (T_DATUM == tok) - appendStringInfoString(&argname, NameOfDatum(&yylval.wdatum)); - else - appendStringInfoString(&argname, yylval.word.ident); - plbsql_push_back_token(tok); - /* - * search the p_argnames to match the right argname with current arg, - * so the real postion of current arg can be determined - */ - for (j = 0; j < narg; j++) - { - if ('o' == p_argmodes[j] || 'b' == p_argmodes[j]) - pos_outer++; - if (0 == pg_strcasecmp(argname.data, p_argnames[j])) - { - /* - * if argmodes is 'i', just append the text, else, - * row or rec should be assigned to store the out arg values - */ - switch (p_argmodes[j]) - { - case 'i': - yylex_inparam(&func_inparas, &nparams, &tok); - break; - case 'o': - case 'b': - if (is_assign && 'o' == p_argmodes[j]) - { - (void)yylex(); - (void)yylex(); - if (T_DATUM == (tok = yylex())) - { - plbsql_push_back_token(tok); - (void)read_sql_expression2(',', ')', ",|)", &tok); - } - else - yyerror("syntax error"); - break; - } - - if (nparams) - appendStringInfoChar(&func_inparas, ','); - - tok = yylex(); - if (T_DATUM == tok) - appendStringInfoString(&func_inparas, NameOfDatum(&yylval.wdatum)); - else - appendStringInfoString(&func_inparas, yylval.word.ident); - - appendStringInfoString(&func_inparas, "=>"); - (void)yylex(); - yylex_outparam(fieldnames, varnos, pos_outer, &row, &rec, &tok); - if (T_DATUM == tok) - { - nfields++; - appendStringInfoString(&func_inparas, NameOfDatum(&yylval.wdatum)); - } - - tok = yylex(); - nparams++; - break; - default: - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NODE_STATE), - errmsg("parameter mode %c doesn't exist", p_argmodes[j]))); - } - break; - } - } - } - else - { - tok = yylex(); - /* p_argmodes may be null, 'i'->in , 'o'-> out ,'b' inout,others error */ - switch (p_argmodes[i]) - { - case 'i': - if (T_PLACEHOLDER == tok) - placeholders++; - plbsql_push_back_token(tok); - yylex_inparam(&func_inparas, &nparams, &tok); - break; - case 'o': - /* - * if the function is in an assign expr, just ignore the - * out parameters. - */ - if (is_assign) - { - if (T_DATUM == tok || T_PLACEHOLDER == tok) - { - plbsql_push_back_token(tok); - (void)read_sql_expression2(',', ')', ",|)", &tok); - } - else - yyerror("syntax error"); - break; - } - - if (T_PLACEHOLDER == tok) - { - placeholders++; - if (nparams) - appendStringInfoChar(&func_inparas, ','); - appendStringInfoString(&func_inparas, yylval.word.ident); - nparams++; - } - else if (T_DATUM == tok) - { - if (nparams) - appendStringInfoString(&func_inparas, ","); - appendStringInfoString(&func_inparas, NameOfDatum(&yylval.wdatum)); - nparams++; - nfields++; - } - - plbsql_push_back_token(tok); - yylex_outparam(fieldnames, varnos, pos_inner, &row, &rec, &tok); - - tok = yylex(); - break; - case 'b': - if (is_assign) - { - /* - * if the function is in an assign expr, read the inout - * parameters. - */ - if (T_DATUM == tok) - { - plbsql_push_back_token(tok); - yylex_inparam(&func_inparas, &nparams, &tok); - } - else - yyerror("syntax error"); - break; - } - - if (T_PLACEHOLDER == tok) - placeholders++; - plbsql_push_back_token(tok); - yylex_outparam(fieldnames, varnos, pos_inner, &row, &rec, &tok); - if (T_DATUM == tok) - nfields++; - plbsql_push_back_token(tok); - yylex_inparam(&func_inparas, &nparams, &tok); - break; - default: - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NODE_STATE), - errmsg("parameter mode %c doesn't exist", p_argmodes[i]))); - } - } - - if (')' == tok) - { - i++; - break; - } - - if (narg - 1 == i) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("when invoking function %s, expected \")\", maybe input something superfluous.", sqlstart))); - - if (',' != tok) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("when invoking function %s, expected \",\"", sqlstart))); - pfree_ext(argname.data); - } - } - else - { - for ( i = 0; i < narg; i++) - { - tok = yylex(); - if (T_PLACEHOLDER == tok) - placeholders++; - plbsql_push_back_token(tok); - - yylex_inparam(&func_inparas, &nparams, &tok); - - if (')' == tok) - { - i++; - break; - } - - if (narg - 1 == i) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("when invoking function %s, expected \")\", maybe input something superfluous.", sqlstart))); - } - } - } - else - { - while (true) - { - - /* for named arguemnt */ - if (plpgsql_is_token_match2(T_DATUM, PARA_EQUALS) - || plpgsql_is_token_match2(T_WORD, PARA_EQUALS)) - { - tok = yylex(); - if (nparams) - appendStringInfoString(&func_inparas, ","); - if (T_DATUM == tok) - { - appendStringInfoString(&func_inparas, NameOfDatum(&yylval.wdatum)); - namedargnamses[nfields] = pstrdup(NameOfDatum(&yylval.wdatum)); - } - else - { - appendStringInfoString(&func_inparas, yylval.word.ident); - namedargnamses[nfields] = yylval.word.ident; - } - - appendStringInfoString(&func_inparas, "=>"); - (void)yylex(); - - yylex_outparam(fieldnames, varnos, nfields, &row, &rec, &tok, true); - int loc = yylloc; - tok = yylex(); - int curloc = yylloc; - plbsql_push_back_token(tok); - plpgsql_append_source_text(&func_inparas, loc, curloc); - - tok = yylex(); - nparams++; - namedarg[nfields] = true; - } - else - { - yylex_outparam(fieldnames, varnos, nfields, &row, &rec, &tok, true); - plbsql_push_back_token(tok); - yylex_inparam(&func_inparas, &nparams, &tok); - namedarg[nfields] = false; - namedargnamses[nfields] = NULL; - } - nfields++; - if (')' == tok) - { - break; - } - } - } - appendStringInfoString(&func_inparas, ")"); - /* read the end token */ - if ((tok = yylex()) != ';') - { - if (!is_assign) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("when invoking function %s, maybe input something superfluous.", sqlstart))); - } - else - { - /* there may be other thing after the function invoke, just append it */ - plbsql_push_back_token(tok); - expr = read_sql_construct(';', 0, 0, ";", "", true, false, true, NULL, &tok); - appendStringInfoString(&func_inparas, expr->query); - pfree_ext(expr->query); - pfree_ext(expr); - } - } - - if (!multi_func && inArgNum - i > ndefaultargs) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s has no enough parameters", sqlstart))); - - (void)MemoryContextSwitchTo(oldCxt); - - /* generate the expression */ - expr = (PLpgSQL_expr*)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(func_inparas.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->idx = (uint32)-1; - - if (multi_func) - { - PLpgSQL_function *function = NULL; - PLpgSQL_execstate *estate = (PLpgSQL_execstate*)palloc(sizeof(PLpgSQL_execstate)); - expr->func = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function)); - function = expr->func; - function->fn_is_trigger = false; - function->fn_input_collation = InvalidOid; - function->out_param_varno = -1; /* set up for no OUT param */ - function->resolve_option = (PLpgSQL_resolve_option)u_sess->plsql_cxt.plpgsql_variable_conflict; - function->fn_cxt = CurrentMemoryContext; - - estate->ndatums = u_sess->plsql_cxt.plpgsql_nDatums; - estate->datums = (PLpgSQL_datum **)palloc(sizeof(PLpgSQL_datum *) * u_sess->plsql_cxt.plpgsql_nDatums); - for (int i = 0; i < u_sess->plsql_cxt.plpgsql_nDatums; i++) - estate->datums[i] = u_sess->plsql_cxt.plpgsql_Datums[i]; - - function->cur_estate = estate; - function->cur_estate->func = function; - - Oid funcid = getMultiFuncInfo(func_inparas.data, expr); - if (expr->func != NULL) - pfree_ext(expr->func); - if (estate->datums != NULL) - pfree_ext(estate->datums); - if (estate != NULL) - pfree_ext(estate); - expr->func = NULL; - int all_arg = 0; - if (OidIsValid(funcid)) - { - proctup = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); - - /* - * function may be deleted after clist be searched. - */ - if (!HeapTupleIsValid(proctup)) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", sqlstart))); - return NULL; - } - /* get the all args informations, only "in" parameters if p_argmodes is null */ - all_arg = get_func_arg_info(proctup, &p_argtypes, &p_argnames, &p_argmodes); - procStruct = (Form_pg_proc) GETSTRUCT(proctup); - ndefaultargs = procStruct->pronargdefaults; - narg = procStruct->pronargs; - ReleaseSysCache(proctup); - - /* if there is no "out" parameters ,use perform stmt,others use exesql */ - if ((0 == all_arg || NULL == p_argmodes)) - { - PLpgSQL_stmt_perform *perform = NULL; - perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); - perform->cmd_type = PLPGSQL_STMT_PERFORM; - perform->lineno = plpgsql_location_to_lineno(location); - perform->expr = expr; - return (PLpgSQL_stmt *)perform; - } - else if (all_arg >= narg) - { - if (NULL == rec && NULL == row) - { - int new_nfields = 0; - int i = 0, j = 0; - for (i = 0; i < all_arg; i++) - { - if (p_argmodes[i] == 'i') - continue; - else - new_nfields++; - } - row = (PLpgSQL_row*)palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = plpgsql_location_to_lineno(location); - row->rowtupdesc = NULL; - row->nfields = new_nfields; - row->fieldnames = (char **)palloc0(sizeof(char *) * new_nfields); - row->varnos = (int *)palloc0(sizeof(int) * new_nfields); - - /* fetch out argument from fieldnames into row->fieldnames */ - for (i = 0; i < nfields; i++) - { - if (namedarg[i] == false) - { - if (p_argmodes[i] == 'i') - continue; - else if (varnos[i] >= 0) - { - row->fieldnames[j] = fieldnames[i]; - row->varnos[j] = varnos[i]; - j++; - } - } - else - { - char argmode = FUNC_PARAM_IN; - pos_outer = -1; - for (int curpos = 0; curpos < all_arg; curpos++) - { - char* paraname = p_argnames[curpos]; - - if (p_argmodes[curpos] != 'i') - pos_outer++; - else - { - continue; - } - - if (paraname != NULL && !strcmp(paraname, namedargnamses[i])) - { - if (!p_argmodes) - argmode = FUNC_PARAM_IN; - else - argmode = p_argmodes[curpos]; - - break; - } - } - - if (argmode == 'i') - continue; - - if (fieldnames[i] == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Named argument \"%s\" can not be a const", namedargnamses[i]))); - } - - if (row->varnos[pos_outer] > 0) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("parameter \"%s\" is assigned more than once", row->fieldnames[pos_outer]))); - } - - if (varnos[i] >= 0) - { - row->fieldnames[pos_outer] = fieldnames[i]; - row->varnos[pos_outer] = varnos[i]; - } - } - } - plpgsql_adddatum((PLpgSQL_datum *)row); - } - - PLpgSQL_stmt_execsql * execsql = NULL; - execsql = (PLpgSQL_stmt_execsql *)palloc(sizeof(PLpgSQL_stmt_execsql)); - execsql->cmd_type = PLPGSQL_STMT_EXECSQL; - execsql->lineno = plpgsql_location_to_lineno(location); - execsql->sqlstmt = expr; - execsql->into = row || rec ? true:false; - execsql->strict = true; - execsql->rec = rec; - execsql->row = row; - execsql->placeholders = placeholders; - execsql->multi_func = multi_func; - return (PLpgSQL_stmt *)execsql; - } - } - else - { - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_FUNCTION), - errmsg("function \"%s\" isn't exclusive ", sqlstart))); - } - } - else - { - /* if have out parameters, generate row type to store the results. */ - if (nfields && NULL == rec && NULL == row) - { - row = (PLpgSQL_row*)palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = plpgsql_location_to_lineno(location); - row->rowtupdesc = NULL; - row->nfields = nfields; - row->fieldnames = (char **)palloc(sizeof(char *) * nfields); - row->varnos = (int *)palloc(sizeof(int) * nfields); - while (--nfields >= 0) - { - row->fieldnames[nfields] = fieldnames[nfields]; - row->varnos[nfields] = varnos[nfields]; - } - plpgsql_adddatum((PLpgSQL_datum *)row); - } - - /* if there is no "out" parameters ,use perform stmt,others use exesql */ - if (0 == narg || NULL == p_argmodes) - { - PLpgSQL_stmt_perform *perform = NULL; - perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); - perform->cmd_type = PLPGSQL_STMT_PERFORM; - perform->lineno = plpgsql_location_to_lineno(location); - perform->expr = expr; - return (PLpgSQL_stmt *)perform; - } - else - { - PLpgSQL_stmt_execsql * execsql = NULL; - execsql = (PLpgSQL_stmt_execsql *)palloc(sizeof(PLpgSQL_stmt_execsql)); - execsql->cmd_type = PLPGSQL_STMT_EXECSQL; - execsql->lineno = plpgsql_location_to_lineno(location); - execsql->sqlstmt = expr; - execsql->into = row || rec ? true:false; - execsql->strict = true; - execsql->rec = rec; - execsql->row = row; - execsql->placeholders = placeholders; - execsql->multi_func = multi_func; - return (PLpgSQL_stmt *)execsql; - } - } - - pfree_ext(func_inparas.data); - /* skip compile warning */ - return NULL; -} - -/* - * Brief : check if it is an function invoke - * Description : - * in name: the ident name - * in is_assign: is an assign stmt or not. - * in no_parenthesis: if no-parenthesis function is called. - * returns: true if is a function. - * Notes : - */ -static bool -is_function(const char *name, bool is_assign, bool no_parenthesis) -{ - ScanKeyword * keyword = NULL; - List *funcname = NIL; - FuncCandidateList clist = NULL; - bool have_outargs = false; - char **p_argnames = NULL; - char *p_argmodes = NULL; - Oid *p_argtypes = NULL; - HeapTuple proctup = NULL; - int narg = 0; - int i = 0; - char *cp[3] = {0}; - - /* the function is_function is only to judge if it's a function call, so memory used in it is all temp */ - AutoContextSwitch plCompileCxtGuard(u_sess->plsql_cxt.compile_tmp_cxt); - - plpgsql_parser_funcname(name, cp, 3); - - /* - * if A.B.C, it's not a function invoke, because can not use function of - * other database. if A.B, then it must be a function invoke. - */ - if (cp[2] && cp[2][0] != '\0') - return false; - else if (cp[0] && cp[0][0] != '\0') - { - /* these are function in pg_proc who are overloaded, so they can not be - * execured by := or direct call. - */ - if (pg_strcasecmp("ts_stat", cp[0]) == 0 || - pg_strcasecmp("ts_token_type", cp[0]) == 0 || - pg_strcasecmp("ts_parse", cp[0]) == 0 || - pg_strcasecmp("dblink_get_notify", cp[0]) == 0 || - pg_strcasecmp("ts_debug", cp[0]) == 0) - return false; - - keyword = (ScanKeyword *)ScanKeywordLookup(cp[0], ScanKeywords, NumScanKeywords); - /* function name can not be reserved keyword */ - if (keyword && RESERVED_KEYWORD == keyword->category) - return false; - /* and function name can not be unreserved keyword when no-parenthesis function is called.*/ - if(keyword && no_parenthesis && UNRESERVED_KEYWORD == keyword->category) - return false; - - if (cp[1] && cp[1][0] != '\0') - funcname = list_make2(makeString(cp[0]), makeString(cp[1])); - else - funcname = list_make1(makeString(cp[0])); - /* search the function */ - clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false); - if (!clist) - { - if (!is_assign) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", name))); - return false; - } - else if (clist->next) - { - if (is_assign) - return false; - else - return true; - } - else - { - proctup = SearchSysCache(PROCOID, - ObjectIdGetDatum(clist->oid), - 0, 0, 0); - if (!HeapTupleIsValid(proctup)) - { - if (!is_assign) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", name))); - return false; - } - - /* get the all args informations, only "in" parameters if p_argmodes is null */ - narg = get_func_arg_info(proctup,&p_argtypes, &p_argnames, &p_argmodes); - if (p_argmodes) - { - for (i = 0; i < narg; i++) - { - if ('o' == p_argmodes[i]) - { - have_outargs = true; - break; - } - } - } - ReleaseSysCache(proctup); - } - - if (!have_outargs && is_assign) - return false; - - return true;/* passed all test */ - } - return false; -} - -/* Convenience routine to read an expression with one possible terminator */ -static PLpgSQL_expr * -read_sql_expression(int until, const char *expected) -{ - return read_sql_construct(until, 0, 0, expected, - "SELECT ", true, true, true, NULL, NULL); -} - -/* Convenience routine to read an expression with two possible terminators */ -static PLpgSQL_expr * -read_sql_expression2(int until, int until2, const char *expected, - int *endtoken) -{ - return read_sql_construct(until, until2, 0, expected, - "SELECT ", true, true, true, NULL, endtoken); -} - -/* Convenience routine to read a SQL statement that must end with ';' */ -static PLpgSQL_expr * -read_sql_stmt(const char *sqlstart) -{ - return read_sql_construct(';', 0, 0, ";", - sqlstart, false, true, true, NULL, NULL); -} - -/* - * Brief : read a sql construct who has 4 expected tokens. - * Description : just like read_sql_construct function below, except that - * this function has 4 expected tokens. - * Notes : - */ - -/* - * Read a SQL construct and build a PLpgSQL_expr for it. - * - * until: token code for expected terminator - * until2: token code for alternate terminator (pass 0 if none) - * until3: token code for another alternate terminator (pass 0 if none) - * until4: token code for alternate terminator (pass 0 if none) - * until5: token code for alternate terminator (pass 0 if none) - * expected: text to use in complaining that terminator was not found - * sqlstart: text to prefix to the accumulated SQL text - * isexpression: whether to say we're reading an "expression" or a "statement" - * valid_sql: whether to check the syntax of the expr (prefixed with sqlstart) - * trim: trim trailing whitespace - * startloc: if not NULL, location of first token is stored at *startloc - * endtoken: if not NULL, ending token is stored at *endtoken - * (this is only interesting if until2 or until3 isn't zero) - */ -static PLpgSQL_expr * -read_sql_construct5(int until, - int until2, - int until3, - int until4, - int until5, - const char *expected, - const char *sqlstart, - bool isexpression, - bool valid_sql, - bool trim, - int *startloc, - int *endtoken) -{ - int tok; - StringInfoData ds; - IdentifierLookup save_IdentifierLookup; - int startlocation = -1; - int parenlevel = 0; - PLpgSQL_expr *expr; - MemoryContext oldCxt = NULL; - - /* - * buf stores the cursor attribute internal variables or - * varray ident with operate function, so NAMEDATALEN + 128 is enough - */ - char buf[NAMEDATALEN + 128]; - bool ds_changed = false; - List *list_left_bracket = 0; - List* list_right_bracket = 0; - const char left_bracket[2] = "["; - const char right_bracket[2] = "]"; - const char left_brack[2] = "("; - const char right_brack[2] = ")"; - int loc = 0; - int curloc = 0; - - /* - * ds will do a lot of enlarge, which need to relloc the space, and the old space - * will be return to current context. So if we don't switch the context, the original - * context will be Plpgsql function context, which has a long term life cycle, - * may cause memory accumulation. - */ - oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - initStringInfo(&ds); - MemoryContextSwitchTo(oldCxt); - - appendStringInfoString(&ds, sqlstart); - - /* special lookup mode for identifiers within the SQL text */ - save_IdentifierLookup = u_sess->plsql_cxt.plpgsql_IdentifierLookup; - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; - - for (;;) - { - tok = yylex(); - loc = yylloc; - if (startlocation < 0) /* remember loc of first token */ - startlocation = yylloc; - if (tok == until && parenlevel == 0) - break; - if (tok == until2 && parenlevel == 0) - break; - if (tok == until3 && parenlevel == 0) - break; - if (tok == until4 && parenlevel == 0) - break; - if (tok == until5 && parenlevel == 0) - break; - if (tok == '(' || tok == '[') - parenlevel++; - else if (tok == ')' || tok == ']') - { - parenlevel--; - if (parenlevel < 0) - yyerror("mismatched parentheses"); - } - /* - * End of function definition is an error, and we don't expect to - * hit a semicolon either (unless it's the until symbol, in which - * case we should have fallen out above). - */ - if (tok == 0 || tok == ';') - { - if (parenlevel != 0) - yyerror("mismatched parentheses"); - if (isexpression) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("missing \"%s\" at end of SQL expression", - expected), - parser_errposition(yylloc))); - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("missing \"%s\" at end of SQL statement", - expected), - parser_errposition(yylloc))); - } - - switch (tok) - { - case T_SQL_FOUND: - appendStringInfo(&ds, " __gsdb_sql_cursor_attri_found__ "); - ds_changed = true; - break; - case T_CURSOR_FOUND: - appendStringInfo(&ds, " __gsdb_cursor_attri_%d_found__ ", yylval.ival); - ds_changed = true; - break; - case T_SQL_NOTFOUND: - appendStringInfo(&ds, " __gsdb_sql_cursor_attri_notfound__ "); - ds_changed = true; - break; - case T_CURSOR_NOTFOUND: - appendStringInfo(&ds, " __gsdb_cursor_attri_%d_notfound__ ", yylval.ival); - ds_changed = true; - break; - case T_SQL_ISOPEN: - appendStringInfo(&ds, " __gsdb_sql_cursor_attri_isopen__ "); - ds_changed = true; - break; - case T_CURSOR_ISOPEN: - appendStringInfo(&ds, " __gsdb_cursor_attri_%d_isopen__ ", yylval.ival); - ds_changed = true; - break; - case T_SQL_ROWCOUNT: - appendStringInfo(&ds, " __gsdb_sql_cursor_attri_rowcount__ "); - ds_changed = true; - break; - case T_CURSOR_ROWCOUNT: - appendStringInfo(&ds, " __gsdb_cursor_attri_%d_rowcount__ ", yylval.ival); - ds_changed = true; - break; - case T_VARRAY_VAR: - tok = yylex(); - if('(' == tok) - { - list_left_bracket = lcons_int(parenlevel,list_left_bracket); - list_right_bracket = lcons_int(parenlevel,list_right_bracket); - } - curloc = yylloc; - plbsql_push_back_token(tok); - plpgsql_append_source_text(&ds, loc, curloc); - ds_changed = true; - break; - case T_ARRAY_FIRST: - appendStringInfo(&ds, " ARRAY_LOWER(%s, 1) ", ((Value *)linitial(yylval.wdatum.idents))->val.str); - ds_changed = true; - break; - case T_ARRAY_LAST: - appendStringInfo(&ds, " ARRAY_UPPER(%s, 1) ", ((Value *)linitial(yylval.wdatum.idents))->val.str); - ds_changed = true; - break; - case T_ARRAY_COUNT: - appendStringInfo(&ds, " ARRAY_LENGTH(%s, 1) ", ((Value *)linitial(yylval.wdatum.idents))->val.str); - ds_changed = true; - break; - case ')': - if (list_right_bracket && list_right_bracket->length - && linitial_int(list_right_bracket) == parenlevel) - { - appendStringInfoString(&ds, right_bracket); - list_right_bracket = list_delete_first(list_right_bracket); - } - else - appendStringInfoString(&ds,right_brack); - ds_changed = true; - break; - case '(': - if (list_left_bracket && list_left_bracket->length - && linitial_int(list_left_bracket) == parenlevel-1) - { - appendStringInfoString(&ds, left_bracket); - list_left_bracket = list_delete_first(list_left_bracket); - } - else - appendStringInfoString(&ds, left_brack); - ds_changed = true; - break; - case T_VARRAY: - if ('(' == yylex() && ')' == yylex()) - { - snprintf(buf, sizeof(buf), " NULL "); - appendStringInfoString(&ds, buf); - ds_changed = true; - } - else - { - /* do nothing */ - } - break; - default: - tok = yylex(); - - if(tok > INT_MAX) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("token value %d is bigger than INT_MAX ", tok))); - } - - curloc = yylloc; - plbsql_push_back_token(tok); - plpgsql_append_source_text(&ds, loc, curloc); - ds_changed = true; - break; - } - } - - u_sess->plsql_cxt.plpgsql_IdentifierLookup = save_IdentifierLookup; - - if (startloc) - *startloc = startlocation; - if (endtoken) - *endtoken = tok; - - /* give helpful complaint about empty input */ - if (startlocation >= yylloc) - { - if (isexpression) - yyerror("missing expression"); - else - yyerror("missing SQL statement"); - } - - if (!ds_changed) - plpgsql_append_source_text(&ds, startlocation, yylloc); - - /* trim any trailing whitespace, for neatness */ - if (trim) - { - while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1])) - ds.data[--ds.len] = '\0'; - } - - expr = (PLpgSQL_expr *)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(ds.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->isouttype = false; - expr->idx = (uint32)-1; - - pfree_ext(ds.data); - - if (valid_sql) - check_sql_expr(expr->query, startlocation, strlen(sqlstart)); - - return expr; -} - -/* - * Read a SQL construct and build a PLpgSQL_expr for it. - * - * until: token code for expected terminator - * until2: token code for alternate terminator (pass 0 if none) - * until3: token code for another alternate terminator (pass 0 if none) - * expected: text to use in complaining that terminator was not found - * sqlstart: text to prefix to the accumulated SQL text - * isexpression: whether to say we're reading an "expression" or a "statement" - * valid_sql: whether to check the syntax of the expr (prefixed with sqlstart) - * trim: trim trailing whitespace - * startloc: if not NULL, location of first token is stored at *startloc - * endtoken: if not NULL, ending token is stored at *endtoken - * (this is only interesting if until2 or until3 isn't zero) - */ -static PLpgSQL_expr * -read_sql_construct(int until, - int until2, - int until3, - const char *expected, - const char *sqlstart, - bool isexpression, - bool valid_sql, - bool trim, - int *startloc, - int *endtoken) -{ - return read_sql_construct5(until, until2, until3, until3, 0, - expected, sqlstart, isexpression, valid_sql, trim, startloc, endtoken); -} - -static PLpgSQL_type * -read_datatype(int tok) -{ - StringInfoData ds; - char *type_name; - int startlocation; - PLpgSQL_type *result; - int parenlevel = 0; - - /* Should only be called while parsing DECLARE sections */ - AssertEreport(u_sess->plsql_cxt.plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE, - MOD_PLSQL, - "Should only be called while parsing DECLARE sections"); - - /* Often there will be a lookahead token, but if not, get one */ - if (tok == YYEMPTY) - tok = yylex(); - - startlocation = yylloc; - - /* - * If we have a simple or composite identifier, check for %TYPE - * and %ROWTYPE constructs. - */ - if (tok == T_WORD) - { - char *dtname = yylval.word.ident; - - tok = yylex(); - if (tok == '%') - { - tok = yylex(); - if (tok_is_keyword(tok, &yylval, - K_TYPE, "type")) - { - result = plpgsql_parse_wordtype(dtname); - if (result) - return result; - } - else if (tok_is_keyword(tok, &yylval, - K_ROWTYPE, "rowtype")) - { - PLpgSQL_nsitem *ns; - ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, - dtname, NULL, NULL, NULL); - if (ns && ns->itemtype == PLPGSQL_NSTYPE_VAR) - { - PLpgSQL_var* var = (PLpgSQL_var*)u_sess->plsql_cxt.plpgsql_Datums[ns->itemno]; - if(var && var->datatype - && var->datatype->typoid == REFCURSOROID) - { - return plpgsql_build_datatype(RECORDOID, -1, InvalidOid); - } - } - result = plpgsql_parse_wordrowtype(dtname); - if (result) - return result; - } - } - } - else if (tok == T_CWORD) - { - List *dtnames = yylval.cword.idents; - - tok = yylex(); - if (tok == '%') - { - tok = yylex(); - if (tok_is_keyword(tok, &yylval, - K_TYPE, "type")) - { - result = plpgsql_parse_cwordtype(dtnames); - if (result) - return result; - } - else if (tok_is_keyword(tok, &yylval, - K_ROWTYPE, "rowtype")) - { - result = plpgsql_parse_cwordrowtype(dtnames); - if (result) - return result; - } - } - } - - while (tok != ';') - { - if (tok == 0) - { - if (parenlevel != 0) - yyerror("mismatched parentheses"); - else - yyerror("incomplete data type declaration"); - } - /* Possible followers for datatype in a declaration */ - if (tok == K_COLLATE || tok == K_NOT || - tok == '=' || tok == COLON_EQUALS || tok == K_DEFAULT) - break; - /* Possible followers for datatype in a cursor_arg list */ - if ((tok == ',' || tok == ')') && parenlevel == 0) - break; - if (tok == '(') - parenlevel++; - else if (tok == ')') - parenlevel--; - - tok = yylex(); - } - - /* set up ds to contain complete typename text */ - initStringInfo(&ds); - plpgsql_append_source_text(&ds, startlocation, yylloc); - type_name = ds.data; - - if (type_name[0] == '\0') - yyerror("missing data type declaration"); - - result = parse_datatype(type_name, startlocation); - - pfree_ext(ds.data); - - plbsql_push_back_token(tok); - - return result; -} - -static PLpgSQL_stmt * -make_execsql_stmt(int firsttoken, int location) -{ - StringInfoData ds; - IdentifierLookup save_IdentifierLookup; - PLpgSQL_stmt_execsql *execsql; - PLpgSQL_expr *expr; - PLpgSQL_row *row = NULL; - PLpgSQL_rec *rec = NULL; - int tok; - int prev_tok; - bool have_into = false; - bool have_strict = false; - int into_start_loc = -1; - int into_end_loc = -1; - int placeholders = 0; - - initStringInfo(&ds); - - /* special lookup mode for identifiers within the SQL text */ - save_IdentifierLookup = u_sess->plsql_cxt.plpgsql_IdentifierLookup; - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; - - /* - * Scan to the end of the SQL command. Identify any INTO-variables - * clause lurking within it, and parse that via read_into_target(). - * - * Because INTO is sometimes used in the main SQL grammar, we have to be - * careful not to take any such usage of INTO as a PL/pgSQL INTO clause. - * There are currently three such cases: - * - * 1. SELECT ... INTO. We don't care, we just override that with the - * PL/pgSQL definition. - * - * 2. INSERT INTO. This is relatively easy to recognize since the words - * must appear adjacently; but we can't assume INSERT starts the command, - * because it can appear in CREATE RULE or WITH. Unfortunately, INSERT is - * *not* fully reserved, so that means there is a chance of a false match; - * but it's not very likely. - * - * 3. ALTER TABLE PARTITION MERGE or SPLIT INTO. - * We just check for ALTER as the command's first token. - * - * Fortunately, INTO is a fully reserved word in the main grammar, so - * at least we need not worry about it appearing as an identifier. - * - * Any future additional uses of INTO in the main grammar will doubtless - * break this logic again ... beware! - */ - tok = firsttoken; - - for (;;) - { - prev_tok = tok; - tok = yylex(); - - if (have_into && into_end_loc < 0) - into_end_loc = yylloc; /* token after the INTO part */ - if (tok == ';') - break; - if (tok == 0) - yyerror("unexpected end of function definition"); - - if(tok == T_PLACEHOLDER) - { - placeholders++; - } - - if (tok == K_INTO) - { - if (prev_tok == K_INSERT) - continue; /* INSERT INTO is not an INTO-target */ - if (firsttoken == K_ALTER) - continue; /* ALTER ... INTO is not an INTO-target */ - if (prev_tok == K_MERGE) - continue; /* MERGE INTO is not an INTO-target */ - if (have_into) - yyerror("INTO specified more than once"); - have_into = true; - into_start_loc = yylloc; - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - read_into_target(&rec, &row, &have_strict); - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; - } - } - - u_sess->plsql_cxt.plpgsql_IdentifierLookup = save_IdentifierLookup; - - if (have_into) - { - /* - * Insert an appropriate number of spaces corresponding to the - * INTO text, so that locations within the redacted SQL statement - * still line up with those in the original source text. - */ - plpgsql_append_source_text(&ds, location, into_start_loc); - appendStringInfoSpaces(&ds, into_end_loc - into_start_loc); - plpgsql_append_source_text(&ds, into_end_loc, yylloc); - } - else - plpgsql_append_source_text(&ds, location, yylloc); - - /* trim any trailing whitespace, for neatness */ - while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1])) - ds.data[--ds.len] = '\0'; - - expr = (PLpgSQL_expr *)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(ds.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->idx = (uint32)-1; - pfree_ext(ds.data); - - check_sql_expr(expr->query, location, 0); - - execsql = (PLpgSQL_stmt_execsql *)palloc(sizeof(PLpgSQL_stmt_execsql)); - execsql->cmd_type = PLPGSQL_STMT_EXECSQL; - execsql->lineno = plpgsql_location_to_lineno(location); - execsql->sqlstmt = expr; - execsql->into = have_into; - execsql->strict = have_strict; - execsql->rec = rec; - execsql->row = row; - execsql->placeholders = placeholders; - - return (PLpgSQL_stmt *) execsql; -} - - -/* - * Read FETCH or MOVE direction clause (everything through FROM/IN). - */ -static PLpgSQL_stmt_fetch * -read_fetch_direction(void) -{ - PLpgSQL_stmt_fetch *fetch; - int tok; - bool check_FROM = true; - - /* - * We create the PLpgSQL_stmt_fetch struct here, but only fill in - * the fields arising from the optional direction clause - */ - fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch)); - fetch->cmd_type = PLPGSQL_STMT_FETCH; - /* set direction defaults: */ - fetch->direction = FETCH_FORWARD; - fetch->how_many = 1; - fetch->expr = NULL; - fetch->returns_multiple_rows = false; - - tok = yylex(); - if (tok == 0) - yyerror("unexpected end of function definition"); - - if (tok_is_keyword(tok, &yylval, - K_NEXT, "next")) - { - /* use defaults */ - } - else if (tok_is_keyword(tok, &yylval, - K_PRIOR, "prior")) - { - fetch->direction = FETCH_BACKWARD; - } - else if (tok_is_keyword(tok, &yylval, - K_FIRST, "first")) - { - fetch->direction = FETCH_ABSOLUTE; - } - else if (tok_is_keyword(tok, &yylval, - K_LAST, "last")) - { - fetch->direction = FETCH_ABSOLUTE; - fetch->how_many = -1; - } - else if (tok_is_keyword(tok, &yylval, - K_ABSOLUTE, "absolute")) - { - fetch->direction = FETCH_ABSOLUTE; - fetch->expr = read_sql_expression2(K_FROM, K_IN, - "FROM or IN", - NULL); - check_FROM = false; - } - else if (tok_is_keyword(tok, &yylval, - K_RELATIVE, "relative")) - { - fetch->direction = FETCH_RELATIVE; - fetch->expr = read_sql_expression2(K_FROM, K_IN, - "FROM or IN", - NULL); - check_FROM = false; - } - else if (tok_is_keyword(tok, &yylval, - K_ALL, "all")) - { - fetch->how_many = FETCH_ALL; - fetch->returns_multiple_rows = true; - } - else if (tok_is_keyword(tok, &yylval, - K_FORWARD, "forward")) - { - complete_direction(fetch, &check_FROM); - } - else if (tok_is_keyword(tok, &yylval, - K_BACKWARD, "backward")) - { - fetch->direction = FETCH_BACKWARD; - complete_direction(fetch, &check_FROM); - } - else if (tok == K_FROM || tok == K_IN) - { - /* empty direction */ - check_FROM = false; - } - else if (tok == T_DATUM) - { - /* Assume there's no direction clause and tok is a cursor name */ - plbsql_push_back_token(tok); - check_FROM = false; - } - else - { - /* - * Assume it's a count expression with no preceding keyword. - * Note: we allow this syntax because core SQL does, but we don't - * document it because of the ambiguity with the omitted-direction - * case. For instance, "MOVE n IN c" will fail if n is a variable. - * Perhaps this can be improved someday, but it's hardly worth a - * lot of work. - */ - plbsql_push_back_token(tok); - fetch->expr = read_sql_expression2(K_FROM, K_IN, - "FROM or IN", - NULL); - fetch->returns_multiple_rows = true; - check_FROM = false; - } - - /* check FROM or IN keyword after direction's specification */ - if (check_FROM) - { - tok = yylex(); - if (tok != K_FROM && tok != K_IN) - yyerror("expected FROM or IN"); - } - - return fetch; -} - -/* - * Process remainder of FETCH/MOVE direction after FORWARD or BACKWARD. - * Allows these cases: - * FORWARD expr, FORWARD ALL, FORWARD - * BACKWARD expr, BACKWARD ALL, BACKWARD - */ -static void -complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM) -{ - int tok; - - tok = yylex(); - if (tok == 0) - yyerror("unexpected end of function definition"); - - if (tok == K_FROM || tok == K_IN) - { - *check_FROM = false; - return; - } - - if (tok == K_ALL) - { - fetch->how_many = FETCH_ALL; - fetch->returns_multiple_rows = true; - *check_FROM = true; - return; - } - - plbsql_push_back_token(tok); - fetch->expr = read_sql_expression2(K_FROM, K_IN, - "FROM or IN", - NULL); - fetch->returns_multiple_rows = true; - *check_FROM = false; -} - - -static PLpgSQL_stmt * -make_return_stmt(int location) -{ - PLpgSQL_stmt_return *newp; - int token = -1; - - newp = (PLpgSQL_stmt_return *)palloc0(sizeof(PLpgSQL_stmt_return)); - newp->cmd_type = PLPGSQL_STMT_RETURN; - newp->lineno = plpgsql_location_to_lineno(location); - newp->expr = NULL; - newp->retvarno = -1; - - if (u_sess->plsql_cxt.plpgsql_curr_compile->fn_retset) - { - if (yylex() != ';') - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN cannot have a parameter in function returning set"), - errhint("Use RETURN NEXT or RETURN QUERY."), - parser_errposition(yylloc))); - } - - // adapting A db, where return value is independent from OUT parameters - else if (';' == (token = yylex()) && u_sess->plsql_cxt.plpgsql_curr_compile->out_param_varno >= 0) - newp->retvarno = u_sess->plsql_cxt.plpgsql_curr_compile->out_param_varno; - else - { - plbsql_push_back_token(token); - if (u_sess->plsql_cxt.plpgsql_curr_compile->fn_rettype == VOIDOID) - { - if (yylex() != ';') - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN cannot have a parameter in function returning void"), - parser_errposition(yylloc))); - } - else if (u_sess->plsql_cxt.plpgsql_curr_compile->fn_retistuple) - { - int tok = yylex(); - if(tok < 0) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("token value %d is smaller than 0 ", tok))); - return NULL; - } - - switch (tok) - { - case K_NULL: - /* we allow this to support RETURN NULL in triggers */ - break; - - case T_DATUM: - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) - newp->retvarno = yylval.wdatum.datum->dno; - else - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN must specify a record or row variable in function returning row"), - parser_errposition(yylloc))); - break; - - default: - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN must specify a record or row variable in function returning row"), - parser_errposition(yylloc))); - break; - } - if (yylex() != ';') - yyerror("syntax error"); - } - else - { - /* - * Note that a well-formed expression is _required_ here; - * anything else is a compile-time error. - */ - newp->expr = read_sql_expression(';', ";"); - } - } - - return (PLpgSQL_stmt *) newp; -} - - -static PLpgSQL_stmt * -make_return_next_stmt(int location) -{ - PLpgSQL_stmt_return_next *newp; - - if (!u_sess->plsql_cxt.plpgsql_curr_compile->fn_retset) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use RETURN NEXT in a non-SETOF function"), - parser_errposition(location))); - - newp = (PLpgSQL_stmt_return_next *)palloc0(sizeof(PLpgSQL_stmt_return_next)); - newp->cmd_type = PLPGSQL_STMT_RETURN_NEXT; - newp->lineno = plpgsql_location_to_lineno(location); - newp->expr = NULL; - newp->retvarno = -1; - - if (u_sess->plsql_cxt.plpgsql_curr_compile->out_param_varno >= 0) - { - if (yylex() != ';') - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"), - parser_errposition(yylloc))); - newp->retvarno = u_sess->plsql_cxt.plpgsql_curr_compile->out_param_varno; - } - else if (u_sess->plsql_cxt.plpgsql_curr_compile->fn_retistuple) - { - switch (yylex()) - { - case T_DATUM: - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) - newp->retvarno = yylval.wdatum.datum->dno; - else - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN NEXT must specify a record or row variable in function returning row"), - parser_errposition(yylloc))); - break; - - default: - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("RETURN NEXT must specify a record or row variable in function returning row"), - parser_errposition(yylloc))); - break; - } - if (yylex() != ';') - yyerror("syntax error"); - } - else - newp->expr = read_sql_expression(';', ";"); - - return (PLpgSQL_stmt *) newp; -} - - -static PLpgSQL_stmt * -make_return_query_stmt(int location) -{ - PLpgSQL_stmt_return_query *newp; - int tok; - - if (!u_sess->plsql_cxt.plpgsql_curr_compile->fn_retset) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot use RETURN QUERY in a non-SETOF function"), - parser_errposition(location))); - - newp = (PLpgSQL_stmt_return_query *)palloc0(sizeof(PLpgSQL_stmt_return_query)); - newp->cmd_type = PLPGSQL_STMT_RETURN_QUERY; - newp->lineno = plpgsql_location_to_lineno(location); - - /* check for RETURN QUERY EXECUTE */ - if ((tok = yylex()) != K_EXECUTE) - { - /* ordinary static query */ - plbsql_push_back_token(tok); - newp->query = read_sql_stmt(""); - } - else - { - /* dynamic SQL */ - int term; - - newp->dynquery = read_sql_expression2(';', K_USING, "; or USING", - &term); - if (term == K_USING) - { - do - { - PLpgSQL_expr *expr; - - expr = read_sql_expression2(',', ';', ", or ;", &term); - newp->params = lappend(newp->params, expr); - } while (term == ','); - } - } - - return (PLpgSQL_stmt *) newp; -} - - -/* convenience routine to fetch the name of a T_DATUM */ -static char * -NameOfDatum(PLwdatum *wdatum) -{ - if (wdatum->ident) - return wdatum->ident; - AssertEreport(wdatum->idents != NIL, - MOD_PLSQL, - "It should not be null"); - return NameListToString(wdatum->idents); -} - -static void -check_assignable(PLpgSQL_datum *datum, int location) -{ - switch (datum->dtype) - { - case PLPGSQL_DTYPE_VAR: - if (((PLpgSQL_var *) datum)->isconst) - ereport(ERROR, - (errcode(ERRCODE_ERROR_IN_ASSIGNMENT), - errmsg("\"%s\" is declared CONSTANT", - ((PLpgSQL_var *) datum)->refname), - parser_errposition(location))); - break; - case PLPGSQL_DTYPE_ROW: - /* always assignable? */ - break; - case PLPGSQL_DTYPE_REC: - /* always assignable? What about NEW/OLD? */ - break; - case PLPGSQL_DTYPE_RECORD: - break; - case PLPGSQL_DTYPE_RECFIELD: - /* always assignable? */ - break; - case PLPGSQL_DTYPE_ARRAYELEM: - /* always assignable? */ - break; - default: - elog(ERROR, "unrecognized dtype: %d", datum->dtype); - break; - } -} - -/* - * Brief : support array variable as select into and using out target. - * Description : if an array element is detected, add it to the u_sess->plsql_cxt.plpgsql_Datums[] - * and return true, else return false. - * Notes : - */ -static bool -read_into_using_add_arrayelem(char **fieldnames, int *varnos, int *nfields, int tmpdno, int *tok) -{ - PLpgSQL_arrayelem *newp = NULL; - char tokExpected[2]; - int toktmp = 0; - - /* validation of arguments */ - if ((NULL == fieldnames) || (NULL == varnos) || (NULL == nfields) || (NULL == tok)) - { - ereport(ERROR, - (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), - errmsg(" pointer is null in read_into_add_arrayelem function! "))); - return false; - } - - if (('[' == *tok) || ('(' == *tok)) - { - if ('[' == *tok) - toktmp = ']'; - else - toktmp = ')'; - - tokExpected[0] = (char)toktmp; - tokExpected[1] = '\0'; - - newp = (PLpgSQL_arrayelem *)palloc0(sizeof(PLpgSQL_arrayelem)); - newp->arrayparentno = tmpdno; - newp->dtype = PLPGSQL_DTYPE_ARRAYELEM; - /* get the array index expression */ - newp->subscript = read_sql_expression(toktmp, &tokExpected[0]); - - if(NULL == newp->subscript) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg(" error near arrary name! "))); - - plpgsql_adddatum((PLpgSQL_datum *)newp); - - fieldnames[*nfields] = pstrdup("arrayelem"); - varnos[(*nfields)++] = newp->dno; - - *tok = yylex(); - - /* is an array element, return true */ - return true; - } - - return false; -} - -/* - * Read the argument of an INTO clause. On entry, we have just read the - * INTO keyword. - */ -static void -read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict) -{ - int tok; - - /* Set default results */ - *rec = NULL; - *row = NULL; - if (strict) - *strict = true; - - tok = yylex(); - if (strict && tok == K_STRICT) - { - *strict = true; - tok = yylex(); - } - - /* - * Currently, a row or record variable can be the single INTO target, - * but not a member of a multi-target list. So we throw error if there - * is a comma after it, because that probably means the user tried to - * write a multi-target list. If this ever gets generalized, we should - * probably refactor read_into_scalar_list so it handles all cases. - */ - switch (tok) - { - case T_DATUM: - case T_VARRAY_VAR: - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW - || yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_RECORD) - { - check_assignable(yylval.wdatum.datum, yylloc); - *row = (PLpgSQL_row *) yylval.wdatum.datum; - - if ((tok = yylex()) == ',') - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("record or row variable cannot be part of multiple-item INTO list"), - parser_errposition(yylloc))); - plbsql_push_back_token(tok); - } - else if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) - { - check_assignable(yylval.wdatum.datum, yylloc); - *rec = (PLpgSQL_rec *) yylval.wdatum.datum; - - if ((tok = yylex()) == ',') - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("record or row variable cannot be part of multiple-item INTO list"), - parser_errposition(yylloc))); - plbsql_push_back_token(tok); - } - else - { - *row = read_into_array_scalar_list(NameOfDatum(&(yylval.wdatum)), - yylval.wdatum.datum, yylloc); - } - break; - - case T_PLACEHOLDER: - *row = read_into_placeholder_scalar_list(yylval.word.ident, yylloc); - break; - - default: - /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok); - break; - } -} - -/* - * Read the argument of an USING IN / OUT clause. - */ -static void -read_using_target(List **in_expr, PLpgSQL_row **out_row) -{ - int tok = 0; - int out_nfields= 0; - int out_varnos[1024] = {0}; - char *out_fieldnames[1024] = {0}; - bool isin = false; - - *in_expr = NULL; - *out_row = NULL; - - do - { - tok=yylex(); - if(K_IN == tok) - { - tok = yylex(); - isin = true; - } - - if(K_OUT == tok) - { - char * tempvar = NULL; - int tempdno = 0; - PLpgSQL_expr * tempexpr = NULL; - - tok = yylex(); - - switch(tok) - { - case T_DATUM: - tempvar = pstrdup(NameOfDatum(&(yylval.wdatum))); - tempdno = yylval.wdatum.datum->dno; - plbsql_push_back_token(tok); - tempexpr =read_sql_construct(',',';',',',", or ;","SELECT ",true,true,true,NULL,&tok); - tempexpr->isouttype = true; - *in_expr=lappend((*in_expr), tempexpr); - - if (!read_into_using_add_arrayelem(out_fieldnames, out_varnos, &out_nfields,tempdno,&tok)) - { - out_fieldnames[out_nfields] = tempvar; - out_varnos[out_nfields++] = tempdno; - } - else - { - if (isin) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg(" using can't support array parameter with in out !"))); - - } - - break; - - default: - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("not all the parameters are scalar variables."))); - } - } - else - { - PLpgSQL_expr * expr = NULL; - plbsql_push_back_token(tok); - expr = read_sql_construct(',',';',',',", or ;","SELECT ",true,true,true,NULL,&tok); - *in_expr=lappend((*in_expr), expr); - - isin = false; - - } - - }while(tok== ','); - - /* - * We read an extra, non-comma token from yylex(), so push it - * back onto the input stream - */ - plbsql_push_back_token(tok); - - if(out_nfields) - { - (*out_row) = (PLpgSQL_row*)palloc0(sizeof(PLpgSQL_row)); - (*out_row)->dtype = PLPGSQL_DTYPE_ROW; - (*out_row)->refname = pstrdup("*internal*"); - (*out_row)->lineno = plpgsql_location_to_lineno(yylloc); - (*out_row)->rowtupdesc = NULL; - (*out_row)->nfields = out_nfields; - (*out_row)->fieldnames = (char **)palloc(sizeof(char *) * out_nfields); - (*out_row)->varnos = (int *)palloc(sizeof(int) * out_nfields); - while (--out_nfields >= 0) - { - (*out_row)->fieldnames[out_nfields] = out_fieldnames[out_nfields]; - (*out_row)->varnos[out_nfields] = out_varnos[out_nfields]; - } - plpgsql_adddatum((PLpgSQL_datum *)(*out_row)); - } -} - -/* - * Given the first datum and name in the INTO list, continue to read - * comma-separated scalar variables until we run out. Then construct - * and return a fake "row" variable that represents the list of - * scalars. - */ -static PLpgSQL_row * -read_into_scalar_list(char *initial_name, - PLpgSQL_datum *initial_datum, - int initial_location) -{ - int nfields; - char *fieldnames[1024] = {NULL}; - int varnos[1024] = {0}; - PLpgSQL_row *row; - int tok; - - check_assignable(initial_datum, initial_location); - fieldnames[0] = initial_name; - varnos[0] = initial_datum->dno; - nfields = 1; - - while ((tok = yylex()) == ',') - { - /* Check for array overflow */ - if (nfields >= 1024) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many INTO variables specified"), - parser_errposition(yylloc))); - - tok = yylex(); - switch (tok) - { - case T_DATUM: - check_assignable(yylval.wdatum.datum, yylloc); - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&(yylval.wdatum))), - parser_errposition(yylloc))); - fieldnames[nfields] = NameOfDatum(&(yylval.wdatum)); - varnos[nfields++] = yylval.wdatum.datum->dno; - break; - - default: - /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok); - break; - } - } - - /* - * We read an extra, non-comma token from yylex(), so push it - * back onto the input stream - */ - plbsql_push_back_token(tok); - - row = (PLpgSQL_row *)palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = plpgsql_location_to_lineno(initial_location); - row->rowtupdesc = NULL; - row->nfields = nfields; - row->fieldnames = (char **)palloc(sizeof(char *) * nfields); - row->varnos = (int *)palloc(sizeof(int) * nfields); - while (--nfields >= 0) - { - row->fieldnames[nfields] = fieldnames[nfields]; - row->varnos[nfields] = varnos[nfields]; - } - - plpgsql_adddatum((PLpgSQL_datum *)row); - - return row; -} - -/* - * Given the first datum and name in the INTO list, continue to read - * comma-separated scalar variables until we run out. Then construct - * and return a fake "row" variable that represents the list of - * scalars. - */ -static PLpgSQL_row * -read_into_array_scalar_list(char *initial_name, - PLpgSQL_datum *initial_datum, - int initial_location) -{ - int nfields = 0; - char *fieldnames[1024] = {NULL}; - int varnos[1024] = {0}; - PLpgSQL_row *row; - int tok; - int toktmp = 0; - int tmpdno = 0; - char* nextname = NULL; - - check_assignable(initial_datum, initial_location); - tmpdno = yylval.wdatum.datum->dno; - tok = yylex(); - if (!read_into_using_add_arrayelem(fieldnames, varnos, &nfields, tmpdno, &tok)) - { - fieldnames[0] = initial_name; - varnos[0] = initial_datum->dno; - nfields = 1; - } - while (',' == tok) - { - /* Check for array overflow */ - if (nfields >= 1024) - { - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many INTO variables specified"), - parser_errposition(yylloc))); - return NULL; - } - - toktmp = yylex(); - - switch (toktmp) - { - case T_DATUM: - check_assignable(yylval.wdatum.datum, yylloc); - - if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || - yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a scalar variable", - NameOfDatum(&(yylval.wdatum))), - parser_errposition(yylloc))); - - tmpdno = yylval.wdatum.datum->dno; - nextname = NameOfDatum(&(yylval.wdatum)); - fieldnames[nfields] = nextname; - varnos[nfields++] = tmpdno; - tok = yylex(); - break; - case T_VARRAY_VAR: - check_assignable(yylval.wdatum.datum, yylloc); - tmpdno = yylval.wdatum.datum->dno; - tok = yylex(); - if (tok < -1) - return NULL; - if (!read_into_using_add_arrayelem(fieldnames, varnos, &nfields, tmpdno, &tok)) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg(" error near arrary name! "))); - return NULL; - } - break; - default: - tok = yylex(); - if (tok < -1) - return NULL; - - /* just to give a better message than "syntax error" */ - current_token_is_not_variable(tok); - break; - } - } - - /* - * We read an extra, non-comma token from yylex(), so push it - * back onto the input stream - */ - plbsql_push_back_token(tok); - - row = (PLpgSQL_row*)palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = plpgsql_location_to_lineno(initial_location); - row->rowtupdesc = NULL; - row->nfields = nfields; - row->fieldnames = (char**)palloc(sizeof(char *) * nfields); - row->varnos = (int*)palloc(sizeof(int) * nfields); - while (--nfields >= 0) - { - row->fieldnames[nfields] = fieldnames[nfields]; - row->varnos[nfields] = varnos[nfields]; - } - - plpgsql_adddatum((PLpgSQL_datum *)row); - - return row; -} - - - -/* - * Given the first datum and name in the INTO list, continue to read - * comma-separated scalar variables until we run out. Then construct - * and return a fake "row" variable that represents the list of - * scalars. The function is for placeholders. - */ -static PLpgSQL_row * -read_into_placeholder_scalar_list(char *initial_name, - int initial_location) -{ - int intoplaceholders; - PLpgSQL_row *row; - int tok; - - intoplaceholders = 1; - - while ((tok = yylex()) == ',') - { - /* Check for array overflow */ - if ( intoplaceholders >= 1024 ) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("too many INTO placeholders specified"), - parser_errposition(yylloc))); - - tok = yylex(); - switch (tok) - { - case T_PLACEHOLDER: - intoplaceholders++; - break; - - default: - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid placeholder specified"), - parser_errposition(yylloc))); - break; - } - } - - /* - * We read an extra, non-comma token from yylex(), so push it - * back onto the input stream - */ - plbsql_push_back_token(tok); - - row = (PLpgSQL_row*)palloc0(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = plpgsql_location_to_lineno(initial_location); - row->rowtupdesc = NULL; - row->nfields = 0; - row->fieldnames = NULL; - row->varnos = NULL; - row->intoplaceholders = intoplaceholders; - row->intodatums = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)row); - - return row; -} - - - -/* - * Convert a single scalar into a "row" list. This is exactly - * like read_into_scalar_list except we never consume any input. - * - * Note: lineno could be computed from location, but since callers - * have it at hand already, we may as well pass it in. - */ -static PLpgSQL_row * -make_scalar_list1(char *initial_name, - PLpgSQL_datum *initial_datum, - int lineno, int location) -{ - PLpgSQL_row *row; - - check_assignable(initial_datum, location); - - row = (PLpgSQL_row *)palloc(sizeof(PLpgSQL_row)); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = pstrdup("*internal*"); - row->lineno = lineno; - row->rowtupdesc = NULL; - row->nfields = 1; - row->fieldnames = (char **)palloc(sizeof(char *)); - row->varnos = (int *)palloc(sizeof(int)); - row->fieldnames[0] = initial_name; - row->varnos[0] = initial_datum->dno; - - plpgsql_adddatum((PLpgSQL_datum *)row); - - return row; -} - -/* - * When the PL/pgSQL parser expects to see a SQL statement, it is very - * liberal in what it accepts; for example, we often assume an - * unrecognized keyword is the beginning of a SQL statement. This - * avoids the need to duplicate parts of the SQL grammar in the - * PL/pgSQL grammar, but it means we can accept wildly malformed - * input. To try and catch some of the more obviously invalid input, - * we run the strings we expect to be SQL statements through the main - * SQL parser. - * - * We only invoke the raw parser (not the analyzer); this doesn't do - * any database access and does not check any semantic rules, it just - * checks for basic syntactic correctness. We do this here, rather - * than after parsing has finished, because a malformed SQL statement - * may cause the PL/pgSQL parser to become confused about statement - * borders. So it is best to bail out as early as we can. - * - * It is assumed that "stmt" represents a copy of the function source text - * beginning at offset "location", with leader text of length "leaderlen" - * (typically "SELECT ") prefixed to the source text. We use this assumption - * to transpose any error cursor position back to the function source text. - * If no error cursor is provided, we'll just point at "location". - */ -static void -check_sql_expr(const char *stmt, int location, int leaderlen) -{ - sql_error_callback_arg cbarg; - ErrorContextCallback syntax_errcontext; - MemoryContext oldCxt; - - if (!u_sess->plsql_cxt.plpgsql_check_syntax) - return; - - cbarg.location = location; - cbarg.leaderlen = leaderlen; - - syntax_errcontext.callback = plpgsql_sql_error_callback; - syntax_errcontext.arg = &cbarg; - syntax_errcontext.previous = t_thrd.log_cxt.error_context_stack; - t_thrd.log_cxt.error_context_stack = &syntax_errcontext; - - oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - (void) db_b_raw_parser(stmt); - MemoryContextSwitchTo(oldCxt); - - /* Restore former ereport callback */ - t_thrd.log_cxt.error_context_stack = syntax_errcontext.previous; -} - -static void -plpgsql_sql_error_callback(void *arg) -{ - sql_error_callback_arg *cbarg = (sql_error_callback_arg *) arg; - int errpos; - - /* - * First, set up internalerrposition to point to the start of the - * statement text within the function text. Note this converts - * location (a byte offset) to a character number. - */ - parser_errposition(cbarg->location); - - /* - * If the core parser provided an error position, transpose it. - * Note we are dealing with 1-based character numbers at this point. - */ - errpos = geterrposition(); - if (errpos > cbarg->leaderlen) - { - int myerrpos = getinternalerrposition(); - - if (myerrpos > 0) /* safety check */ - internalerrposition(myerrpos + errpos - cbarg->leaderlen - 1); - } - - /* In any case, flush errposition --- we want internalerrpos only */ - errposition(0); -} - -/* - * Parse a SQL datatype name and produce a PLpgSQL_type structure. - * - * The heavy lifting is done elsewhere. Here we are only concerned - * with setting up an errcontext link that will let us give an error - * cursor pointing into the plpgsql function source, if necessary. - * This is handled the same as in check_sql_expr(), and we likewise - * expect that the given string is a copy from the source text. - */ -static PLpgSQL_type * -parse_datatype(const char *string, int location) -{ - Oid type_id; - int32 typmod; - sql_error_callback_arg cbarg; - ErrorContextCallback syntax_errcontext; - MemoryContext oldCxt = NULL; - - cbarg.location = location; - cbarg.leaderlen = 0; - - syntax_errcontext.callback = plpgsql_sql_error_callback; - syntax_errcontext.arg = &cbarg; - syntax_errcontext.previous = t_thrd.log_cxt.error_context_stack; - t_thrd.log_cxt.error_context_stack = &syntax_errcontext; - - /* - * parseTypeString is only for getting type_id and typemod, who are both scalars, - * so memory used in it is all temp. - */ - oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - - /* Let the main parser try to parse it under standard SQL rules */ - parseTypeString(string, &type_id, &typmod); - - (void)MemoryContextSwitchTo(oldCxt); - - /* Restore former ereport callback */ - t_thrd.log_cxt.error_context_stack = syntax_errcontext.previous; - - /* Okay, build a PLpgSQL_type data structure for it */ - return plpgsql_build_datatype(type_id, typmod, - u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation); -} - -/* - * Check block starting and ending labels match. - */ -static void -check_labels(const char *start_label, const char *end_label, int end_location) -{ - if (end_label) - { - if (!start_label) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("end label \"%s\" specified for unlabelled block", - end_label), - parser_errposition(end_location))); - - if (strcmp(start_label, end_label) != 0) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("end label \"%s\" differs from block's label \"%s\"", - end_label, start_label), - parser_errposition(end_location))); - } -} - -/* - * Read the arguments (if any) for a cursor, followed by the until token - * - * If cursor has no args, just swallow the until token and return NULL. - * If it does have args, we expect to see "( arg [, arg ...] )" followed - * by the until token, where arg may be a plain expression, or a named - * parameter assignment of the form argname := expr. Consume all that and - * return a SELECT query that evaluates the expression(s) (without the outer - * parens). - */ -static PLpgSQL_expr * -read_cursor_args(PLpgSQL_var *cursor, int until, const char *expected) -{ - PLpgSQL_expr *expr; - PLpgSQL_row *row; - int tok; - int argc; - char **argv; - StringInfoData ds; - char *sqlstart = "SELECT "; - bool any_named = false; - - tok = yylex(); - if (cursor->cursor_explicit_argrow < 0) - { - /* No arguments expected */ - if (tok == '(') - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cursor \"%s\" has no arguments", - cursor->refname), - parser_errposition(yylloc))); - - if (tok != until) - yyerror("syntax error"); - - return NULL; - } - - /* Else better provide arguments */ - if (tok != '(') - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cursor \"%s\" has arguments", - cursor->refname), - parser_errposition(yylloc))); - - /* - * Read the arguments, one by one. - */ - row = (PLpgSQL_row *) u_sess->plsql_cxt.plpgsql_Datums[cursor->cursor_explicit_argrow]; - argv = (char **) palloc0(row->nfields * sizeof(char *)); - - for (argc = 0; argc < row->nfields; argc++) - { - PLpgSQL_expr *item; - int endtoken; - int argpos; - int tok1, - tok2; - int arglocation; - - /* Check if it's a named parameter: "param := value" */ - plpgsql_peek2(&tok1, &tok2, &arglocation, NULL); - if (tok1 == IDENT && tok2 == COLON_EQUALS) - { - char *argname; - IdentifierLookup save_IdentifierLookup; - - /* Read the argument name, ignoring any matching variable */ - save_IdentifierLookup = u_sess->plsql_cxt.plpgsql_IdentifierLookup; - u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE; - yylex(); - argname = yylval.str; - u_sess->plsql_cxt.plpgsql_IdentifierLookup = save_IdentifierLookup; - - /* Match argument name to cursor arguments */ - for (argpos = 0; argpos < row->nfields; argpos++) - { - if (strcmp(row->fieldnames[argpos], argname) == 0) - break; - } - if (argpos == row->nfields) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("cursor \"%s\" has no argument named \"%s\"", - cursor->refname, argname), - parser_errposition(yylloc))); - - /* - * Eat the ":=". We already peeked, so the error should never - * happen. - */ - tok2 = yylex(); - if (tok2 != COLON_EQUALS) - yyerror("syntax error"); - - any_named = true; - } - else - argpos = argc; - - if (argv[argpos] != NULL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("value for parameter \"%s\" of cursor \"%s\" specified more than once", - row->fieldnames[argpos], cursor->refname), - parser_errposition(arglocation))); - - /* - * Read the value expression. To provide the user with meaningful - * parse error positions, we check the syntax immediately, instead of - * checking the final expression that may have the arguments - * reordered. Trailing whitespace must not be trimmed, because - * otherwise input of the form (param -- comment\n, param) would be - * translated into a form where the second parameter is commented - * out. - */ - item = read_sql_construct(',', ')', 0, - ",\" or \")", - sqlstart, - true, true, - false, /* do not trim */ - NULL, &endtoken); - - argv[argpos] = item->query + strlen(sqlstart); - - if (endtoken == ')' && !(argc == row->nfields - 1)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("not enough arguments for cursor \"%s\"", - cursor->refname), - parser_errposition(yylloc))); - - if (endtoken == ',' && (argc == row->nfields - 1)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("too many arguments for cursor \"%s\"", - cursor->refname), - parser_errposition(yylloc))); - } - - /* Make positional argument list */ - initStringInfo(&ds); - appendStringInfoString(&ds, sqlstart); - for (argc = 0; argc < row->nfields; argc++) - { - AssertEreport(argv[argc] != NULL, - MOD_PLSQL, - "It should not be null"); - - /* - * Because named notation allows permutated argument lists, include - * the parameter name for meaningful runtime errors. - */ - appendStringInfoString(&ds, argv[argc]); - if (any_named) - appendStringInfo(&ds, " AS %s", - quote_identifier(row->fieldnames[argc])); - if (argc < row->nfields - 1) - appendStringInfoString(&ds, ", "); - } - appendStringInfoChar(&ds, ';'); - - expr = (PLpgSQL_expr*)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(ds.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->idx = (uint32)-1; - pfree_ext(ds.data); - - /* Next we'd better find the until token */ - tok = yylex(); - if (tok != until) - yyerror("syntax error"); - - return expr; -} - -/* - * Parse RAISE ... USING options - */ -static List * -read_raise_options(void) -{ - List *result = NIL; - - for (;;) - { - PLpgSQL_raise_option *opt; - int tok; - - if ((tok = yylex()) == 0) - yyerror("unexpected end of function definition"); - - opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option)); - - if (tok_is_keyword(tok, &yylval, - K_ERRCODE, "errcode")) - opt->opt_type = PLPGSQL_RAISEOPTION_ERRCODE; - else if (tok_is_keyword(tok, &yylval, - K_MESSAGE, "message")) - opt->opt_type = PLPGSQL_RAISEOPTION_MESSAGE; - else if (tok_is_keyword(tok, &yylval, - K_DETAIL, "detail")) - opt->opt_type = PLPGSQL_RAISEOPTION_DETAIL; - else if (tok_is_keyword(tok, &yylval, - K_HINT, "hint")) - opt->opt_type = PLPGSQL_RAISEOPTION_HINT; - else - yyerror("unrecognized RAISE statement option"); - - tok = yylex(); - if (tok != '=' && tok != COLON_EQUALS) - yyerror("syntax error, expected \"=\""); - - opt->expr = read_sql_expression2(',', ';', ", or ;", &tok); - - result = lappend(result, opt); - - if (tok == ';') - break; - } - - return result; -} - -/* - * Fix up CASE statement - */ -static PLpgSQL_stmt * -make_case(int location, PLpgSQL_expr *t_expr, - List *case_when_list, List *else_stmts) -{ - PLpgSQL_stmt_case *newp; - - newp = (PLpgSQL_stmt_case *)palloc(sizeof(PLpgSQL_stmt_case)); - newp->cmd_type = PLPGSQL_STMT_CASE; - newp->lineno = plpgsql_location_to_lineno(location); - newp->t_expr = t_expr; - newp->t_varno = 0; - newp->case_when_list = case_when_list; - newp->have_else = (else_stmts != NIL); - /* Get rid of list-with-NULL hack */ - if (list_length(else_stmts) == 1 && linitial(else_stmts) == NULL) - newp->else_stmts = NIL; - else - newp->else_stmts = else_stmts; - - /* - * When test expression is present, we create a var for it and then - * convert all the WHEN expressions to "VAR IN (original_expression)". - * This is a bit klugy, but okay since we haven't yet done more than - * read the expressions as text. (Note that previous parsing won't - * have complained if the WHEN ... THEN expression contained multiple - * comma-separated values.) - */ - if (t_expr) - { - char varname[32]; - PLpgSQL_var *t_var; - ListCell *l; - - /* use a name unlikely to collide with any user names */ - snprintf(varname, sizeof(varname), "__Case__Variable_%d__", - u_sess->plsql_cxt.plpgsql_nDatums); - - /* - * We don't yet know the result datatype of t_expr. Build the - * variable as if it were INT4; we'll fix this at runtime if needed. - */ - t_var = (PLpgSQL_var *) - plpgsql_build_variable(varname, newp->lineno, - plpgsql_build_datatype(INT4OID, - -1, - InvalidOid), - true); - newp->t_varno = t_var->dno; - - foreach(l, case_when_list) - { - PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l); - PLpgSQL_expr *expr = cwt->expr; - StringInfoData ds; - - /* copy expression query without SELECT keyword (expr->query + 7) */ - AssertEreport(strncmp(expr->query, "SELECT ", 7) == 0, - MOD_PLSQL, - "copy expression query without SELECT keyword"); - - /* And do the string hacking */ - initStringInfo(&ds); - - appendStringInfo(&ds, "SELECT \"%s\" IN (%s)", - varname, expr->query + 7); - - pfree_ext(expr->query); - expr->query = pstrdup(ds.data); - /* Adjust expr's namespace to include the case variable */ - expr->ns = plpgsql_ns_top(); - - pfree_ext(ds.data); - } - } - - return (PLpgSQL_stmt *) newp; -} - -static PLpgSQL_stmt * -make_callfunc_stmt_no_arg(const char *sqlstart, int location) -{ - char *cp[3] = {0}; - HeapTuple proctup = NULL; - Oid *p_argtypes = NULL; - char **p_argnames = NULL; - char *p_argmodes = NULL; - int narg = 0; - List *funcname = NIL; - PLpgSQL_expr* expr = NULL; - FuncCandidateList clist = NULL; - StringInfoData func_inparas; - char *quoted_sqlstart = NULL; - MemoryContext oldCxt = NULL; - - /* - * the function make_callfunc_stmt_no_arg is only to assemble a sql statement, - * so the context is set to tmp context. - */ - oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - /* get the function's name. */ - plpgsql_parser_funcname(sqlstart, cp, 3); - - if (cp[2] != NULL && cp[2][0] != '\0') - funcname = list_make3(makeString(cp[0]), makeString(cp[1]), makeString(cp[2])); - else if (cp[1] && cp[1][0] != '\0') - funcname = list_make2(makeString(cp[0]), makeString(cp[1])); - else - funcname = list_make1(makeString(cp[0])); - - /* search the function */ - clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false); - if (clist == NULL) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", sqlstart))); - } - - proctup = SearchSysCache(PROCOID, - ObjectIdGetDatum(clist->oid), - 0, 0, 0); - /* function may be deleted after clist be searched. */ - if (!HeapTupleIsValid(proctup)) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function \"%s\" doesn't exist ", sqlstart))); - } - /* get the all args informations, only "in" parameters if p_argmodes is null */ - narg = get_func_arg_info(proctup,&p_argtypes, &p_argnames, &p_argmodes); - ReleaseSysCache(proctup); - if (narg != 0) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s has no enough parameters", sqlstart))); - - initStringInfo(&func_inparas); - - appendStringInfoString(&func_inparas, "CALL "); - - quoted_sqlstart = NameListToQuotedString(funcname); - appendStringInfoString(&func_inparas, quoted_sqlstart); - pfree_ext(quoted_sqlstart); - - appendStringInfoString(&func_inparas, "("); - - appendStringInfoString(&func_inparas, ")"); - - /* read the end token */ - yylex(); - - (void)MemoryContextSwitchTo(oldCxt); - - /* generate the expression */ - expr = (PLpgSQL_expr*)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(func_inparas.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->idx = (uint32)-1; - - PLpgSQL_stmt_perform *perform = NULL; - perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); - perform->cmd_type = PLPGSQL_STMT_PERFORM; - perform->lineno = plpgsql_location_to_lineno(location); - perform->expr = expr; - - return (PLpgSQL_stmt *)perform; -} - -/* - * Brief : special handling of dbms_lob.open and dbms_lob.close - * Description : open and close are keyword, which need to be handled separately - * Notes : - */ -static PLpgSQL_stmt * -parse_lob_open_close(int location) -{ - StringInfoData func; - int tok = yylex(); - char *mode = NULL; - bool is_open = false; - PLpgSQL_expr *expr = NULL; - PLpgSQL_stmt_perform *perform = NULL; - - initStringInfo(&func); - appendStringInfoString(&func, "CALL DBMS_LOB."); - tok = yylex(); - if (K_OPEN == tok) - { - is_open = true; - appendStringInfoString(&func,"OPEN("); - } - else - appendStringInfoString(&func,"CLOSE("); - - if ('(' == (tok = yylex())) - { - tok = yylex(); - if (T_DATUM == tok) - appendStringInfoString(&func, NameOfDatum(&yylval.wdatum)); - else if (T_PLACEHOLDER == tok) - appendStringInfoString(&func, yylval.word.ident); - else - yyerror("syntax error"); - - if (is_open) - { - if (',' == (tok = yylex()) && T_CWORD == (tok = yylex())) - { - mode = NameListToString(yylval.cword.idents); - if (strcasecmp(mode, "DBMS_LOB.LOB_READWRITE") != 0 - && strcasecmp(mode, "DBMS_LOB.LOB_READWRITE") != 0) - yyerror("syntax error"); - else if (!(')' == yylex() && ';' == yylex())) - yyerror("syntax error"); - - appendStringInfoChar(&func, ')'); - } - else - yyerror("syntax error"); - } - else if(')' == yylex() && ';' == yylex()) - appendStringInfoChar(&func, ')'); - else - yyerror("syntax error"); - - expr = (PLpgSQL_expr *)palloc0(sizeof(PLpgSQL_expr)); - expr->dtype = PLPGSQL_DTYPE_EXPR; - expr->query = pstrdup(func.data); - expr->plan = NULL; - expr->paramnos = NULL; - expr->ns = plpgsql_ns_top(); - expr->idx = (uint32)-1; - - perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); - perform->cmd_type = PLPGSQL_STMT_PERFORM; - perform->lineno = plpgsql_location_to_lineno(location); - perform->expr = expr; - return (PLpgSQL_stmt *)perform; - } - yyerror("syntax error"); - return NULL; -} diff --git a/contrib/db_b_parser/pl/pl_b_gram.hpp b/contrib/db_b_parser/pl/pl_b_gram.hpp deleted file mode 100644 index b0a62ddb3..000000000 --- a/contrib/db_b_parser/pl/pl_b_gram.hpp +++ /dev/null @@ -1,282 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.5. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Undocumented macros, especially those whose name start with YY_, - are private implementation details. Do not rely on them. */ - -#ifndef YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED -# define YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int plbsql_yydebug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - IDENT = 258, - FCONST = 259, - SCONST = 260, - BCONST = 261, - VCONST = 262, - XCONST = 263, - Op = 264, - CmpOp = 265, - COMMENTSTRING = 266, - ICONST = 267, - PARAM = 268, - TYPECAST = 269, - ORA_JOINOP = 270, - DOT_DOT = 271, - COLON_EQUALS = 272, - PARA_EQUALS = 273, - T_WORD = 274, - T_CWORD = 275, - T_DATUM = 276, - T_PLACEHOLDER = 277, - T_VARRAY = 278, - T_ARRAY_FIRST = 279, - T_ARRAY_LAST = 280, - T_ARRAY_COUNT = 281, - T_ARRAY_EXTEND = 282, - T_VARRAY_VAR = 283, - T_RECORD = 284, - LESS_LESS = 285, - GREATER_GREATER = 286, - T_REFCURSOR = 287, - T_SQL_ISOPEN = 288, - T_SQL_FOUND = 289, - T_SQL_NOTFOUND = 290, - T_SQL_ROWCOUNT = 291, - T_CURSOR_ISOPEN = 292, - T_CURSOR_FOUND = 293, - T_CURSOR_NOTFOUND = 294, - T_CURSOR_ROWCOUNT = 295, - K_ABSOLUTE = 296, - K_ALIAS = 297, - K_ALL = 298, - K_ALTER = 299, - K_ARRAY = 300, - K_BACKWARD = 301, - K_BEGIN = 302, - K_BY = 303, - K_CASE = 304, - K_CLOSE = 305, - K_COLLATE = 306, - K_COMMIT = 307, - K_CONSTANT = 308, - K_CONTINUE = 309, - K_CURRENT = 310, - K_CURSOR = 311, - K_DEBUG = 312, - K_DECLARE = 313, - K_DEFAULT = 314, - K_DELETE = 315, - K_DETAIL = 316, - K_DIAGNOSTICS = 317, - K_DUMP = 318, - K_ELSE = 319, - K_ELSIF = 320, - K_END = 321, - K_ERRCODE = 322, - K_ERROR = 323, - K_EXCEPTION = 324, - K_EXECUTE = 325, - K_EXIT = 326, - K_FETCH = 327, - K_FIRST = 328, - K_FOR = 329, - K_FORALL = 330, - K_FOREACH = 331, - K_FORWARD = 332, - K_FROM = 333, - K_GET = 334, - K_GOTO = 335, - K_HINT = 336, - K_IF = 337, - K_IMMEDIATE = 338, - K_IN = 339, - K_INFO = 340, - K_INSERT = 341, - K_INTO = 342, - K_IS = 343, - K_LAST = 344, - K_LOG = 345, - K_LOOP = 346, - K_MERGE = 347, - K_MESSAGE = 348, - K_MESSAGE_TEXT = 349, - K_MOVE = 350, - K_NEXT = 351, - K_NO = 352, - K_NOT = 353, - K_NOTICE = 354, - K_NULL = 355, - K_OF = 356, - K_OPEN = 357, - K_OPTION = 358, - K_OR = 359, - K_OUT = 360, - K_PERFORM = 361, - K_PG_EXCEPTION_CONTEXT = 362, - K_PG_EXCEPTION_DETAIL = 363, - K_PG_EXCEPTION_HINT = 364, - K_PRAGMA = 365, - K_PRIOR = 366, - K_QUERY = 367, - K_RAISE = 368, - K_RECORD = 369, - K_REF = 370, - K_RELATIVE = 371, - K_RESULT_OID = 372, - K_RETURN = 373, - K_RETURNED_SQLSTATE = 374, - K_REVERSE = 375, - K_ROLLBACK = 376, - K_ROWTYPE = 377, - K_ROW_COUNT = 378, - K_SAVEPOINT = 379, - K_SELECT = 380, - K_SCROLL = 381, - K_SLICE = 382, - K_SQLSTATE = 383, - K_STACKED = 384, - K_STRICT = 385, - K_SYS_REFCURSOR = 386, - K_THEN = 387, - K_TO = 388, - K_TYPE = 389, - K_UPDATE = 390, - K_USE_COLUMN = 391, - K_USE_VARIABLE = 392, - K_USING = 393, - K_VARIABLE_CONFLICT = 394, - K_VARRAY = 395, - K_WARNING = 396, - K_WHEN = 397, - K_WHILE = 398, - K_WITH = 399 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -union YYSTYPE -{ -#line 188 "pl/pl_b_gram.y" - - core_YYSTYPE core_yystype; - /* these fields must match core_YYSTYPE: */ - int ival; - char *str; - const char *keyword; - - PLword word; - PLcword cword; - PLwdatum wdatum; - bool boolean; - Oid oid; - struct - { - char *name; - int lineno; - } varname; - struct - { - char *name; - int lineno; - PLpgSQL_datum *scalar; - PLpgSQL_rec *rec; - PLpgSQL_row *row; - } forvariable; - struct - { - char *label; - int n_initvars; - int *initvarnos; - bool autonomous; - } declhdr; - struct - { - List *stmts; - char *end_label; - int end_label_location; - } loop_body; - List *list; - PLpgSQL_type *dtype; - PLpgSQL_datum *datum; - PLpgSQL_var *var; - PLpgSQL_expr *expr; - PLpgSQL_stmt *stmt; - PLpgSQL_condition *condition; - PLpgSQL_exception *exception; - PLpgSQL_exception_block *exception_block; - PLpgSQL_nsitem *nsitem; - PLpgSQL_diag_item *diagitem; - PLpgSQL_stmt_fetch *fetch; - PLpgSQL_case_when *casewhen; - PLpgSQL_rec_attr *recattr; - -#line 256 "pl/pl_b_gram.hpp" - -}; -typedef union YYSTYPE YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - -/* Location type. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - -extern THR_LOCAL YYSTYPE plbsql_yylval; -extern THR_LOCAL YYLTYPE plbsql_yylloc; -int plbsql_yyparse (void); - -#endif /* !YY_PLBSQL_YY_PL_PL_B_GRAM_HPP_INCLUDED */ diff --git a/contrib/db_b_parser/pl/pl_b_gram.y b/contrib/db_b_parser/pl/pl_b_gram.y index 33130821c..97000d7ea 100644 --- a/contrib/db_b_parser/pl/pl_b_gram.y +++ b/contrib/db_b_parser/pl/pl_b_gram.y @@ -17,6 +17,7 @@ #include "catalog/namespace.h" #include "catalog/pg_proc.h" +#include "catalog/gs_package.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "nodes/makefuncs.h" @@ -32,6 +33,7 @@ #include "utils/builtins.h" #include "utils/memutils.h" #include "utils/syscache.h" +#include "utils/pl_package.h" #include @@ -65,6 +67,20 @@ record_stmt_label(char * label, PLpgSQL_stmt *stmt) u_sess->plsql_cxt.goto_labels = lappend(u_sess->plsql_cxt.goto_labels, (void *)gl); } +static void IsInPublicNamespace(char* varname) { + if (u_sess->plsql_cxt.plpgsql_curr_compile == NULL && + u_sess->plsql_cxt.plpgsql_curr_compile_package != NULL) { + PLpgSQL_package* pkg = u_sess->plsql_cxt.plpgsql_curr_compile_package; + if (plpgsql_ns_lookup(pkg->public_ns, true, varname, NULL, NULL, NULL) != NULL) { + ereport(ERROR, + (errmodule(MOD_PLSQL), errcode(ERRCODE_SYNTAX_ERROR), + errmsg("variable name \"%s\" already defined", varname), + errdetail("variable name already defined"), + errcause("variable name maybe defined in public variable"), + erraction("rename variable"))); + } + } +} /* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents @@ -107,7 +123,7 @@ static bool is_function(const char *name, bool is_assign, bool no_parenthesis); static void plpgsql_parser_funcname(const char *s, char **output, int numidents); static PLpgSQL_stmt *make_callfunc_stmt(const char *sqlstart, - int location, bool is_assign); + int location, bool is_assign, bool eaten_first_token); static PLpgSQL_stmt *make_callfunc_stmt_no_arg(const char *sqlstart, int location); static PLpgSQL_expr *read_sql_construct5(int until, int until2, @@ -179,6 +195,10 @@ static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, static List *read_raise_options(void); static bool last_pragma; +static char* get_proc_str(int tok); +static char* get_init_proc(int tok); +static void raw_parse_package_function(char* proc_str); +static void checkFuncName(List* funcname); %} %expect 0 @@ -215,7 +235,7 @@ static bool last_pragma; char *label; int n_initvars; int *initvarnos; - bool autonomous; + bool isAutonomous; } declhdr; struct { @@ -259,7 +279,7 @@ static bool last_pragma; %type for_variable %type for_control forall_control -%type any_identifier opt_block_label opt_label goto_block_label label_name +%type any_identifier opt_block_label opt_label goto_block_label label_name spec_proc init_proc %type proc_sect proc_stmts stmt_elsifs stmt_else forall_body %type loop_body @@ -338,6 +358,7 @@ static bool last_pragma; %token K_ALL %token K_ALTER %token K_ARRAY +%token K_AS %token K_BACKWARD %token K_BEGIN %token K_BY @@ -354,6 +375,7 @@ static bool last_pragma; %token K_DEFAULT %token K_DELETE %token K_DETAIL +%token K_DETERMINISTIC %token K_DIAGNOSTICS %token K_DUMP %token K_ELSE @@ -371,11 +393,13 @@ static bool last_pragma; %token K_FOREACH %token K_FORWARD %token K_FROM +%token K_FUNCTION %token K_GET %token K_GOTO %token K_HINT %token K_IF %token K_IMMEDIATE +%token K_INSTANTIATION %token K_IN %token K_INFO %token K_INSERT @@ -398,12 +422,14 @@ static bool last_pragma; %token K_OPTION %token K_OR %token K_OUT +%token K_PACKAGE %token K_PERFORM %token K_PG_EXCEPTION_CONTEXT %token K_PG_EXCEPTION_DETAIL %token K_PG_EXCEPTION_HINT %token K_PRAGMA %token K_PRIOR +%token K_PROCEDURE %token K_QUERY %token K_RAISE %token K_RECORD @@ -440,6 +466,52 @@ static bool last_pragma; %% +pl_body : pl_package_spec + | pl_function + | pl_package_init + ; +pl_package_spec : K_PACKAGE decl_sect K_END + { + int nDatums = 0; + if (u_sess->plsql_cxt.plpgsql_curr_compile!=NULL) { + nDatums = u_sess->plsql_cxt.plpgsql_nDatums; + } else { + nDatums = u_sess->plsql_cxt.plpgsql_pkg_nDatums; + } + + for (int i = 0; i < nDatums; i++) { + u_sess->plsql_cxt.plpgsql_Datums[i]->ispkg = true; + } + PLpgSQL_nsitem* ns_cur = plpgsql_ns_top(); + while (ns_cur != NULL) { + ns_cur->pkgname = u_sess->plsql_cxt.plpgsql_curr_compile_package->pkg_signature; + ns_cur = ns_cur->prev; + } + u_sess->plsql_cxt.plpgsql_curr_compile_package->n_initvars = $2.n_initvars; + u_sess->plsql_cxt.plpgsql_curr_compile_package->initvarnos = $2.initvarnos; + } + ; +pl_package_init : K_INSTANTIATION init_proc + { + if (u_sess->plsql_cxt.plpgsql_curr_compile_package!=NULL) + { + List* raw_parsetree_list = NULL; + raw_parsetree_list = raw_parser($2); + DoStmt* stmt; + stmt = (DoStmt *)linitial(raw_parsetree_list); + stmt->isExecuted = false; + if (u_sess->plsql_cxt.plpgsql_curr_compile_package->is_spec_compiling) { + stmt->isSpec = true; + } else { + stmt->isSpec = false; + } + List *proc_list = u_sess->plsql_cxt.plpgsql_curr_compile_package->proc_list; + u_sess->plsql_cxt.plpgsql_curr_compile_package->proc_list = lappend(proc_list,stmt); + } else { + yyerror("instantiation only use in package compile"); + } + } + pl_function : comp_options pl_block opt_semi { u_sess->plsql_cxt.plpgsql_parse_result = (PLpgSQL_stmt_block *) $2; @@ -480,10 +552,9 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label newp->cmd_type = PLPGSQL_STMT_BLOCK; newp->lineno = plpgsql_location_to_lineno(@2); + newp->sqlString = plpgsql_get_curline_query(); newp->label = $1.label; -#ifndef ENABLE_MULTIPLE_NODES - newp->autonomous = $1.autonomous; -#endif + newp->isAutonomous = $1.isAutonomous; newp->n_initvars = $1.n_initvars; newp->initvarnos = $1.initvarnos; newp->body = $3; @@ -507,7 +578,7 @@ decl_sect : opt_block_label $$.label = $1; $$.n_initvars = 0; $$.initvarnos = NULL; - $$.autonomous = false; + $$.isAutonomous = false; } | opt_block_label decl_start { @@ -515,7 +586,7 @@ decl_sect : opt_block_label $$.label = $1; $$.n_initvars = 0; $$.initvarnos = NULL; - $$.autonomous = false; + $$.isAutonomous = false; } | opt_block_label decl_start decl_stmts { @@ -523,7 +594,7 @@ decl_sect : opt_block_label $$.label = $1; /* Remember variables declared in decl_stmts */ $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos)); - $$.autonomous = last_pragma; + $$.isAutonomous = last_pragma; last_pragma = false; } ; @@ -567,6 +638,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull { PLpgSQL_variable *var; + IsInPublicNamespace($1.name); /* * If a collation is supplied, insert it into the * datatype. We assume decl_datatype always returns @@ -622,12 +694,16 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } | decl_varname K_ALIAS K_FOR decl_aliasitem ';' { + IsInPublicNamespace($1.name); plpgsql_ns_additem($4->itemtype, $4->itemno, $1.name); pfree_ext($1.name); } | K_CURSOR decl_varname opt_scrollable - { plpgsql_ns_push($2.name); } + { + IsInPublicNamespace($2.name); + plpgsql_ns_push($2.name); + } decl_cursor_args decl_is_for decl_cursor_query { PLpgSQL_var *newp; @@ -653,12 +729,14 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } | K_TYPE decl_varname K_IS K_REF K_CURSOR ';' { + IsInPublicNamespace($2.name); /* add name of cursor type to PLPGSQL_NSTYPE_REFCURSOR */ plpgsql_ns_additem(PLPGSQL_NSTYPE_REFCURSOR,0,$2.name); pfree_ext($2.name); } | decl_varname T_REFCURSOR ';' { + IsInPublicNamespace($1.name); plpgsql_build_variable( $1.name, $1.lineno, @@ -669,6 +747,10 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull | decl_varname K_SYS_REFCURSOR ';' { + IsInPublicNamespace($1.name); + if (IsOnlyCompilePackage()) { + yyerror("not allow use ref cursor in package"); + } plpgsql_build_variable( $1.name, $1.lineno, @@ -683,11 +765,13 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull */ | K_TYPE decl_varname K_IS K_VARRAY '(' ICONST ')' K_OF decl_datatype ';' { + IsInPublicNamespace($2.name); plpgsql_build_varrayType($2.name, $2.lineno, $9, true); pfree_ext($2.name); } | decl_varname varray_var decl_defval { + IsInPublicNamespace($1.name); char *type_name; errno_t ret; PLpgSQL_type * var_type = ((PLpgSQL_var *)u_sess->plsql_cxt.plpgsql_Datums[$2])->datatype; @@ -710,6 +794,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } | K_TYPE decl_varname K_IS K_RECORD '(' record_attr_list ')' ';' { + IsInPublicNamespace($2.name); PLpgSQL_rec_type *newp = NULL; newp = plpgsql_build_rec_type($2.name, $2.lineno, $6, true); @@ -721,6 +806,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull } | decl_varname record_var ';' { + IsInPublicNamespace($1.name); PLpgSQL_var *newp = NULL; PLpgSQL_type * var_type = (PLpgSQL_type *)u_sess->plsql_cxt.plpgsql_Datums[$2]; @@ -732,22 +818,36 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull errmsg("build variable failed"))); pfree_ext($1.name); } - | K_PRAGMA any_identifier ';' - { - if (pg_strcasecmp($2, "autonomous_transaction") == 0) -#ifndef ENABLE_MULTIPLE_NODES - last_pragma = true; -#else - - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("autonomous transaction is not yet supported."))); -#endif - else - elog(ERROR, "invalid pragma"); - } + | K_FUNCTION {u_sess->parser_cxt.is_procedure=false;} spec_proc + { + raw_parse_package_function($3); + } + | K_PROCEDURE {u_sess->parser_cxt.is_procedure=true;} spec_proc + { + raw_parse_package_function($3); + } + | K_PRAGMA any_identifier ';' + { + if (pg_strcasecmp($2, "autonomous_transaction") == 0) + last_pragma = true; + else + elog(ERROR, "invalid pragma"); + } ; +spec_proc : + { + $$ = get_proc_str(yychar); + yyclearin; + } + +init_proc : + { + $$ = get_init_proc(yychar); + yyclearin; + } + + record_attr_list : record_attr { $$ = list_make1($1); @@ -833,6 +933,7 @@ decl_cursor_args : newp->nfields = list_length($2); newp->fieldnames = (char **)palloc(newp->nfields * sizeof(char *)); newp->varnos = (int *)palloc(newp->nfields * sizeof(int)); + newp->isImplicit = true; i = 0; foreach (l, $2) @@ -908,12 +1009,17 @@ decl_aliasitem : T_WORD NULL); else nsi = NULL; - if (nsi == NULL) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("variable \"%s\" does not exist", - NameListToString($1.idents)), - parser_errposition(@1))); + if (nsi == NULL) { + int yylloc_bak = yylloc; + int isPkg =plpgsql_pkg_adddatum2ns($1.idents); + yylloc = yylloc_bak; + if (isPkg < 0) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("variable \"%s\" does not exist", + NameListToString($1.idents)), + parser_errposition(@1))); + } $$ = nsi; } ; @@ -1124,6 +1230,7 @@ stmt_perform : K_PERFORM expr_until_semi newp->cmd_type = PLPGSQL_STMT_PERFORM; newp->lineno = plpgsql_location_to_lineno(@1); newp->expr = $2; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -1138,9 +1245,22 @@ stmt_assign : assign_var assign_operator expr_until_semi newp->lineno = plpgsql_location_to_lineno(@1); newp->varno = $1; newp->expr = $3; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } + | T_CWORD assign_operator expr_until_semi + { + List* wholeName = $1.idents; + int dno = plpgsql_pkg_add_unknown_var_to_namespace(wholeName); + PLpgSQL_stmt_assign *newp; + newp = (PLpgSQL_stmt_assign *)palloc0(sizeof(PLpgSQL_stmt_assign)); + newp->cmd_type = PLPGSQL_STMT_ASSIGN; + newp->lineno = plpgsql_location_to_lineno(@1); + newp->varno = dno; + newp->expr = $3; + $$ = (PLpgSQL_stmt *)newp; + } ; stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';' @@ -1153,6 +1273,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';' newp->lineno = plpgsql_location_to_lineno(@1); newp->is_stacked = $2; newp->diag_items = $4; + newp->sqlString = plpgsql_get_curline_query(); /* * Check information items are valid for area option. @@ -1352,6 +1473,7 @@ stmt_goto : K_GOTO label_name newp->cmd_type = PLPGSQL_STMT_GOTO; newp->lineno = plpgsql_location_to_lineno(@1); newp->label = $2; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -1373,6 +1495,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';' newp->then_body = $3; newp->elsif_list = $4; newp->else_body = $5; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -1443,6 +1566,7 @@ case_when : K_WHEN expr_until_then proc_sect newp->lineno = plpgsql_location_to_lineno(@1); newp->expr = $2; newp->stmts = $3; + newp->sqlString = plpgsql_get_curline_query(); $$ = newp; } ; @@ -1475,6 +1599,7 @@ stmt_loop : opt_block_label K_LOOP loop_body newp->lineno = plpgsql_location_to_lineno(@2); newp->label = $1; newp->body = $3.stmts; + newp->sqlString = plpgsql_get_curline_query(); check_labels($1, $3.end_label, $3.end_label_location); plpgsql_ns_pop(); @@ -1496,6 +1621,7 @@ stmt_while : opt_block_label K_WHILE expr_until_loop loop_body newp->label = $1; newp->cond = $3; newp->body = $4.stmts; + newp->sqlString = plpgsql_get_curline_query(); check_labels($1, $4.end_label, $4.end_label_location); plpgsql_ns_pop(); @@ -1518,6 +1644,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body newp->lineno = plpgsql_location_to_lineno(@2); newp->label = $1; newp->body = $4.stmts; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *) newp; /* register the stmt if it is labeled */ @@ -1537,6 +1664,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body newp->lineno = plpgsql_location_to_lineno(@2); newp->label = $1; newp->body = $4.stmts; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *) newp; /* register the stmt if it is labeled */ @@ -1561,8 +1689,10 @@ stmt_for : opt_block_label K_FOR for_control loop_body PLpgSQL_stmt_fori *newm; newm = (PLpgSQL_stmt_fori *) $3; + newm->lineno = plpgsql_location_to_lineno(@2); newm->label = NULL; newm->body = $4; + newm->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *) newm; } else @@ -2032,6 +2162,7 @@ stmt_foreach_a : opt_block_label K_FOREACH for_variable foreach_slice K_IN K_ARR newp->slice = $4; newp->expr = $7; newp->body = $8.stmts; + newp->sqlString = plpgsql_get_curline_query(); if ($3.rec) { @@ -2091,6 +2222,7 @@ stmt_exit : exit_type opt_label opt_exitcond newp->lineno = plpgsql_location_to_lineno(@1); newp->label = $2; newp->cond = $3; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -2151,6 +2283,7 @@ stmt_raise : K_RAISE newp->message = NULL; newp->params = NIL; newp->options = NIL; + newp->sqlString = plpgsql_get_curline_query(); tok = yylex(); if (tok == 0) @@ -2162,7 +2295,31 @@ stmt_raise : K_RAISE */ if (tok != ';') { - if (T_DATUM == tok && PLPGSQL_DTYPE_ROW == yylval.wdatum.datum->dtype) + if (T_CWORD == tok) { + PLpgSQL_expr *expr = NULL; + List* wholeName = yylval.cword.idents; + int dno = plpgsql_pkg_add_unknown_var_to_namespace(wholeName, PLPGSQL_DTYPE_ROW); + if (dno == -1) { + yyerror("not found package"); + } + sprintf(message, "line:%d ", plpgsql_location_to_lineno(@1)); + appendStringInfoString(&ds, message); + appendStringInfoString(&ds,"%"); + row = (PLpgSQL_row*)u_sess->plsql_cxt.plpgsql_Datums[dno]; + row->dtype = PLPGSQL_DTYPE_ROW; + row->customErrorCode = plpgsql_getCustomErrorCode(); + /* condname is system embedded error name, so it is still null in this case. */ + newp->condname = pstrdup(unpack_sql_state(row->customErrorCode)); + newp->message = pstrdup(ds.data); + plbsql_push_back_token(tok); + expr = read_sql_construct(';', 0, 0, ";", + "SELECT ", true, true, true, NULL, &tok); + + if (tok != ';') + yyerror("syntax error"); + + newp->params = lappend(newp->params, expr); + } else if (T_DATUM == tok && PLPGSQL_DTYPE_ROW == yylval.wdatum.datum->dtype) { PLpgSQL_expr *expr = NULL; @@ -2399,7 +2556,7 @@ stmt_execsql : K_ALTER } else { - PLpgSQL_stmt *stmt = make_callfunc_stmt($1.ident, @1, false); + PLpgSQL_stmt *stmt = make_callfunc_stmt($1.ident, @1, false, false); if (stmt->cmd_type == PLPGSQL_STMT_PERFORM) { ((PLpgSQL_stmt_perform *)stmt)->expr->is_funccall = true; @@ -2417,38 +2574,58 @@ stmt_execsql : K_ALTER } } } - | T_CWORD + | T_CWORD '(' { - int tok = yylex(); + char *name = NULL; bool isCallFunc = false; bool FuncNoarg = false; + checkFuncName($1.idents); + MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + name = NameListToString($1.idents); + (void)MemoryContextSwitchTo(colCxt); + isCallFunc = is_function(name, false, false); + if (isCallFunc) + { + if (FuncNoarg) + $$ = make_callfunc_stmt_no_arg(name, @1); + else + { + PLpgSQL_stmt *stmt = make_callfunc_stmt(name, @1, false, true); + if (stmt->cmd_type == PLPGSQL_STMT_PERFORM) + { + ((PLpgSQL_stmt_perform *)stmt)->expr->is_funccall = true; + } + else if (stmt->cmd_type == PLPGSQL_STMT_EXECSQL) + { + ((PLpgSQL_stmt_execsql *)stmt)->sqlstmt->is_funccall = true; + } + $$ = stmt; + } + } + else + { + $$ = make_execsql_stmt(T_CWORD, @1); + } + } + | T_CWORD ';' + { + char *name = NULL; + bool isCallFunc = false; + checkFuncName($1.idents); + MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + name = NameListToString($1.idents); + (void)MemoryContextSwitchTo(colCxt); + isCallFunc = is_function(name, false, true); + bool FuncNoarg = true; - if ('(' == tok) - { - MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - name = NameListToString($1.idents); - (void)MemoryContextSwitchTo(colCxt); - isCallFunc = is_function(name, false, false); - } - else if ('=' == tok || COLON_EQUALS == tok || '[' == tok) - cword_is_not_variable(&($1), @1); - else if (';' == tok) { - MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); - name = NameListToString($1.idents); - (void)MemoryContextSwitchTo(colCxt); - isCallFunc = is_function(name, false, true); - FuncNoarg = true; - } - - plbsql_push_back_token(tok); if (isCallFunc) { if (FuncNoarg) $$ = make_callfunc_stmt_no_arg(name, @1); else { - PLpgSQL_stmt *stmt = make_callfunc_stmt(name, @1, false); + PLpgSQL_stmt *stmt = make_callfunc_stmt(name, @1, false, true); if (stmt->cmd_type == PLPGSQL_STMT_PERFORM) { ((PLpgSQL_stmt_perform *)stmt)->expr->is_funccall = true; @@ -2475,7 +2652,7 @@ stmt_execsql : K_ALTER else { plbsql_push_back_token(tok); - $$ = make_callfunc_stmt("array_extend", @1, false); + $$ = make_callfunc_stmt("array_extend", @1, false, false); } } ; @@ -2510,6 +2687,7 @@ stmt_dynexecute : K_EXECUTE newp->isinouttype = false; newp->ppd = NULL; newp->isanonymousblock = true; + newp->sqlString = plpgsql_get_curline_query(); /* If we found "INTO", collect the argument */ @@ -2565,6 +2743,7 @@ stmt_open : K_OPEN cursor_variable newp->lineno = plpgsql_location_to_lineno(@1); newp->curvar = $2->dno; newp->cursor_options = CURSOR_OPT_FAST_PLAN; + newp->sqlString = plpgsql_get_curline_query(); if ($2->cursor_explicit_expr == NULL) { @@ -2665,6 +2844,7 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO fetch->row = row; fetch->curvar = $3->dno; fetch->is_move = false; + fetch->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)fetch; } @@ -2677,6 +2857,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';' fetch->lineno = plpgsql_location_to_lineno(@1); fetch->curvar = $3->dno; fetch->is_move = true; + fetch->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)fetch; } @@ -2696,6 +2877,7 @@ stmt_close : K_CLOSE cursor_variable ';' newp->cmd_type = PLPGSQL_STMT_CLOSE; newp->lineno = plpgsql_location_to_lineno(@1); newp->curvar = $2->dno; + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -2704,11 +2886,12 @@ stmt_close : K_CLOSE cursor_variable ';' stmt_null : K_NULL ';' { /* We do building a node for NULL for GOTO */ - PLpgSQL_stmt *newp; + PLpgSQL_stmt_null *newp; newp = (PLpgSQL_stmt_null *)palloc(sizeof(PLpgSQL_stmt_null)); newp->cmd_type = PLPGSQL_STMT_NULL; newp->lineno = plpgsql_location_to_lineno(@1); + newp->sqlString = plpgsql_get_curline_query(); $$ = (PLpgSQL_stmt *)newp; } @@ -2720,7 +2903,8 @@ stmt_commit : opt_block_label K_COMMIT ';' newp = (PLpgSQL_stmt_commit *)palloc(sizeof(PLpgSQL_stmt_commit)); newp->cmd_type = PLPGSQL_STMT_COMMIT; - newp->lineno = plpgsql_location_to_lineno(@1); + newp->lineno = plpgsql_location_to_lineno(@2); + newp->sqlString = plpgsql_get_curline_query(); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *)newp; @@ -2734,7 +2918,8 @@ stmt_rollback : opt_block_label K_ROLLBACK ';' newp = (PLpgSQL_stmt_rollback *) palloc(sizeof(PLpgSQL_stmt_rollback)); newp->cmd_type = PLPGSQL_STMT_ROLLBACK; - newp->lineno = plpgsql_location_to_lineno(@1); + newp->lineno = plpgsql_location_to_lineno(@2); + newp->sqlString = plpgsql_get_curline_query(); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *)newp; @@ -2789,7 +2974,7 @@ exception_sect : plpgsql_build_datatype(TEXTOID, -1, u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation), - true); + true, true); ((PLpgSQL_var *) var)->isconst = true; newp->sqlstate_varno = var->dno; @@ -2797,7 +2982,7 @@ exception_sect : plpgsql_build_datatype(TEXTOID, -1, u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation), - true); + true, true); ((PLpgSQL_var *) var)->isconst = true; newp->sqlerrm_varno = var->dno; @@ -2924,17 +3109,19 @@ expr_until_semi : plpgsql_is_token_match2(T_CWORD,'(')) { tok = yylex(); - if (T_WORD == tok) + if (T_WORD == tok) { name = yylval.word.ident; - else + } else { + checkFuncName(yylval.cword.idents); name = NameListToString(yylval.cword.idents); + } isCallFunc = is_function(name, true, false); } if (isCallFunc) { - stmt = make_callfunc_stmt(name, yylloc, true); + stmt = make_callfunc_stmt(name, yylloc, true, false); if (PLPGSQL_STMT_EXECSQL == stmt->cmd_type) expr = ((PLpgSQL_stmt_execsql*)stmt)->sqlstmt; else if (PLPGSQL_STMT_PERFORM == stmt->cmd_type) @@ -2945,8 +3132,19 @@ expr_until_semi : } else { - if (name != NULL) + if (name != NULL) { plbsql_push_back_token(tok); + name = NULL; + } + + if (!plpgsql_is_token_match2(T_CWORD,'(')) + { + if (plpgsql_is_token_match(T_CWORD)) { + List* wholeName = yylval.cword.idents; + plpgsql_pkg_add_unknown_var_to_namespace(wholeName); + } + } + $$ = read_sql_expression(';', ";"); } } @@ -3044,6 +3242,8 @@ unreserved_keyword : | K_NO | K_NOTICE | K_OPTION + | K_PACKAGE + | K_INSTANTIATION | K_PG_EXCEPTION_CONTEXT | K_PG_EXCEPTION_DETAIL | K_PG_EXCEPTION_HINT @@ -3282,7 +3482,7 @@ plpgsql_parser_funcname(const char *s, char **output, int numidents) * Notes : */ static PLpgSQL_stmt * -make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) +make_callfunc_stmt(const char *sqlstart, int location, bool is_assign, bool eaten_first_token) { int nparams = 0; int nfields = 0; @@ -3398,9 +3598,18 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) tok = yylex(); - /* check the format for the function without parameters */ - if ((tok = yylex()) == ')') - noargs = TRUE; + /* + * check the format for the function without parameters + * if eaten_first_token is true,first token is '(' ,so if next token is ')',it means + * no args + */ + if (eaten_first_token==true) { + if (tok == ')') + noargs = TRUE; + } else { + if ((tok = yylex()) == ')') + noargs = TRUE; + } plbsql_push_back_token(tok); /* has any "out" parameters, user execsql stmt */ @@ -3794,6 +4003,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) perform->cmd_type = PLPGSQL_STMT_PERFORM; perform->lineno = plpgsql_location_to_lineno(location); perform->expr = expr; + perform->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)perform; } else if (all_arg >= narg) @@ -3817,6 +4027,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) row->nfields = new_nfields; row->fieldnames = (char **)palloc0(sizeof(char *) * new_nfields); row->varnos = (int *)palloc0(sizeof(int) * new_nfields); + row->isImplicit = true; /* fetch out argument from fieldnames into row->fieldnames */ for (i = 0; i < nfields; i++) @@ -3896,6 +4107,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) execsql->row = row; execsql->placeholders = placeholders; execsql->multi_func = multi_func; + execsql->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)execsql; } } @@ -3919,6 +4131,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) row->nfields = nfields; row->fieldnames = (char **)palloc(sizeof(char *) * nfields); row->varnos = (int *)palloc(sizeof(int) * nfields); + row->isImplicit = true; while (--nfields >= 0) { row->fieldnames[nfields] = fieldnames[nfields]; @@ -3935,6 +4148,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) perform->cmd_type = PLPGSQL_STMT_PERFORM; perform->lineno = plpgsql_location_to_lineno(location); perform->expr = expr; + perform->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)perform; } else @@ -3950,6 +4164,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign) execsql->row = row; execsql->placeholders = placeholders; execsql->multi_func = multi_func; + execsql->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)execsql; } } @@ -3992,9 +4207,7 @@ is_function(const char *name, bool is_assign, bool no_parenthesis) * if A.B.C, it's not a function invoke, because can not use function of * other database. if A.B, then it must be a function invoke. */ - if (cp[2] && cp[2][0] != '\0') - return false; - else if (cp[0] && cp[0][0] != '\0') + if (cp[0] && cp[0][0] != '\0') { /* these are function in pg_proc who are overloaded, so they can not be * execured by := or direct call. @@ -4014,7 +4227,9 @@ is_function(const char *name, bool is_assign, bool no_parenthesis) if(keyword && no_parenthesis && UNRESERVED_KEYWORD == keyword->category) return false; - if (cp[1] && cp[1][0] != '\0') + if (cp[2] && cp[2][0] != '\0') + funcname = list_make3(makeString(cp[0]), makeString(cp[1]),makeString(cp[2])); + else if (cp[1] && cp[1][0] != '\0') funcname = list_make2(makeString(cp[0]), makeString(cp[1])); else funcname = list_make1(makeString(cp[0])); @@ -4073,6 +4288,29 @@ is_function(const char *name, bool is_assign, bool no_parenthesis) return false; } +static void checkFuncName(List* funcname) +{ + MemoryContext colCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + char* name = NameListToString(funcname); + Oid packageOid = InvalidOid; + Oid namespaceId = InvalidOid; + if (list_length(funcname) > 2) { + if (list_length(funcname) == 3) { + char* schemaname = strVal(linitial(funcname)); + char* pkgname = strVal(lsecond(funcname)); + namespaceId = SchemaNameGetSchemaOid(schemaname, false); + if (OidIsValid(namespaceId)) { + packageOid = PackageNameGetOid(pkgname, namespaceId); + } + } + if (!OidIsValid(packageOid)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: %s", name))); + } + } + (void)MemoryContextSwitchTo(colCxt); +} + /* Convenience routine to read an expression with one possible terminator */ static PLpgSQL_expr * read_sql_expression(int until, const char *expected) @@ -4158,7 +4396,11 @@ read_sql_construct5(int until, const char right_brack[2] = ")"; int loc = 0; int curloc = 0; - + List* idents = NULL; + char* word1 = NULL; + char* word2 = NULL; + int nnames = 0; + int dno = -1; /* * ds will do a lot of enlarge, which need to relloc the space, and the old space * will be return to current context. So if we don't switch the context, the original @@ -4314,6 +4556,25 @@ read_sql_construct5(int until, /* do nothing */ } break; + case T_CWORD: + idents = yylval.cword.idents; + if (list_length(idents) == 2) { + word1 = strVal(linitial(idents)); + word2 = strVal(lsecond(idents)); + } else if (list_length(idents) == 3) { + word1 = strVal(lsecond(idents)); + word2 = strVal(lthird(idents)); + }else { + yyerror("syntax error"); + } + if (plpgsql_ns_lookup(plpgsql_ns_top(), false, word1, word2, NULL, &nnames) == NULL) { + dno = plpgsql_pkg_add_unknown_var_to_namespace(yylval.cword.idents); + } + if (dno != -1) { + appendStringInfoString(&ds, NameListToString(idents)); + ds_changed = true; + break; + } default: tok = yylex(); @@ -4405,6 +4666,134 @@ read_sql_construct(int until, return read_sql_construct5(until, until2, until3, until3, 0, expected, sqlstart, isexpression, valid_sql, trim, startloc, endtoken); } +/* + * get function declare or definition string in package. + */ +static char * +get_proc_str(int tok) +{ + int blocklevel = 0; + int pre_tok = 0; + if (u_sess->plsql_cxt.plpgsql_curr_compile_package==NULL) { + yyerror("not allowed create procedure in function or procedure."); + } + tok = yylex(); + StringInfoData ds; + bool is_defining_proc = false; + int startlocation = yylloc; + char * spec_proc_str = NULL; + MemoryContext oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.compile_tmp_cxt); + initStringInfo(&ds); + MemoryContextSwitchTo(oldCxt); + if (u_sess->parser_cxt.is_procedure==false){ + appendStringInfoString(&ds, " CREATE OR REPLACE FUNCTION "); + } else { + appendStringInfoString(&ds, " CREATE OR REPLACE PROCEDURE "); + } + u_sess->parser_cxt.in_package_function_compile = true; + while(true) + { + + if (tok == YYEOF) { + if (u_sess->parser_cxt.is_procedure==false){ + yyerror("function is not ended correctly"); + } else { + yyerror("procedure is not ended correctly"); + } + } + + if (tok == ';' && !is_defining_proc) + { + break; + } + /* procedure or function can have multiple blocklevel*/ + if (tok == K_BEGIN) + { + blocklevel++; + } + + /* if have is or as,it means in body*/ + if (tok == K_IS || tok == K_AS) + { + if (u_sess->plsql_cxt.plpgsql_curr_compile_package->is_spec_compiling) { + yyerror("not allow define function or procedure in package specification"); + } + is_defining_proc = true; + } + + if (tok == K_END) + { + tok = yylex(); + /* process end loop*/ + if (tok == K_LOOP) { + continue; + } + if (blocklevel == 1 && (pre_tok == ';' || pre_tok == K_BEGIN) && (tok == ';' || tok == 0)) + { + break; + } + if (blocklevel > 1 && (pre_tok == ';' || pre_tok == K_BEGIN) && (tok == ';' || tok == 0)) + { + blocklevel--; + } + } + pre_tok = tok; + tok = yylex(); + } + u_sess->parser_cxt.in_package_function_compile = false; + plpgsql_append_source_text(&ds, startlocation, yylloc); + + /* + To use the SQL Parser, we add a string to make SQL parser recognize. + Package specification use SQL parser parse the string too. + */ + if (is_defining_proc == false) { + appendStringInfoString(&ds, " AS BEGIN "); + appendStringInfoString(&ds, " END;\n"); + u_sess->parser_cxt.isFunctionDeclare = true; + } else { + u_sess->parser_cxt.isFunctionDeclare = false; + } + + spec_proc_str = pstrdup(ds.data); + pfree_ext(ds.data); + return spec_proc_str; +} +static char* get_init_proc(int tok) +{ + int startlocation = yylloc; + char* init_package_str = NULL; + StringInfoData ds; + initStringInfo(&ds); + while(true) + { + /* + package instantiation still need a token 'END' as end, + but it's from package end, For details about how to instantiate + a package, see the package instantiation grammer. + */ + if (tok == K_BEGIN) + startlocation = yylloc; + if (tok == YYEOF) + yyerror("procedure is not ended correctly"); + if (tok == K_END) + { + tok = yylex(); + if (tok == ';' || tok == 0) + { + break; + } + } + tok = yylex(); + } + /* + package instantiation not need specify end. + */ + plpgsql_append_source_text(&ds, startlocation, yylloc); + init_package_str = pstrdup(ds.data); + pfree_ext(ds.data); + return init_package_str; +} static PLpgSQL_type * read_datatype(int tok) @@ -4616,6 +5005,17 @@ make_execsql_stmt(int firsttoken, int location) read_into_target(&rec, &row, &have_strict); u_sess->plsql_cxt.plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR; } + if (tok == T_CWORD && prev_tok!=K_SELECT + && prev_tok!= K_PERFORM) { + List *dtname = yylval.cword.idents; + tok = yylex(); + if (tok == '(') { + plbsql_push_back_token(tok); + continue; + } + plbsql_push_back_token(tok); + plpgsql_pkg_add_unknown_var_to_namespace(dtname); + } } u_sess->plsql_cxt.plpgsql_IdentifierLookup = save_IdentifierLookup; @@ -4658,6 +5058,7 @@ make_execsql_stmt(int firsttoken, int location) execsql->rec = rec; execsql->row = row; execsql->placeholders = placeholders; + execsql->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *) execsql; } @@ -4684,6 +5085,7 @@ read_fetch_direction(void) fetch->how_many = 1; fetch->expr = NULL; fetch->returns_multiple_rows = false; + fetch->sqlString = plpgsql_get_curline_query(); tok = yylex(); if (tok == 0) @@ -4834,6 +5236,7 @@ make_return_stmt(int location) newp->lineno = plpgsql_location_to_lineno(location); newp->expr = NULL; newp->retvarno = -1; + newp->sqlString = plpgsql_get_curline_query(); if (u_sess->plsql_cxt.plpgsql_curr_compile->fn_retset) { @@ -4927,6 +5330,7 @@ make_return_next_stmt(int location) newp->lineno = plpgsql_location_to_lineno(location); newp->expr = NULL; newp->retvarno = -1; + newp->sqlString = plpgsql_get_curline_query(); if (u_sess->plsql_cxt.plpgsql_curr_compile->out_param_varno >= 0) { @@ -4984,6 +5388,7 @@ make_return_query_stmt(int location) newp = (PLpgSQL_stmt_return_query *)palloc0(sizeof(PLpgSQL_stmt_return_query)); newp->cmd_type = PLPGSQL_STMT_RETURN_QUERY; newp->lineno = plpgsql_location_to_lineno(location); + newp->sqlString = plpgsql_get_curline_query(); /* check for RETURN QUERY EXECUTE */ if ((tok = yylex()) != K_EXECUTE) @@ -5054,6 +5459,9 @@ check_assignable(PLpgSQL_datum *datum, int location) case PLPGSQL_DTYPE_ARRAYELEM: /* always assignable? */ break; + case PLPGSQL_DTYPE_UNKNOWN: + /* package variable? */ + break; default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); break; @@ -5286,6 +5694,7 @@ read_using_target(List **in_expr, PLpgSQL_row **out_row) (*out_row)->nfields = out_nfields; (*out_row)->fieldnames = (char **)palloc(sizeof(char *) * out_nfields); (*out_row)->varnos = (int *)palloc(sizeof(int) * out_nfields); + (*out_row)->isImplicit = true; while (--out_nfields >= 0) { (*out_row)->fieldnames[out_nfields] = out_fieldnames[out_nfields]; @@ -5363,6 +5772,7 @@ read_into_scalar_list(char *initial_name, row->nfields = nfields; row->fieldnames = (char **)palloc(sizeof(char *) * nfields); row->varnos = (int *)palloc(sizeof(int) * nfields); + row->isImplicit = true; while (--nfields >= 0) { row->fieldnames[nfields] = fieldnames[nfields]; @@ -5475,6 +5885,7 @@ read_into_array_scalar_list(char *initial_name, row->nfields = nfields; row->fieldnames = (char**)palloc(sizeof(char *) * nfields); row->varnos = (int*)palloc(sizeof(int) * nfields); + row->isImplicit = true; while (--nfields >= 0) { row->fieldnames[nfields] = fieldnames[nfields]; @@ -5545,6 +5956,7 @@ read_into_placeholder_scalar_list(char *initial_name, row->varnos = NULL; row->intoplaceholders = intoplaceholders; row->intodatums = NULL; + row->isImplicit = true; plpgsql_adddatum((PLpgSQL_datum *)row); @@ -5579,6 +5991,7 @@ make_scalar_list1(char *initial_name, row->varnos = (int *)palloc(sizeof(int)); row->fieldnames[0] = initial_name; row->varnos[0] = initial_datum->dno; + row->isImplicit = true; plpgsql_adddatum((PLpgSQL_datum *)row); @@ -5705,6 +6118,11 @@ parse_datatype(const char *string, int location) t_thrd.log_cxt.error_context_stack = syntax_errcontext.previous; /* Okay, build a PLpgSQL_type data structure for it */ + if (u_sess->plsql_cxt.plpgsql_curr_compile == NULL) + { + return plpgsql_build_datatype(type_id, typmod, 0); + } + return plpgsql_build_datatype(type_id, typmod, u_sess->plsql_cxt.plpgsql_curr_compile->fn_input_collation); } @@ -5978,6 +6396,7 @@ make_case(int location, PLpgSQL_expr *t_expr, newp->t_varno = 0; newp->case_when_list = case_when_list; newp->have_else = (else_stmts != NIL); + newp->sqlString = plpgsql_get_curline_query(); /* Get rid of list-with-NULL hack */ if (list_length(else_stmts) == 1 && linitial(else_stmts) == NULL) newp->else_stmts = NIL; @@ -6011,7 +6430,7 @@ make_case(int location, PLpgSQL_expr *t_expr, plpgsql_build_datatype(INT4OID, -1, InvalidOid), - true); + true, true); newp->t_varno = t_var->dno; foreach(l, case_when_list) @@ -6132,6 +6551,7 @@ make_callfunc_stmt_no_arg(const char *sqlstart, int location) perform->cmd_type = PLPGSQL_STMT_PERFORM; perform->lineno = plpgsql_location_to_lineno(location); perform->expr = expr; + perform->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)perform; } @@ -6205,8 +6625,35 @@ parse_lob_open_close(int location) perform->cmd_type = PLPGSQL_STMT_PERFORM; perform->lineno = plpgsql_location_to_lineno(location); perform->expr = expr; + perform->sqlString = plpgsql_get_curline_query(); return (PLpgSQL_stmt *)perform; } yyerror("syntax error"); return NULL; } + +static void raw_parse_package_function(char* proc_str) +{ + if (u_sess->plsql_cxt.plpgsql_curr_compile_package!=NULL) + { + List* raw_parsetree_list = NULL; + raw_parsetree_list = raw_parser(proc_str); + CreateFunctionStmt* stmt;; + stmt = (CreateFunctionStmt *)linitial(raw_parsetree_list); + stmt->queryStr = proc_str; + if (u_sess->plsql_cxt.plpgsql_curr_compile_package->is_spec_compiling) { + stmt->isPrivate = false; + } else { + stmt->isPrivate = true; + } + if (u_sess->parser_cxt.isFunctionDeclare) { + stmt->isFunctionDeclare = true; + } else { + stmt->isFunctionDeclare = false; + } + List *proc_list = u_sess->plsql_cxt.plpgsql_curr_compile_package->proc_list; + u_sess->plsql_cxt.plpgsql_curr_compile_package->proc_list = lappend(proc_list,stmt); + } else { + yyerror("kerword PROCEDURE only use in package compile"); + } +} diff --git a/contrib/db_b_parser/pl/pl_b_scanner.cpp b/contrib/db_b_parser/pl/pl_b_scanner.cpp index 2b5cf41b7..7601eeae0 100644 --- a/contrib/db_b_parser/pl/pl_b_scanner.cpp +++ b/contrib/db_b_parser/pl/pl_b_scanner.cpp @@ -56,55 +56,56 @@ */ static const ScanKeyword reserved_keywords[] = { - PG_KEYWORD("all", K_ALL, RESERVED_KEYWORD) - PG_KEYWORD("begin", K_BEGIN, RESERVED_KEYWORD) - PG_KEYWORD("by", K_BY, RESERVED_KEYWORD) - PG_KEYWORD("case", K_CASE, RESERVED_KEYWORD) - PG_KEYWORD("close", K_CLOSE, RESERVED_KEYWORD) - PG_KEYWORD("collate", K_COLLATE, RESERVED_KEYWORD) - PG_KEYWORD("declare", K_DECLARE, RESERVED_KEYWORD) - PG_KEYWORD("default", K_DEFAULT, RESERVED_KEYWORD) - PG_KEYWORD("delete", K_DELETE, RESERVED_KEYWORD) - PG_KEYWORD("diagnostics", K_DIAGNOSTICS, RESERVED_KEYWORD) - PG_KEYWORD("else", K_ELSE, RESERVED_KEYWORD) - PG_KEYWORD("elseif", K_ELSIF, RESERVED_KEYWORD) - PG_KEYWORD("elsif", K_ELSIF, RESERVED_KEYWORD) - PG_KEYWORD("end", K_END, RESERVED_KEYWORD) - PG_KEYWORD("exception", K_EXCEPTION, RESERVED_KEYWORD) - PG_KEYWORD("execute", K_EXECUTE, RESERVED_KEYWORD) - PG_KEYWORD("exit", K_EXIT, RESERVED_KEYWORD) - PG_KEYWORD("fetch", K_FETCH, RESERVED_KEYWORD) - PG_KEYWORD("for", K_FOR, RESERVED_KEYWORD) - PG_KEYWORD("forall", K_FORALL, RESERVED_KEYWORD) - PG_KEYWORD("foreach", K_FOREACH, RESERVED_KEYWORD) - PG_KEYWORD("from", K_FROM, RESERVED_KEYWORD) + PG_KEYWORD("all", K_ALL, RESERVED_KEYWORD) + PG_KEYWORD("begin", K_BEGIN, RESERVED_KEYWORD) + PG_KEYWORD("by", K_BY, RESERVED_KEYWORD) + PG_KEYWORD("case", K_CASE, RESERVED_KEYWORD) + PG_KEYWORD("close", K_CLOSE, RESERVED_KEYWORD) + PG_KEYWORD("collate", K_COLLATE, RESERVED_KEYWORD) + PG_KEYWORD("declare", K_DECLARE, RESERVED_KEYWORD) + PG_KEYWORD("default", K_DEFAULT, RESERVED_KEYWORD) + PG_KEYWORD("delete", K_DELETE, RESERVED_KEYWORD) + PG_KEYWORD("diagnostics", K_DIAGNOSTICS, RESERVED_KEYWORD) + PG_KEYWORD("else", K_ELSE, RESERVED_KEYWORD) + PG_KEYWORD("elseif", K_ELSIF, RESERVED_KEYWORD) + PG_KEYWORD("elsif", K_ELSIF, RESERVED_KEYWORD) + PG_KEYWORD("end", K_END, RESERVED_KEYWORD) + PG_KEYWORD("exception", K_EXCEPTION, RESERVED_KEYWORD) + PG_KEYWORD("execute", K_EXECUTE, RESERVED_KEYWORD) + PG_KEYWORD("exit", K_EXIT, RESERVED_KEYWORD) + PG_KEYWORD("fetch", K_FETCH, RESERVED_KEYWORD) + PG_KEYWORD("for", K_FOR, RESERVED_KEYWORD) + PG_KEYWORD("forall", K_FORALL, RESERVED_KEYWORD) + PG_KEYWORD("foreach", K_FOREACH, RESERVED_KEYWORD) + PG_KEYWORD("from", K_FROM, RESERVED_KEYWORD) + PG_KEYWORD("function", K_FUNCTION, RESERVED_KEYWORD) PG_KEYWORD("get", K_GET, RESERVED_KEYWORD) - PG_KEYWORD("goto", K_GOTO, RESERVED_KEYWORD) - PG_KEYWORD("if", K_IF, RESERVED_KEYWORD) - PG_KEYWORD("in", K_IN, RESERVED_KEYWORD) - PG_KEYWORD("insert", K_INSERT, RESERVED_KEYWORD) - PG_KEYWORD("into", K_INTO, RESERVED_KEYWORD) - PG_KEYWORD("loop", K_LOOP, RESERVED_KEYWORD) + PG_KEYWORD("goto", K_GOTO, RESERVED_KEYWORD) + PG_KEYWORD("if", K_IF, RESERVED_KEYWORD) + PG_KEYWORD("in", K_IN, RESERVED_KEYWORD) + PG_KEYWORD("insert", K_INSERT, RESERVED_KEYWORD) + PG_KEYWORD("into", K_INTO, RESERVED_KEYWORD) + PG_KEYWORD("loop", K_LOOP, RESERVED_KEYWORD) PG_KEYWORD("move", K_MOVE, RESERVED_KEYWORD) - PG_KEYWORD("not", K_NOT, RESERVED_KEYWORD) + PG_KEYWORD("not", K_NOT, RESERVED_KEYWORD) PG_KEYWORD("null", K_NULL, RESERVED_KEYWORD) - PG_KEYWORD("of", K_OF, RESERVED_KEYWORD) - PG_KEYWORD("open", K_OPEN, RESERVED_KEYWORD) - PG_KEYWORD("or", K_OR, RESERVED_KEYWORD) - PG_KEYWORD("out", K_OUT, RESERVED_KEYWORD) - PG_KEYWORD("perform", K_PERFORM, RESERVED_KEYWORD) - PG_KEYWORD("raise", K_RAISE, RESERVED_KEYWORD) - PG_KEYWORD("ref", K_REF, RESERVED_KEYWORD) - PG_KEYWORD("return", K_RETURN, RESERVED_KEYWORD) - PG_KEYWORD("select", K_SELECT, RESERVED_KEYWORD) + PG_KEYWORD("of", K_OF, RESERVED_KEYWORD) + PG_KEYWORD("open", K_OPEN, RESERVED_KEYWORD) + PG_KEYWORD("or", K_OR, RESERVED_KEYWORD) + PG_KEYWORD("out", K_OUT, RESERVED_KEYWORD) + PG_KEYWORD("procedure", K_PROCEDURE, RESERVED_KEYWORD) + PG_KEYWORD("raise", K_RAISE, RESERVED_KEYWORD) + PG_KEYWORD("ref", K_REF, RESERVED_KEYWORD) + PG_KEYWORD("return", K_RETURN, RESERVED_KEYWORD) + PG_KEYWORD("select", K_SELECT, RESERVED_KEYWORD) PG_KEYWORD("strict", K_STRICT, RESERVED_KEYWORD) - PG_KEYWORD("then", K_THEN, RESERVED_KEYWORD) + PG_KEYWORD("then", K_THEN, RESERVED_KEYWORD) PG_KEYWORD("to", K_TO, RESERVED_KEYWORD) - PG_KEYWORD("type", K_TYPE, RESERVED_KEYWORD) + PG_KEYWORD("type", K_TYPE, RESERVED_KEYWORD) PG_KEYWORD("update", K_UPDATE, RESERVED_KEYWORD) - PG_KEYWORD("using", K_USING, RESERVED_KEYWORD) + PG_KEYWORD("using", K_USING, RESERVED_KEYWORD) PG_KEYWORD("when", K_WHEN, RESERVED_KEYWORD) - PG_KEYWORD("while", K_WHILE, RESERVED_KEYWORD) + PG_KEYWORD("while", K_WHILE, RESERVED_KEYWORD) }; static const int num_reserved_keywords = lengthof(reserved_keywords); @@ -114,6 +115,7 @@ static const ScanKeyword unreserved_keywords[] = { PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD) PG_KEYWORD("alter", K_ALTER, UNRESERVED_KEYWORD) PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD) + PG_KEYWORD("as", K_AS, UNRESERVED_KEYWORD) PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD) PG_KEYWORD("commit", K_COMMIT, UNRESERVED_KEYWORD) PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD) @@ -127,9 +129,11 @@ static const ScanKeyword unreserved_keywords[] = { PG_KEYWORD("error", K_ERROR, UNRESERVED_KEYWORD) PG_KEYWORD("first", K_FIRST, UNRESERVED_KEYWORD) PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD) + PG_KEYWORD("function", K_FUNCTION, UNRESERVED_KEYWORD) PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD) PG_KEYWORD("immediate", K_IMMEDIATE, UNRESERVED_KEYWORD) PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD) + PG_KEYWORD("instantiation", K_INSTANTIATION, UNRESERVED_KEYWORD) PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD) PG_KEYWORD("last", K_LAST, UNRESERVED_KEYWORD) PG_KEYWORD("log", K_LOG, UNRESERVED_KEYWORD) @@ -140,13 +144,14 @@ static const ScanKeyword unreserved_keywords[] = { PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD) PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD) PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD) + PG_KEYWORD("package", K_PACKAGE, UNRESERVED_KEYWORD) + PG_KEYWORD("perform", K_PERFORM, UNRESERVED_KEYWORD) PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD) PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD) PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD) -#ifndef ENABLE_MULTIPLE_NODES PG_KEYWORD("pragma", K_PRAGMA, UNRESERVED_KEYWORD) -#endif PG_KEYWORD("prior", K_PRIOR, UNRESERVED_KEYWORD) + PG_KEYWORD("procedure", K_PROCEDURE, UNRESERVED_KEYWORD) PG_KEYWORD("query", K_QUERY, UNRESERVED_KEYWORD) PG_KEYWORD("record", K_RECORD, UNRESERVED_KEYWORD) PG_KEYWORD("relative", K_RELATIVE, UNRESERVED_KEYWORD) @@ -537,6 +542,24 @@ int plpgsql_location_to_lineno(int location) return u_sess->plsql_cxt.cur_line_num; } +char* plpgsql_get_curline_query() +{ + int len = 0; + if (u_sess->plsql_cxt.cur_line_end == NULL) { + /* no '\n' in whole procedure source text */ + len = strlen(u_sess->plsql_cxt.cur_line_start); + } else { + len = u_sess->plsql_cxt.cur_line_end - u_sess->plsql_cxt.cur_line_start; + } + char* curQuery = NULL; + if (len > 0) { + curQuery = (char*)palloc0(sizeof(char) * (len + 1)); + int rc = memcpy_s(curQuery, len + 1, u_sess->plsql_cxt.cur_line_start, len); + securec_check(rc, "\0", "\0"); + } + return curQuery; +} + /* initialize or reset the state for plpgsql_location_to_lineno */ static void location_lineno_init(void) { @@ -651,6 +674,9 @@ static int plpgsql_parse_cursor_attribute(int* loc) int token = -1; PLpgSQL_nsitem* ns = NULL; + if (u_sess->parser_cxt.in_package_function_compile) { + return token; + } /* coverity warning clear */ tok1 = internal_yylex(&aux1); if (tok1 != IDENT && tok1 != PARAM) { @@ -791,5 +817,6 @@ bool plpgsql_is_token_match(int token) plbsql_push_back_token(tok); return true; } + plbsql_push_back_token(tok); return false; } diff --git a/contrib/db_b_parser/pl/pl_b_sql.h b/contrib/db_b_parser/pl/pl_b_sql.h index 5c55abe58..14199e2d2 100644 --- a/contrib/db_b_parser/pl/pl_b_sql.h +++ b/contrib/db_b_parser/pl/pl_b_sql.h @@ -1,17 +1,17 @@ -/* ------------------------------------------------------------------------- - * - * plpgsql.h - Definitions for the PL/pgSQL - * procedural language - * +/*--------------------------------------------------------------------------------------- + * + * plpgsql.h + * Definitions for the PL/pgSQL procedural language + * * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California - * - * + * * IDENTIFICATION - * src/pl/plpgsql/src/plpgsql.h + * src/include/utils/plpgsql.h * - * ------------------------------------------------------------------------- + * --------------------------------------------------------------------------------------- */ + #ifndef PLPGSQL_H #define PLPGSQL_H #ifndef PLBSQL_H @@ -24,9 +24,7 @@ #include "catalog/namespace.h" #include "commands/trigger.h" #include "executor/spi.h" -#ifndef ENABLE_MULTIPLE_NODES -#include "tcop/autonomoustransaction.h" -#endif +#include "executor/functions.h" /********************************************************************** * Definitions @@ -50,7 +48,9 @@ enum { PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_RECORD, PLPGSQL_NSTYPE_REFCURSOR, - PLPGSQL_NSTYPE_VARRAY + PLPGSQL_NSTYPE_VARRAY, + PLPGSQL_NSTYPE_PROC, + PLPGSQL_NSTYPE_UNKNOWN }; /* ---------- @@ -64,7 +64,8 @@ enum { PLPGSQL_DTYPE_RECORD, PLPGSQL_DTYPE_RECFIELD, PLPGSQL_DTYPE_ARRAYELEM, - PLPGSQL_DTYPE_EXPR + PLPGSQL_DTYPE_EXPR, + PLPGSQL_DTYPE_UNKNOWN }; // enums token flag @@ -177,8 +178,8 @@ typedef enum { PLPGSQL_TRUE, PLPGSQL_FALSE, PLPGSQL_NULL } PLpgSQL_state; typedef struct PLpgSQL_datum { /* Generic datum array item */ int dtype; int dno; + bool ispkg; } PLpgSQL_datum; - /* * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these * fields @@ -186,13 +187,16 @@ typedef struct PLpgSQL_datum { /* Generic datum array item */ typedef struct { /* Scalar or composite variable */ int dtype; int dno; + bool ispkg; char* refname; int lineno; + bool isImplicit; } PLpgSQL_variable; typedef struct PLpgSQL_expr { /* SQL Query to plan and execute */ int dtype; int dno; + bool ispkg; char* query; SPIPlanPtr plan; Bitmapset* paramnos; /* all dnos referenced by this query */ @@ -224,9 +228,10 @@ typedef struct PLpgSQL_expr { /* SQL Query to plan and execute */ bool is_cachedplan_shared; } PLpgSQL_expr; -typedef struct { /* Postgres data type */ +typedef struct { /* openGauss data type */ int dtype; int dno; + bool ispkg; char* typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ int ttype; /* PLPGSQL_TTYPE_ code */ @@ -242,8 +247,10 @@ typedef struct { /* Postgres data type */ typedef struct { /* Scalar variable */ int dtype; int dno; + bool ispkg; char* refname; int lineno; + bool isImplicit; PLpgSQL_type* datatype; int isconst; @@ -258,13 +265,17 @@ typedef struct { /* Scalar variable */ bool freeval; bool is_cursor_var; /* variable is a refcursor */ bool is_cursor_open; /* mark var is isopen for isopen option shoule be always not null */ + List* pkg_name = NULL; + PLpgSQL_package* pkg = NULL; } PLpgSQL_var; typedef struct { /* Row variable */ int dtype; int dno; + bool ispkg; char* refname; int lineno; + bool isImplicit; TupleDesc rowtupdesc; @@ -282,6 +293,8 @@ typedef struct { /* Row variable */ int intoplaceholders; /* number of placeholders, for anonymous block in dynamic stmt */ PLpgSQL_datum** intodatums; + List* pkg_name = NULL; + PLpgSQL_package* pkg = NULL; } PLpgSQL_row; typedef struct { @@ -294,6 +307,7 @@ typedef struct { typedef struct { int dtype; int dno; + bool ispkg; char* typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ int ttype; /* PLPGSQL_TTYPE_ code */ @@ -314,8 +328,10 @@ typedef struct { typedef struct { /* Record variable (non-fixed structure) */ int dtype; int dno; + bool ispkg; char* refname; int lineno; + bool isImplicit; HeapTuple tup; TupleDesc tupdesc; @@ -326,6 +342,7 @@ typedef struct { /* Record variable (non-fixed structure) */ typedef struct { /* Field in record */ int dtype; int dno; + bool ispkg; char* fieldname; int recparentno; /* dno of parent record */ } PLpgSQL_recfield; @@ -333,6 +350,7 @@ typedef struct { /* Field in record */ typedef struct { /* Element of array variable */ int dtype; int dno; + bool ispkg; PLpgSQL_expr* subscript; int arrayparentno; /* dno of parent array variable */ /* Remaining fields are cached info about the array variable's type */ @@ -351,6 +369,7 @@ typedef struct PLpgSQL_nsitem { /* Item in the compilers namespace tree */ int itemtype; int itemno; struct PLpgSQL_nsitem* prev; + char* pkgname; char name[FLEXIBLE_ARRAY_MEMBER]; /* actually, as long as needed */ } PLpgSQL_nsitem; @@ -359,9 +378,14 @@ typedef struct { /* Generic execution node */ int lineno; } PLpgSQL_stmt; -typedef PLpgSQL_stmt PLpgSQL_stmt_null; +typedef struct PLpgSQL_stmt_null { + int cmd_type; + int lineno; + char* sqlString; +} PLpgSQL_stmt_null; extern THR_LOCAL List* goto_labels; + typedef struct { char* label; PLpgSQL_stmt* stmt; @@ -389,13 +413,12 @@ typedef struct PLpgSQL_stmt_block { /* Block of statements */ int cmd_type; int lineno; char* label; -#ifndef ENABLE_MULTIPLE_NODES - bool autonomous; -#endif + bool isAutonomous; List* body; /* List of statements */ int n_initvars; int* initvarnos; PLpgSQL_exception_block* exceptions; + char* sqlString; } PLpgSQL_stmt_block; typedef struct { /* Assign statement */ @@ -403,12 +426,14 @@ typedef struct { /* Assign statement */ int lineno; int varno; PLpgSQL_expr* expr; + char* sqlString; } PLpgSQL_stmt_assign; typedef struct { /* PERFORM statement */ int cmd_type; int lineno; PLpgSQL_expr* expr; + char* sqlString; } PLpgSQL_stmt_perform; /* @@ -417,6 +442,7 @@ typedef struct { /* PERFORM statement */ typedef struct { int cmd_type; int lineno; + char* sqlString; } PLpgSQL_stmt_commit; /* @@ -425,6 +451,7 @@ typedef struct { typedef struct { int cmd_type; int lineno; + char* sqlString; } PLpgSQL_stmt_rollback; typedef struct { /* Get Diagnostics item */ @@ -437,6 +464,7 @@ typedef struct { /* Get Diagnostics statement */ int lineno; bool is_stacked; /* STACKED or CURRENT diagnostics area? */ List* diag_items; /* List of PLpgSQL_diag_item */ + char* sqlString; } PLpgSQL_stmt_getdiag; typedef struct { /* IF statement */ @@ -446,21 +474,25 @@ typedef struct { /* IF statement */ List* then_body; /* List of statements */ List* elsif_list; /* List of PLpgSQL_if_elsif structs */ List* else_body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_if; typedef struct { /* GOTO statement */ int cmd_type; int lineno; char* label; + char* sqlString; } PLpgSQL_stmt_goto; -typedef struct { /* one ELSIF arm of IF statement */ +typedef struct /* one ELSIF arm of IF statement */ +{ int lineno; PLpgSQL_expr* cond; /* boolean expression for this case */ List* stmts; /* List of statements */ } PLpgSQL_if_elsif; -typedef struct { /* CASE statement */ +typedef struct /* CASE statement */ +{ int cmd_type; int lineno; PLpgSQL_expr* t_expr; /* test expression, or NULL if none */ @@ -468,12 +500,15 @@ typedef struct { /* CASE statement */ List* case_when_list; /* List of PLpgSQL_case_when structs */ bool have_else; /* flag needed because list could be empty */ List* else_stmts; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_case; -typedef struct { /* one arm of CASE statement */ +typedef struct /* one arm of CASE statement */ +{ int lineno; PLpgSQL_expr* expr; /* boolean expression for this case */ List* stmts; /* List of statements */ + char* sqlString; } PLpgSQL_case_when; typedef struct { /* Unconditional LOOP statement */ @@ -481,6 +516,7 @@ typedef struct { /* Unconditional LOOP statement */ int lineno; char* label; List* body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_loop; typedef struct { /* WHILE cond LOOP statement */ @@ -489,6 +525,7 @@ typedef struct { /* WHILE cond LOOP statement */ char* label; PLpgSQL_expr* cond; List* body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_while; typedef struct { /* FOR statement with integer loopvar */ @@ -501,6 +538,7 @@ typedef struct { /* FOR statement with integer loopvar */ PLpgSQL_expr* step; /* NULL means default (ie, BY 1) */ int reverse; List* body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_fori; /* @@ -515,6 +553,7 @@ typedef struct { PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_forq; typedef struct { /* FOR statement running over SELECT */ @@ -524,6 +563,7 @@ typedef struct { /* FOR statement running over SELECT */ PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ + char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ PLpgSQL_expr* query; } PLpgSQL_stmt_fors; @@ -535,6 +575,7 @@ typedef struct { /* FOR statement running over cursor */ PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ + char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ int curvar; PLpgSQL_expr* argquery; /* cursor arguments if any */ @@ -547,6 +588,7 @@ typedef struct { /* FOR statement running over EXECUTE */ PLpgSQL_rec* rec; PLpgSQL_row* row; List* body; /* List of statements */ + char* sqlString; /* end of fields that must match PLpgSQL_stmt_forq */ PLpgSQL_expr* query; List* params; /* USING expressions */ @@ -560,6 +602,7 @@ typedef struct { /* FOREACH item in array loop */ int slice; /* slice dimension, or 0 */ PLpgSQL_expr* expr; /* array expression */ List* body; /* List of statements */ + char* sqlString; } PLpgSQL_stmt_foreach_a; typedef struct { /* OPEN a curvar */ @@ -572,6 +615,7 @@ typedef struct { /* OPEN a curvar */ PLpgSQL_expr* query; PLpgSQL_expr* dynquery; List* params; /* USING expressions */ + char* sqlString; } PLpgSQL_stmt_open; typedef struct { /* FETCH or MOVE statement */ @@ -585,12 +629,14 @@ typedef struct { /* FETCH or MOVE statement */ PLpgSQL_expr* expr; /* count, if expression */ bool is_move; /* is this a fetch or move? */ bool returns_multiple_rows; /* can return more than one row? */ + char* sqlString; } PLpgSQL_stmt_fetch; typedef struct { /* CLOSE curvar */ int cmd_type; int lineno; int curvar; + char* sqlString; } PLpgSQL_stmt_close; typedef struct { /* EXIT or CONTINUE statement */ @@ -599,6 +645,7 @@ typedef struct { /* EXIT or CONTINUE statement */ bool is_exit; /* Is this an exit or a continue? */ char* label; /* NULL if it's an unlabelled EXIT/CONTINUE */ PLpgSQL_expr* cond; + char* sqlString; } PLpgSQL_stmt_exit; typedef struct { /* RETURN statement */ @@ -606,6 +653,7 @@ typedef struct { /* RETURN statement */ int lineno; PLpgSQL_expr* expr; int retvarno; + char* sqlString; } PLpgSQL_stmt_return; typedef struct { /* RETURN NEXT statement */ @@ -613,6 +661,7 @@ typedef struct { /* RETURN NEXT statement */ int lineno; PLpgSQL_expr* expr; int retvarno; + char* sqlString; } PLpgSQL_stmt_return_next; typedef struct { /* RETURN QUERY statement */ @@ -621,6 +670,7 @@ typedef struct { /* RETURN QUERY statement */ PLpgSQL_expr* query; /* if static query */ PLpgSQL_expr* dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */ List* params; /* USING arguments for dynamic query */ + char* sqlString; } PLpgSQL_stmt_return_query; typedef struct { /* RAISE statement */ @@ -631,6 +681,7 @@ typedef struct { /* RAISE statement */ char* message; /* old-style message format literal, or NULL */ List* params; /* list of expressions for old-style message */ List* options; /* list of PLpgSQL_raise_option */ + char* sqlString; } PLpgSQL_stmt_raise; typedef struct { /* RAISE statement option */ @@ -651,6 +702,7 @@ typedef struct { /* Generic SQL statement to execute */ // A db function invoke feature int placeholders; bool multi_func; + char* sqlString; } PLpgSQL_stmt_execsql; // Added USING IN/OUT/IN OUT for plpgsql @@ -669,6 +721,7 @@ typedef struct { /* Dynamic SQL string to execute */ bool isinouttype; /* IN OUT parameters, differ from INTO statment */ bool isanonymousblock; /* check if it is anonymous block */ void* ppd; /* IN or IN OUT parameters */ + char* sqlString; } PLpgSQL_stmt_dynexecute; typedef struct PLpgSQL_func_hashkey { /* Hash lookup key for functions */ @@ -698,15 +751,19 @@ typedef struct PLpgSQL_func_hashkey { /* Hash lookup key for functions */ * PLpgSQL functions. Be careful that extra positions are zeroed! */ Oid argtypes[FUNC_MAX_ARGS]; + + Oid packageOid; /* package oid if is in a package */ } PLpgSQL_func_hashkey; typedef struct PLpgSQL_function { /* Complete compiled function */ char* fn_signature; Oid fn_oid; + Oid pkg_oid; OverrideSearchPath* fn_searchpath; Oid fn_owner; TransactionId fn_xmin; ItemPointerData fn_tid; + bool is_private; bool fn_is_trigger; Oid fn_input_collation; PLpgSQL_func_hashkey* fn_hashkey; /* back-link to hashtable key */ @@ -761,10 +818,15 @@ typedef struct PLpgSQL_function { /* Complete compiled function */ /* these fields are used during trigger pre-parsing */ bool pre_parse_trig; Relation tg_relation; + + /* pl debugger ptr */ + struct DebugInfo* debug; } PLpgSQL_function; +class AutonomousSession; typedef struct PLpgSQL_execstate { /* Runtime execution data */ PLpgSQL_function* func; /* function being executed */ + Datum retval; bool retisnull; Oid rettype; /* type of current retval */ @@ -776,16 +838,15 @@ typedef struct PLpgSQL_execstate { /* Runtime execution data */ bool readonly_func; TupleDesc rettupdesc; - char* exitlabel; /* the "target" label of the current EXIT or CONTINUE stmt, if any */ - ErrorData* cur_error; /* current exception handler's error */ + char* exitlabel; /* the "target" label of the current EXIT or + * CONTINUE stmt, if any */ + ErrorData* cur_error; /* current exception handler's error */ Tuplestorestate* tuple_store; /* SRFs accumulate results here */ MemoryContext tuple_store_cxt; ResourceOwner tuple_store_owner; ReturnSetInfo* rsi; -#ifndef ENABLE_MULTIPLE_NODES - AutonomousSession *autonomous_session; -#endif + int found_varno; /* @@ -824,6 +885,22 @@ typedef struct PLpgSQL_execstate { /* Runtime execution data */ Cursor_Data* cursor_return_data; } PLpgSQL_execstate; +typedef struct PLpgSQL_pkg_execstate { /* Runtime execution data */ + Oid pkgoid; + char pkgkind; + MemoryContext pkgcontext; + int ndatums; + int n_initvars; + int* initvarnos; + PLpgSQL_datum** datums; + bool is_bodydefined; + struct PLpgSQL_nsitem* public_ns; + /* namespace chain visible to this package */ + struct PLpgSQL_nsitem* private_ns; +} PLpgSQL_pkg_execstate; + + + /* * A PLpgSQL_plugin structure represents an instrumentation plugin. * To instrument PL/pgSQL, a plugin library must access the rendezvous @@ -890,6 +967,234 @@ typedef struct { List* idents; /* valid if composite name */ } PLwdatum; + +typedef struct PLpgSQL_pkg_hashkey { /* Hash lookup key for functions */ + Oid pkgOid; + + /* + * We must include the input collation as part of the hash key too, + * because we have to generate different plans (with different Param + * collations) for different collation settings. + */ + Oid inputCollation; +} PLpgSQL_pkg_hashkey; + +typedef struct plpgsql_pkg_hashent { + + PLpgSQL_pkg_hashkey key; + + PLpgSQL_package* package; + + DListCell* cell; /* Dlist cell for delete package compile results. */ + +} plpgsql_pkg_HashEnt; + +typedef struct PLpgSQL_package { /* Complete compiled package */ + char* pkg_signature; + Oid pkg_oid; + OverrideSearchPath* pkg_searchpath; + Oid pkg_owner; + TransactionId pkg_xmin; + ItemPointerData pkg_tid; + MemoryContext pkg_cxt; + PLpgSQL_pkg_hashkey* pkg_hashkey; /* back-link to hashtable key */ + bool is_spec_compiling; + bool is_bodydefined; + + /* namespace chain visible to this package */ + struct PLpgSQL_nsitem* public_ns; + + /*proc list in package*/ + List* proc_list; + /* namespace chain visible to this package */ + struct PLpgSQL_nsitem* private_ns; + + /*compiled list in package*/ + List* proc_compiled_list; + + // magic variables' varno for implicit cursor attributes + int sql_cursor_found_varno; + int sql_notfound_varno; + int sql_isopen_varno; + int sql_rowcount_varno; + PLpgSQL_resolve_option resolve_option; + int ndatums; + int public_ndatums; + PLpgSQL_datum** datums; + int n_initvars; + int* initvarnos; + + Cursor_Data* cursor_return_data; + char* plpgsql_error_funcname; + knl_u_plpgsql_pkg_context* u_pkg; + Oid namespaceOid; +} PLpgSQL_package; +/********************************************************************** + * Pl debugger + **********************************************************************/ +typedef void (*PlpgsqlDebugFunc)(PLpgSQL_function* func, PLpgSQL_execstate* estate); +typedef void (*PlpgsqlStartUpFunc)(PLpgSQL_function* func); + +typedef struct CodeLine { + int lineno; + char* code; + bool canBreak; +} CodeLine; + +typedef struct PLDebug_variable { + NodeTag type; + char* name; + char* var_type; + char* value; +} PLDebug_variable; + +typedef struct PLDebug_frame { + NodeTag type; + int frameno; + char* funcname; + int lineno; + char* query; +} PLDebug_frame; + +typedef struct DebugInfoComm { + int comm_idx; + /* buffer */ + char* send_buffer; + char* rec_buffer; + int send_ptr; /* send msg len */ + int rec_ptr; /* received msg len */ + int send_buf_len; /* send_buffer's size */ + int rec_buf_len; /* rec_buffer's size */ +} DebugInfoSocket; + +typedef struct DebugInfo { + int lineno; + bool stop_next_stmt; + char cur_opt; + int debugStackIdx; + PlpgsqlDebugFunc debugCallback; + PlpgsqlStartUpFunc startUp; + PLpgSQL_function* func; + MemoryContext debug_cxt; + DebugInfo* inner_called_debugger; + /* debug socket */ + DebugInfoComm* comm; + /* break point */ + List* bp_list; + /* current stmt */ + PLpgSQL_stmt* cur_stmt; +} DebugInfo; + +typedef struct PLDebug_breakPoint { + NodeTag type; + int bpIndex; + Oid funcoid; + int lineno; + bool active; + char* query; +} PLDebug_breakPoint; + +typedef struct DebugClientInfo { + int comm_idx; + MemoryContext context; + /* buffer */ + char* send_buffer; + char* rec_buffer; + int send_ptr; + int rec_ptr; + int send_buf_len; + int rec_buf_len; +} DebugClientInfo; + +typedef struct PlDebugEntry { + Oid key; + int commIdx; + PLpgSQL_function* func; +} PlDebugEntry; + +const int DEBUG_SOCKET_TIMEOUT = 15 * 60; +const int MAXINT8LEN = 25; +const int DEFAULT_DEBUG_BUF_SIZE = 1024; +const long NANOSECOND_PER_SECOND = 1000000000L; /* 1s */ + +/* after header use upper case letter */ +const char DEBUG_NOTHING_HEADER = 'e'; +const char DEBUG_ATTACH_HEADER = 'p'; +const char DEBUG_LOCALS_HEADER = 'v'; +const char DEBUG_NEXT_HEADER = 'n'; +const char DEBUG_NEXT_HEADER_AFTER = 'N'; +const char DEBUG_ABORT_HEADER = 'a'; +const char DEBUG_CONTINUE_HEADER = 'c'; +const char DEBUG_CONTINUE_HEADER_AFTER = 'C'; +const char DEBUG_PRINT_HEADER = 'd'; +const char DEBUG_ADDBREAKPOINT_HEADER = 'b'; +const char DEBUG_DELETEBREAKPOINT_HEADER = 'r'; +const char DEBUG_BREAKPOINT_HEADER = 'q'; +const char DEBUG_STEP_INTO_HEADER = 's'; +const char DEBUG_STEP_INTO_HEADER_AFTER = 'S'; +const char DEBUG_BACKTRACE_HEADER = 't'; + +#define PLDEBUG_FEATURE_NOT_SUPPORT_IN_DISTRIBUTED() \ + do { \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("Un-support feature"), \ + errdetail("Pldebug is not supported for distribute currently."))); \ + } while (0) + +#define PLDEBUG_FUNCTION_NOT_SUPPORT(funcname) \ + do { \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("Un-support feature"), \ + errdetail("func %s is not supported currently.", funcname))); \ + } while (0) + +#define CHECK_DEBUG_COMM_VALID(idx) \ + do { \ + if (!g_instance.pldebug_cxt.debug_comm[idx].Used()) \ + ereport(ERROR, \ + (errmodule(MOD_PLDEBUGGER), errcode(ERRCODE_PLDEBUGGER_ERROR), \ + errmsg("Debug Comm %d has been released or not turn on yet.", idx))); \ + } while (0) + +extern Datum debug_server_turn_on(PG_FUNCTION_ARGS); +extern Datum debug_server_turn_off(PG_FUNCTION_ARGS); + +extern Datum debug_client_attatch(PG_FUNCTION_ARGS); +extern Datum debug_client_abort(PG_FUNCTION_ARGS); +extern Datum debug_client_next(PG_FUNCTION_ARGS); +extern Datum debug_client_local_variables(PG_FUNCTION_ARGS); +extern Datum debug_client_continue(PG_FUNCTION_ARGS); + +/* Reserved interface */ +extern Datum debug_client_add_breakpoint(PG_FUNCTION_ARGS); +extern Datum debug_client_delete_breakpoint(PG_FUNCTION_ARGS); +extern Datum debug_client_info_breakpoints(PG_FUNCTION_ARGS); +extern Datum debug_client_backtrace(PG_FUNCTION_ARGS); +extern Datum debug_client_info_code(PG_FUNCTION_ARGS); +extern Datum debug_client_info_step(PG_FUNCTION_ARGS); +extern Datum local_debug_server_info(PG_FUNCTION_ARGS); + +void check_debug(PLpgSQL_function* func); +void server_pass_upper_debug_opt(DebugInfo* debug); +void clean_up_debug_client(bool hasError = false); +void clean_up_debug_server(DebugInfo* debug, bool sessClose, bool hasError); +void server_send_end_msg(DebugInfo* debug); +int GetValidDebugCommIdx(); +void WaitSendMsg(int commIdx, bool isClient); +bool WakeUpReceiver(int commIdx, bool isClient); +extern void PlDebugerCleanUp(int code, Datum arg); +extern void ReportInvalidMsg(const char* buf); +extern char* AssignStr(char* src, bool copy = true); +extern char* GetDebugTempFilePath(int idx, bool is_server); +extern PlDebugEntry* has_debug_func(Oid key, bool* found); +extern bool delete_debug_func(Oid key); +extern void RecvUnixMsg(int socket, char* buffer, int len); +extern char* ResizeDebugBufferIfNecessary(char* buffer, int* oldSize, int needSize); +extern void ReleaseDebugCommIdx(int idx); +extern void SendUnixMsg(int socket, const char* val, int len); + /********************************************************************** * Function declarations **********************************************************************/ @@ -906,7 +1211,8 @@ typedef struct plpgsql_hashent { } plpgsql_HashEnt; extern PLpgSQL_function* plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator); -extern PLpgSQL_function* plpgsql_compile_nohashkey(FunctionCallInfo fcinfo); +extern void delete_function(PLpgSQL_function* func); +extern PLpgSQL_function* plpgsql_compile_nohashkey(FunctionCallInfo fcinfo); /* parse trigger func */ extern PLpgSQL_function* plpgsql_compile_inline(char* proc_source); extern void plpgsql_parser_setup(struct ParseState* pstate, PLpgSQL_expr* expr); extern bool plpgsql_parse_word(char* word1, const char* yytxt, PLwdatum* wdatum, PLword* word, int* tok_flag); @@ -917,14 +1223,14 @@ extern PLpgSQL_type* plpgsql_parse_cwordtype(List* idents); extern PLpgSQL_type* plpgsql_parse_wordrowtype(char* ident); extern PLpgSQL_type* plpgsql_parse_cwordrowtype(List* idents); extern PLpgSQL_type* plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation); -extern PLpgSQL_variable* plpgsql_build_variable( - const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace, const char* varname = NULL); +extern PLpgSQL_variable* plpgsql_build_variable(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace, bool isImplicit = false, + const char* varname = NULL, knl_pl_body_type plType = PL_BODY_FUNCTION); PLpgSQL_variable* plpgsql_build_varrayType(const char* refname, int lineno, PLpgSQL_type* dtype, bool add2namespace); extern PLpgSQL_rec_type* plpgsql_build_rec_type(const char* typname, int lineno, List* list, bool add2namespace); extern PLpgSQL_rec* plpgsql_build_record(const char* refname, int lineno, bool add2namespace); extern int plpgsql_recognize_err_condition(const char* condname, bool allow_sqlstate); extern PLpgSQL_condition* plpgsql_parse_err_condition(char* condname); -extern void plpgsql_adddatum(PLpgSQL_datum* newm); +extern int plpgsql_adddatum(PLpgSQL_datum* newm); extern int plpgsql_add_initdatums(int** varnos); extern void plpgsql_HashTableInit(void); extern PLpgSQL_row* build_row_from_rec_type(const char* rowname, int lineno, PLpgSQL_rec_type* type); @@ -935,6 +1241,14 @@ extern void plpgsql_HashTableDelete(PLpgSQL_function* func); extern bool plpgsql_get_current_value_stp_with_exception(); extern void plpgsql_restore_current_value_stp_with_exception(bool saved_current_stp_with_exception); extern void plpgsql_set_current_value_stp_with_exception(); +extern void delete_pkg_in_HashTable(Oid pkgOid); +extern PLpgSQL_package* plpgsql_pkg_compile(Oid pkgOid, bool for_validator, bool isSpec, bool isCreate=false); +extern PLpgSQL_datum* plpgsql_pkg_adddatum(const List* wholeName, char** objname, char** pkgname); +extern int plpgsql_pkg_adddatum2ns(const List* name); +extern bool plpgsql_check_insert_colocate( + Query* query, List* qry_part_attr_num, List* trig_part_attr_num, PLpgSQL_function* func); +extern int plpgsql_pkg_add_unknown_var_to_namespace(List* name, int dtype = PLPGSQL_DTYPE_VAR); +extern void plpgsql_pkg_HashTableDelete(PLpgSQL_package* pkg); /* ---------- * Functions in pl_handler.c * ---------- @@ -943,6 +1257,7 @@ extern "C" void _PG_init(void); extern "C" Datum plpgsql_call_handler(PG_FUNCTION_ARGS); extern "C" Datum plpgsql_inline_handler(PG_FUNCTION_ARGS); extern "C" Datum plpgsql_validator(PG_FUNCTION_ARGS); +extern "C" PLpgSQL_package* plpgsql_package_validator(Oid packageOid, bool isSpec, bool isCreate=false); /* --- --- --- * Functions in plsql_packages.c @@ -962,12 +1277,18 @@ extern THR_LOCAL PLpgSQL_execstate* plpgsql_estate; * ---------- */ extern Datum plpgsql_exec_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, bool dynexec_anonymous_block); + +extern Datum plpgsql_exec_autonm_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, char* source_text); + extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function* func, TriggerData* trigdata); extern void plpgsql_xact_cb(XactEvent event, void* arg); extern void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void* arg); extern Oid exec_get_datum_type(PLpgSQL_execstate* estate, PLpgSQL_datum* datum); extern void exec_get_datum_type_info(PLpgSQL_execstate* estate, PLpgSQL_datum* datum, Oid* typid, int32* typmod, Oid* collation, PLpgSQL_function* func = NULL); +extern Datum exec_simple_cast_datum( + PLpgSQL_execstate* estate, Datum value, Oid valtype, Oid reqtype, int32 reqtypmod, bool isnull); +extern void ResetCursorOption(Portal portal, bool reset); extern void exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_datum *target, Datum value, Oid valtype, bool *isNull); @@ -980,6 +1301,7 @@ extern void exec_eval_datum(PLpgSQL_execstate *estate, bool isretry); extern void exec_eval_cleanup(PLpgSQL_execstate *estate); extern void free_expr(PLpgSQL_expr* expr); +extern HeapTuple make_tuple_from_row(PLpgSQL_execstate* estate, PLpgSQL_row* row, TupleDesc tupdesc); /* ---------- * Functions for namespace handling in pl_funcs.c @@ -987,9 +1309,12 @@ extern void free_expr(PLpgSQL_expr* expr); */ extern void plpgsql_ns_init(void); extern void plpgsql_ns_push(const char* label); +extern void add_pkg_compile(); +extern void plpgsql_add_pkg_ns(PLpgSQL_package* pkg); +extern void plpgsql_add_pkg_public_ns(PLpgSQL_package* pkg); extern void plpgsql_ns_pop(void); extern PLpgSQL_nsitem* plpgsql_ns_top(void); -extern void plpgsql_ns_additem(int itemtype, int itemno, const char* name); +extern void plpgsql_ns_additem(int itemtype, int itemno, const char* name, const char* pkgname = NULL); extern PLpgSQL_nsitem* plpgsql_ns_lookup( PLpgSQL_nsitem* ns_cur, bool localmode, const char* name1, const char* name2, const char* name3, int* names_used); extern PLpgSQL_nsitem* plpgsql_ns_lookup_label(PLpgSQL_nsitem* ns_cur, const char* name); @@ -1001,9 +1326,16 @@ extern PLpgSQL_nsitem* plpgsql_ns_lookup_label(PLpgSQL_nsitem* ns_cur, const cha extern const char* plpgsql_stmt_typename(PLpgSQL_stmt* stmt); extern const char* plpgsql_getdiag_kindname(int kind); extern void plpgsql_free_function_memory(PLpgSQL_function* func); +extern void plpgsql_free_package_memory(PLpgSQL_package* pkg); extern void plpgsql_dumptree(PLpgSQL_function* func); extern bool plpgsql_is_trigger_shippable(PLpgSQL_function* func); +/* ---------- + * Other functions in ruleutils.cpp + * ---------- + */ +extern char* pg_get_functiondef_worker(Oid funcid, int* headerlines); + /* ---------- * Scanner functions in pl_scanner.c * ---------- @@ -1019,6 +1351,7 @@ extern int plpgsql_location_to_lineno(int location); extern int plpgsql_latest_lineno(void); extern void plpgsql_scanner_init(const char* str); extern void plpgsql_scanner_finish(void); +extern char* plpgsql_get_curline_query(); extern int plbsql_yylex(void); extern void plbsql_yyerror(const char* message); @@ -1031,6 +1364,14 @@ extern void plbsql_yyerror(const char* message); extern int plbsql_yyparse(void); extern bool plpgsql_is_token_match2(int token, int token_next); extern bool plpgsql_is_token_match(int token); - +extern void pl_validate_function_sql(PLpgSQL_function* func, bool is_replace); +extern void validate_stmt_dynexecute(PLpgSQL_stmt_dynexecute* stmt, PLpgSQL_function* func, + SQLFunctionParseInfoPtr pinfo, List** stmt_list); +extern void pl_validate_expression(PLpgSQL_expr* expr, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, + SPIPlanPtr* plan); +extern void pl_validate_stmt_block(PLpgSQL_stmt_block *block, PLpgSQL_function* func, SQLFunctionParseInfoPtr pinfo, + SPIPlanPtr* plan, List** dynexec_list); +extern void pl_validate_stmt_block_in_subtransaction(PLpgSQL_stmt_block* block, PLpgSQL_function* func, + SQLFunctionParseInfoPtr pinfo, SPIPlanPtr* plan, List** dynexec_list); #endif /* PLBSQL_H */ #endif /* PLPGSQL_H */ diff --git a/contrib/db_b_parser/sql/db_b_parser.sql b/contrib/db_b_parser/sql/db_b_parser.sql new file mode 100644 index 000000000..b1cbd708a --- /dev/null +++ b/contrib/db_b_parser/sql/db_b_parser.sql @@ -0,0 +1,572 @@ +create database db_b_parser_test_db dbcompatibility 'B'; +\c db_b_parser_test_db + +create extension db_b_parser; + +-- test with parser disabled +set enable_custom_parser to off; + +--text(n), tinytext, mediumtext, longtext, failed +create table t1(a text(10)); +create table t2(a tinytext); +create table t3(a mediumtext); +create table t4(a longtext); + +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +drop table if exists t4; + +--default presicion of decimal/number/dec/numeric +create table t_default_decimal(a decimal, b number, c dec, d numeric); +\d t_default_decimal +drop table t_default_decimal; + +--failed +create table t_default_float1(a float4(10)); +create table t_default_float2(a double); + +drop table if exists t_default_float1; +drop table if exists t_default_float2; + +--real is single presicion, float is double presicion +create table t_default_float3(a real, b float); +\d t_default_float3 +drop table if exists t_default_float3; + +-- := +-- only support +-- update set clause +-- set stmt\alter system set +---------------------------- +create table a(a1 int, a2 int); +insert into a select generate_series(1,5); +update a set a1 := 11; +select a1 from a; +update a set (a1, a2) := (12,13); +set io_limits := 100; +set io_limits := default; + +drop table if exists a; + +-- DIV\MOD\REGEXP\NOT REGEXP\RLIKE\XOR gram test +Select 8div3; +Select 8 div3; +Select 8div 3, 8div 3div2, 8div 3div 2; +Select 8mod; +Select 8 div; +Select 8 as div; +Select xor1; +Select div 1; + +create schema xor; +create table xor(a int); +create table opr_test2(regexp int); +create type regexp; +create type regexpp as (regexp int); +CREATE FUNCTION regexp(int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +CREATE FUNCTION regexp2(regexp int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +create procedure mod(int,int) +as +begin + select $1 + $2; +end; +/ +create procedure mod2(mod int, xxx int) +as +begin + select $1 + $2; +end; +/ + +drop schema xor; +drop table xor; +drop table opr_test2; +drop type regexp; +drop type regexpp; +drop function regexp; +drop function regexp2; +drop procedure mod(int,int); +drop procedure mod2; + +SELECT '-12.3abc' div NULL; +SELECT '-12.3abc' div -100.1; +SELECT '-12.3abc' div 0; +SELECT '-12.3abc' div 5; +SELECT '-12.3abc' div 158.3; +SELECT '-12.3abc' div -8.222e4; +SELECT '-12.3abc' div true; +SELECT '-12.3abc' div false; +SELECT '-12.3abc' div 'NULL'; + +select 123456 div 5 div 4; +select 8 div 1 where 100 div 3 div 4 = 0; +select 8 div 3 where 100 div 3 div 4 > 0; + +SELECT '-12.3abc' mod NULL; +SELECT '-12.3abc' mod -100.1; +SELECT '-12.3abc' mod 0; +SELECT '-12.3abc' mod 5; +SELECT '-12.3abc' mod 158.3; +SELECT '-12.3abc' mod -8.222e4; +SELECT '-12.3abc' mod true; +SELECT '-12.3abc' mod false; +SELECT '-12.3abc' mod 'NULL'; + +select 123456 mod 5 mod 4; +select 8 mod 1 where 100 mod 3 mod 4 = 0; +select 8 mod 3 where 100 mod 3 mod 4 > 0; + +SELECT '-12.3abc' regexp NULL; +SELECT '-12.3abc' regexp -100.1; +SELECT '-12.3abc' regexp 0; +SELECT '-12.3abc' regexp 5; +SELECT '-12.3abc' regexp 158.3; +SELECT '-12.3abc' regexp -8.222e4; +SELECT '-12.3abc' regexp true; +SELECT '-12.3abc' regexp false; +SELECT '-12.3abc' regexp 'NULL'; + +SELECT '-12.3abc' not regexp NULL; +SELECT '-12.3abc' not regexp -100.1; +SELECT '-12.3abc' not regexp 0; +SELECT '-12.3abc' not regexp 5; +SELECT '-12.3abc' not regexp 158.3; +SELECT '-12.3abc' not regexp -8.222e4; +SELECT '-12.3abc' not regexp true; +SELECT '-12.3abc' not regexp false; +SELECT '-12.3abc' not regexp 'NULL'; + +SELECT '-12.3abc' xor NULL; +SELECT '-12.3abc' xor -100.1; +SELECT '-12.3abc' xor 0; +SELECT '-12.3abc' xor 5; +SELECT '-12.3abc' xor 158.3; +SELECT '-12.3abc' xor -8.222e4; +SELECT '-12.3abc' xor true; +SELECT '-12.3abc' xor false; +SELECT '-12.3abc' xor 'NULL'; + +SELECT '-12.3abc' rlike NULL; +SELECT '-12.3abc' rlike -100.1; +SELECT '-12.3abc' rlike 0; +SELECT '-12.3abc' rlike 5; +SELECT '-12.3abc' rlike 158.3; +SELECT '-12.3abc' rlike -8.222e4; +SELECT '-12.3abc' rlike true; +SELECT '-12.3abc' rlike false; +SELECT '-12.3abc' rlike 'NULL'; + +---------------------------------------- +-- copy from regex.sql of fastcheck +---------------------------------------- +set enable_bitmapscan = off; +set standard_conforming_strings = on; +select 'bbbbb' regexp '^([bc])\1*$' as t, 'bbbbb' not regexp '^([bc])\1*$' as t2, 'bbbbb' rlike '^([bc])\1*$' as t; +select 'ccc' regexp '^([bc])\1*$' as t, 'ccc' not regexp '^([bc])\1*$' as t2, 'ccc' rlike '^([bc])\1*$' as t; +select 'xxx' regexp '^([bc])\1*$' as f, 'xxx' not regexp '^([bc])\1*$' as f2, 'xxx' rlike '^([bc])\1*$' as f; +select 'bbc' regexp '^([bc])\1*$' as f, 'bbc' not regexp '^([bc])\1*$' as f2, 'bbc' rlike '^([bc])\1*$' as f; +select 'b' regexp '^([bc])\1*$' as t, 'b' not regexp '^([bc])\1*$' as t2, 'b' rlike '^([bc])\1*$' as t; +select 'abc abc abc' regexp '^(\w+)( \1)+$' as t, 'abc abc abc' not regexp '^(\w+)( \1)+$' as t, 'abc abc abc' rlike '^(\w+)( \1)+$' as t; +select 'abc abd abc' regexp '^(\w+)( \1)+$' as f, 'abc abd abc' not regexp '^(\w+)( \1)+$' as f, 'abc abd abc' rlike '^(\w+)( \1)+$' as f; +select 'abc abc abd' regexp '^(\w+)( \1)+$' as f, 'abc abc abd' not regexp '^(\w+)( \1)+$' as f, 'abc abc abd' rlike '^(\w+)( \1)+$' as f; +select 'abc abc abc' regexp '^(.+)( \1)+$' as t, 'abc abc abc' not regexp '^(.+)( \1)+$' as t, 'abc abc abc' rlike '^(.+)( \1)+$' as t; +select 'abc abd abc' regexp '^(.+)( \1)+$' as f, 'abc abd abc' not regexp '^(.+)( \1)+$' as f, 'abc abd abc' rlike '^(.+)( \1)+$' as f; +select 'abc abc abd' regexp '^(.+)( \1)+$' as f, 'abc abc abd' not regexp '^(.+)( \1)+$' as f, 'abc abc abd' rlike '^(.+)( \1)+$' as f; +select 'a' regexp '($|^)*', 'a' not regexp '($|^)*', 'a' rlike '($|^)*'; +select 'a' regexp '(^)+^', 'a' not regexp '(^)+^', 'a' rlike '(^)+^'; +select 'a' regexp '$($$)+', 'a' not regexp '$($$)+', 'a' rlike '$($$)+'; +select 'a' regexp '($^)+', 'a' not regexp '($^)+', 'a' rlike '($^)+'; +select 'a' regexp '(^$)*', 'a' not regexp '(^$)*', 'a' rlike '(^$)*'; +select 'aa bb cc' regexp '(^(?!aa))+', 'aa bb cc' not regexp '(^(?!aa))+', 'aa bb cc' rlike '(^(?!aa))+'; +select 'aa x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'bb x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'cc x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'dd x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'x' regexp 'abcd(\m)+xyz', 'x' not regexp 'abcd(\m)+xyz', 'x' rlike 'abcd(\m)+xyz'; +select 'x' regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' not regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' rlike 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'; +select 'a' regexp '((((((a)*)*)*)*)*)*', 'a' not regexp '((((((a)*)*)*)*)*)*', 'a' rlike '((((((a)*)*)*)*)*)*'; +select 'a' regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' not regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' rlike '((((((a+|)+|)+|)+|)+|)+|)'; +select 'a' regexp '\x7fffffff', 'a' not regexp '\x7fffffff', 'a' rlike '\x7fffffff'; +select 'a' regexp '$()|^\1', 'a' not regexp '$()|^\1', 'a' rlike '$()|^\1'; +select 'a' regexp '.. ()|\1', 'a' not regexp '.. ()|\1', 'a' rlike '.. ()|\1'; +select 'a' regexp '()*\1', 'a' not regexp '()*\1', 'a' rlike '()*\1'; +select 'a' regexp '()+\1', 'a' not regexp '()+\1', 'a' rlike '()+\1'; + +explain (costs off) select * from pg_proc where proname regexp 'abc'; +explain (costs off) select * from pg_proc where proname regexp '^abc'; +explain (costs off) select * from pg_proc where proname regexp '^abc$'; +explain (costs off) select * from pg_proc where proname regexp '^abcd*e'; +explain (costs off) select * from pg_proc where proname regexp '^abc+d'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)$'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)?d'; + +explain (costs off) select * from pg_proc where proname not regexp 'abc'; +explain (costs off) select * from pg_proc where proname not regexp '^abc'; +explain (costs off) select * from pg_proc where proname not regexp '^abc$'; +explain (costs off) select * from pg_proc where proname not regexp '^abcd*e'; +explain (costs off) select * from pg_proc where proname not regexp '^abc+d'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)$'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)?d'; + +explain (costs off) select * from pg_proc where proname rlike 'abc'; +explain (costs off) select * from pg_proc where proname rlike '^abc'; +explain (costs off) select * from pg_proc where proname rlike '^abc$'; +explain (costs off) select * from pg_proc where proname rlike '^abcd*e'; +explain (costs off) select * from pg_proc where proname rlike '^abc+d'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)$'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)?d'; + +set enable_bitmapscan = default; +set standard_conforming_strings = default; + +------DAYOFMONTH() DAYOFWEEK() DAYOFYEAR() HOUR() MICROSECOND() MINUTE() QUARTER() SECOND() WEEKDAY() WEEKOFYEAR() YEAR() +select DAYOFMONTH(timestamp '2021-05-26 16:30:44.341191'); +select DAYOFWEEK(timestamp '2021-05-26 16:30:44.341191'); +select DAYOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +select HOUR(timestamp '2021-05-26 16:30:44.341191'); +select MICROSECOND(timestamp '2021-05-26 16:30:44.341191'); +select MINUTE(timestamp '2021-05-26 16:30:44.341191'); +select QUARTER(timestamp '2021-05-26 16:30:44.341191'); +select SECOND(timestamp '2021-05-26 16:30:44.341191'); +select WEEKDAY(timestamp '2021-05-26 16:30:44.341191'); +select WEEKOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +select YEAR(timestamp '2021-05-26 16:30:44.341191'); + +--- LOCATE +select locate('test','testgood'); +select locate('test','11testgood',5); +select locate('test','11testgood',3); + +-- IFNULL +SELECT IFNULL(NULL, 'test'); + +-- IF +SELECT IF(TRUE,'A','B'); +SELECT IF(FALSE,'A','B'); + +------------------------------------------------------------------------------------------------------------------------ +---------------------------- +-- bit_length\octet_length\length +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length'); + +select bit_length(b'1'), bit_length(b'101'), bit_length(b'1011111111'); +select bit_length( '1'), bit_length( '101'), bit_length( '1011111111'); +select bit_length( '哈1哈\n'),bit_length( '\n'),bit_length( '\\n'); + +select octet_length(b'1'), octet_length(b'101'), octet_length(b'1011111111'); +select octet_length( '1'), octet_length( '101'), octet_length( '1011111111'); +select octet_length( '哈1哈\n'),octet_length( '\n'),octet_length( '\\n'); + +select length(b'1'), length(b'101'), length(b'1011111111'); +select length( '1'), length( '101'), length( '1011111111'); +select length( '哈1哈\n'),length( '\n'),length( '\\n'); + +---------------------------- +-- \lcase\ucase\rand\truncate\current_date() +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length', 'lower', 'upper', 'random', 'trunc') order by oid; + +select lcase('ABc'), lcase('哈哈'), lcase('123456'); +select lower('ABc'), lower('哈哈'), lower('123456'); +select ucase('ABc'), ucase('哈哈'), ucase('123456'); +select upper('ABc'), upper('哈哈'), upper('123456'); + +select rand(), random(); + +select truncate(111.28), truncate(111.28,1), truncate(111.28,5), truncate(111.28,500), truncate(111.28,-1), truncate(111.28,-4); +select trunc(111.28), trunc(111.28,1), trunc(111.28,5), trunc(111.28,500), trunc(111.28,-1), trunc(111.28,-4); +truncate a; + +select current_date(), current_date; + +---------------------------------------------- +-- test with parser enabled, same testcases -- +---------------------------------------------- +set enable_custom_parser to on; + +--text(n), tinytext, mediumtext, longtext, failed +create table t1(a text(10)); +create table t2(a tinytext); +create table t3(a mediumtext); +create table t4(a longtext); + +drop table if exists t1; +drop table if exists t2; +drop table if exists t3; +drop table if exists t4; + +--default presicion of decimal/number/dec/numeric +create table t_default_decimal(a decimal, b number, c dec, d numeric); +\d t_default_decimal +drop table t_default_decimal; + +--failed +create table t_default_float1(a float4(10)); +create table t_default_float2(a double); + +drop table if exists t_default_float1; +drop table if exists t_default_float2; + +--real is single presicion, float is double presicion +create table t_default_float3(a real, b float); +\d t_default_float3 +drop table t_default_float3; + +-- := +-- only support +-- update set clause +-- set stmt\alter system set +---------------------------- +create table a(a1 int, a2 int); +insert into a select generate_series(1,5); +update a set a1 := 11; +select a1 from a; +update a set (a1, a2) := (12,13); +set io_limits := 100; +set io_limits := default; + +drop table if exists a; + +-- DIV\MOD\REGEXP\NOT REGEXP\RLIKE\XOR gram test +Select 8div3; +Select 8 div3; +Select 8div 3, 8div 3div2, 8div 3div 2; +Select 8mod; +Select 8 div; +Select 8 as div; +Select xor1; +Select div 1; + +create schema xor; +create table xor(a int); +create table opr_test2(regexp int); +create type regexp; +create type regexpp as (regexp int); +CREATE FUNCTION regexp(int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +CREATE FUNCTION regexp2(regexp int) returns bigint as 'SELECT count(*) FROM pg_class ;' LANGUAGE SQL; +create procedure mod(int,int) +as +begin + select $1 + $2; +end; +/ +create procedure mod2(mod int, xxx int) +as +begin + select $1 + $2; +end; +/ + +drop schema xor; +drop table xor; +drop table opr_test2; +drop type regexp; +drop type regexpp; +drop function regexp; +drop function regexp2; +drop procedure mod(int,int); +drop procedure mod2; + +SELECT '-12.3abc' div NULL; +SELECT '-12.3abc' div -100.1; +SELECT '-12.3abc' div 0; +SELECT '-12.3abc' div 5; +SELECT '-12.3abc' div 158.3; +SELECT '-12.3abc' div -8.222e4; +SELECT '-12.3abc' div true; +SELECT '-12.3abc' div false; +SELECT '-12.3abc' div 'NULL'; + +select 123456 div 5 div 4; +select 8 div 1 where 100 div 3 div 4 = 0; +select 8 div 3 where 100 div 3 div 4 > 0; + +SELECT '-12.3abc' mod NULL; +SELECT '-12.3abc' mod -100.1; +SELECT '-12.3abc' mod 0; +SELECT '-12.3abc' mod 5; +SELECT '-12.3abc' mod 158.3; +SELECT '-12.3abc' mod -8.222e4; +SELECT '-12.3abc' mod true; +SELECT '-12.3abc' mod false; +SELECT '-12.3abc' mod 'NULL'; + +select 123456 mod 5 mod 4; +select 8 mod 1 where 100 mod 3 mod 4 = 0; +select 8 mod 3 where 100 mod 3 mod 4 > 0; + +SELECT '-12.3abc' regexp NULL; +SELECT '-12.3abc' regexp -100.1; +SELECT '-12.3abc' regexp 0; +SELECT '-12.3abc' regexp 5; +SELECT '-12.3abc' regexp 158.3; +SELECT '-12.3abc' regexp -8.222e4; +SELECT '-12.3abc' regexp true; +SELECT '-12.3abc' regexp false; +SELECT '-12.3abc' regexp 'NULL'; + +SELECT '-12.3abc' not regexp NULL; +SELECT '-12.3abc' not regexp -100.1; +SELECT '-12.3abc' not regexp 0; +SELECT '-12.3abc' not regexp 5; +SELECT '-12.3abc' not regexp 158.3; +SELECT '-12.3abc' not regexp -8.222e4; +SELECT '-12.3abc' not regexp true; +SELECT '-12.3abc' not regexp false; +SELECT '-12.3abc' not regexp 'NULL'; + +SELECT '-12.3abc' xor NULL; +SELECT '-12.3abc' xor -100.1; +SELECT '-12.3abc' xor 0; +SELECT '-12.3abc' xor 5; +SELECT '-12.3abc' xor 158.3; +SELECT '-12.3abc' xor -8.222e4; +SELECT '-12.3abc' xor true; +SELECT '-12.3abc' xor false; +SELECT '-12.3abc' xor 'NULL'; + +SELECT '-12.3abc' rlike NULL; +SELECT '-12.3abc' rlike -100.1; +SELECT '-12.3abc' rlike 0; +SELECT '-12.3abc' rlike 5; +SELECT '-12.3abc' rlike 158.3; +SELECT '-12.3abc' rlike -8.222e4; +SELECT '-12.3abc' rlike true; +SELECT '-12.3abc' rlike false; +SELECT '-12.3abc' rlike 'NULL'; + +---------------------------------------- +-- copy from regex.sql of fastcheck +---------------------------------------- +set enable_bitmapscan = off; +set standard_conforming_strings = on; +select 'bbbbb' regexp '^([bc])\1*$' as t, 'bbbbb' not regexp '^([bc])\1*$' as t2, 'bbbbb' rlike '^([bc])\1*$' as t; +select 'ccc' regexp '^([bc])\1*$' as t, 'ccc' not regexp '^([bc])\1*$' as t2, 'ccc' rlike '^([bc])\1*$' as t; +select 'xxx' regexp '^([bc])\1*$' as f, 'xxx' not regexp '^([bc])\1*$' as f2, 'xxx' rlike '^([bc])\1*$' as f; +select 'bbc' regexp '^([bc])\1*$' as f, 'bbc' not regexp '^([bc])\1*$' as f2, 'bbc' rlike '^([bc])\1*$' as f; +select 'b' regexp '^([bc])\1*$' as t, 'b' not regexp '^([bc])\1*$' as t2, 'b' rlike '^([bc])\1*$' as t; +select 'abc abc abc' regexp '^(\w+)( \1)+$' as t, 'abc abc abc' not regexp '^(\w+)( \1)+$' as t, 'abc abc abc' rlike '^(\w+)( \1)+$' as t; +select 'abc abd abc' regexp '^(\w+)( \1)+$' as f, 'abc abd abc' not regexp '^(\w+)( \1)+$' as f, 'abc abd abc' rlike '^(\w+)( \1)+$' as f; +select 'abc abc abd' regexp '^(\w+)( \1)+$' as f, 'abc abc abd' not regexp '^(\w+)( \1)+$' as f, 'abc abc abd' rlike '^(\w+)( \1)+$' as f; +select 'abc abc abc' regexp '^(.+)( \1)+$' as t, 'abc abc abc' not regexp '^(.+)( \1)+$' as t, 'abc abc abc' rlike '^(.+)( \1)+$' as t; +select 'abc abd abc' regexp '^(.+)( \1)+$' as f, 'abc abd abc' not regexp '^(.+)( \1)+$' as f, 'abc abd abc' rlike '^(.+)( \1)+$' as f; +select 'abc abc abd' regexp '^(.+)( \1)+$' as f, 'abc abc abd' not regexp '^(.+)( \1)+$' as f, 'abc abc abd' rlike '^(.+)( \1)+$' as f; +select 'a' regexp '($|^)*', 'a' not regexp '($|^)*', 'a' rlike '($|^)*'; +select 'a' regexp '(^)+^', 'a' not regexp '(^)+^', 'a' rlike '(^)+^'; +select 'a' regexp '$($$)+', 'a' not regexp '$($$)+', 'a' rlike '$($$)+'; +select 'a' regexp '($^)+', 'a' not regexp '($^)+', 'a' rlike '($^)+'; +select 'a' regexp '(^$)*', 'a' not regexp '(^$)*', 'a' rlike '(^$)*'; +select 'aa bb cc' regexp '(^(?!aa))+', 'aa bb cc' not regexp '(^(?!aa))+', 'aa bb cc' rlike '(^(?!aa))+'; +select 'aa x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'aa x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'bb x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'bb x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'cc x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'cc x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'dd x' regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' not regexp '(^(?!aa)(?!bb)(?!cc))+', 'dd x' rlike '(^(?!aa)(?!bb)(?!cc))+'; +select 'x' regexp 'abcd(\m)+xyz', 'x' not regexp 'abcd(\m)+xyz', 'x' rlike 'abcd(\m)+xyz'; +select 'x' regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' not regexp 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$', 'x' rlike 'a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$'; +select 'a' regexp '((((((a)*)*)*)*)*)*', 'a' not regexp '((((((a)*)*)*)*)*)*', 'a' rlike '((((((a)*)*)*)*)*)*'; +select 'a' regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' not regexp '((((((a+|)+|)+|)+|)+|)+|)', 'a' rlike '((((((a+|)+|)+|)+|)+|)+|)'; +select 'a' regexp '\x7fffffff', 'a' not regexp '\x7fffffff', 'a' rlike '\x7fffffff'; +select 'a' regexp '$()|^\1', 'a' not regexp '$()|^\1', 'a' rlike '$()|^\1'; +select 'a' regexp '.. ()|\1', 'a' not regexp '.. ()|\1', 'a' rlike '.. ()|\1'; +select 'a' regexp '()*\1', 'a' not regexp '()*\1', 'a' rlike '()*\1'; +select 'a' regexp '()+\1', 'a' not regexp '()+\1', 'a' rlike '()+\1'; + +explain (costs off) select * from pg_proc where proname regexp 'abc'; +explain (costs off) select * from pg_proc where proname regexp '^abc'; +explain (costs off) select * from pg_proc where proname regexp '^abc$'; +explain (costs off) select * from pg_proc where proname regexp '^abcd*e'; +explain (costs off) select * from pg_proc where proname regexp '^abc+d'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)$'; +explain (costs off) select * from pg_proc where proname regexp '^(abc)?d'; + +explain (costs off) select * from pg_proc where proname not regexp 'abc'; +explain (costs off) select * from pg_proc where proname not regexp '^abc'; +explain (costs off) select * from pg_proc where proname not regexp '^abc$'; +explain (costs off) select * from pg_proc where proname not regexp '^abcd*e'; +explain (costs off) select * from pg_proc where proname not regexp '^abc+d'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)$'; +explain (costs off) select * from pg_proc where proname not regexp '^(abc)?d'; + +explain (costs off) select * from pg_proc where proname rlike 'abc'; +explain (costs off) select * from pg_proc where proname rlike '^abc'; +explain (costs off) select * from pg_proc where proname rlike '^abc$'; +explain (costs off) select * from pg_proc where proname rlike '^abcd*e'; +explain (costs off) select * from pg_proc where proname rlike '^abc+d'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)(def)'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)$'; +explain (costs off) select * from pg_proc where proname rlike '^(abc)?d'; + +set enable_bitmapscan = default; +set standard_conforming_strings = default; + +------DAYOFMONTH() DAYOFWEEK() DAYOFYEAR() HOUR() MICROSECOND() MINUTE() QUARTER() SECOND() WEEKDAY() WEEKOFYEAR() YEAR() +select DAYOFMONTH(timestamp '2021-05-26 16:30:44.341191'); +select DAYOFWEEK(timestamp '2021-05-26 16:30:44.341191'); +select DAYOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +select HOUR(timestamp '2021-05-26 16:30:44.341191'); +select MICROSECOND(timestamp '2021-05-26 16:30:44.341191'); +select MINUTE(timestamp '2021-05-26 16:30:44.341191'); +select QUARTER(timestamp '2021-05-26 16:30:44.341191'); +select SECOND(timestamp '2021-05-26 16:30:44.341191'); +select WEEKDAY(timestamp '2021-05-26 16:30:44.341191'); +select WEEKOFYEAR(timestamp '2021-05-26 16:30:44.341191'); +select YEAR(timestamp '2021-05-26 16:30:44.341191'); + +--- LOCATE +select locate('test','testgood'); +select locate('test','11testgood',5); +select locate('test','11testgood',3); + +-- IFNULL +SELECT IFNULL(NULL, 'test'); + +-- IF +SELECT IF(TRUE,'A','B'); +SELECT IF(FALSE,'A','B'); + +------------------------------------------------------------------------------------------------------------------------ +---------------------------- +-- bit_length\octet_length\length +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length'); + +select bit_length(b'1'), bit_length(b'101'), bit_length(b'1011111111'); +select bit_length( '1'), bit_length( '101'), bit_length( '1011111111'); +select bit_length( '哈1哈\n'),bit_length( '\n'),bit_length( '\\n'); + +select octet_length(b'1'), octet_length(b'101'), octet_length(b'1011111111'); +select octet_length( '1'), octet_length( '101'), octet_length( '1011111111'); +select octet_length( '哈1哈\n'),octet_length( '\n'),octet_length( '\\n'); + +select length(b'1'), length(b'101'), length(b'1011111111'); +select length( '1'), length( '101'), length( '1011111111'); +select length( '哈1哈\n'),length( '\n'),length( '\\n'); + +---------------------------- +-- \lcase\ucase\rand\truncate\current_date() +---------------------------- +select * from pg_proc where proname in ('db_b_parser_bit_length', 'lower', 'upper', 'random', 'trunc') order by oid; + +select lcase('ABc'), lcase('哈哈'), lcase('123456'); +select lower('ABc'), lower('哈哈'), lower('123456'); +select ucase('ABc'), ucase('哈哈'), ucase('123456'); +select upper('ABc'), upper('哈哈'), upper('123456'); + +select rand(), random(); + +select truncate(111.28), truncate(111.28,1), truncate(111.28,5), truncate(111.28,500), truncate(111.28,-1), truncate(111.28,-4); +select trunc(111.28), trunc(111.28,1), trunc(111.28,5), trunc(111.28,500), trunc(111.28,-1), trunc(111.28,-4); +truncate a; + +select current_date(), current_date; + +------------------------------------------------------------------------------------------------------------------------ +\c contrib_regression +drop database db_b_parser_test_db; \ No newline at end of file -- Gitee