| %{ |
| |
| /*#define YYDEBUG 1*/ |
| /*------------------------------------------------------------------------- |
| * |
| * gram.y |
| * POSTGRESQL BISON rules/actions |
| * |
| * Portions Copyright (c) 2006-2010, Greenplum inc |
| * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates. |
| * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * |
| * IDENTIFICATION |
| * src/backend/parser/gram.y |
| * |
| * HISTORY |
| * AUTHOR DATE MAJOR EVENT |
| * Andrew Yu Sept, 1994 POSTQUEL to SQL conversion |
| * Andrew Yu Oct, 1994 lispy code conversion |
| * |
| * NOTES |
| * CAPITALS are used to represent terminal symbols. |
| * non-capitals are used to represent non-terminals. |
| * |
| * In general, nothing in this file should initiate database accesses |
| * nor depend on changeable state (such as SET variables). If you do |
| * database accesses, your code will fail when we have aborted the |
| * current transaction and are just parsing commands to find the next |
| * ROLLBACK or COMMIT. If you make use of SET variables, then you |
| * will do the wrong thing in multi-query strings like this: |
| * SET constraint_exclusion TO off; SELECT * FROM foo; |
| * because the entire string is parsed by gram.y before the SET gets |
| * executed. Anything that depends on the database or changeable state |
| * should be handled during parse analysis so that it happens at the |
| * right time not the wrong time. |
| * |
| * WARNINGS |
| * If you use a list, make sure the datum is a node so that the printing |
| * routines work. |
| * |
| * Sometimes we assign constants to makeStrings. Make sure we don't free |
| * those. |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #include "postgres.h" |
| |
| #include <ctype.h> |
| #include <limits.h> |
| |
| #include "access/tableam.h" |
| #include "catalog/index.h" |
| #include "catalog/namespace.h" |
| #include "catalog/pg_am.h" |
| #include "catalog/pg_foreign_server.h" |
| #include "catalog/pg_trigger.h" |
| #include "catalog/pg_directory_table.h" |
| #include "commands/defrem.h" |
| #include "commands/trigger.h" |
| #include "gramparse.h" |
| #include "nodes/makefuncs.h" |
| #include "nodes/nodeFuncs.h" |
| #include "parser/parser.h" |
| #include "storage/lmgr.h" |
| #include "utils/date.h" |
| #include "utils/datetime.h" |
| #include "utils/numeric.h" |
| #include "utils/varlena.h" |
| #include "utils/xml.h" |
| #include "cdb/cdbutil.h" |
| #include "cdb/cdbvars.h" |
| |
| #include "utils/guc.h" |
| |
| |
| /* |
| * Location tracking support --- simpler than bison's default, since we only |
| * want to track the start position not the end position of each nonterminal. |
| */ |
| #define YYLLOC_DEFAULT(Current, Rhs, N) \ |
| do { \ |
| if ((N) > 0) \ |
| (Current) = (Rhs)[1]; \ |
| else \ |
| (Current) = (-1); \ |
| } while (0) |
| |
| /* |
| * The above macro assigns -1 (unknown) as the parse location of any |
| * nonterminal that was reduced from an empty rule, or whose leftmost |
| * component was reduced from an empty rule. This is problematic |
| * for nonterminals defined like |
| * OptFooList: / * EMPTY * / { ... } | OptFooList Foo { ... } ; |
| * because we'll set -1 as the location during the first reduction and then |
| * copy it during each subsequent reduction, leaving us with -1 for the |
| * location even when the list is not empty. To fix that, do this in the |
| * action for the nonempty rule(s): |
| * if (@$ < 0) @$ = @2; |
| * (Although we have many nonterminals that follow this pattern, we only |
| * bother with fixing @$ like this when the nonterminal's parse location |
| * is actually referenced in some rule.) |
| * |
| * A cleaner answer would be to make YYLLOC_DEFAULT scan all the Rhs |
| * locations until it's found one that's not -1. Then we'd get a correct |
| * location for any nonterminal that isn't entirely empty. But this way |
| * would add overhead to every rule reduction, and so far there's not been |
| * a compelling reason to pay that overhead. |
| */ |
| |
| /* |
| * 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. |
| */ |
| #define YYMALLOC palloc |
| #define YYFREE pfree |
| |
| /* Private struct for the result of privilege_target production */ |
| typedef struct PrivTarget |
| { |
| GrantTargetType targtype; |
| ObjectType objtype; |
| List *objs; |
| } PrivTarget; |
| |
| /* Private struct for the result of import_qualification production */ |
| typedef struct ImportQual |
| { |
| ImportForeignSchemaType type; |
| List *table_names; |
| } ImportQual; |
| |
| /* Private struct for the result of opt_select_limit production */ |
| typedef struct SelectLimit |
| { |
| Node *limitOffset; |
| Node *limitCount; |
| LimitOption limitOption; |
| } SelectLimit; |
| |
| /* Private struct for the result of group_clause production */ |
| typedef struct GroupClause |
| { |
| bool distinct; |
| List *list; |
| } GroupClause; |
| |
| /* Private structs for the result of key_actions and key_action productions */ |
| typedef struct KeyAction |
| { |
| char action; |
| List *cols; |
| } KeyAction; |
| |
| typedef struct KeyActions |
| { |
| KeyAction *updateAction; |
| KeyAction *deleteAction; |
| } KeyActions; |
| |
| /* ConstraintAttributeSpec yields an integer bitmask of these flags: */ |
| #define CAS_NOT_DEFERRABLE 0x01 |
| #define CAS_DEFERRABLE 0x02 |
| #define CAS_INITIALLY_IMMEDIATE 0x04 |
| #define CAS_INITIALLY_DEFERRED 0x08 |
| #define CAS_NOT_VALID 0x10 |
| #define CAS_NO_INHERIT 0x20 |
| |
| |
| #define parser_yyerror(msg) scanner_yyerror(msg, yyscanner) |
| #define parser_errposition(pos) scanner_errposition(pos, yyscanner) |
| |
| static void base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, |
| const char *msg); |
| static RawStmt *makeRawStmt(Node *stmt, int stmt_location); |
| static void updateRawStmtEnd(RawStmt *rs, int end_location); |
| static Node *makeColumnRef(char *colname, List *indirection, |
| int location, core_yyscan_t yyscanner); |
| static Node *makeTypeCast(Node *arg, TypeName *typename, int location); |
| static Node *makeStringConst(char *str, int location); |
| static Node *makeStringConstCast(char *str, int location, TypeName *typename); |
| static Node *makeIntConst(int val, int location); |
| static Node *makeFloatConst(char *str, int location); |
| static Node *makeBoolAConst(bool state, int location); |
| static Node *makeBitStringConst(char *str, int location); |
| static Node *makeNullAConst(int location); |
| static Node *makeAConst(Node *v, int location); |
| static RoleSpec *makeRoleSpec(RoleSpecType type, int location); |
| static void check_qualified_name(List *names, core_yyscan_t yyscanner); |
| static List *check_func_name(List *names, core_yyscan_t yyscanner); |
| static List *check_indirection(List *indirection, core_yyscan_t yyscanner); |
| static List *extractArgTypes(List *parameters); |
| static List *extractAggrArgTypes(List *aggrargs); |
| static List *makeOrderedSetArgs(List *directargs, List *orderedargs, |
| core_yyscan_t yyscanner); |
| static void insertSelectOptions(SelectStmt *stmt, |
| List *sortClause, List *lockingClause, |
| SelectLimit *limitClause, |
| WithClause *withClause, |
| core_yyscan_t yyscanner); |
| static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); |
| static Node *doNegate(Node *n, int location); |
| static void doNegateFloat(Float *v); |
| static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location); |
| static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location); |
| static Node *makeNotExpr(Node *expr, int location); |
| static Node *makeAArrayExpr(List *elements, int location); |
| static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, |
| int location); |
| static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, |
| List *args, int location); |
| static List *mergeTableFuncParameters(List *func_args, List *columns); |
| static TypeName *TableFuncTypeName(List *columns); |
| static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); |
| static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, |
| core_yyscan_t yyscanner); |
| static void SplitColQualList(List *qualList, |
| List **constraintList, CollateClause **collClause, |
| core_yyscan_t yyscanner); |
| 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 PartitionStrategy parsePartitionStrategy(char *strategy); |
| static void preprocess_pubobj_list(List *pubobjspec_list, |
| core_yyscan_t yyscanner); |
| static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); |
| |
| static Node *makeIsNotDistinctFromNode(Node *expr, int position); |
| |
| static bool isSetWithReorganize(List **options); |
| static char *greenplumLegacyAOoptions(const char *accessMethod, List **options); |
| static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_t yyscanner); |
| |
| %} |
| |
| %pure-parser |
| %expect 0 |
| %name-prefix="base_yy" |
| %locations |
| |
| %parse-param {core_yyscan_t yyscanner} |
| %lex-param {core_yyscan_t yyscanner} |
| |
| %union |
| { |
| core_YYSTYPE core_yystype; |
| /* these fields must match core_YYSTYPE: */ |
| int ival; |
| char *str; |
| const char *keyword; |
| |
| char chr; |
| bool boolean; |
| JoinType jtype; |
| DropBehavior dbehavior; |
| OnCommitAction oncommit; |
| List *list; |
| Node *node; |
| ObjectType objtype; |
| TypeName *typnam; |
| FunctionParameter *fun_param; |
| FunctionParameterMode fun_param_mode; |
| ObjectWithArgs *objwithargs; |
| DefElem *defelt; |
| SortBy *sortby; |
| WindowDef *windef; |
| JoinExpr *jexpr; |
| IndexElem *ielem; |
| StatsElem *selem; |
| Alias *alias; |
| RangeVar *range; |
| IntoClause *into; |
| WithClause *with; |
| InferClause *infer; |
| OnConflictClause *onconflict; |
| A_Indices *aind; |
| ResTarget *target; |
| struct PrivTarget *privtarget; |
| AccessPriv *accesspriv; |
| struct ImportQual *importqual; |
| InsertStmt *istmt; |
| VariableSetStmt *vsetstmt; |
| PartitionElem *partelem; |
| PartitionSpec *partspec; |
| PartitionBoundSpec *partboundspec; |
| RoleSpec *rolespec; |
| PublicationObjSpec *publicationobjectspec; |
| struct SelectLimit *selectlimit; |
| DistributionKeyElem *dkelem; |
| SetQuantifier setquantifier; |
| struct GroupClause *groupclause; |
| MergeWhenClause *mergewhen; |
| struct KeyActions *keyactions; |
| struct KeyAction *keyaction; |
| } |
| |
| %type <node> stmt toplevel_stmt schema_stmt routine_body_stmt |
| AddForeignSegStmt AlterEventTrigStmt AlterCollationStmt |
| AlterDatabaseStmt AlterDatabaseSetStmt AlterDirectoryTableStmt AlterDomainStmt AlterEnumStmt |
| AlterFdwStmt AlterForeignServerStmt AlterGroupStmt |
| AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt |
| AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterStorageServerStmt AlterSystemStmt AlterTableStmt |
| AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt |
| AlterCompositeTypeStmt AlterUserMappingStmt AlterStorageUserMappingStmt |
| AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt AlterStatsStmt |
| AlterDefaultPrivilegesStmt DefACLAction |
| AnalyzeStmt CallStmt ClosePortalStmt ClusterStmt CommentStmt |
| ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt |
| CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateOpClassStmt |
| CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt |
| CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt |
| CreateStorageServerStmt CreateStorageUserMappingStmt |
| CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt CreateDirectoryTableStmt |
| CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt |
| CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt |
| CreatedbStmt CreateWarehouseStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt |
| DropDirectoryTableStmt DropOpClassStmt DropOpFamilyStmt DropStmt DropWarehouseStmt |
| DropCastStmt DropRoleStmt |
| DropdbStmt DropTableSpaceStmt |
| DropTransformStmt |
| DropUserMappingStmt DropStorageServerStmt DropStorageUserMappingStmt ExplainStmt FetchStmt |
| GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt |
| ListenStmt LoadStmt LockStmt MergeStmt NotifyStmt ExplainableStmt PreparableStmt |
| CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt |
| RemoveFuncStmt RemoveOperStmt RenameStmt ReturnStmt RevokeStmt RevokeRoleStmt |
| RuleActionStmt RuleActionStmtOrEmpty RuleStmt |
| SecLabelStmt SelectStmt TransactionStmt TransactionStmtLegacy TruncateStmt |
| UnlistenStmt UpdateStmt VacuumStmt |
| VariableResetStmt VariableSetStmt VariableShowStmt |
| ViewStmt CheckPointStmt CreateConversionStmt |
| DeallocateStmt PrepareStmt ExecuteStmt |
| DropOwnedStmt ReassignOwnedStmt |
| AlterTSConfigurationStmt AlterTSDictionaryStmt |
| CreateMatViewStmt RefreshMatViewStmt CreateAmStmt |
| CreatePublicationStmt AlterPublicationStmt |
| CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt |
| RetrieveStmt CreateTaskStmt AlterTaskStmt DropTaskStmt |
| |
| /* GPDB-specific commands */ |
| %type <node> AlterProfileStmt AlterQueueStmt AlterResourceGroupStmt AlterSchemaStmt AlterTagStmt |
| CreateExternalStmt |
| CreateProfileStmt CreateQueueStmt CreateResourceGroupStmt CreateTagStmt |
| DropProfileStmt DropQueueStmt DropResourceGroupStmt DropTagStmt |
| ExtTypedesc ExtSingleRowErrorHandling |
| |
| %type<list> OptSingleRowErrorHandling |
| |
| %type <node> deny_login_role deny_interval deny_point deny_day_specifier |
| |
| %type <node> select_no_parens select_with_parens select_clause |
| simple_select values_clause |
| PLpgSQL_Expr PLAssignStmt |
| |
| %type <str> opt_single_name |
| %type <list> opt_qualified_name |
| %type <dbehavior> opt_drop_behavior |
| |
| %type <node> alter_column_default opclass_item opclass_drop alter_using |
| %type <ival> add_drop opt_asc_desc opt_nulls_order |
| |
| %type <node> alter_table_cmd alter_type_cmd opt_collate_clause |
| replica_identity partition_cmd index_partition_cmd |
| %type <list> alter_table_cmds alter_type_cmds |
| %type <list> alter_identity_column_option_list |
| %type <defelt> alter_identity_column_option |
| |
| %type <node> alter_table_partition_cmd alter_table_partition_id_spec |
| alter_table_partition_id_spec_with_opt_default |
| %type <list> part_values_clause multi_spec_value_list part_values_single |
| %type <ival> opt_table_partition_exchange_validate |
| |
| %type <dbehavior> opt_drop_directory_table_behavior |
| %type <list> createdb_opt_list createdb_opt_items copy_opt_list |
| transaction_mode_list |
| create_extension_opt_list alter_extension_opt_list |
| %type <defelt> createdb_opt_item copy_opt_item |
| transaction_mode_item |
| create_extension_opt_item alter_extension_opt_item |
| |
| %type <list> ext_on_clause_list format_opt format_opt_list format_def_list |
| ext_options ext_options_opt ext_options_list |
| ext_opt_encoding_list |
| %type <defelt> ext_on_clause_item format_opt_item format_def_item |
| ext_options_item |
| ext_opt_encoding_item |
| |
| %type <ival> opt_lock lock_type cast_context |
| %type <str> utility_option_name |
| %type <defelt> utility_option_elem |
| %type <list> utility_option_list |
| %type <node> utility_option_arg |
| %type <defelt> drop_option |
| %type <boolean> opt_or_replace opt_no |
| opt_grant_grant_option |
| opt_nowait opt_if_exists opt_with_data |
| opt_transaction_chain |
| %type <list> grant_role_opt_list |
| %type <defelt> grant_role_opt |
| %type <node> grant_role_opt_value |
| %type <ival> opt_nowait_or_skip |
| |
| %type <list> OptRoleList AlterOptRoleList |
| %type <list> OptProfileList |
| %type <list> OptTagValuesList OptTagOptList TagOptList |
| %type <defelt> TagOptElem |
| %type <defelt> CreateOptRoleElem AlterOptRoleElem |
| %type <defelt> AlterOnlyOptRoleElem |
| %type <defelt> OptProfileElem |
| |
| %type <str> opt_type |
| %type <str> foreign_server_version opt_foreign_server_version |
| %type <str> opt_in_database |
| |
| %type <list> OptQueueList |
| %type <defelt> OptQueueElem |
| |
| %type <list> OptResourceGroupList |
| %type <defelt> OptResourceGroupElem |
| |
| %type <str> parameter_name |
| %type <list> OptSchemaEltList parameter_name_list |
| |
| %type <chr> am_type |
| |
| %type <boolean> TriggerForSpec TriggerForType |
| %type <ival> TriggerActionTime |
| %type <list> TriggerEvents TriggerOneEvent |
| %type <node> TriggerFuncArg |
| %type <node> TriggerWhen |
| %type <str> TransitionRelName |
| %type <boolean> TransitionRowOrTable TransitionOldOrNew |
| %type <node> TriggerTransition |
| |
| %type <list> event_trigger_when_list event_trigger_value_list |
| %type <defelt> event_trigger_when_item |
| %type <chr> enable_trigger |
| |
| %type <str> copy_file_name |
| access_method_clause attr_name |
| table_access_method_clause name cursor_name file_name |
| cluster_index_specification opt_file_name |
| %type <str> OptWithLocation |
| |
| %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op |
| opt_class opt_inline_handler opt_validator validator_clause |
| opt_collate |
| |
| %type <range> qualified_name insert_target OptConstrFromTable |
| |
| %type <str> all_Op MathOp |
| |
| %type <str> row_security_cmd RowSecurityDefaultForCmd |
| %type <boolean> RowSecurityDefaultPermissive |
| %type <node> RowSecurityOptionalWithCheck RowSecurityOptionalExpr |
| %type <list> RowSecurityDefaultToRole RowSecurityOptionalToRole |
| |
| %type <str> iso_level opt_encoding |
| %type <rolespec> grantee |
| %type <list> grantee_list |
| %type <accesspriv> privilege |
| %type <list> privileges privilege_list |
| %type <privtarget> privilege_target |
| %type <objwithargs> function_with_argtypes aggregate_with_argtypes operator_with_argtypes |
| %type <list> function_with_argtypes_list aggregate_with_argtypes_list operator_with_argtypes_list |
| %type <ival> defacl_privilege_target |
| %type <defelt> DefACLOption |
| %type <list> DefACLOptionList |
| %type <ival> import_qualification_type |
| %type <importqual> import_qualification |
| %type <node> vacuum_relation |
| %type <selectlimit> opt_select_limit select_limit limit_clause |
| |
| %type <list> parse_toplevel stmtmulti routine_body_stmt_list |
| OptTableElementList TableElementList OptInherit definition |
| OptExtTableElementList ExtTableElementList |
| OptTypedTableElementList TypedTableElementList |
| reloptions opt_reloptions |
| OptWith opt_definition func_args func_args_list |
| func_args_with_defaults func_args_with_defaults_list |
| aggr_args aggr_args_list |
| func_as createfunc_opt_list opt_createfunc_opt_list alterfunc_opt_list |
| old_aggr_definition old_aggr_list |
| oper_argtypes RuleActionList RuleActionMulti |
| cdb_string_list |
| opt_column_list columnList opt_name_list |
| exttab_auth_list keyvalue_list |
| sort_clause opt_sort_clause sortby_list index_params |
| stats_params |
| opt_include opt_c_include index_including_params |
| name_list role_list from_clause from_list opt_array_bounds |
| qualified_name_list qualified_name_list_with_only any_name any_name_list type_name_list |
| any_operator expr_list attrs |
| distinct_clause opt_distinct_clause |
| target_list opt_target_list insert_column_list set_target_list |
| merge_values_clause |
| set_clause_list set_clause |
| def_list operator_def_list indirection opt_indirection |
| reloption_list TriggerFuncArgs opclass_item_list opclass_drop_list |
| opclass_purpose opt_opfamily transaction_mode_list_or_empty |
| OptTableFuncElementList TableFuncElementList opt_type_modifiers |
| prep_type_clause |
| execute_param_clause using_clause returning_clause |
| opt_enum_val_list enum_val_list table_func_column_list |
| scatter_clause |
| create_generic_options alter_generic_options |
| relation_expr_list dostmt_opt_list |
| transform_element_list transform_type_list |
| TriggerTransitions TriggerReferencing |
| vacuum_relation_list opt_vacuum_relation_list |
| drop_option_list pub_obj_list |
| |
| %type <node> opt_routine_body |
| %type <groupclause> group_clause |
| %type <list> group_by_list |
| %type <node> group_by_item empty_grouping_set rollup_clause cube_clause |
| %type <node> grouping_sets_clause |
| |
| %type <node> table_value_select_clause |
| |
| %type <list> opt_fdw_options fdw_options |
| %type <defelt> fdw_option |
| |
| %type <range> OptTempTableName |
| %type <into> into_clause create_as_target create_mv_target |
| %type <boolean> incremental |
| |
| %type <defelt> createfunc_opt_item common_func_opt_item dostmt_opt_item |
| %type <fun_param> func_arg func_arg_with_default table_func_column aggr_arg |
| %type <fun_param_mode> arg_class |
| %type <typnam> func_return func_type |
| |
| %type <boolean> OptWeb OptWritable OptSrehLimitType |
| |
| %type <chr> OptLogErrorTable ExtLogErrorTable |
| |
| %type <boolean> opt_trusted opt_restart_seqs |
| %type <ival> OptTemp |
| %type <ival> OptNoLog |
| %type <oncommit> OnCommitOption |
| |
| %type <ival> for_locking_strength |
| %type <node> for_locking_item |
| %type <list> for_locking_clause opt_for_locking_clause for_locking_items |
| %type <list> locked_rels_list |
| %type <setquantifier> set_quantifier |
| |
| %type <node> join_qual |
| %type <jtype> join_type |
| |
| %type <list> extract_list overlay_list position_list |
| %type <list> substr_list trim_list |
| %type <list> opt_interval interval_second |
| %type <str> unicode_normal_form |
| |
| %type <boolean> opt_instead |
| %type <boolean> opt_unique opt_concurrently opt_verbose opt_full |
| %type <boolean> opt_freeze opt_analyze opt_ao_aux_only opt_default opt_recheck |
| %type <boolean> opt_dxl |
| %type <defelt> opt_binary copy_delimiter |
| |
| %type <boolean> copy_from opt_program |
| |
| %type <ival> event cursor_options opt_hold opt_set_data |
| %type <objtype> object_type_any_name object_type_name object_type_name_on_any_name |
| drop_type_name |
| |
| %type <node> fetch_args select_limit_value |
| offset_clause select_offset_value |
| select_fetch_first_value I_or_F_const |
| %type <ival> row_or_rows first_or_next |
| |
| %type <list> OptSeqOptList SeqOptList OptParenthesizedSeqOptList |
| %type <defelt> SeqOptElem |
| |
| %type <list> OptTaskOptList TaskOptList AlterTaskOptList |
| %type <defelt> TaskOptElem AlterTaskElem |
| %type <str> task_schedule task_command |
| |
| %type <istmt> insert_rest |
| %type <infer> opt_conf_expr |
| %type <onconflict> opt_on_conflict |
| %type <mergewhen> merge_insert merge_update merge_delete |
| |
| %type <node> merge_when_clause opt_merge_when_condition |
| %type <list> merge_when_list |
| |
| %type <vsetstmt> generic_set set_rest set_rest_more generic_reset reset_rest |
| SetResetClause FunctionSetResetClause |
| |
| %type <node> TableElement TypedTableElement ConstraintElem TableFuncElement |
| %type <node> columnDef columnOptions |
| %type <defelt> def_elem reloption_elem old_aggr_elem keyvalue_pair operator_def_elem |
| %type <node> ExtTableElement |
| %type <node> ExtcolumnDef |
| %type <node> cdb_string |
| %type <node> def_arg columnElem where_clause where_or_current_clause |
| a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound |
| columnref in_expr having_clause func_table xmltable array_expr |
| OptWhereClause operator_def_arg |
| %type <list> rowsfrom_item rowsfrom_list opt_col_def_list |
| %type <boolean> opt_ordinality |
| %type <list> ExclusionConstraintList ExclusionConstraintElem |
| %type <list> func_arg_list func_arg_list_opt |
| %type <node> func_arg_expr |
| %type <list> row explicit_row implicit_row type_list array_expr_list |
| %type <node> case_expr case_arg when_clause when_operand case_default |
| %type <list> when_clause_list |
| %type <node> decode_expr search_result decode_default |
| %type <list> search_result_list |
| %type <node> opt_search_clause opt_cycle_clause |
| %type <ival> sub_type opt_materialized |
| %type <node> NumericOnly |
| %type <list> NumericOnly_list |
| %type <alias> alias_clause opt_alias_clause opt_alias_clause_for_join_using |
| %type <list> func_alias_clause |
| %type <sortby> sortby |
| %type <ielem> index_elem index_elem_options |
| %type <selem> stats_param |
| %type <node> table_ref |
| %type <jexpr> joined_table |
| %type <range> relation_expr |
| %type <range> extended_relation_expr |
| %type <range> relation_expr_opt_alias |
| %type <node> tablesample_clause opt_repeatable_clause |
| %type <target> target_el set_target insert_column_item |
| |
| %type <str> generic_option_name |
| %type <node> generic_option_arg |
| %type <defelt> generic_option_elem alter_generic_option_elem |
| %type <list> generic_option_list alter_generic_option_list |
| |
| %type <ival> reindex_target_relation reindex_target_all |
| %type <list> opt_reindex_option_list |
| |
| %type <node> copy_generic_opt_arg copy_generic_opt_arg_list_item |
| %type <defelt> copy_generic_opt_elem |
| %type <list> copy_generic_opt_list copy_generic_opt_arg_list |
| %type <list> copy_options |
| |
| %type <typnam> Typename SimpleTypename ConstTypename |
| GenericType Numeric opt_float |
| Character ConstCharacter |
| CharacterWithLength CharacterWithoutLength |
| ConstDatetime ConstInterval |
| Bit ConstBit BitWithLength BitWithoutLength |
| %type <str> character |
| %type <str> extract_arg |
| %type <boolean> opt_varying opt_timezone opt_no_inherit |
| |
| %type <ival> Iconst SignedIconst |
| %type <str> Sconst comment_text notify_payload |
| %type <str> RoleId opt_boolean_or_string |
| %type <str> QueueId |
| %type <list> var_list |
| %type <str> ColId ColLabel BareColLabel |
| %type <keyword> PartitionIdentKeyword |
| %type <str> PartitionColId |
| %type <str> NonReservedWord NonReservedWord_or_Sconst |
| %type <str> var_name type_function_name param_name |
| %type <str> createdb_opt_name plassign_target |
| %type <node> var_value zone_value |
| %type <rolespec> auth_ident RoleSpec opt_granted_by |
| %type <publicationobjectspec> PublicationObjSpec |
| |
| %type <keyword> unreserved_keyword type_func_name_keyword |
| %type <keyword> col_name_keyword reserved_keyword |
| %type <keyword> bare_label_keyword |
| |
| %type <node> TableConstraint TableLikeClause |
| %type <ival> TableLikeOptionList TableLikeOption |
| %type <str> column_compression opt_column_compression column_storage opt_column_storage |
| %type <list> ColQualList |
| %type <node> ColConstraint ColConstraintElem ConstraintAttr |
| %type <ival> key_match |
| %type <keyaction> key_delete key_update key_action |
| %type <keyactions> key_actions |
| %type <ival> ConstraintAttributeSpec ConstraintAttributeElem |
| %type <str> ExistingIndex |
| |
| %type <list> constraints_set_list |
| %type <boolean> constraints_set_mode |
| %type <str> OptTableSpace OptConsTableSpace |
| %type <defelt> OptServer |
| %type <str> OptFileHandler |
| |
| %type <rolespec> OptTableSpaceOwner |
| %type <node> DistributedBy OptDistributedBy |
| %type <ival> OptTabPartitionRangeInclusive |
| %type <node> TabSubPartitionBy TabSubPartition |
| tab_part_val tab_part_val_no_paran |
| %type <node> opt_list_subparts |
| %type <ival> opt_check_option |
| %type <node> OptTabPartitionSpec OptTabSubPartitionSpec TabSubPartitionTemplate /* PartitionSpec */ |
| %type <list> TabPartitionElemList TabSubPartitionElemList /* list of PartitionElem */ |
| |
| %type <node> TabPartitionElem TabSubPartitionElem /* PartitionElem */ |
| |
| %type <node> TabPartitionBoundarySpec OptTabPartitionBoundarySpec /* PartitionBoundSpec */ |
| %type <node> TabAddPartitionBoundarySpec OptTabAddPartitionBoundarySpec /* AddPartitionBoundSpec */ |
| %type <list> TabPartitionBoundarySpecValList |
| part_values_or_spec_list |
| %type <node> TabPartitionBoundarySpecStart TabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEnd /* GpPartitionRangeItem */ |
| %type <list> OptTabPartitionBoundarySpecEvery |
| %type <str> TabPartitionNameDecl TabSubPartitionNameDecl |
| TabPartitionDefaultNameDecl TabSubPartitionDefaultNameDecl |
| %type <node> opt_table_partition_split_into |
| %type <node> opt_time |
| |
| %type <node> column_reference_storage_directive |
| %type <list> opt_storage_encoding OptTabPartitionColumnEncList |
| TabPartitionColumnEncList |
| |
| %type <str> opt_provider security_label |
| |
| %type <target> xml_attribute_el |
| %type <list> xml_attribute_list xml_attributes |
| %type <node> xml_root_version opt_xml_root_standalone |
| %type <node> xmlexists_argument |
| %type <ival> document_or_content |
| %type <boolean> xml_indent_option xml_whitespace_option |
| %type <list> xmltable_column_list xmltable_column_option_list |
| %type <node> xmltable_column_el |
| %type <defelt> xmltable_column_option_el |
| %type <list> xml_namespace_list |
| %type <target> xml_namespace_el |
| |
| %type <node> func_application func_expr_common_subexpr |
| %type <node> func_expr func_expr_windowless |
| %type <node> common_table_expr |
| %type <with> with_clause opt_with_clause |
| %type <list> cte_list |
| |
| %type <list> within_group_clause |
| %type <node> filter_clause |
| %type <list> window_clause window_definition_list opt_partition_clause |
| %type <windef> window_definition over_clause window_specification |
| opt_frame_clause frame_extent frame_bound |
| %type <ival> opt_window_exclusion_clause |
| %type <str> opt_existing_window_name |
| |
| %type <list> distributed_by_list |
| %type <dkelem> distributed_by_elem |
| |
| %type <boolean> opt_if_not_exists |
| %type <boolean> opt_unique_null_treatment |
| %type <ival> generated_when override_kind |
| %type <partspec> PartitionSpec OptFirstPartitionSpec OptSecondPartitionSpec |
| %type <partelem> part_elem |
| %type <list> part_params |
| %type <partboundspec> PartitionBoundSpec |
| %type <list> hash_partbound |
| %type <defelt> hash_partbound_elem |
| |
| %type <list> OptWarehouseOptList WarehouseOptList |
| %type <defelt> WarehouseOptElem |
| |
| %type <node> json_format_clause_opt |
| json_value_expr |
| json_output_clause_opt |
| json_name_and_value |
| json_aggregate_func |
| %type <list> json_name_and_value_list |
| json_value_expr_list |
| json_array_aggregate_order_by_clause_opt |
| %type <ival> json_encoding_clause_opt |
| json_predicate_type_constraint |
| %type <boolean> json_key_uniqueness_constraint_opt |
| json_object_constructor_null_clause_opt |
| json_array_constructor_null_clause_opt |
| |
| |
| /* |
| * Non-keyword token types. These are hard-wired into the "flex" lexer. |
| * They must be listed first so that their numeric codes do not depend on |
| * the set of keywords. PL/pgSQL depends on this so that it can share the |
| * same lexer. If you add/change tokens here, fix PL/pgSQL to match! |
| * |
| * UIDENT and USCONST are reduced to IDENT and SCONST in parser.c, so that |
| * they need no productions here; but we must assign token codes to them. |
| * |
| * DOT_DOT is unused in the core SQL grammar, and so will always provoke |
| * parse errors. It is needed by PL/pgSQL. |
| */ |
| %token <str> IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op |
| %token <ival> ICONST PARAM |
| %token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER |
| %token LESS_EQUALS GREATER_EQUALS NOT_EQUALS |
| |
| /* |
| * If you want to make any keyword changes, update the keyword table in |
| * src/include/parser/kwlist.h and add new keywords to the appropriate one |
| * of the reserved-or-not-so-reserved keyword lists, below; search |
| * this file for "Keyword category lists". |
| */ |
| |
| /* ordinary key words in alphabetical order */ |
| %token <keyword> ABORT_P ABSENT ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER |
| AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC |
| ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION |
| |
| BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT |
| BOOLEAN_P BOTH BREADTH BY |
| |
| CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P |
| CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE |
| CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT |
| COMMITTED COMPRESSION CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT |
| CONCURRENCY |
| CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE |
| CROSS CSV CUBE CURRENT_P |
| CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA |
| CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE |
| |
| DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS |
| DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC |
| DETACH DICTIONARY DIRECTORY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P |
| DOUBLE_P DROP DYNAMIC |
| |
| EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENDPOINT ENUM_P ESCAPE EVENT EXCEPT |
| EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION |
| EXTENSION EXTERNAL EXTRACT |
| |
| FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR |
| FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS |
| |
| GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPS |
| |
| HANDLER HAVING HEADER_P HOLD HOUR_P |
| |
| IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE |
| INCLUDING INCREMENT INCREMENTAL INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P |
| INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER |
| INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION |
| |
| JOIN JSON JSON_ARRAY JSON_ARRAYAGG JSON_OBJECT JSON_OBJECTAGG |
| |
| KEY KEYS |
| |
| LABEL LANGUAGE LARGE_P LAST_P LATERAL_P |
| LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL |
| LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOCUS LOGGED |
| |
| MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE MEMORY_QUOTA |
| METHOD MINUTE_P MINVALUE MIN_COST MODE MONTH_P MOVE |
| |
| NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE |
| NORMALIZE NORMALIZED |
| NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF |
| NULLS_P NUMERIC |
| |
| OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR |
| ORDER ORDINALITY OTHERS OUT_P OUTER_P |
| OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER |
| |
| PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD |
| PLACING PLANS POLICY |
| POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY |
| PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION |
| |
| QUOTE |
| |
| RANGE READ REAL REASSIGN RECHECK RECURSIVE REF_P REFERENCES REFERENCING |
| REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA |
| RESET RESTART RESTRICT RETRIEVE RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP |
| ROUTINE ROUTINES ROW ROWS RULE |
| |
| SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT |
| SEQUENCE SEQUENCES |
| SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW |
| SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P |
| START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P |
| SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER |
| |
| TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN |
| TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM |
| TREAT TRIGGER TRIM TRUE_P |
| TRUNCATE TRUSTED TYPE_P TYPES_P |
| |
| UESCAPE UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN |
| UNLISTEN UNLOGGED UNTIL UPDATE USER USING |
| |
| VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING |
| VERBOSE VERSION_P VIEW VIEWS VOLATILE |
| |
| WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE |
| |
| XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLNAMESPACES |
| XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE |
| |
| YEAR_P YES_P |
| |
| ZONE |
| |
| |
| /* GPDB-added keywords, in alphabetical order */ |
| %token <keyword> |
| ACCOUNT ACTIVE ALLOWED_VALUES AO_AUX_ONLY |
| |
| CONTAINS COORDINATOR CPUSET CPU_MAX_PERCENT CPU_WEIGHT |
| |
| CREATEEXTTABLE |
| |
| DECODE DENY DISTRIBUTED DXL |
| |
| ERRORS EVERY EXCHANGE EXPAND |
| |
| FAILED_LOGIN_ATTEMPTS FIELDS FILL |
| |
| FULLSCAN |
| |
| GROUP_ID |
| |
| HASH HOST |
| |
| IGNORE_P INCLUSIVE INITPLAN IO_LIMIT |
| |
| LIST LOG_P |
| |
| MASTER MEDIAN MISSING MODIFIES |
| |
| NEWLINE NOCREATEEXTTABLE NOOVERCOMMIT |
| |
| ORDERED OVERCOMMIT |
| |
| PARTITIONS PASSWORD_LOCK_TIME PASSWORD_REUSE_MAX PERCENT PERSISTENTLY PROFILE PROTOCOL |
| |
| QUEUE |
| |
| RANDOMLY READABLE READS REJECT_P REPLICATED RESOURCE |
| ROOTPARTITION |
| |
| SCATTER SEGMENT SEGMENTS SHRINK SPLIT SUBPARTITION |
| |
| TAG |
| |
| TASK SCHEDULE |
| |
| THRESHOLD |
| |
| UNLOCK_P |
| |
| UNSET_P |
| |
| VALIDATION |
| |
| WAREHOUSE |
| |
| WAREHOUSE_SIZE |
| |
| WEB WRITABLE |
| |
| /* |
| * The grammar thinks these are keywords, but they are not in the kwlist.h |
| * list and so can never be entered directly. The filter in parser.c |
| * creates these tokens when required (based on looking one token ahead). |
| * |
| * NOT_LA exists so that productions such as NOT LIKE can be given the same |
| * precedence as LIKE; otherwise they'd effectively have the same precedence |
| * as NOT, at least with respect to their left-hand subexpression. |
| * FORMAT_LA, NULLS_LA, WITH_LA, and WITHOUT_LA are needed to make the grammar |
| * LALR(1). |
| */ |
| %token FORMAT_LA NOT_LA NULLS_LA WITH_LA WITHOUT_LA |
| %token PARTITION_TAIL |
| |
| /* |
| * The grammar likewise thinks these tokens are keywords, but they are never |
| * generated by the scanner. Rather, they can be injected by parser.c as |
| * the initial token of the string (using the lookahead-token mechanism |
| * implemented there). This provides a way to tell the grammar to parse |
| * something other than the usual list of SQL commands. |
| */ |
| %token MODE_TYPE_NAME |
| %token MODE_PLPGSQL_EXPR |
| %token MODE_PLPGSQL_ASSIGN1 |
| %token MODE_PLPGSQL_ASSIGN2 |
| %token MODE_PLPGSQL_ASSIGN3 |
| |
| |
| /* Precedence: lowest to highest */ |
| %nonassoc SET /* see relation_expr_opt_alias */ |
| %left UNION EXCEPT |
| %left INTERSECT |
| %left OR |
| %left AND |
| %right NOT |
| %nonassoc IS ISNULL NOTNULL /* IS sets precedence for IS NULL, etc */ |
| %nonassoc '<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS |
| %nonassoc BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA |
| %nonassoc ESCAPE /* ESCAPE must be just above LIKE/ILIKE/SIMILAR */ |
| |
| /* SQL/JSON related keywords */ |
| %nonassoc UNIQUE JSON |
| %nonassoc KEYS SCALAR |
| |
| /* |
| * To support target_el without AS, it used to be necessary to assign IDENT an |
| * explicit precedence just less than Op. While that's not really necessary |
| * since we removed postfix operators, it's still helpful to do so because |
| * there are some other unreserved keywords that need precedence assignments. |
| * If those keywords have the same precedence as IDENT then they clearly act |
| * the same as non-keywords, reducing the risk of unwanted precedence effects. |
| * |
| * We need to do this for PARTITION, RANGE, ROWS, and GROUPS to support |
| * opt_existing_window_name (see comment there). |
| * |
| * The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING |
| * are even messier: since UNBOUNDED is an unreserved keyword (per spec!), |
| * there is no principled way to distinguish these from the productions |
| * a_expr PRECEDING/FOLLOWING. We hack this up by giving UNBOUNDED slightly |
| * lower precedence than PRECEDING and FOLLOWING. At present this doesn't |
| * appear to cause UNBOUNDED to be treated differently from other unreserved |
| * keywords anywhere else in the grammar, but it's definitely risky. We can |
| * blame any funny behavior of UNBOUNDED on the SQL standard, though. |
| * |
| * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them |
| * an explicit priority lower than '(', so that a rule with CUBE '(' will shift |
| * rather than reducing a conflicting rule that takes CUBE as a function name. |
| * Using the same precedence as IDENT seems right for the reasons given above. |
| */ |
| %nonassoc UNBOUNDED /* ideally should have same precedence as IDENT */ |
| %nonassoc IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP |
| |
| /* |
| * GPDB_14_MERGE_FIXME: need to update this list to reflect new keywords added |
| * as part of merge in bare_label_keyword,..... |
| */ |
| /* |
| * This is a bit ugly... To allow these to be column aliases without |
| * the "AS" keyword, and not conflict with PostgreSQL's non-standard |
| * suffix operators, we need to give these a precedence. |
| */ |
| %nonassoc ABORT_P |
| %nonassoc ABSOLUTE_P |
| %nonassoc ACCESS |
| %nonassoc ACTION |
| %nonassoc ACTIVE |
| %nonassoc ADD_P |
| %nonassoc ADMIN |
| %nonassoc AFTER |
| %nonassoc AGGREGATE |
| %nonassoc ALSO |
| %nonassoc ALTER |
| %nonassoc AO_AUX_ONLY |
| %nonassoc ASSERTION |
| %nonassoc ASSIGNMENT |
| %nonassoc ATTACH |
| %nonassoc BACKWARD |
| %nonassoc BEFORE |
| %nonassoc BEGIN_P |
| %nonassoc BY |
| %nonassoc CACHE |
| %nonassoc CALL |
| %nonassoc CALLED |
| %nonassoc CASCADE |
| %nonassoc CASCADED |
| %nonassoc CHAIN |
| %nonassoc CHARACTERISTICS |
| %nonassoc CHECKPOINT |
| %nonassoc CLASS |
| %nonassoc CLOSE |
| %nonassoc CLUSTER |
| %nonassoc COLUMNS |
| %nonassoc COMMENT |
| %nonassoc COMMIT |
| %nonassoc COMMITTED |
| %nonassoc CONCURRENCY |
| %nonassoc CONCURRENTLY |
| %nonassoc CONNECTION |
| %nonassoc CONSTRAINTS |
| %nonassoc CONTAINS |
| %nonassoc CONTENT_P |
| %nonassoc CONTINUE_P |
| %nonassoc CONVERSION_P |
| %nonassoc COORDINATOR |
| %nonassoc COPY |
| %nonassoc COST |
| %nonassoc CPUSET |
| %nonassoc CPU_MAX_PERCENT |
| %nonassoc CPU_WEIGHT |
| %nonassoc CREATEEXTTABLE |
| %nonassoc CSV |
| %nonassoc CURRENT_P |
| %nonassoc CURSOR |
| %nonassoc CYCLE |
| %nonassoc DATA_P |
| %nonassoc DATABASE |
| %nonassoc DAY_P |
| %nonassoc DEALLOCATE |
| %nonassoc DECLARE |
| %nonassoc DEFAULTS |
| %nonassoc DEFERRED |
| %nonassoc DEFINER |
| %nonassoc DELETE_P |
| %nonassoc DELIMITER |
| %nonassoc DELIMITERS |
| %nonassoc DEPENDS |
| %nonassoc DETACH |
| %nonassoc DISABLE_P |
| %nonassoc DOMAIN_P |
| %nonassoc DOUBLE_P |
| %nonassoc DROP |
| %nonassoc EACH |
| %nonassoc ENABLE_P |
| %nonassoc ENCODING |
| %nonassoc ENCRYPTED |
| %nonassoc END_P |
| %nonassoc ENDPOINT |
| %nonassoc ENUM_P |
| %nonassoc ERRORS |
| %nonassoc EVERY |
| %nonassoc EXCHANGE |
| %nonassoc EXCLUDING |
| %nonassoc EXCLUSIVE |
| %nonassoc EXECUTE |
| %nonassoc EXPLAIN |
| %nonassoc EXTERNAL |
| %nonassoc FETCH |
| %nonassoc FIELDS |
| %nonassoc FILL |
| %nonassoc FIRST_P |
| %nonassoc FORCE |
| %nonassoc FORMAT |
| %nonassoc FORWARD |
| %nonassoc FUNCTION |
| %nonassoc GLOBAL |
| %nonassoc GRANTED |
| %nonassoc GROUPING |
| %nonassoc HANDLER |
| %nonassoc HASH |
| %nonassoc HEADER_P |
| %nonassoc HOLD |
| %nonassoc HOST |
| %nonassoc HOUR_P |
| %nonassoc IF_P |
| %nonassoc IMMEDIATE |
| %nonassoc IMMUTABLE |
| %nonassoc IMPLICIT_P |
| %nonassoc IMPORT_P |
| %nonassoc INCLUDE |
| %nonassoc INCLUDING |
| %nonassoc INCLUSIVE |
| %nonassoc INCREMENT |
| %nonassoc INDEX |
| %nonassoc INDEXES |
| %nonassoc INHERIT |
| %nonassoc INHERITS |
| %nonassoc INPUT_P |
| %nonassoc INSENSITIVE |
| %nonassoc INSERT |
| %nonassoc INSTEAD |
| %nonassoc INVOKER |
| %nonassoc ISOLATION |
| %nonassoc KEY |
| %nonassoc LANGUAGE |
| %nonassoc LARGE_P |
| %nonassoc LAST_P |
| %nonassoc LEVEL |
| %nonassoc LIST |
| %nonassoc LISTEN |
| %nonassoc LOAD |
| %nonassoc LOCAL |
| %nonassoc LOCATION |
| %nonassoc LOCKED |
| %nonassoc LOCK_P |
| %nonassoc LOGGED |
| %nonassoc MASTER |
| %nonassoc MATCH |
| %nonassoc MAXVALUE |
| %nonassoc MEMORY_QUOTA |
| %nonassoc METHOD |
| %nonassoc MIN_COST |
| %nonassoc MINUTE_P |
| %nonassoc MINVALUE |
| %nonassoc MISSING |
| %nonassoc MODE |
| %nonassoc MODIFIES |
| %nonassoc MONTH_P |
| %nonassoc MOVE |
| %nonassoc NAME_P |
| %nonassoc NAMES |
| %nonassoc NEW |
| %nonassoc NEWLINE |
| %nonassoc NEXT |
| %nonassoc NO |
| %nonassoc NOCREATEEXTTABLE |
| %nonassoc NOOVERCOMMIT |
| %nonassoc NOTHING |
| %nonassoc NOTIFY |
| %nonassoc NOWAIT |
| %nonassoc NULLS_P |
| %nonassoc OBJECT_P |
| %nonassoc OF |
| %nonassoc OIDS |
| %nonassoc OLD |
| %nonassoc OPTION |
| %nonassoc OPTIONS |
| %nonassoc OTHERS |
| %nonassoc OVER |
| %nonassoc OVERCOMMIT |
| %nonassoc OVERRIDING |
| %nonassoc OWNED |
| %nonassoc OWNER |
| %nonassoc PARALLEL |
| %nonassoc PARTIAL |
| %nonassoc PARTITIONS |
| %nonassoc PASSWORD |
| %nonassoc PERCENT |
| %nonassoc PERSISTENTLY |
| %nonassoc POLICY |
| %nonassoc PREPARE |
| %nonassoc PREPARED |
| %nonassoc PRIOR |
| %nonassoc PRIVILEGES |
| %nonassoc PROCEDURAL |
| %nonassoc PROCEDURE |
| %nonassoc PROCEDURES |
| %nonassoc PROTOCOL |
| %nonassoc PUBLICATION |
| %nonassoc QUEUE |
| %nonassoc QUOTE |
| %nonassoc RANDOMLY |
| %nonassoc READ |
| %nonassoc READABLE |
| %nonassoc READS |
| %nonassoc REASSIGN |
| %nonassoc RECHECK |
| %nonassoc RECURSIVE |
| %nonassoc REFERENCING |
| %nonassoc REINDEX |
| %nonassoc REJECT_P |
| %nonassoc RELATIVE_P |
| %nonassoc RELEASE |
| %nonassoc RENAME |
| %nonassoc REPEATABLE |
| %nonassoc REPLACE |
| %nonassoc RESET |
| %nonassoc RESOURCE |
| %nonassoc RESTART |
| %nonassoc RESTRICT |
| %nonassoc RETRIEVE |
| %nonassoc RETURNS |
| %nonassoc REVOKE |
| %nonassoc ROLE |
| %nonassoc ROLLBACK |
| %nonassoc ROUTINE |
| %nonassoc ROUTINES |
| %nonassoc RULE |
| %nonassoc SAVEPOINT |
| %nonassoc SCHEDULE |
| %nonassoc SCHEMA |
| %nonassoc SCHEMAS |
| %nonassoc SCROLL |
| %nonassoc SEARCH |
| %nonassoc SECOND_P |
| %nonassoc SECURITY |
| %nonassoc SEGMENT |
| %nonassoc SEGMENTS |
| %nonassoc SEQUENCE |
| %nonassoc SERIALIZABLE |
| %nonassoc SESSION |
| %nonassoc SHARE |
| %nonassoc SHOW |
| %nonassoc SIMPLE |
| %nonassoc SQL_P |
| %nonassoc SPLIT |
| %nonassoc STABLE |
| %nonassoc START |
| %nonassoc STATEMENT |
| %nonassoc STATISTICS |
| %nonassoc STDIN |
| %nonassoc STDOUT |
| %nonassoc STORAGE |
| %nonassoc STORED |
| %nonassoc SUBPARTITION |
| %nonassoc SUPPORT |
| %nonassoc SYSID |
| %nonassoc SYSTEM_P |
| %nonassoc STRICT_P |
| %nonassoc TABLESAMPLE |
| %nonassoc TABLESPACE |
| %nonassoc TAG |
| %nonassoc TASK |
| %nonassoc TEMP |
| %nonassoc TEMPLATE |
| %nonassoc TEMPORARY |
| %nonassoc THRESHOLD |
| %nonassoc TIES |
| %nonassoc TRANSACTION |
| %nonassoc TRANSFORM |
| %nonassoc TRIGGER |
| %nonassoc TRUNCATE |
| %nonassoc TRUSTED |
| %nonassoc TYPE_P |
| %nonassoc UNCOMMITTED |
| %nonassoc UNENCRYPTED |
| %nonassoc UNLISTEN |
| %nonassoc UNLOCK_P |
| %nonassoc UNTIL |
| %nonassoc UPDATE |
| %nonassoc VACUUM |
| %nonassoc VALID |
| %nonassoc VALIDATION |
| %nonassoc VALIDATOR |
| %nonassoc VALUE_P |
| %nonassoc VARYING |
| %nonassoc VERSION_P |
| %nonassoc VIEW |
| %nonassoc VOLATILE |
| %nonassoc WEB |
| %nonassoc WITH |
| %nonassoc WITHIN |
| %nonassoc WITHOUT |
| %nonassoc WORK |
| %nonassoc WRITABLE |
| %nonassoc WRITE |
| %nonassoc YEAR_P |
| %nonassoc BIGINT |
| %nonassoc BIT |
| %nonassoc BOOLEAN_P |
| %nonassoc CHAR_P |
| %nonassoc CHARACTER |
| %nonassoc COALESCE |
| %nonassoc DEC |
| %nonassoc DECIMAL_P |
| %nonassoc EXISTS |
| %nonassoc EXTRACT |
| %nonassoc FLOAT_P |
| %nonassoc GREATEST |
| %nonassoc INOUT |
| %nonassoc INT_P |
| %nonassoc INTEGER |
| %nonassoc INTERVAL |
| %nonassoc LEAST |
| %nonassoc MEDIAN |
| %nonassoc NATIONAL |
| %nonassoc NCHAR |
| %nonassoc NONE |
| %nonassoc NULLIF |
| %nonassoc NUMERIC |
| %nonassoc OUT_P |
| %nonassoc OVERLAY |
| %nonassoc POSITION |
| %nonassoc PRECISION |
| %nonassoc REAL |
| %nonassoc ROW |
| %nonassoc SETOF |
| %nonassoc SETS |
| %nonassoc SMALLINT |
| %nonassoc SUBSTRING |
| %nonassoc TIME |
| %nonassoc TIMESTAMP |
| %nonassoc TREAT |
| %nonassoc TRIM |
| %nonassoc VALUES |
| %nonassoc VARCHAR |
| %nonassoc AUTHORIZATION |
| %nonassoc BINARY |
| %nonassoc FREEZE |
| %nonassoc LOG_P |
| %nonassoc OUTER_P |
| %nonassoc VERBOSE |
| %nonassoc UNKNOWN |
| %nonassoc ZONE |
| |
| %left Op OPERATOR /* multi-character ops and user-defined operators */ |
| %left '+' '-' |
| %left '*' '/' '%' |
| %left '^' |
| /* Unary Operators */ |
| %left AT /* sets precedence for AT TIME ZONE */ |
| %left COLLATE |
| %right UMINUS |
| %left '[' ']' |
| %left '(' ')' |
| %left TYPECAST |
| %left '.' |
| /* |
| * These might seem to be low-precedence, but actually they are not part |
| * of the arithmetic hierarchy at all in their use as JOIN operators. |
| * We make them high-precedence to support their use as function names. |
| * They wouldn't be given a precedence at all, were it not that we need |
| * left-associativity among the JOIN rules themselves. |
| */ |
| %left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL |
| |
| %% |
| |
| /* |
| * The target production for the whole parse. |
| * |
| * Ordinarily we parse a list of statements, but if we see one of the |
| * special MODE_XXX symbols as first token, we parse something else. |
| * The options here correspond to enum RawParseMode, which see for details. |
| */ |
| parse_toplevel: |
| stmtmulti |
| { |
| pg_yyget_extra(yyscanner)->parsetree = $1; |
| (void) yynerrs; /* suppress compiler warning */ |
| } |
| | MODE_TYPE_NAME Typename |
| { |
| pg_yyget_extra(yyscanner)->parsetree = list_make1($2); |
| } |
| | MODE_PLPGSQL_EXPR PLpgSQL_Expr |
| { |
| pg_yyget_extra(yyscanner)->parsetree = |
| list_make1(makeRawStmt($2, 0)); |
| } |
| | MODE_PLPGSQL_ASSIGN1 PLAssignStmt |
| { |
| PLAssignStmt *n = (PLAssignStmt *) $2; |
| |
| n->nnames = 1; |
| pg_yyget_extra(yyscanner)->parsetree = |
| list_make1(makeRawStmt((Node *) n, 0)); |
| } |
| | MODE_PLPGSQL_ASSIGN2 PLAssignStmt |
| { |
| PLAssignStmt *n = (PLAssignStmt *) $2; |
| |
| n->nnames = 2; |
| pg_yyget_extra(yyscanner)->parsetree = |
| list_make1(makeRawStmt((Node *) n, 0)); |
| } |
| | MODE_PLPGSQL_ASSIGN3 PLAssignStmt |
| { |
| PLAssignStmt *n = (PLAssignStmt *) $2; |
| |
| n->nnames = 3; |
| pg_yyget_extra(yyscanner)->parsetree = |
| list_make1(makeRawStmt((Node *) n, 0)); |
| } |
| ; |
| |
| /* |
| * At top level, we wrap each stmt with a RawStmt node carrying start location |
| * and length of the stmt's text. Notice that the start loc/len are driven |
| * entirely from semicolon locations (@2). It would seem natural to use |
| * @1 or @3 to get the true start location of a stmt, but that doesn't work |
| * for statements that can start with empty nonterminals (opt_with_clause is |
| * the main offender here); as noted in the comments for YYLLOC_DEFAULT, |
| * we'd get -1 for the location in such cases. |
| * We also take care to discard empty statements entirely. |
| */ |
| stmtmulti: stmtmulti ';' toplevel_stmt |
| { |
| if ($1 != NIL) |
| { |
| /* update length of previous stmt */ |
| updateRawStmtEnd(llast_node(RawStmt, $1), @2); |
| } |
| if ($3 != NULL) |
| $$ = lappend($1, makeRawStmt($3, @2 + 1)); |
| else |
| $$ = $1; |
| } |
| | toplevel_stmt |
| { |
| if ($1 != NULL) |
| $$ = list_make1(makeRawStmt($1, 0)); |
| else |
| $$ = NIL; |
| } |
| ; |
| |
| /* |
| * toplevel_stmt includes BEGIN and END. stmt does not include them, because |
| * those words have different meanings in function bodies. |
| */ |
| toplevel_stmt: |
| stmt |
| | TransactionStmtLegacy |
| ; |
| |
| stmt: |
| AddForeignSegStmt |
| | AlterEventTrigStmt |
| | AlterCollationStmt |
| | AlterDatabaseStmt |
| | AlterDatabaseSetStmt |
| | AlterDefaultPrivilegesStmt |
| | AlterDirectoryTableStmt |
| | AlterDomainStmt |
| | AlterEnumStmt |
| | AlterExtensionStmt |
| | AlterExtensionContentsStmt |
| | AlterFdwStmt |
| | AlterForeignServerStmt |
| | AlterFunctionStmt |
| | AlterGroupStmt |
| | AlterObjectDependsStmt |
| | AlterObjectSchemaStmt |
| | AlterOwnerStmt |
| | AlterOperatorStmt |
| | AlterTaskStmt |
| | AlterTypeStmt |
| | AlterPolicyStmt |
| | AlterProfileStmt |
| | AlterQueueStmt |
| | AlterResourceGroupStmt |
| | AlterSchemaStmt |
| | AlterSeqStmt |
| | AlterStorageServerStmt |
| | AlterSystemStmt |
| | AlterTableStmt |
| | AlterTagStmt |
| | AlterTblSpcStmt |
| | AlterCompositeTypeStmt |
| | AlterPublicationStmt |
| | AlterRoleSetStmt |
| | AlterRoleStmt |
| | AlterSubscriptionStmt |
| | AlterStatsStmt |
| | AlterTSConfigurationStmt |
| | AlterTSDictionaryStmt |
| | AlterUserMappingStmt |
| | AlterStorageUserMappingStmt |
| | AnalyzeStmt |
| | CallStmt |
| | CheckPointStmt |
| | ClosePortalStmt |
| | ClusterStmt |
| | CommentStmt |
| | ConstraintsSetStmt |
| | CopyStmt |
| | CreateAmStmt |
| | CreateAsStmt |
| | CreateAssertionStmt |
| | CreateCastStmt |
| | CreateConversionStmt |
| | CreateDomainStmt |
| | CreateDirectoryTableStmt |
| | CreateExtensionStmt |
| | CreateExternalStmt |
| | CreateFdwStmt |
| | CreateForeignServerStmt |
| | CreateForeignTableStmt |
| | CreateFunctionStmt |
| | CreateGroupStmt |
| | CreateMatViewStmt |
| | CreateOpClassStmt |
| | CreateOpFamilyStmt |
| | CreatePublicationStmt |
| | CreateWarehouseStmt |
| | AlterOpFamilyStmt |
| | CreatePolicyStmt |
| | CreateProfileStmt |
| | CreatePLangStmt |
| | CreateQueueStmt |
| | CreateResourceGroupStmt |
| | CreateSchemaStmt |
| | CreateSeqStmt |
| | CreateStmt |
| | CreateSubscriptionStmt |
| | CreateStatsStmt |
| | CreateStorageServerStmt |
| | CreateStorageUserMappingStmt |
| | CreateTableSpaceStmt |
| | CreateTagStmt |
| | CreateTaskStmt |
| | CreateTransformStmt |
| | CreateTrigStmt |
| | CreateEventTrigStmt |
| | CreateRoleStmt |
| | CreateUserStmt |
| | CreateUserMappingStmt |
| | CreatedbStmt |
| | DeallocateStmt |
| | DeclareCursorStmt |
| | DefineStmt |
| | DeleteStmt |
| | DiscardStmt |
| | DoStmt |
| | DropCastStmt |
| | DropDirectoryTableStmt |
| | DropOpClassStmt |
| | DropOpFamilyStmt |
| | DropOwnedStmt |
| | DropProfileStmt |
| | DropQueueStmt |
| | DropResourceGroupStmt |
| | DropStmt |
| | DropSubscriptionStmt |
| | DropTableSpaceStmt |
| | DropTagStmt |
| | DropTaskStmt |
| | DropTransformStmt |
| | DropRoleStmt |
| | DropUserMappingStmt |
| | DropdbStmt |
| | DropStorageServerStmt |
| | DropStorageUserMappingStmt |
| | DropWarehouseStmt |
| | ExecuteStmt |
| | ExplainStmt |
| | FetchStmt |
| | GrantStmt |
| | GrantRoleStmt |
| | ImportForeignSchemaStmt |
| | IndexStmt |
| | InsertStmt |
| | ListenStmt |
| | RefreshMatViewStmt |
| | LoadStmt |
| | LockStmt |
| | MergeStmt |
| | NotifyStmt |
| | PrepareStmt |
| | ReassignOwnedStmt |
| | ReindexStmt |
| | RemoveAggrStmt |
| | RemoveFuncStmt |
| | RemoveOperStmt |
| | RenameStmt |
| | RevokeStmt |
| | RevokeRoleStmt |
| | RuleStmt |
| | SecLabelStmt |
| | SelectStmt |
| | TransactionStmt |
| | TruncateStmt |
| | UnlistenStmt |
| | UpdateStmt |
| | VacuumStmt |
| | VariableResetStmt |
| | VariableSetStmt |
| | VariableShowStmt |
| | ViewStmt |
| | RetrieveStmt |
| | /*EMPTY*/ |
| { $$ = NULL; } |
| ; |
| |
| /* |
| * Generic supporting productions for DDL |
| */ |
| opt_single_name: |
| ColId { $$ = $1; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| opt_qualified_name: |
| any_name { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_concurrently: |
| CONCURRENTLY { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_drop_behavior: |
| CASCADE { $$ = DROP_CASCADE; } |
| | RESTRICT { $$ = DROP_RESTRICT; } |
| | /* EMPTY */ { $$ = DROP_RESTRICT; /* default */ } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| CreateQueueStmt: |
| CREATE RESOURCE QUEUE QueueId OptQueueList |
| { |
| CreateQueueStmt *n = makeNode(CreateQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem("withliststart", |
| (Node *)makeInteger(true), @5); |
| n->queue = $4; |
| n->options = list_concat(lappend($5, def1), NULL); |
| $$ = (Node *)n; |
| } |
| | CREATE RESOURCE QUEUE QueueId OptQueueList WITH definition |
| { |
| CreateQueueStmt *n = makeNode(CreateQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem("withliststart", |
| (Node *)makeInteger(true), @5); |
| n->queue = $4; |
| n->options = list_concat(lappend($5, def1), $7); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Options for CREATE and ALTER RESOURCE QUEUE |
| */ |
| OptQueueList: |
| OptQueueList OptQueueElem { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptQueueElem: |
| ACTIVE THRESHOLD NumericOnly |
| { |
| /* was "activelimit" */ |
| $$ = makeDefElem("active_statements", (Node *) $3, @1); |
| } |
| | COST THRESHOLD NumericOnly /* enforce float type in queue.c */ |
| { |
| /* was "costlimit" */ |
| $$ = makeDefElem("max_cost", (Node *) $3, @1); |
| } |
| | IGNORE_P THRESHOLD NumericOnly /* enforce float type in queue.c */ |
| { |
| /* was "ignorecostlimit" */ |
| $$ = makeDefElem("min_cost", (Node *) $3, @1); |
| } |
| | OVERCOMMIT |
| { |
| /* was "overcommit" */ |
| $$ = makeDefElem("cost_overcommit", (Node *) makeInteger(true), @1); |
| } |
| | NOOVERCOMMIT |
| { |
| /* was "overcommit" */ |
| $$ = makeDefElem("cost_overcommit", (Node *) makeInteger(false), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Alter a postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| AlterQueueStmt: |
| ALTER RESOURCE QUEUE QueueId OptQueueList |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| n->queue = $4; |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| | ALTER RESOURCE QUEUE QueueId OptQueueList WITH definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem("withliststart", |
| (Node *) makeInteger(true), @6); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem("withoutliststart", |
| (Node *) makeInteger(true), @6); |
| n->queue = $4; |
| n->options = list_concat(lappend($5, def1), $7); |
| n->options = lappend(n->options, def2); |
| $$ = (Node *)n; |
| } |
| | ALTER RESOURCE QUEUE QueueId OptQueueList WITHOUT definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem("withliststart", |
| (Node *) makeInteger(true), @6); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem("withoutliststart", |
| (Node *) makeInteger(true), @6); |
| n->queue = $4; |
| n->options = lappend($5, def1); |
| n->options = list_concat(lappend(n->options, def2), $7); |
| $$ = (Node *)n; |
| } |
| | ALTER RESOURCE QUEUE QueueId OptQueueList WITH definition |
| WITHOUT definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem("withliststart", |
| (Node *) makeInteger(true), @6); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem("withoutliststart", |
| (Node *) makeInteger(true), @6); |
| n->queue = $4; |
| n->options = list_concat(lappend($5, def1), $7); |
| n->options = list_concat(lappend(n->options, def2), $9); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Drop a postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| DropQueueStmt: |
| DROP RESOURCE QUEUE QueueId |
| { |
| DropQueueStmt *n = makeNode(DropQueueStmt); |
| n->queue = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Create a new GPDB Resource Group |
| * |
| *****************************************************************************/ |
| |
| CreateResourceGroupStmt: |
| CREATE RESOURCE GROUP_P name WITH definition |
| { |
| CreateResourceGroupStmt *n = makeNode(CreateResourceGroupStmt); |
| n->name = $4; |
| n->options = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Drop a GPDB Resource Group |
| * |
| *****************************************************************************/ |
| |
| DropResourceGroupStmt: |
| DROP RESOURCE GROUP_P name |
| { |
| DropResourceGroupStmt *n = makeNode(DropResourceGroupStmt); |
| n->name = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Alter a GPDB Resource Group |
| * |
| *****************************************************************************/ |
| AlterResourceGroupStmt: |
| ALTER RESOURCE GROUP_P name SET OptResourceGroupList |
| { |
| AlterResourceGroupStmt *n = makeNode(AlterResourceGroupStmt); |
| n->name = $4; |
| n->options = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Option for ALTER RESOURCE GROUP |
| */ |
| OptResourceGroupList: OptResourceGroupElem { $$ = list_make1($1); } |
| ; |
| |
| OptResourceGroupElem: |
| CONCURRENCY SignedIconst |
| { |
| /* was "concurrency" */ |
| $$ = makeDefElem("concurrency", (Node *) makeInteger($2), @1); |
| } |
| | CPU_MAX_PERCENT SignedIconst |
| { |
| $$ = makeDefElem("cpu_max_percent", (Node *) makeInteger($2), @1); |
| } |
| | CPU_WEIGHT SignedIconst |
| { |
| $$ = makeDefElem("cpu_weight", (Node *) makeInteger($2), @1); |
| } |
| | CPUSET Sconst |
| { |
| $$ = makeDefElem("cpuset", (Node *) makeString($2), @1); |
| } |
| | MEMORY_QUOTA SignedIconst |
| { |
| $$ = makeDefElem("memory_quota", (Node *) makeInteger($2), @1); |
| } |
| | MIN_COST SignedIconst |
| { |
| $$ = makeDefElem("min_cost", (Node *) makeInteger($2), @1); |
| } |
| | IO_LIMIT Sconst |
| { |
| $$ = makeDefElem("io_limit", (Node *) makeString($2), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * CALL statement |
| * |
| *****************************************************************************/ |
| |
| CallStmt: CALL func_application |
| { |
| CallStmt *n = makeNode(CallStmt); |
| |
| n->funccall = castNode(FuncCall, $2); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres DBMS role |
| * |
| *****************************************************************************/ |
| |
| CreateRoleStmt: |
| CREATE ROLE RoleId opt_with OptRoleList |
| { |
| CreateRoleStmt *n = makeNode(CreateRoleStmt); |
| |
| n->stmt_type = ROLESTMT_ROLE; |
| n->role = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| opt_with: WITH |
| | WITH_LA |
| | /*EMPTY*/ |
| ; |
| |
| /* |
| * Options for CREATE ROLE and ALTER ROLE (also used by CREATE/ALTER USER |
| * for backwards compatibility). Note: the only option required by SQL99 |
| * is "WITH ADMIN name". |
| */ |
| OptRoleList: |
| OptRoleList CreateOptRoleElem { $$ = lappend($1, $2); } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| AlterOptRoleList: |
| AlterOptRoleList AlterOnlyOptRoleElem { $$ = lappend($1, $2); } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| /* |
| * GPDB: Options that are allowed in ALTER ROLE, but *not* CREATE ROLE. |
| * AlterOptRoleElem is for elements that are allowed in either. |
| * |
| * At the moment this applies only to ALTER ROLE ... DROP DENY. |
| */ |
| AlterOnlyOptRoleElem: |
| AlterOptRoleElem { $$ = $1; } |
| | DROP DENY FOR deny_point { $$ = makeDefElem("drop_deny", $4, @1); } |
| ; |
| |
| AlterOptRoleElem: |
| PASSWORD Sconst |
| { |
| $$ = makeDefElem("password", |
| (Node *) makeString($2), @1); |
| } |
| | PASSWORD NULL_P |
| { |
| $$ = makeDefElem("password", NULL, @1); |
| } |
| | ENCRYPTED PASSWORD Sconst |
| { |
| /* |
| * These days, passwords are always stored in encrypted |
| * form, so there is no difference between PASSWORD and |
| * ENCRYPTED PASSWORD. |
| */ |
| $$ = makeDefElem("password", |
| (Node *) makeString($3), @1); |
| } |
| | UNENCRYPTED PASSWORD Sconst |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("UNENCRYPTED PASSWORD is no longer supported"), |
| errhint("Remove UNENCRYPTED to store the password in encrypted form instead."), |
| parser_errposition(@1))); |
| } |
| | INHERIT |
| { |
| $$ = makeDefElem("inherit", (Node *) makeBoolean(true), @1); |
| } |
| | CONNECTION LIMIT SignedIconst |
| { |
| $$ = makeDefElem("connectionlimit", (Node *) makeInteger($3), @1); |
| } |
| | VALID UNTIL Sconst |
| { |
| $$ = makeDefElem("validUntil", (Node *) makeString($3), @1); |
| } |
| | RESOURCE QUEUE any_name |
| { |
| $$ = makeDefElem("resourceQueue", (Node *) $3, @1); |
| } |
| | RESOURCE GROUP_P any_name |
| { |
| $$ = makeDefElem("resourceGroup", (Node *) $3, @1); |
| } |
| | CREATEEXTTABLE exttab_auth_list |
| { |
| $$ = makeDefElem("exttabauth", (Node *) $2, @1); |
| } |
| | NOCREATEEXTTABLE exttab_auth_list |
| { |
| $$ = makeDefElem("exttabnoauth", (Node *) $2, @1); |
| } |
| /* Supported but not documented for roles, for use by ALTER GROUP. */ |
| | USER role_list |
| { |
| $$ = makeDefElem("rolemembers", (Node *) $2, @1); |
| } |
| | deny_login_role |
| { |
| $$ = makeDefElem("deny", (Node *) $1, @1); |
| } |
| | PROFILE name |
| { |
| $$ = makeDefElem("profile", (Node *)makeString($2), @1); |
| } |
| | ACCOUNT LOCK_P |
| { |
| $$ = makeDefElem("accountislock", (Node *) makeInteger(true), @1); |
| } |
| | ACCOUNT UNLOCK_P |
| { |
| $$ = makeDefElem("accountislock", (Node*) makeInteger(false), @1); |
| } |
| | ENABLE_P PROFILE |
| { |
| $$ = makeDefElem("enableProfile", (Node *) makeInteger(true), @1); |
| } |
| | DISABLE_P PROFILE |
| { |
| $$ = makeDefElem("enableProfile", (Node *) makeInteger(false), @1); |
| } |
| | IDENT |
| { |
| /* |
| * We handle identifiers that aren't parser keywords with |
| * the following special-case codes, to avoid bloating the |
| * size of the main parser. |
| */ |
| if (strcmp($1, "superuser") == 0) |
| $$ = makeDefElem("superuser", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "nosuperuser") == 0) |
| $$ = makeDefElem("superuser", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "createrole") == 0) |
| $$ = makeDefElem("createrole", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "nocreaterole") == 0) |
| $$ = makeDefElem("createrole", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "replication") == 0) |
| $$ = makeDefElem("isreplication", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "noreplication") == 0) |
| $$ = makeDefElem("isreplication", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "createdb") == 0) |
| $$ = makeDefElem("createdb", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "nocreatedb") == 0) |
| $$ = makeDefElem("createdb", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "login") == 0) |
| $$ = makeDefElem("canlogin", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "nologin") == 0) |
| $$ = makeDefElem("canlogin", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "bypassrls") == 0) |
| $$ = makeDefElem("bypassrls", (Node *) makeBoolean(true), @1); |
| else if (strcmp($1, "nobypassrls") == 0) |
| $$ = makeDefElem("bypassrls", (Node *) makeBoolean(false), @1); |
| else if (strcmp($1, "noinherit") == 0) |
| { |
| /* |
| * Note that INHERIT is a keyword, so it's handled by main parser, but |
| * NOINHERIT is handled here. |
| */ |
| $$ = makeDefElem("inherit", (Node *) makeBoolean(false), @1); |
| } |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("unrecognized role option \"%s\"", $1), |
| parser_errposition(@1))); |
| } |
| ; |
| |
| CreateOptRoleElem: |
| AlterOptRoleElem { $$ = $1; } |
| /* The following are not supported by ALTER ROLE/USER/GROUP */ |
| | SYSID Iconst |
| { |
| $$ = makeDefElem("sysid", (Node *) makeInteger($2), @1); |
| } |
| | ADMIN role_list |
| { |
| $$ = makeDefElem("adminmembers", (Node *) $2, @1); |
| } |
| | ROLE role_list |
| { |
| $$ = makeDefElem("rolemembers", (Node *) $2, @1); |
| } |
| | IN_P ROLE role_list |
| { |
| $$ = makeDefElem("addroleto", (Node *) $3, @1); |
| } |
| | IN_P GROUP_P role_list |
| { |
| $$ = makeDefElem("addroleto", (Node *) $3, @1); |
| } |
| ; |
| |
| deny_login_role: DENY deny_interval { $$ = (Node *)$2; } |
| | DENY deny_point { $$ = (Node *)$2; } |
| ; |
| |
| deny_interval: BETWEEN deny_point AND deny_point |
| { |
| DenyLoginInterval *n = makeNode(DenyLoginInterval); |
| n->start = (DenyLoginPoint *)$2; |
| n->end = (DenyLoginPoint *)$4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| deny_day_specifier: Sconst { $$ = (Node *)makeString($1); } |
| | Iconst { $$ = (Node *)makeInteger($1); } |
| ; |
| |
| deny_point: DAY_P deny_day_specifier opt_time |
| { |
| DenyLoginPoint *n = makeNode(DenyLoginPoint); |
| n->day = $2; |
| n->time = $3; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_time: TIME Sconst { $$ = (Node *)makeString($2); } |
| | /* nothing */ { $$ = NULL; } |
| ; |
| |
| exttab_auth_list: |
| '(' keyvalue_list ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| keyvalue_list: |
| keyvalue_pair { $$ = list_make1($1); } |
| | keyvalue_list ',' keyvalue_pair { $$ = lappend($1, $3); } |
| ; |
| |
| keyvalue_pair: |
| ColLabel '=' Sconst |
| { |
| $$ = makeDefElem($1, (Node *) makeString($3), @1); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres DBMS user (role with implied login ability) |
| * |
| *****************************************************************************/ |
| |
| CreateUserStmt: |
| CREATE USER RoleId opt_with OptRoleList OptTagOptList |
| { |
| CreateRoleStmt *n = makeNode(CreateRoleStmt); |
| |
| n->stmt_type = ROLESTMT_USER; |
| n->role = $3; |
| n->options = $5; |
| n->tags = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql DBMS role |
| * |
| *****************************************************************************/ |
| |
| AlterRoleStmt: |
| ALTER ROLE RoleSpec opt_with AlterOptRoleList |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| |
| n->role = $3; |
| n->action = +1; /* add, if there are members */ |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER USER RoleSpec opt_with AlterOptRoleList |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| |
| n->role = $3; |
| n->action = +1; /* add, if there are members */ |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER USER RoleSpec TAG '(' TagOptList ')' |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| n->role = $3; |
| n->tags = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER USER RoleSpec UNSET_P TAG '(' name_list ')' |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| n->role = $3; |
| n->tags = $7; |
| n->unsettag = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_in_database: |
| /* EMPTY */ { $$ = NULL; } |
| | IN_P DATABASE name { $$ = $3; } |
| ; |
| |
| AlterRoleSetStmt: |
| ALTER ROLE RoleSpec opt_in_database SetResetClause |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| |
| n->role = $3; |
| n->database = $4; |
| n->setstmt = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER ROLE ALL opt_in_database SetResetClause |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| |
| n->role = NULL; |
| n->database = $4; |
| n->setstmt = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER USER RoleSpec opt_in_database SetResetClause |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| |
| n->role = $3; |
| n->database = $4; |
| n->setstmt = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER USER ALL opt_in_database SetResetClause |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| |
| n->role = NULL; |
| n->database = $4; |
| n->setstmt = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql DBMS role |
| * |
| * XXX Ideally this would have CASCADE/RESTRICT options, but a role |
| * might own objects in multiple databases, and there is presently no way to |
| * implement cascading to other databases. So we always behave as RESTRICT. |
| *****************************************************************************/ |
| |
| DropRoleStmt: |
| DROP ROLE role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->missing_ok = false; |
| n->roles = $3; |
| $$ = (Node *) n; |
| } |
| | DROP ROLE IF_P EXISTS role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->missing_ok = true; |
| n->roles = $5; |
| $$ = (Node *) n; |
| } |
| | DROP USER role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->missing_ok = false; |
| n->roles = $3; |
| $$ = (Node *) n; |
| } |
| | DROP USER IF_P EXISTS role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->roles = $5; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | DROP GROUP_P role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->missing_ok = false; |
| n->roles = $3; |
| $$ = (Node *) n; |
| } |
| | DROP GROUP_P IF_P EXISTS role_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| |
| n->missing_ok = true; |
| n->roles = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres DBMS Profile |
| * |
| *****************************************************************************/ |
| |
| CreateProfileStmt: |
| CREATE PROFILE name |
| { |
| CreateProfileStmt *n = makeNode(CreateProfileStmt); |
| n->profile_name = $3; |
| $$ = (Node *)n; |
| } |
| | CREATE PROFILE name LIMIT OptProfileList |
| { |
| CreateProfileStmt *n = makeNode(CreateProfileStmt); |
| n->profile_name = $3; |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Options for CREATE PROFILE and ALTER PROFILE. |
| */ |
| OptProfileList: |
| OptProfileList OptProfileElem { $$ = lappend($1, $2); } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| OptProfileElem: |
| FAILED_LOGIN_ATTEMPTS SignedIconst |
| { |
| $$ = makeDefElem("failed_login_attempts", |
| (Node *)makeInteger($2), @1); |
| } |
| | PASSWORD_LOCK_TIME SignedIconst |
| { |
| $$ = makeDefElem("password_lock_time", |
| (Node *)makeInteger($2), @1); |
| } |
| | PASSWORD_REUSE_MAX SignedIconst |
| { |
| $$ = makeDefElem("password_reuse_max", |
| (Node *)makeInteger($2), @1); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql DBMS profile |
| * |
| *****************************************************************************/ |
| |
| AlterProfileStmt: |
| ALTER PROFILE name LIMIT OptProfileList |
| { |
| AlterProfileStmt *n = makeNode(AlterProfileStmt); |
| n->profile_name = $3; |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql DBMS profile |
| * |
| * XXX Ideally this would have CASCADE/RESTRICT options, but a profile |
| * might be attached by users in multiple databases, using CASCADE will drop |
| * users meanwhile which is unreasonable. So we always behave as RESTRICT. |
| *****************************************************************************/ |
| |
| DropProfileStmt: |
| DROP PROFILE name_list |
| { |
| DropProfileStmt *n = makeNode(DropProfileStmt); |
| n->profiles = $3; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP PROFILE IF_P EXISTS name_list |
| { |
| DropProfileStmt *n = makeNode(DropProfileStmt); |
| n->profiles = $5; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Create a postgresql group (role without login ability) |
| * |
| *****************************************************************************/ |
| |
| CreateGroupStmt: |
| CREATE GROUP_P RoleId opt_with OptRoleList |
| { |
| CreateRoleStmt *n = makeNode(CreateRoleStmt); |
| |
| n->stmt_type = ROLESTMT_GROUP; |
| n->role = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql group |
| * |
| *****************************************************************************/ |
| |
| AlterGroupStmt: |
| ALTER GROUP_P RoleSpec add_drop USER role_list |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| |
| n->role = $3; |
| n->action = $4; |
| n->options = list_make1(makeDefElem("rolemembers", |
| (Node *) $6, @6)); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| add_drop: ADD_P { $$ = +1; } |
| | DROP { $$ = -1; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a schema |
| * |
| *****************************************************************************/ |
| |
| CreateSchemaStmt: |
| CREATE SCHEMA opt_single_name AUTHORIZATION RoleSpec OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| |
| /* One can omit the schema name or the authorization id. */ |
| n->schemaname = $3; |
| n->authrole = $5; |
| n->schemaElts = $6; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE SCHEMA ColId OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| |
| /* ...but not both */ |
| n->schemaname = $3; |
| n->authrole = NULL; |
| n->schemaElts = $4; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE SCHEMA IF_P NOT EXISTS opt_single_name AUTHORIZATION RoleSpec OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| |
| /* schema name can be omitted here, too */ |
| n->schemaname = $6; |
| n->authrole = $8; |
| if ($9 != NIL) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE SCHEMA IF NOT EXISTS cannot include schema elements"), |
| parser_errposition(@9))); |
| n->schemaElts = $9; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| | CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| |
| /* ...but not here */ |
| n->schemaname = $6; |
| n->authrole = NULL; |
| if ($7 != NIL) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE SCHEMA IF NOT EXISTS cannot include schema elements"), |
| parser_errposition(@7))); |
| n->schemaElts = $7; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| | CREATE SCHEMA ColId WITH TAG '(' TagOptList ')' |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| n->schemaname = $3; |
| n->if_not_exists = false; |
| n->tags = $7; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Alter a schema to add a tag |
| * |
| *****************************************************************************/ |
| |
| AlterSchemaStmt: |
| ALTER SCHEMA name TAG '(' TagOptList ')' |
| { |
| AlterSchemaStmt *n = makeNode(AlterSchemaStmt); |
| n->schemaname = $3; |
| n->tags = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER SCHEMA name UNSET_P TAG '(' name_list ')' |
| { |
| AlterSchemaStmt *n = makeNode(AlterSchemaStmt); |
| n->schemaname = $3; |
| n->tags = $7; |
| n->unsettag = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptSchemaEltList: |
| OptSchemaEltList schema_stmt |
| { |
| if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ |
| @$ = @2; |
| $$ = lappend($1, $2); |
| } |
| | /* EMPTY */ |
| { $$ = NIL; } |
| ; |
| |
| /* |
| * schema_stmt are the ones that can show up inside a CREATE SCHEMA |
| * statement (in addition to by themselves). |
| */ |
| schema_stmt: |
| CreateStmt |
| | IndexStmt |
| | CreateSeqStmt |
| | CreateTrigStmt |
| | GrantStmt |
| | ViewStmt |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres DBMS Tag |
| * |
| *****************************************************************************/ |
| |
| CreateTagStmt: |
| CREATE TAG name |
| { |
| CreateTagStmt *n = makeNode(CreateTagStmt); |
| n->tag_name = $3; |
| n->missing_ok = false; |
| n->allowed_values = NIL; |
| $$ = (Node *)n; |
| } |
| | CREATE TAG IF_P NOT EXISTS name |
| { |
| CreateTagStmt *n = makeNode(CreateTagStmt); |
| n->tag_name = $6; |
| n->missing_ok = true; |
| n->allowed_values = NIL; |
| $$ = (Node *)n; |
| } |
| | CREATE TAG name ALLOWED_VALUES OptTagValuesList |
| { |
| CreateTagStmt *n = makeNode(CreateTagStmt); |
| n->tag_name = $3; |
| n->missing_ok = false; |
| n->allowed_values = $5; |
| $$ = (Node *)n; |
| } |
| | CREATE TAG IF_P NOT EXISTS name ALLOWED_VALUES OptTagValuesList |
| { |
| CreateTagStmt *n = makeNode(CreateTagStmt); |
| n->tag_name = $6; |
| n->missing_ok = true; |
| n->allowed_values = $8; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql DBMS Tag |
| * |
| *****************************************************************************/ |
| |
| AlterTagStmt: |
| ALTER TAG name add_drop ALLOWED_VALUES OptTagValuesList |
| { |
| AlterTagStmt *n = makeNode(AlterTagStmt); |
| n->missing_ok = false; |
| n->tag_name = $3; |
| n->action = $4; |
| n->tag_values = $6; |
| n->unset = false; |
| $$ = (Node *)n; |
| } |
| | ALTER TAG IF_P EXISTS name add_drop ALLOWED_VALUES OptTagValuesList |
| { |
| AlterTagStmt *n = makeNode(AlterTagStmt); |
| n->missing_ok = true; |
| n->tag_name = $5; |
| n->action = $6; |
| n->tag_values = $8; |
| n->unset = false; |
| $$ = (Node *)n; |
| } |
| | ALTER TAG name UNSET_P ALLOWED_VALUES |
| { |
| AlterTagStmt *n = makeNode(AlterTagStmt); |
| n->tag_name = $3; |
| n->unset = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql DBMS Tag |
| * |
| * XXX Ideally this would have CASCADE/RESTRICT options, but a profile |
| * might be attached by users in multiple databases, using CASCADE will drop |
| * users meanwhile which is unreasonable. So we always behave as RESTRICT. |
| *****************************************************************************/ |
| |
| DropTagStmt: |
| DROP TAG name_list |
| { |
| DropTagStmt *n = makeNode(DropTagStmt); |
| n->tags = $3; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP TAG IF_P EXISTS name_list |
| { |
| DropTagStmt *n = makeNode(DropTagStmt); |
| n->tags = $5; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * List of allowed values for Tag. |
| */ |
| OptTagValuesList: |
| OptTagValuesList ',' Sconst { $$ = lappend($1, makeString($3)); } |
| | Sconst { $$ = list_make1(makeString($1)); } |
| ; |
| |
| OptTagOptList: |
| TAG '(' TagOptList ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TagOptList: |
| TagOptElem { $$ = list_make1($1); } |
| | TagOptList ',' TagOptElem { $$ = lappend($1, $3); } |
| ; |
| |
| TagOptElem: |
| ColLabel '=' Sconst |
| { |
| $$ = makeDefElem($1, (Node *) makeString($3), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Set PG internal variable |
| * SET name TO 'var_value' |
| * Include SQL syntax (thomas 1997-10-22): |
| * SET TIME ZONE 'var_value' |
| * |
| *****************************************************************************/ |
| |
| VariableSetStmt: |
| SET set_rest |
| { |
| VariableSetStmt *n = $2; |
| |
| n->is_local = false; |
| $$ = (Node *) n; |
| } |
| | SET LOCAL set_rest |
| { |
| VariableSetStmt *n = $3; |
| |
| n->is_local = true; |
| $$ = (Node *) n; |
| } |
| | SET SESSION set_rest |
| { |
| VariableSetStmt *n = $3; |
| |
| n->is_local = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| set_rest: |
| TRANSACTION transaction_mode_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_MULTI; |
| n->name = "TRANSACTION"; |
| n->args = $2; |
| $$ = n; |
| } |
| | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_MULTI; |
| n->name = "SESSION CHARACTERISTICS"; |
| n->args = $5; |
| $$ = n; |
| } |
| | set_rest_more |
| ; |
| |
| generic_set: |
| var_name TO var_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = $1; |
| n->args = $3; |
| $$ = n; |
| } |
| | var_name '=' var_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = $1; |
| n->args = $3; |
| $$ = n; |
| } |
| | var_name TO DEFAULT |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_DEFAULT; |
| n->name = $1; |
| $$ = n; |
| } |
| | var_name '=' DEFAULT |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_DEFAULT; |
| n->name = $1; |
| $$ = n; |
| } |
| ; |
| |
| set_rest_more: /* Generic SET syntaxes: */ |
| generic_set {$$ = $1;} |
| | var_name FROM CURRENT_P |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_CURRENT; |
| n->name = $1; |
| $$ = n; |
| } |
| /* Special syntaxes mandated by SQL standard: */ |
| | TIME ZONE zone_value |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "timezone"; |
| if ($3 != NULL) |
| n->args = list_make1($3); |
| else |
| n->kind = VAR_SET_DEFAULT; |
| $$ = n; |
| } |
| | CATALOG_P Sconst |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("current database cannot be changed"), |
| parser_errposition(@2))); |
| $$ = NULL; /*not reached*/ |
| } |
| | SCHEMA Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "search_path"; |
| n->args = list_make1(makeStringConst($2, @2)); |
| $$ = n; |
| } |
| | NAMES opt_encoding |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "client_encoding"; |
| if ($2 != NULL) |
| n->args = list_make1(makeStringConst($2, @2)); |
| else |
| n->kind = VAR_SET_DEFAULT; |
| $$ = n; |
| } |
| | ROLE NonReservedWord_or_Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "role"; |
| n->args = list_make1(makeStringConst($2, @2)); |
| $$ = n; |
| } |
| | SESSION AUTHORIZATION NonReservedWord_or_Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "session_authorization"; |
| n->args = list_make1(makeStringConst($3, @3)); |
| $$ = n; |
| } |
| | SESSION AUTHORIZATION DEFAULT |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_DEFAULT; |
| n->name = "session_authorization"; |
| $$ = n; |
| } |
| | XML_P OPTION document_or_content |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_VALUE; |
| n->name = "xmloption"; |
| n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3)); |
| $$ = n; |
| } |
| /* Special syntaxes invented by PostgreSQL: */ |
| | TRANSACTION SNAPSHOT Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_SET_MULTI; |
| n->name = "TRANSACTION SNAPSHOT"; |
| n->args = list_make1(makeStringConst($3, @3)); |
| $$ = n; |
| } |
| ; |
| |
| var_name: ColId { $$ = $1; } |
| | var_name '.' ColId |
| { $$ = psprintf("%s.%s", $1, $3); } |
| ; |
| |
| var_list: var_value { $$ = list_make1($1); } |
| | var_list ',' var_value { $$ = lappend($1, $3); } |
| ; |
| |
| var_value: opt_boolean_or_string |
| { $$ = makeStringConst($1, @1); } |
| | NumericOnly |
| { $$ = makeAConst($1, @1); } |
| ; |
| |
| iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; } |
| | READ COMMITTED { $$ = "read committed"; } |
| | REPEATABLE READ { $$ = "repeatable read"; } |
| | SERIALIZABLE { $$ = "serializable"; } |
| ; |
| |
| opt_boolean_or_string: |
| TRUE_P { $$ = "true"; } |
| | FALSE_P { $$ = "false"; } |
| | ON { $$ = "on"; } |
| /* |
| * OFF is also accepted as a boolean value, but is handled by |
| * the NonReservedWord rule. The action for booleans and strings |
| * is the same, so we don't need to distinguish them here. |
| */ |
| | NonReservedWord_or_Sconst { $$ = $1; } |
| ; |
| |
| /* Timezone values can be: |
| * - a string such as 'pst8pdt' |
| * - an identifier such as "pst8pdt" |
| * - an integer or floating point number |
| * - a time interval per SQL99 |
| * ColId gives reduce/reduce errors against ConstInterval and LOCAL, |
| * so use IDENT and reject anything which is a reserved word. |
| */ |
| zone_value: |
| Sconst |
| { |
| $$ = makeStringConst($1, @1); |
| } |
| | IDENT |
| { |
| $$ = makeStringConst($1, @1); |
| } |
| | ConstInterval Sconst opt_interval |
| { |
| TypeName *t = $1; |
| |
| if ($3 != NIL) |
| { |
| A_Const *n = (A_Const *) linitial($3); |
| |
| if ((n->val.ival.ival & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("time zone interval must be HOUR or HOUR TO MINUTE"), |
| parser_errposition(@3))); |
| } |
| t->typmods = $3; |
| $$ = makeStringConstCast($2, @2, t); |
| } |
| | ConstInterval '(' Iconst ')' Sconst |
| { |
| TypeName *t = $1; |
| |
| t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), |
| makeIntConst($3, @3)); |
| $$ = makeStringConstCast($5, @5, t); |
| } |
| | NumericOnly { $$ = makeAConst($1, @1); } |
| | DEFAULT { $$ = NULL; } |
| | LOCAL { $$ = NULL; } |
| ; |
| |
| opt_encoding: |
| Sconst { $$ = $1; } |
| | DEFAULT { $$ = NULL; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| NonReservedWord_or_Sconst: |
| NonReservedWord { $$ = $1; } |
| | Sconst { $$ = $1; } |
| ; |
| |
| VariableResetStmt: |
| RESET reset_rest { $$ = (Node *) $2; } |
| ; |
| |
| reset_rest: |
| generic_reset { $$ = $1; } |
| | TIME ZONE |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_RESET; |
| n->name = "timezone"; |
| $$ = n; |
| } |
| | TRANSACTION ISOLATION LEVEL |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_RESET; |
| n->name = "transaction_isolation"; |
| $$ = n; |
| } |
| | SESSION AUTHORIZATION |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_RESET; |
| n->name = "session_authorization"; |
| $$ = n; |
| } |
| ; |
| |
| generic_reset: |
| var_name |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_RESET; |
| n->name = $1; |
| $$ = n; |
| } |
| | ALL |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| |
| n->kind = VAR_RESET_ALL; |
| $$ = n; |
| } |
| ; |
| |
| /* SetResetClause allows SET or RESET without LOCAL */ |
| SetResetClause: |
| SET set_rest { $$ = $2; } |
| | VariableResetStmt { $$ = (VariableSetStmt *) $1; } |
| ; |
| |
| /* SetResetClause allows SET or RESET without LOCAL */ |
| FunctionSetResetClause: |
| SET set_rest_more { $$ = $2; } |
| | VariableResetStmt { $$ = (VariableSetStmt *) $1; } |
| ; |
| |
| |
| VariableShowStmt: |
| SHOW var_name |
| { |
| VariableShowStmt *n = makeNode(VariableShowStmt); |
| |
| n->name = $2; |
| $$ = (Node *) n; |
| } |
| | SHOW TIME ZONE |
| { |
| VariableShowStmt *n = makeNode(VariableShowStmt); |
| |
| n->name = "timezone"; |
| $$ = (Node *) n; |
| } |
| | SHOW TRANSACTION ISOLATION LEVEL |
| { |
| VariableShowStmt *n = makeNode(VariableShowStmt); |
| |
| n->name = "transaction_isolation"; |
| $$ = (Node *) n; |
| } |
| | SHOW SESSION AUTHORIZATION |
| { |
| VariableShowStmt *n = makeNode(VariableShowStmt); |
| |
| n->name = "session_authorization"; |
| $$ = (Node *) n; |
| } |
| | SHOW ALL |
| { |
| VariableShowStmt *n = makeNode(VariableShowStmt); |
| |
| n->name = "all"; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| ConstraintsSetStmt: |
| SET CONSTRAINTS constraints_set_list constraints_set_mode |
| { |
| ConstraintsSetStmt *n = makeNode(ConstraintsSetStmt); |
| |
| n->constraints = $3; |
| n->deferred = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| constraints_set_list: |
| ALL { $$ = NIL; } |
| | qualified_name_list { $$ = $1; } |
| ; |
| |
| constraints_set_mode: |
| DEFERRED { $$ = true; } |
| | IMMEDIATE { $$ = false; } |
| ; |
| |
| |
| /* |
| * Checkpoint statement |
| */ |
| CheckPointStmt: |
| CHECKPOINT |
| { |
| CheckPointStmt *n = makeNode(CheckPointStmt); |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * DISCARD { ALL | TEMP | PLANS | SEQUENCES } |
| * |
| *****************************************************************************/ |
| |
| DiscardStmt: |
| DISCARD ALL |
| { |
| DiscardStmt *n = makeNode(DiscardStmt); |
| |
| n->target = DISCARD_ALL; |
| $$ = (Node *) n; |
| } |
| | DISCARD TEMP |
| { |
| DiscardStmt *n = makeNode(DiscardStmt); |
| |
| n->target = DISCARD_TEMP; |
| $$ = (Node *) n; |
| } |
| | DISCARD TEMPORARY |
| { |
| DiscardStmt *n = makeNode(DiscardStmt); |
| |
| n->target = DISCARD_TEMP; |
| $$ = (Node *) n; |
| } |
| | DISCARD PLANS |
| { |
| DiscardStmt *n = makeNode(DiscardStmt); |
| |
| n->target = DISCARD_PLANS; |
| $$ = (Node *) n; |
| } |
| | DISCARD SEQUENCES |
| { |
| DiscardStmt *n = makeNode(DiscardStmt); |
| |
| n->target = DISCARD_SEQUENCES; |
| $$ = (Node *) n; |
| } |
| |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER [ TABLE | INDEX | SEQUENCE | VIEW | MATERIALIZED VIEW | FOREIGN TABLE ] variations |
| * |
| * Note: we accept all subcommands for each of the variants, and sort |
| * out what's really legal at execution time. |
| *****************************************************************************/ |
| |
| AlterTableStmt: |
| ALTER TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = $4; |
| n->objtype = OBJECT_TABLE; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $5; |
| n->cmds = $6; |
| n->objtype = OBJECT_TABLE; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE relation_expr partition_cmd |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = list_make1($4); |
| n->objtype = OBJECT_TABLE; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr partition_cmd |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $5; |
| n->cmds = list_make1($6); |
| n->objtype = OBJECT_TABLE; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $6; |
| n->objtype = OBJECT_TABLE; |
| n->roles = NIL; |
| n->new_tablespacename = $9; |
| n->nowait = $10; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $6; |
| n->objtype = OBJECT_TABLE; |
| n->roles = $9; |
| n->new_tablespacename = $12; |
| n->nowait = $13; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTERNAL TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| n->relation = $4; |
| n->cmds = $5; |
| n->objtype = OBJECT_FOREIGN_TABLE; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | ALTER INDEX qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = $4; |
| n->objtype = OBJECT_INDEX; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX IF_P EXISTS qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $5; |
| n->cmds = $6; |
| n->objtype = OBJECT_INDEX; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX qualified_name index_partition_cmd |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = list_make1($4); |
| n->objtype = OBJECT_INDEX; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $6; |
| n->objtype = OBJECT_INDEX; |
| n->roles = NIL; |
| n->new_tablespacename = $9; |
| n->nowait = $10; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $6; |
| n->objtype = OBJECT_INDEX; |
| n->roles = $9; |
| n->new_tablespacename = $12; |
| n->nowait = $13; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = $4; |
| n->objtype = OBJECT_SEQUENCE; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE IF_P EXISTS qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $5; |
| n->cmds = $6; |
| n->objtype = OBJECT_SEQUENCE; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $3; |
| n->cmds = $4; |
| n->objtype = OBJECT_VIEW; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW IF_P EXISTS qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $5; |
| n->cmds = $6; |
| n->objtype = OBJECT_VIEW; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $4; |
| n->cmds = $5; |
| n->objtype = OBJECT_MATVIEW; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $6; |
| n->cmds = $7; |
| n->objtype = OBJECT_MATVIEW; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $7; |
| n->objtype = OBJECT_MATVIEW; |
| n->roles = NIL; |
| n->new_tablespacename = $10; |
| n->nowait = $11; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait |
| { |
| AlterTableMoveAllStmt *n = |
| makeNode(AlterTableMoveAllStmt); |
| |
| n->orig_tablespacename = $7; |
| n->objtype = OBJECT_MATVIEW; |
| n->roles = $10; |
| n->new_tablespacename = $13; |
| n->nowait = $14; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $4; |
| n->cmds = $5; |
| n->objtype = OBJECT_FOREIGN_TABLE; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE IF_P EXISTS relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| n->relation = $6; |
| n->cmds = $7; |
| n->objtype = OBJECT_FOREIGN_TABLE; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alter_table_cmds: |
| alter_table_cmd { $$ = list_make1($1); } |
| | alter_table_cmds ',' alter_table_cmd { $$ = lappend($1, $3); } |
| ; |
| |
| partition_cmd: |
| /* ALTER TABLE <name> ATTACH PARTITION <table_name> FOR VALUES */ |
| ATTACH PARTITION qualified_name PartitionBoundSpec |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| PartitionCmd *cmd = makeNode(PartitionCmd); |
| |
| n->subtype = AT_AttachPartition; |
| cmd->name = $3; |
| cmd->bound = $4; |
| cmd->concurrent = false; |
| n->def = (Node *) cmd; |
| |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DETACH PARTITION <partition_name> [CONCURRENTLY] */ |
| | DETACH PARTITION qualified_name opt_concurrently |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| PartitionCmd *cmd = makeNode(PartitionCmd); |
| |
| n->subtype = AT_DetachPartition; |
| cmd->name = $3; |
| cmd->bound = NULL; |
| cmd->concurrent = $4; |
| n->def = (Node *) cmd; |
| |
| $$ = (Node *) n; |
| } |
| | DETACH PARTITION qualified_name FINALIZE |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| PartitionCmd *cmd = makeNode(PartitionCmd); |
| |
| n->subtype = AT_DetachPartitionFinalize; |
| cmd->name = $3; |
| cmd->bound = NULL; |
| cmd->concurrent = false; |
| n->def = (Node *) cmd; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| index_partition_cmd: |
| /* ALTER INDEX <name> ATTACH PARTITION <index_name> */ |
| ATTACH PARTITION qualified_name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| PartitionCmd *cmd = makeNode(PartitionCmd); |
| |
| n->subtype = AT_AttachPartition; |
| cmd->name = $3; |
| cmd->bound = NULL; |
| cmd->concurrent = false; |
| n->def = (Node *) cmd; |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alter_table_cmd: |
| /* ALTER TABLE <name> ADD <coldef> */ |
| ADD_P columnDef |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddColumn; |
| n->def = $2; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ADD IF NOT EXISTS <coldef> */ |
| | ADD_P IF_P NOT EXISTS columnDef |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddColumn; |
| n->def = $5; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ADD COLUMN <coldef> */ |
| | ADD_P COLUMN columnDef |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddColumn; |
| n->def = $3; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ADD COLUMN IF NOT EXISTS <coldef> */ |
| | ADD_P COLUMN IF_P NOT EXISTS columnDef |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddColumn; |
| n->def = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */ |
| | ALTER opt_column ColId alter_column_default |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ColumnDefault; |
| n->name = $3; |
| n->def = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP NOT NULL */ |
| | ALTER opt_column ColId DROP NOT NULL_P |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropNotNull; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET NOT NULL */ |
| | ALTER opt_column ColId SET NOT NULL_P |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetNotNull; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP EXPRESSION */ |
| | ALTER opt_column ColId DROP EXPRESSION |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropExpression; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP EXPRESSION IF EXISTS */ |
| | ALTER opt_column ColId DROP EXPRESSION IF_P EXISTS |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropExpression; |
| n->name = $3; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS <SignedIconst> */ |
| | ALTER opt_column ColId SET STATISTICS SignedIconst |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetStatistics; |
| n->name = $3; |
| n->def = (Node *) makeInteger($6); |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colnum> SET STATISTICS <SignedIconst> */ |
| | ALTER opt_column Iconst SET STATISTICS SignedIconst |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| if ($3 <= 0 || $3 > PG_INT16_MAX) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("column number must be in range from 1 to %d", PG_INT16_MAX), |
| parser_errposition(@3))); |
| |
| n->subtype = AT_SetStatistics; |
| n->num = (int16) $3; |
| n->def = (Node *) makeInteger($6); |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */ |
| | ALTER opt_column ColId SET reloptions |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetOptions; |
| n->name = $3; |
| n->def = (Node *) $5; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> RESET ( column_parameter [, ... ] ) */ |
| | ALTER opt_column ColId RESET reloptions |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ResetOptions; |
| n->name = $3; |
| n->def = (Node *) $5; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */ |
| | ALTER opt_column ColId SET column_storage |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetStorage; |
| n->name = $3; |
| n->def = (Node *) makeString($5); |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET COMPRESSION <cm> */ |
| | ALTER opt_column ColId SET column_compression |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetCompression; |
| n->name = $3; |
| n->def = (Node *) makeString($5); |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> ADD GENERATED ... AS IDENTITY ... */ |
| | ALTER opt_column ColId ADD_P GENERATED generated_when AS IDENTITY_P OptParenthesizedSeqOptList |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Constraint *c = makeNode(Constraint); |
| |
| c->contype = CONSTR_IDENTITY; |
| c->generated_when = $6; |
| c->options = $9; |
| c->location = @5; |
| |
| n->subtype = AT_AddIdentity; |
| n->name = $3; |
| n->def = (Node *) c; |
| |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET <sequence options>/RESET */ |
| | ALTER opt_column ColId alter_identity_column_option_list |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetIdentity; |
| n->name = $3; |
| n->def = (Node *) $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP IDENTITY */ |
| | ALTER opt_column ColId DROP IDENTITY_P |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropIdentity; |
| n->name = $3; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP IDENTITY IF EXISTS */ |
| | ALTER opt_column ColId DROP IDENTITY_P IF_P EXISTS |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropIdentity; |
| n->name = $3; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DROP [COLUMN] IF EXISTS <colname> [RESTRICT|CASCADE] */ |
| | DROP opt_column IF_P EXISTS ColId opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropColumn; |
| n->name = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DROP [COLUMN] <colname> [RESTRICT|CASCADE] */ |
| | DROP opt_column ColId opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropColumn; |
| n->name = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* |
| * ALTER TABLE <name> ALTER [COLUMN] <colname> [SET DATA] TYPE <typename> |
| * [ USING <expression> ] |
| */ |
| | ALTER opt_column ColId opt_set_data TYPE_P Typename opt_collate_clause alter_using |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| ColumnDef *def = makeNode(ColumnDef); |
| |
| n->subtype = AT_AlterColumnType; |
| n->name = $3; |
| n->def = (Node *) def; |
| /* We only use these fields of the ColumnDef node */ |
| def->typeName = $6; |
| def->collClause = (CollateClause *) $7; |
| def->raw_default = $8; |
| def->location = @3; |
| $$ = (Node *) n; |
| } |
| /* ALTER FOREIGN TABLE <name> ALTER [COLUMN] <colname> OPTIONS */ |
| | ALTER opt_column ColId alter_generic_options |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AlterColumnGenericOptions; |
| n->name = $3; |
| n->def = (Node *) $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ADD CONSTRAINT ... */ |
| | ADD_P TableConstraint |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddConstraint; |
| n->def = $2; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ALTER CONSTRAINT ... */ |
| | ALTER CONSTRAINT name ConstraintAttributeSpec |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Constraint *c = makeNode(Constraint); |
| |
| n->subtype = AT_AlterConstraint; |
| n->def = (Node *) c; |
| c->contype = CONSTR_FOREIGN; /* others not supported, yet */ |
| c->conname = $3; |
| processCASbits($4, @4, "FOREIGN KEY", |
| &c->deferrable, |
| &c->initdeferred, |
| NULL, NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> VALIDATE CONSTRAINT ... */ |
| | VALIDATE CONSTRAINT name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ValidateConstraint; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */ |
| | DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropConstraint; |
| n->name = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */ |
| | DROP CONSTRAINT name opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropConstraint; |
| n->name = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET WITHOUT OIDS, for backward compat */ |
| | SET WITHOUT OIDS |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropOids; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> CLUSTER ON <indexname> */ |
| | CLUSTER ON name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ClusterOn; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET WITHOUT CLUSTER */ |
| | SET WITHOUT CLUSTER |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropCluster; |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET LOGGED */ |
| | SET LOGGED |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetLogged; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET UNLOGGED */ |
| | SET UNLOGGED |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetUnLogged; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE TRIGGER <trig> */ |
| | ENABLE_P TRIGGER name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableTrig; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE ALWAYS TRIGGER <trig> */ |
| | ENABLE_P ALWAYS TRIGGER name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableAlwaysTrig; |
| n->name = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */ |
| | ENABLE_P REPLICA TRIGGER name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableReplicaTrig; |
| n->name = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE TRIGGER ALL */ |
| | ENABLE_P TRIGGER ALL |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableTrigAll; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE TRIGGER USER */ |
| | ENABLE_P TRIGGER USER |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableTrigUser; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DISABLE TRIGGER <trig> */ |
| | DISABLE_P TRIGGER name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DisableTrig; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DISABLE TRIGGER ALL */ |
| | DISABLE_P TRIGGER ALL |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DisableTrigAll; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DISABLE TRIGGER USER */ |
| | DISABLE_P TRIGGER USER |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DisableTrigUser; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE RULE <rule> */ |
| | ENABLE_P RULE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableRule; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */ |
| | ENABLE_P ALWAYS RULE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableAlwaysRule; |
| n->name = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */ |
| | ENABLE_P REPLICA RULE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableReplicaRule; |
| n->name = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DISABLE RULE <rule> */ |
| | DISABLE_P RULE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DisableRule; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> INHERIT <parent> */ |
| | INHERIT qualified_name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddInherit; |
| n->def = (Node *) $2; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> NO INHERIT <parent> */ |
| | NO INHERIT qualified_name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropInherit; |
| n->def = (Node *) $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET [WITH] [DISTRIBUTED BY] */ |
| /* distro only */ |
| | SET DistributedBy |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2(NULL, $2); |
| $$ = (Node *)n; |
| } |
| /* storage and distro */ |
| | SET WITH definition DistributedBy |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2($3, $4); |
| $$ = (Node *)n; |
| } |
| /* table storage type or reorganize only */ |
| | SET WITH definition |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| if (isSetWithReorganize(&$3)) |
| { |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2($3, NULL); |
| } |
| else |
| { |
| n->subtype = AT_SetAccessMethod; |
| n->name = greenplumLegacyAOoptions(n->name, &$3); |
| if (!n->name) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid storage type"), |
| parser_errposition(@3))); |
| n->def = (Node *) $3; |
| } |
| $$ = (Node *)n; |
| } |
| | alter_table_partition_cmd |
| { |
| $$ = $1; |
| } |
| /* ALTER TABLE <name> EXPAND TABLE*/ |
| | EXPAND TABLE |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_ExpandTable; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> EXPAND PARTITION PREPARE*/ |
| | EXPAND PARTITION PREPARE |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_ExpandPartitionTablePrepare; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> SHRINK TABLE TO <segmentnum>*/ |
| | SHRINK TABLE TO SignedIconst |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_ShrinkTable; |
| n->def = (Node *) makeInteger($4); |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> OF <type_name> */ |
| | OF any_name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| TypeName *def = makeTypeNameFromNameList($2); |
| |
| def->location = @2; |
| n->subtype = AT_AddOf; |
| n->def = (Node *) def; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> NOT OF */ |
| | NOT OF |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropOf; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> OWNER TO RoleSpec */ |
| | OWNER TO RoleSpec |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ChangeOwner; |
| n->newowner = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET ACCESS METHOD <amname> WITH (<reloptions>) */ |
| | SET ACCESS METHOD name OptWith |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| char *witham = greenplumLegacyAOoptions(n->name, &$5); |
| n->subtype = AT_SetAccessMethod; |
| n->name = $4; |
| /* |
| * If there's any legacy AO options specified in the WITH |
| * clause such as 'appendonly' or 'appendoptimized', it has |
| * to match with the AM name. |
| */ |
| if (witham) |
| { |
| if (strlen(witham) != strlen(n->name) || |
| strcmp(n->name, witham) != 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("ACCESS METHOD is specified as \"%s\" but " |
| "the WITH option indicates it to be \"%s\"", |
| n->name, witham), |
| parser_errposition(@5))); |
| else |
| ereport(NOTICE, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Redundant clauses are used to indicate the access method."), |
| errhint("Only one of these is needed to indicate access method: the " |
| "SET ACCESS METHOD clause or the options in the WITH clause."))); |
| } |
| n->def = (Node *) $5; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> SET TABLESPACE <tablespacename> */ |
| | SET TABLESPACE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetTableSpace; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> SET (...) */ |
| | SET reloptions |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_SetRelOptions; |
| n->def = (Node *) $2; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> RESET (...) */ |
| | RESET reloptions |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ResetRelOptions; |
| n->def = (Node *) $2; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> REPLICA IDENTITY */ |
| | REPLICA IDENTITY_P replica_identity |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ReplicaIdentity; |
| n->def = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> ENABLE ROW LEVEL SECURITY */ |
| | ENABLE_P ROW LEVEL SECURITY |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_EnableRowSecurity; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> DISABLE ROW LEVEL SECURITY */ |
| | DISABLE_P ROW LEVEL SECURITY |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DisableRowSecurity; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> FORCE ROW LEVEL SECURITY */ |
| | FORCE ROW LEVEL SECURITY |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_ForceRowSecurity; |
| $$ = (Node *) n; |
| } |
| /* ALTER TABLE <name> NO FORCE ROW LEVEL SECURITY */ |
| | NO FORCE ROW LEVEL SECURITY |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_NoForceRowSecurity; |
| $$ = (Node *) n; |
| } |
| | alter_generic_options |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_GenericOptions; |
| n->def = (Node *) $1; |
| $$ = (Node *) n; |
| } |
| | TAG '(' TagOptList ')' |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetTags; |
| n->tags = $3; |
| $$ = (Node *) n; |
| } |
| | UNSET_P TAG '(' name_list ')' |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_UnsetTags; |
| n->tags = $4; |
| n->unsettag = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alter_column_default: |
| SET DEFAULT a_expr { $$ = $3; } |
| | DROP DEFAULT { $$ = NULL; } |
| ; |
| |
| opt_drop_directory_table_behavior: |
| WITH CONTENT_P { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| opt_collate_clause: |
| COLLATE any_name |
| { |
| CollateClause *n = makeNode(CollateClause); |
| |
| n->arg = NULL; |
| n->collname = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| alter_using: |
| USING a_expr { $$ = $2; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| replica_identity: |
| NOTHING |
| { |
| ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt); |
| |
| n->identity_type = REPLICA_IDENTITY_NOTHING; |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| | FULL |
| { |
| ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt); |
| |
| n->identity_type = REPLICA_IDENTITY_FULL; |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| | DEFAULT |
| { |
| ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt); |
| |
| n->identity_type = REPLICA_IDENTITY_DEFAULT; |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| | USING INDEX name |
| { |
| ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt); |
| |
| n->identity_type = REPLICA_IDENTITY_INDEX; |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| reloptions: |
| '(' reloption_list ')' { $$ = $2; } |
| ; |
| |
| opt_reloptions: WITH reloptions { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| reloption_list: |
| reloption_elem { $$ = list_make1($1); } |
| | reloption_list ',' reloption_elem { $$ = lappend($1, $3); } |
| ; |
| |
| /* This should match def_elem and also allow qualified names */ |
| reloption_elem: |
| ColLabel '=' def_arg |
| { |
| $$ = makeDefElem($1, (Node *) $3, @1); |
| } |
| | ColLabel |
| { |
| $$ = makeDefElem($1, NULL, @1); |
| } |
| | ColLabel '.' ColLabel '=' def_arg |
| { |
| $$ = makeDefElemExtended($1, $3, (Node *) $5, |
| DEFELEM_UNSPEC, @1); |
| } |
| | ColLabel '.' ColLabel |
| { |
| $$ = makeDefElemExtended($1, $3, NULL, DEFELEM_UNSPEC, @1); |
| } |
| ; |
| |
| alter_identity_column_option_list: |
| alter_identity_column_option |
| { $$ = list_make1($1); } |
| | alter_identity_column_option_list alter_identity_column_option |
| { $$ = lappend($1, $2); } |
| ; |
| |
| alter_identity_column_option: |
| RESTART |
| { |
| $$ = makeDefElem("restart", NULL, @1); |
| } |
| | RESTART opt_with NumericOnly |
| { |
| $$ = makeDefElem("restart", (Node *) $3, @1); |
| } |
| | SET SeqOptElem |
| { |
| if (strcmp($2->defname, "as") == 0 || |
| strcmp($2->defname, "restart") == 0 || |
| strcmp($2->defname, "owned_by") == 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("sequence option \"%s\" not supported here", $2->defname), |
| parser_errposition(@2))); |
| $$ = $2; |
| } |
| | SET GENERATED generated_when |
| { |
| $$ = makeDefElem("generated", (Node *) makeInteger($3), @1); |
| } |
| ; |
| |
| PartitionBoundSpec: |
| /* a HASH partition */ |
| FOR VALUES WITH '(' hash_partbound ')' |
| { |
| ListCell *lc; |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| |
| n->strategy = PARTITION_STRATEGY_HASH; |
| n->modulus = n->remainder = -1; |
| |
| foreach (lc, $5) |
| { |
| DefElem *opt = lfirst_node(DefElem, lc); |
| |
| if (strcmp(opt->defname, "modulus") == 0) |
| { |
| if (n->modulus != -1) |
| ereport(ERROR, |
| (errcode(ERRCODE_DUPLICATE_OBJECT), |
| errmsg("modulus for hash partition provided more than once"), |
| parser_errposition(opt->location))); |
| n->modulus = defGetInt32(opt); |
| } |
| else if (strcmp(opt->defname, "remainder") == 0) |
| { |
| if (n->remainder != -1) |
| ereport(ERROR, |
| (errcode(ERRCODE_DUPLICATE_OBJECT), |
| errmsg("remainder for hash partition provided more than once"), |
| parser_errposition(opt->location))); |
| n->remainder = defGetInt32(opt); |
| } |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("unrecognized hash partition bound specification \"%s\"", |
| opt->defname), |
| parser_errposition(opt->location))); |
| } |
| |
| if (n->modulus == -1) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("modulus for hash partition must be specified"))); |
| if (n->remainder == -1) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("remainder for hash partition must be specified"))); |
| |
| n->location = @3; |
| |
| $$ = n; |
| } |
| |
| /* a LIST partition */ |
| | FOR VALUES IN_P '(' expr_list ')' |
| { |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| |
| n->strategy = PARTITION_STRATEGY_LIST; |
| n->is_default = false; |
| n->listdatums = $5; |
| n->location = @3; |
| |
| $$ = n; |
| } |
| |
| /* a RANGE partition */ |
| | FOR VALUES FROM '(' expr_list ')' TO '(' expr_list ')' |
| { |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| |
| n->strategy = PARTITION_STRATEGY_RANGE; |
| n->is_default = false; |
| n->lowerdatums = $5; |
| n->upperdatums = $9; |
| n->location = @3; |
| |
| $$ = n; |
| } |
| |
| /* a DEFAULT partition */ |
| | DEFAULT |
| { |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| |
| n->is_default = true; |
| n->location = @1; |
| |
| $$ = n; |
| } |
| ; |
| |
| hash_partbound_elem: |
| NonReservedWord Iconst |
| { |
| $$ = makeDefElem($1, (Node *) makeInteger($2), @1); |
| } |
| ; |
| |
| hash_partbound: |
| hash_partbound_elem |
| { |
| $$ = list_make1($1); |
| } |
| | hash_partbound ',' hash_partbound_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER TABLE legacy GPDB partition manipulation subcommands. |
| * |
| *****************************************************************************/ |
| opt_table_partition_split_into: |
| INTO '(' |
| alter_table_partition_id_spec_with_opt_default ',' |
| alter_table_partition_id_spec_with_opt_default ')' |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| pc->partid = (GpAlterPartitionId *)$3; |
| if (pc->partid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("INTO can only have first partition by name"), |
| parser_errposition(@3))); |
| pc->arg = (Node *)$5; |
| pc->location = @5; |
| $$ = (Node *)pc; |
| } |
| | /*EMPTY*/ { $$ = NULL; /* default */ } |
| ; |
| |
| opt_table_partition_exchange_validate: |
| WITH VALIDATION |
| { |
| $$ = +1; |
| ereport(NOTICE, |
| (errmsg("specifying \"WITH VALIDATION\" acts as no operation"), |
| errdetail("If the new partition is a regular table, validation is performed " |
| "to make sure all the rows obey partition constraint. " |
| "If the new partition is external or foreign table, no validation is performed."))); |
| } |
| | WITHOUT VALIDATION |
| { |
| $$ = +0; |
| ereport(NOTICE, |
| (errmsg("specifying \"WITHOUT VALIDATION\" acts as no operation"), |
| errdetail("If the new partition is a regular table, validation is performed " |
| "to make sure all the rows obey partition constraint. " |
| "If the new partition is external or foreign table, no validation is performed."))); |
| } |
| | /*EMPTY*/ { $$ = +1; /* default */ } |
| ; |
| |
| alter_table_partition_id_spec: |
| PartitionColId |
| { |
| GpAlterPartitionId *n = makeNode(GpAlterPartitionId); |
| n->idtype = AT_AP_IDName; |
| n->partiddef = (Node *)makeString($1); |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | FOR |
| '(' TabPartitionBoundarySpecValList ')' |
| { |
| GpAlterPartitionId *n = makeNode(GpAlterPartitionId); |
| n->idtype = AT_AP_IDValue; |
| n->partiddef = (Node *)$3; |
| n->location = @3; |
| $$ = (Node *)n; |
| } |
| /* |
| * In GPDB 6 and below, we supported addressing partitions by |
| * their position among siblings: |
| * |
| * FOR '(' RANK '(' NumericOnly ')' ')' |
| * |
| * We don't support that anymore, but recognize the syntax to |
| * give a better error message. |
| * |
| * But we don't want to make RANK a reserved keyword. Also, |
| * just replacing RANK with IDENT creates a conflict with this |
| * AexprConst rule: |
| * |
| * func_name '(' func_arg_list opt_sort_clause ')' Sconst |
| * |
| * I.e. after the parser has shifted "func_name '('", it doesn't |
| * know whether there's the Sconst at the end, which implies an |
| * AexprConst, or not. |
| * |
| * To avoid that conflict, this rule (after FOR '(') matches |
| * exactly the AexprConst rule except for the final Sconst. |
| * That way, the parser doesn't need to decide which one this is, |
| * until it has shifted the whole thing. Then we check in the |
| * code that func_name was RANK, and that the expr_list was a |
| * NumericOnly. |
| */ |
| | FOR '(' func_name '(' func_arg_list opt_sort_clause ')' ')' |
| { |
| Node *arg; |
| Node *fname; |
| |
| /* allow RANK only */ |
| if (list_length($3) != 1) |
| parser_yyerror("syntax error"); |
| fname = linitial($3); |
| if (!(strcmp(strVal(linitial($3)), "rank") == 0)) |
| parser_yyerror("syntax error"); |
| |
| /* expr_list must be a single numeric constant */ |
| if (list_length($5) != 1) |
| parser_yyerror("syntax error"); |
| |
| arg = linitial($5); |
| if (!IsA(arg, A_Const)) |
| parser_yyerror("syntax error"); |
| if (!IsA(&((A_Const *) arg)->val, Integer) && !IsA(&((A_Const *) arg)->val, Float)) |
| parser_yyerror("syntax error"); |
| |
| /* we don't want a sort clause */ |
| if ($6) |
| parser_yyerror("syntax error"); |
| |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("addressing partition by RANK is no longer supported"), |
| errhint("Use partition name or FOR (<partition key value>) instead."), |
| parser_errposition(@3))); |
| } |
| ; |
| |
| alter_table_partition_id_spec_with_opt_default: |
| PARTITION alter_table_partition_id_spec |
| { |
| GpAlterPartitionId *n = (GpAlterPartitionId*)$2; |
| $$ = (Node *)n; |
| } |
| | DEFAULT PARTITION alter_table_partition_id_spec |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("cannot specify a name, rank, or value for a DEFAULT partition in this context"))); |
| } |
| | DEFAULT PARTITION |
| { |
| GpAlterPartitionId *n = makeNode(GpAlterPartitionId); |
| n->idtype = AT_AP_IDDefault; |
| n->partiddef = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_table_partition_cmd: |
| ADD_P PARTITION |
| OptTabAddPartitionBoundarySpec |
| OptWith |
| OptTableSpace |
| OptTabSubPartitionSpec |
| |
| { |
| GpAlterPartitionId *pid = makeNode(GpAlterPartitionId); |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpPartDefElem *pelem = makeNode(GpPartDefElem); |
| |
| pid->idtype = AT_AP_IDNone; |
| pid->location = @3; |
| pid->partiddef = NULL; |
| |
| pc->partid = (GpAlterPartitionId *) pid; |
| |
| pelem->partName = NULL; |
| pelem->boundSpec = $3; |
| pelem->subSpec = $6; |
| pelem->location = @3; |
| pelem->isDefault = false; /* not default */ |
| pelem->options = $4; |
| pelem->accessMethod = greenplumLegacyAOoptions(NULL, &pelem->options); |
| pelem->tablespacename = $5; |
| |
| pc->arg = (Node *) pelem; |
| pc->location = @3; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ADD_P DEFAULT PARTITION |
| alter_table_partition_id_spec |
| OptWith |
| OptTableSpace |
| OptTabSubPartitionSpec |
| { |
| GpAlterPartitionId *pid = (GpAlterPartitionId *)$4; |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpPartDefElem *pelem = makeNode(GpPartDefElem); |
| |
| if (pid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("can only ADD a partition by name"))); |
| |
| pc->partid = (GpAlterPartitionId *) pid; |
| |
| pelem->partName = strVal(pid->partiddef); |
| pelem->subSpec = $7; |
| pelem->location = @5; |
| pelem->isDefault = true; |
| pelem->options = $5; |
| pelem->accessMethod = greenplumLegacyAOoptions(NULL, &pelem->options); |
| pelem->tablespacename = $6; |
| |
| pc->arg = (Node *) pelem; |
| pc->location = @5; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ADD_P PARTITION |
| alter_table_partition_id_spec |
| OptTabAddPartitionBoundarySpec |
| OptWith |
| OptTableSpace |
| OptTabSubPartitionSpec |
| { |
| GpAlterPartitionId *pid = (GpAlterPartitionId *)$3; |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpPartDefElem *pelem = makeNode(GpPartDefElem); |
| |
| if (pid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("can only ADD a partition by name"))); |
| |
| pc->partid = (GpAlterPartitionId *) pid; |
| |
| pelem->partName = strVal(pid->partiddef); |
| pelem->boundSpec = $4; |
| pelem->subSpec = $7; |
| pelem->location = @4; |
| pelem->isDefault = false; |
| pelem->options = $5; |
| pelem->accessMethod = greenplumLegacyAOoptions(NULL, &pelem->options); |
| pelem->tablespacename = $6; |
| |
| pc->arg = (Node *) pelem; |
| pc->location = @4; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ALTER |
| alter_table_partition_id_spec_with_opt_default |
| alter_table_cmd |
| { |
| /* |
| * NOTE: only allow a subset of valid ALTER TABLE |
| * cmds for partitions. |
| */ |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (GpAlterPartitionId *)$2; |
| pc->arg = (Node *)$3; |
| pc->location = @3; |
| |
| n->subtype = AT_PartAlter; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | DROP PARTITION IF_P EXISTS |
| alter_table_partition_id_spec |
| opt_drop_behavior |
| { |
| GpDropPartitionCmd *dpc = makeNode(GpDropPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| dpc->partid = (Node *) $5; |
| dpc->behavior = $6; |
| dpc->missing_ok = true; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *) dpc; |
| $$ = (Node *) n; |
| |
| } |
| | DROP DEFAULT PARTITION IF_P EXISTS |
| opt_drop_behavior |
| { |
| GpAlterPartitionId *id = makeNode(GpAlterPartitionId); |
| GpDropPartitionCmd *dpc = makeNode(GpDropPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| id->idtype = AT_AP_IDDefault; |
| id->partiddef = NULL; |
| id->location = @1; |
| |
| dpc->partid = (Node *) id; |
| dpc->behavior = $6; |
| dpc->missing_ok = true; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *) dpc; |
| $$ = (Node *) n; |
| } |
| | DROP |
| alter_table_partition_id_spec_with_opt_default |
| opt_drop_behavior |
| { |
| GpDropPartitionCmd *dpc = makeNode(GpDropPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| dpc->partid = $2; |
| dpc->behavior = $3; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *) dpc; |
| $$ = (Node *) n; |
| } |
| | EXCHANGE |
| alter_table_partition_id_spec_with_opt_default |
| WITH TABLE qualified_name |
| opt_table_partition_exchange_validate |
| { |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (GpAlterPartitionId *)$2; |
| pc->arg = (Node *)$5; |
| pc->location = @5; |
| |
| n->subtype = AT_PartExchange; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | RENAME |
| alter_table_partition_id_spec_with_opt_default TO IDENT |
| { |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (GpAlterPartitionId *) $2; |
| pc->arg = (Node *)makeString($4); |
| pc->location = @4; |
| |
| n->subtype = AT_PartRename; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SET TabSubPartitionTemplate |
| { |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = NULL; |
| pc->arg = $2; |
| pc->location = @2; |
| |
| n->subtype = AT_PartSetTemplate; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SET SUBPARTITION TEMPLATE |
| '(' ')' |
| { |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = NULL; |
| pc->arg = NULL; |
| pc->location = @4; |
| |
| n->subtype = AT_PartSetTemplate; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SPLIT |
| DEFAULT PARTITION TabPartitionBoundarySpecStart |
| TabPartitionBoundarySpecEnd |
| opt_table_partition_split_into |
| { |
| GpSplitPartitionCmd *pc = makeNode(GpSplitPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpAlterPartitionId *pid = makeNode(GpAlterPartitionId); |
| |
| pid->idtype = AT_AP_IDDefault; |
| pid->partiddef = NULL; |
| pid->location = @2; |
| |
| pc->partid = pid; |
| pc->start = (GpPartitionRangeItem *)$4; |
| pc->end = (GpPartitionRangeItem *)$5; |
| pc->at = NULL; |
| pc->arg2 = (GpAlterPartitionCmd *)$6; |
| pc->location = @5; |
| |
| n->subtype = AT_PartSplit; |
| n->def = (Node *)pc; |
| |
| $$ = (Node *)n; |
| } |
| | SPLIT |
| DEFAULT PARTITION AT |
| '(' part_values_or_spec_list ')' |
| opt_table_partition_split_into |
| { |
| GpSplitPartitionCmd *pc = makeNode(GpSplitPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpAlterPartitionId *pid = makeNode(GpAlterPartitionId); |
| |
| pid->idtype = AT_AP_IDDefault; |
| pid->partiddef = NULL; |
| pid->location = @2; |
| |
| pc->partid = pid; |
| pc->start = NULL; |
| pc->end = NULL; |
| pc->at = $6; |
| pc->arg2 = (GpAlterPartitionCmd *)$8; |
| pc->location = @6; |
| |
| n->subtype = AT_PartSplit; |
| n->def = (Node *)pc; |
| |
| $$ = (Node *)n; |
| } |
| | SPLIT |
| PARTITION alter_table_partition_id_spec AT |
| '(' part_values_or_spec_list ')' |
| opt_table_partition_split_into |
| { |
| GpSplitPartitionCmd *pc = makeNode(GpSplitPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| GpAlterPartitionCmd *into; |
| |
| pc->partid = (GpAlterPartitionId*) $3; |
| pc->start = NULL; |
| pc->end = NULL; |
| pc->at = $6; |
| pc->arg2 = (GpAlterPartitionCmd *)$8; |
| pc->location = @6; |
| |
| n->subtype = AT_PartSplit; |
| n->def = (Node *)pc; |
| |
| into = (GpAlterPartitionCmd *)pc->arg2; |
| if (into) |
| { |
| GpAlterPartitionId *part2 = (GpAlterPartitionId *) into->arg; |
| if (part2->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("INTO can only have second partition by name"), |
| parser_errposition(@8))); |
| } |
| $$ = (Node *)n; |
| } |
| | TRUNCATE |
| alter_table_partition_id_spec_with_opt_default |
| opt_drop_behavior |
| { |
| GpAlterPartitionCmd *pc = makeNode(GpAlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| TruncateStmt *ts = makeNode(TruncateStmt); |
| |
| /* |
| * build an (incomplete) truncate statement. Fill in the |
| * rest after the Fill in the rest after the partition id |
| * spec is validated. |
| */ |
| ts->relations = NULL; |
| ts->behavior = $3; |
| |
| pc->partid = (GpAlterPartitionId *) $2; |
| pc->arg = (Node *) ts; |
| pc->location = @2; |
| |
| n->subtype = AT_PartTruncate; |
| n->def = (Node *) pc; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER TYPE |
| * |
| * really variants of the ALTER TABLE subcommands with different spellings |
| *****************************************************************************/ |
| |
| AlterCompositeTypeStmt: |
| ALTER TYPE_P any_name alter_type_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| /* can't use qualified_name, sigh */ |
| n->relation = makeRangeVarFromAnyName($3, @3, yyscanner); |
| n->cmds = $4; |
| n->objtype = OBJECT_TYPE; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alter_type_cmds: |
| alter_type_cmd { $$ = list_make1($1); } |
| | alter_type_cmds ',' alter_type_cmd { $$ = lappend($1, $3); } |
| ; |
| |
| alter_type_cmd: |
| /* ALTER TYPE <name> ADD ATTRIBUTE <coldef> [RESTRICT|CASCADE] */ |
| ADD_P ATTRIBUTE TableFuncElement opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_AddColumn; |
| n->def = $3; |
| n->behavior = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> [RESTRICT|CASCADE] */ |
| | DROP ATTRIBUTE IF_P EXISTS ColId opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropColumn; |
| n->name = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER TYPE <name> DROP ATTRIBUTE <attname> [RESTRICT|CASCADE] */ |
| | DROP ATTRIBUTE ColId opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| n->subtype = AT_DropColumn; |
| n->name = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */ |
| | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_collate_clause opt_drop_behavior |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| ColumnDef *def = makeNode(ColumnDef); |
| |
| n->subtype = AT_AlterColumnType; |
| n->name = $3; |
| n->def = (Node *) def; |
| n->behavior = $8; |
| /* We only use these fields of the ColumnDef node */ |
| def->typeName = $6; |
| def->collClause = (CollateClause *) $7; |
| def->raw_default = NULL; |
| def->location = @3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * close <portalname> |
| * |
| *****************************************************************************/ |
| |
| ClosePortalStmt: |
| CLOSE cursor_name |
| { |
| ClosePortalStmt *n = makeNode(ClosePortalStmt); |
| |
| n->portalname = $2; |
| $$ = (Node *) n; |
| } |
| | CLOSE ALL |
| { |
| ClosePortalStmt *n = makeNode(ClosePortalStmt); |
| |
| n->portalname = NULL; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * COPY relname [(columnList)] FROM/TO file [WITH] [(options)] |
| * COPY ( query ) TO file [WITH] [(options)] |
| * |
| * where 'query' can be one of: |
| * { SELECT | UPDATE | INSERT | DELETE } |
| * |
| * and 'file' can be one of: |
| * { PROGRAM 'command' | STDIN | STDOUT | 'filename' } |
| * |
| * In the preferred syntax the options are comma-separated |
| * and use generic identifiers instead of keywords. The pre-9.0 |
| * syntax had a hard-wired, space-separated set of options. |
| * |
| * Really old syntax, from versions 7.2 and prior: |
| * COPY [ BINARY ] table FROM/TO file |
| * [ [ USING ] DELIMITERS 'delimiter' ] ] |
| * [ WITH NULL AS 'null string' ] |
| * This option placement is not supported with COPY (query...). |
| * |
| *****************************************************************************/ |
| |
| CopyStmt: COPY opt_binary qualified_name opt_column_list |
| copy_from opt_program copy_file_name opt_file_name copy_delimiter opt_with |
| copy_options where_clause OptSingleRowErrorHandling |
| { |
| CopyStmt *n = makeNode(CopyStmt); |
| |
| n->relation = $3; |
| n->query = NULL; |
| n->attlist = $4; |
| n->is_from = $5; |
| n->is_program = $6; |
| n->filename = $7; |
| n->dirfilename = $8; |
| n->whereClause = $12; |
| n->sreh = $13; |
| |
| if (n->is_program && n->filename == NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("STDIN/STDOUT not allowed with PROGRAM"), |
| parser_errposition(@7))); |
| |
| if (!n->is_from && n->whereClause != NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("WHERE clause not allowed with COPY TO"), |
| parser_errposition(@12))); |
| |
| n->options = NIL; |
| /* Concatenate user-supplied flags */ |
| if ($2) |
| n->options = lappend(n->options, $2); |
| if ($9) |
| n->options = lappend(n->options, $9); |
| if ($11) |
| n->options = list_concat(n->options, $11); |
| if ($13) |
| n->options = list_concat(n->options, $13); |
| |
| $$ = (Node *)n; |
| } |
| | COPY '(' PreparableStmt ')' TO opt_program copy_file_name opt_with copy_options |
| { |
| CopyStmt *n = makeNode(CopyStmt); |
| |
| n->relation = NULL; |
| n->query = $3; |
| n->attlist = NIL; |
| n->is_from = false; |
| n->is_program = $6; |
| n->filename = $7; |
| n->options = $9; |
| |
| if (n->is_program && n->filename == NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("STDIN/STDOUT not allowed with PROGRAM"), |
| parser_errposition(@5))); |
| |
| $$ = (Node *) n; |
| /* |
| * GPDB_96_MERGE_FIXME: The above statement changed in |
| * upstream commit 92e38182d7c from select_with_parens to |
| * '(' PreparableStmt ')'. This syntax was not supported in |
| * ecpg upstream. It was supported and untested in GPDB. If |
| * it is needed to be added back, then |
| * preparable_stmt_with_parens should be added as ecpg does |
| * not fair very well with \' or \( \) chars. |
| */ |
| } |
| | COPY BINARY DIRECTORY TABLE qualified_name Sconst TO opt_program copy_file_name |
| { |
| CopyStmt *n = makeNode(CopyStmt); |
| n->relation = $5; |
| n->query = NULL; |
| n->attlist = NIL; |
| n->is_from = false; |
| n->is_program = $8; |
| n->filename = $9; |
| n->dirfilename = $6; |
| n->options = lappend(n->options, makeDefElem("format", (Node *)makeString("binary"), @2)); |
| |
| if (n->is_program && n->filename == NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("STDIN/STDOUT not allowed with PROGRAM"), |
| parser_errposition(@7))); |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| copy_from: |
| FROM { $$ = true; } |
| | TO { $$ = false; } |
| ; |
| |
| opt_program: |
| PROGRAM { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| /* |
| * copy_file_name NULL indicates stdio is used. Whether stdin or stdout is |
| * used depends on the direction. (It really doesn't make sense to copy from |
| * stdout. We silently correct the "typo".) - AY 9/94 |
| */ |
| copy_file_name: |
| Sconst { $$ = $1; } |
| | STDIN { $$ = NULL; } |
| | STDOUT { $$ = NULL; } |
| ; |
| |
| opt_file_name: |
| Sconst { $$ = $1; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| copy_options: copy_opt_list { $$ = $1; } |
| | '(' copy_generic_opt_list ')' { $$ = $2; } |
| ; |
| |
| /* old COPY option syntax */ |
| copy_opt_list: |
| copy_opt_list copy_opt_item { $$ = lappend($1, $2); } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| copy_opt_item: |
| BINARY |
| { |
| $$ = makeDefElem("format", (Node *) makeString("binary"), @1); |
| } |
| | FREEZE |
| { |
| $$ = makeDefElem("freeze", (Node *) makeBoolean(true), @1); |
| } |
| | DELIMITER opt_as Sconst |
| { |
| $$ = makeDefElem("delimiter", (Node *) makeString($3), @1); |
| } |
| | NULL_P opt_as Sconst |
| { |
| $$ = makeDefElem("null", (Node *) makeString($3), @1); |
| } |
| | CSV |
| { |
| $$ = makeDefElem("format", (Node *) makeString("csv"), @1); |
| } |
| | HEADER_P |
| { |
| $$ = makeDefElem("header", (Node *) makeBoolean(true), @1); |
| } |
| | QUOTE opt_as Sconst |
| { |
| $$ = makeDefElem("quote", (Node *) makeString($3), @1); |
| } |
| | ESCAPE opt_as Sconst |
| { |
| $$ = makeDefElem("escape", (Node *) makeString($3), @1); |
| } |
| | FORCE QUOTE columnList |
| { |
| $$ = makeDefElem("force_quote", (Node *) $3, @1); |
| } |
| | FORCE QUOTE '*' |
| { |
| $$ = makeDefElem("force_quote", (Node *) makeNode(A_Star), @1); |
| } |
| | FORCE NOT NULL_P columnList |
| { |
| $$ = makeDefElem("force_not_null", (Node *) $4, @1); |
| } |
| | FORCE NULL_P columnList |
| { |
| $$ = makeDefElem("force_null", (Node *) $3, @1); |
| } |
| | ENCODING Sconst |
| { |
| $$ = makeDefElem("encoding", (Node *) makeString($2), @1); |
| } |
| | FILL MISSING FIELDS |
| { |
| $$ = makeDefElem("fill_missing_fields", (Node *)makeInteger(true), @1); |
| } |
| | NEWLINE opt_as Sconst |
| { |
| $$ = makeDefElem("newline", (Node *)makeString($3), @1); |
| } |
| | ON SEGMENT |
| { |
| $$ = makeDefElem("on_segment", (Node *)makeInteger(true), @1); |
| } |
| | IGNORE_P EXTERNAL PARTITIONS |
| { |
| $$ = makeDefElem("skip_foreign_partitions", (Node *)makeInteger(true), @1); |
| } |
| | IGNORE_P FOREIGN PARTITIONS |
| { |
| $$ = makeDefElem("skip_foreign_partitions", (Node *)makeInteger(true), @1); |
| } |
| | TAG Sconst |
| { |
| $$ = makeDefElem("tag", (Node *)makeString($2), @1); |
| } |
| ; |
| |
| /* The following exist for backward compatibility with very old versions */ |
| |
| opt_binary: |
| BINARY |
| { |
| $$ = makeDefElem("format", (Node *) makeString("binary"), @1); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| copy_delimiter: |
| opt_using DELIMITERS Sconst |
| { |
| $$ = makeDefElem("delimiter", (Node *) makeString($3), @2); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| opt_using: |
| USING |
| | /*EMPTY*/ |
| ; |
| |
| /* new COPY option syntax */ |
| copy_generic_opt_list: |
| copy_generic_opt_elem |
| { |
| $$ = list_make1($1); |
| } |
| | copy_generic_opt_list ',' copy_generic_opt_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| copy_generic_opt_elem: |
| ColLabel copy_generic_opt_arg |
| { |
| $$ = makeDefElem($1, $2, @1); |
| } |
| ; |
| |
| copy_generic_opt_arg: |
| opt_boolean_or_string { $$ = (Node *) makeString($1); } |
| | NumericOnly { $$ = (Node *) $1; } |
| | '*' { $$ = (Node *) makeNode(A_Star); } |
| | '(' copy_generic_opt_arg_list ')' { $$ = (Node *) $2; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| copy_generic_opt_arg_list: |
| copy_generic_opt_arg_list_item |
| { |
| $$ = list_make1($1); |
| } |
| | copy_generic_opt_arg_list ',' copy_generic_opt_arg_list_item |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| /* beware of emitting non-string list elements here; see commands/define.c */ |
| copy_generic_opt_arg_list_item: |
| opt_boolean_or_string { $$ = (Node *) makeString($1); } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE TABLE relname |
| * |
| *****************************************************************************/ |
| |
| CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' |
| OptInherit OptFirstPartitionSpec table_access_method_clause OptWith |
| OnCommitOption OptTableSpace |
| OptDistributedBy OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $4->relpersistence = $2; |
| n->relation = $4; |
| n->tableElts = $6; |
| n->inhRelations = $8; |
| if ($9 && $15) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@15))); |
| n->partspec = $9 ? $9 : $15; |
| n->ofTypename = NULL; |
| n->constraints = NIL; |
| n->accessMethod = $10; |
| n->options = $11; |
| n->oncommit = $12; |
| n->tablespacename = $13; |
| n->if_not_exists = false; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = (DistributedBy *) $14; |
| n->tags = $16; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' |
| OptTableElementList ')' OptInherit OptFirstPartitionSpec table_access_method_clause |
| OptWith OnCommitOption OptTableSpace |
| OptDistributedBy OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $7->relpersistence = $2; |
| n->relation = $7; |
| n->tableElts = $9; |
| n->inhRelations = $11; |
| if ($12 && $18) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@18))); |
| n->partspec = $12 ? $12 : $18; |
| n->ofTypename = NULL; |
| n->constraints = NIL; |
| n->accessMethod = $13; |
| n->options = $14; |
| n->oncommit = $15; |
| n->tablespacename = $16; |
| n->if_not_exists = true; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = (DistributedBy *) $17; |
| n->tags = $19; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE qualified_name OF any_name |
| OptTypedTableElementList OptFirstPartitionSpec table_access_method_clause |
| OptWith OnCommitOption OptTableSpace |
| OptDistributedBy OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $4->relpersistence = $2; |
| n->relation = $4; |
| n->tableElts = $7; |
| n->inhRelations = NIL; |
| if ($8 && $14) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@14))); |
| n->partspec = $8 ? $8 : $14; |
| n->ofTypename = makeTypeNameFromNameList($6); |
| n->ofTypename->location = @6; |
| n->constraints = NIL; |
| n->accessMethod = $9; |
| n->options = $10; |
| n->oncommit = $11; |
| n->tablespacename = $12; |
| n->if_not_exists = false; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = (DistributedBy *) $13; |
| n->tags = $15; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name |
| OptTypedTableElementList OptFirstPartitionSpec table_access_method_clause |
| OptWith OnCommitOption OptTableSpace |
| OptDistributedBy OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $7->relpersistence = $2; |
| n->relation = $7; |
| n->tableElts = $10; |
| n->inhRelations = NIL; |
| if ($11 && $17) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@17))); |
| n->partspec = $11 ? $11 : $17; |
| n->ofTypename = makeTypeNameFromNameList($9); |
| n->ofTypename->location = @9; |
| n->constraints = NIL; |
| n->accessMethod = $12; |
| n->options = $13; |
| n->oncommit = $14; |
| n->tablespacename = $15; |
| n->if_not_exists = true; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = (DistributedBy *) $16; |
| n->tags = $18; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name |
| OptTypedTableElementList PartitionBoundSpec OptFirstPartitionSpec |
| table_access_method_clause OptWith OnCommitOption OptTableSpace |
| OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $4->relpersistence = $2; |
| n->relation = $4; |
| n->tableElts = $8; |
| n->inhRelations = list_make1($7); |
| n->partbound = $9; |
| if ($10 && $15) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@15))); |
| n->partspec = $10 ? $10 : $15; |
| n->ofTypename = NULL; |
| n->constraints = NIL; |
| n->accessMethod = $11; |
| n->options = $12; |
| n->oncommit = $13; |
| n->tablespacename = $14; |
| n->if_not_exists = false; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = NULL; |
| n->tags = $16; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF |
| qualified_name OptTypedTableElementList PartitionBoundSpec OptFirstPartitionSpec |
| table_access_method_clause OptWith OnCommitOption OptTableSpace |
| OptSecondPartitionSpec OptTagOptList |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $7->relpersistence = $2; |
| n->relation = $7; |
| n->tableElts = $11; |
| n->inhRelations = list_make1($10); |
| n->partbound = $12; |
| if ($13 && $18) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PARTITION BY clause is allowed"), |
| parser_errposition(@18))); |
| n->partspec = $13 ? $13 : $18; |
| n->ofTypename = NULL; |
| n->constraints = NIL; |
| n->accessMethod = $14; |
| n->options = $15; |
| n->oncommit = $16; |
| n->tablespacename = $17; |
| n->if_not_exists = true; |
| n->origin = ORIGIN_NO_GEN; |
| n->distributedBy = NULL; |
| n->tags = $19; |
| n->relKind = RELKIND_RELATION; |
| |
| n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * Redundancy here is needed to avoid shift/reduce conflicts, |
| * since TEMP is not a reserved word. See also OptTempTableName. |
| * |
| * NOTE: we accept both GLOBAL and LOCAL options. They currently do nothing, |
| * but future versions might consider GLOBAL to request SQL-spec-compliant |
| * temp table behavior, so warn about that. Since we have no modules the |
| * LOCAL keyword is really meaningless; furthermore, some other products |
| * implement LOCAL as meaning the same as our default temp table behavior, |
| * so we'll probably continue to treat LOCAL as a noise word. |
| */ |
| OptTemp: TEMPORARY { $$ = RELPERSISTENCE_TEMP; } |
| | TEMP { $$ = RELPERSISTENCE_TEMP; } |
| | LOCAL TEMPORARY { $$ = RELPERSISTENCE_TEMP; } |
| | LOCAL TEMP { $$ = RELPERSISTENCE_TEMP; } |
| | GLOBAL TEMPORARY |
| { |
| ereport(WARNING, |
| (errmsg("GLOBAL is deprecated in temporary table creation"), |
| parser_errposition(@1))); |
| $$ = RELPERSISTENCE_TEMP; |
| } |
| | GLOBAL TEMP |
| { |
| ereport(WARNING, |
| (errmsg("GLOBAL is deprecated in temporary table creation"), |
| parser_errposition(@1))); |
| $$ = RELPERSISTENCE_TEMP; |
| } |
| | UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; } |
| | /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; } |
| ; |
| |
| OptTableElementList: |
| TableElementList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptTypedTableElementList: |
| '(' TypedTableElementList ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TableElementList: |
| TableElement |
| { |
| $$ = list_make1($1); |
| } |
| | TableElementList ',' TableElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| TypedTableElementList: |
| TypedTableElement |
| { |
| $$ = list_make1($1); |
| } |
| | TypedTableElementList ',' TypedTableElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| TableElement: |
| columnDef { $$ = $1; } |
| | TableLikeClause { $$ = $1; } |
| | TableConstraint { $$ = $1; } |
| | column_reference_storage_directive { $$ = $1; } |
| ; |
| |
| TypedTableElement: |
| columnOptions { $$ = $1; } |
| | TableConstraint { $$ = $1; } |
| ; |
| |
| column_reference_storage_directive: |
| COLUMN ColId ENCODING definition |
| { |
| ColumnReferenceStorageDirective *n = |
| makeNode(ColumnReferenceStorageDirective); |
| |
| n->column = $2; |
| n->encoding = $4; |
| $$ = (Node *)n; |
| } |
| | DEFAULT COLUMN ENCODING definition |
| { |
| ColumnReferenceStorageDirective *n = |
| makeNode(ColumnReferenceStorageDirective); |
| |
| n->deflt = true; |
| n->encoding = $4; |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| columnDef: ColId Typename opt_column_storage opt_column_compression create_generic_options ColQualList opt_storage_encoding |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| |
| n->colname = $1; |
| n->typeName = $2; |
| n->storage_name = $3; |
| n->compression = $4; |
| n->inhcount = 0; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->is_from_type = false; |
| n->storage = 0; |
| n->raw_default = NULL; |
| n->cooked_default = NULL; |
| n->collOid = InvalidOid; |
| n->fdwoptions = $5; |
| SplitColQualList($6, &n->constraints, &n->collClause, |
| yyscanner); |
| n->encoding = $7; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| columnOptions: ColId ColQualList |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| |
| n->colname = $1; |
| n->typeName = NULL; |
| n->inhcount = 0; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->is_from_type = false; |
| n->storage = 0; |
| n->raw_default = NULL; |
| n->cooked_default = NULL; |
| n->collOid = InvalidOid; |
| SplitColQualList($2, &n->constraints, &n->collClause, |
| yyscanner); |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | ColId WITH OPTIONS ColQualList |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| |
| n->colname = $1; |
| n->typeName = NULL; |
| n->inhcount = 0; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->is_from_type = false; |
| n->storage = 0; |
| n->raw_default = NULL; |
| n->cooked_default = NULL; |
| n->collOid = InvalidOid; |
| SplitColQualList($4, &n->constraints, &n->collClause, |
| yyscanner); |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| column_compression: |
| COMPRESSION ColId { $$ = $2; } |
| | COMPRESSION DEFAULT { $$ = pstrdup("default"); } |
| ; |
| |
| opt_column_compression: |
| column_compression { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| column_storage: |
| STORAGE ColId { $$ = $2; } |
| | STORAGE DEFAULT { $$ = pstrdup("default"); } |
| ; |
| |
| opt_column_storage: |
| column_storage { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ColQualList: |
| ColQualList ColConstraint { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ColConstraint: |
| CONSTRAINT name ColConstraintElem |
| { |
| Constraint *n = castNode(Constraint, $3); |
| |
| n->conname = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | ColConstraintElem { $$ = $1; } |
| | ConstraintAttr { $$ = $1; } |
| | COLLATE any_name |
| { |
| /* |
| * Note: the CollateClause is momentarily included in |
| * the list built by ColQualList, but we split it out |
| * again in SplitColQualList. |
| */ |
| CollateClause *n = makeNode(CollateClause); |
| |
| n->arg = NULL; |
| n->collname = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_storage_encoding: ENCODING definition { $$ = $2; } |
| | /* nothing */ { $$ = NIL; } |
| ; |
| |
| /* DEFAULT NULL is already the default for Postgres. |
| * But define it here and carry it forward into the system |
| * to make it explicit. |
| * - thomas 1998-09-13 |
| * |
| * WITH NULL and NULL are not SQL-standard syntax elements, |
| * so leave them out. Use DEFAULT NULL to explicitly indicate |
| * that a column may have that value. WITH NULL leads to |
| * shift/reduce conflicts with WITH TIME ZONE anyway. |
| * - thomas 1999-01-08 |
| * |
| * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce |
| * conflict on NOT (since NOT might start a subsequent NOT NULL constraint, |
| * or be part of a_expr NOT LIKE or similar constructs). |
| */ |
| ColConstraintElem: |
| NOT NULL_P |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_NOTNULL; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | NULL_P |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_NULL; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | UNIQUE opt_unique_null_treatment opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_UNIQUE; |
| n->location = @1; |
| n->nulls_not_distinct = !$2; |
| n->keys = NULL; |
| n->options = $3; |
| n->indexname = NULL; |
| n->indexspace = $4; |
| $$ = (Node *) n; |
| } |
| | PRIMARY KEY opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_PRIMARY; |
| n->location = @1; |
| n->keys = NULL; |
| n->options = $3; |
| n->indexname = NULL; |
| n->indexspace = $4; |
| $$ = (Node *) n; |
| } |
| | CHECK '(' a_expr ')' opt_no_inherit |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_CHECK; |
| n->location = @1; |
| n->is_no_inherit = $5; |
| n->raw_expr = $3; |
| n->cooked_expr = NULL; |
| n->skip_validation = false; |
| n->initially_valid = true; |
| $$ = (Node *) n; |
| } |
| | DEFAULT b_expr |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_DEFAULT; |
| n->location = @1; |
| n->raw_expr = $2; |
| n->cooked_expr = NULL; |
| $$ = (Node *) n; |
| } |
| | GENERATED generated_when AS IDENTITY_P OptParenthesizedSeqOptList |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_IDENTITY; |
| n->generated_when = $2; |
| n->options = $5; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | GENERATED generated_when AS '(' a_expr ')' STORED |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_GENERATED; |
| n->generated_when = $2; |
| n->raw_expr = $5; |
| n->cooked_expr = NULL; |
| n->location = @1; |
| |
| /* |
| * Can't do this in the grammar because of shift/reduce |
| * conflicts. (IDENTITY allows both ALWAYS and BY |
| * DEFAULT, but generated columns only allow ALWAYS.) We |
| * can also give a more useful error message and location. |
| */ |
| if ($2 != ATTRIBUTE_IDENTITY_ALWAYS) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("for a generated column, GENERATED ALWAYS must be specified"), |
| parser_errposition(@2))); |
| |
| $$ = (Node *) n; |
| } |
| | REFERENCES qualified_name opt_column_list key_match key_actions |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_FOREIGN; |
| n->location = @1; |
| n->pktable = $2; |
| n->fk_attrs = NIL; |
| n->pk_attrs = $3; |
| n->fk_matchtype = $4; |
| n->fk_upd_action = ($5)->updateAction->action; |
| n->fk_del_action = ($5)->deleteAction->action; |
| n->fk_del_set_cols = ($5)->deleteAction->cols; |
| n->skip_validation = false; |
| n->initially_valid = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_unique_null_treatment: |
| NULLS_P DISTINCT { $$ = true; } |
| | NULLS_P NOT DISTINCT { $$ = false; } |
| | /*EMPTY*/ { $$ = true; } |
| ; |
| |
| generated_when: |
| ALWAYS { $$ = ATTRIBUTE_IDENTITY_ALWAYS; } |
| | BY DEFAULT { $$ = ATTRIBUTE_IDENTITY_BY_DEFAULT; } |
| ; |
| |
| /* |
| * ConstraintAttr represents constraint attributes, which we parse as if |
| * they were independent constraint clauses, in order to avoid shift/reduce |
| * conflicts (since NOT might start either an independent NOT NULL clause |
| * or an attribute). parse_utilcmd.c is responsible for attaching the |
| * attribute information to the preceding "real" constraint node, and for |
| * complaining if attribute clauses appear in the wrong place or wrong |
| * combinations. |
| * |
| * See also ConstraintAttributeSpec, which can be used in places where |
| * there is no parsing conflict. (Note: currently, NOT VALID and NO INHERIT |
| * are allowed clauses in ConstraintAttributeSpec, but not here. Someday we |
| * might need to allow them here too, but for the moment it doesn't seem |
| * useful in the statements that use ConstraintAttr.) |
| */ |
| ConstraintAttr: |
| DEFERRABLE |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_ATTR_DEFERRABLE; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | NOT DEFERRABLE |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_ATTR_NOT_DEFERRABLE; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | INITIALLY DEFERRED |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_ATTR_DEFERRED; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | INITIALLY IMMEDIATE |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_ATTR_IMMEDIATE; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| TableLikeClause: |
| LIKE qualified_name TableLikeOptionList |
| { |
| TableLikeClause *n = makeNode(TableLikeClause); |
| |
| n->relation = $2; |
| n->options = $3; |
| n->relationOid = InvalidOid; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| TableLikeOptionList: |
| TableLikeOptionList INCLUDING TableLikeOption { $$ = $1 | $3; } |
| | TableLikeOptionList EXCLUDING TableLikeOption { $$ = $1 & ~$3; } |
| | /* EMPTY */ { $$ = 0; } |
| ; |
| |
| TableLikeOption: |
| COMMENTS { $$ = CREATE_TABLE_LIKE_COMMENTS; } |
| | COMPRESSION { $$ = CREATE_TABLE_LIKE_COMPRESSION; } |
| | CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; } |
| | DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; } |
| | IDENTITY_P { $$ = CREATE_TABLE_LIKE_IDENTITY; } |
| | GENERATED { $$ = CREATE_TABLE_LIKE_GENERATED; } |
| | INDEXES { $$ = CREATE_TABLE_LIKE_INDEXES; } |
| | STATISTICS { $$ = CREATE_TABLE_LIKE_STATISTICS; } |
| | STORAGE { $$ = CREATE_TABLE_LIKE_STORAGE; } |
| | ALL { $$ = CREATE_TABLE_LIKE_ALL; } |
| ; |
| |
| |
| /* ConstraintElem specifies constraint syntax which is not embedded into |
| * a column definition. ColConstraintElem specifies the embedded form. |
| * - thomas 1997-12-03 |
| */ |
| TableConstraint: |
| CONSTRAINT name ConstraintElem |
| { |
| Constraint *n = castNode(Constraint, $3); |
| |
| n->conname = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | ConstraintElem { $$ = $1; } |
| ; |
| |
| ConstraintElem: |
| CHECK '(' a_expr ')' ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_CHECK; |
| n->location = @1; |
| n->raw_expr = $3; |
| n->cooked_expr = NULL; |
| processCASbits($5, @5, "CHECK", |
| NULL, NULL, &n->skip_validation, |
| &n->is_no_inherit, yyscanner); |
| n->initially_valid = !n->skip_validation; |
| $$ = (Node *) n; |
| } |
| | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace |
| ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_UNIQUE; |
| n->location = @1; |
| n->nulls_not_distinct = !$2; |
| n->keys = $4; |
| n->including = $6; |
| n->options = $7; |
| n->indexname = NULL; |
| n->indexspace = $8; |
| processCASbits($9, @9, "UNIQUE", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| | UNIQUE ExistingIndex ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_UNIQUE; |
| n->location = @1; |
| n->keys = NIL; |
| n->including = NIL; |
| n->options = NIL; |
| n->indexname = $2; |
| n->indexspace = NULL; |
| processCASbits($3, @3, "UNIQUE", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| | PRIMARY KEY '(' columnList ')' opt_c_include opt_definition OptConsTableSpace |
| ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_PRIMARY; |
| n->location = @1; |
| n->keys = $4; |
| n->including = $6; |
| n->options = $7; |
| n->indexname = NULL; |
| n->indexspace = $8; |
| processCASbits($9, @9, "PRIMARY KEY", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| | PRIMARY KEY ExistingIndex ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_PRIMARY; |
| n->location = @1; |
| n->keys = NIL; |
| n->including = NIL; |
| n->options = NIL; |
| n->indexname = $3; |
| n->indexspace = NULL; |
| processCASbits($4, @4, "PRIMARY KEY", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| | EXCLUDE access_method_clause '(' ExclusionConstraintList ')' |
| opt_c_include opt_definition OptConsTableSpace OptWhereClause |
| ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_EXCLUSION; |
| n->location = @1; |
| n->access_method = $2; |
| n->exclusions = $4; |
| n->including = $6; |
| n->options = $7; |
| n->indexname = NULL; |
| n->indexspace = $8; |
| n->where_clause = $9; |
| processCASbits($10, @10, "EXCLUDE", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| $$ = (Node *) n; |
| } |
| | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name |
| opt_column_list key_match key_actions ConstraintAttributeSpec |
| { |
| Constraint *n = makeNode(Constraint); |
| |
| n->contype = CONSTR_FOREIGN; |
| n->location = @1; |
| n->pktable = $7; |
| n->fk_attrs = $4; |
| n->pk_attrs = $8; |
| n->fk_matchtype = $9; |
| n->fk_upd_action = ($10)->updateAction->action; |
| n->fk_del_action = ($10)->deleteAction->action; |
| n->fk_del_set_cols = ($10)->deleteAction->cols; |
| processCASbits($11, @11, "FOREIGN KEY", |
| &n->deferrable, &n->initdeferred, |
| &n->skip_validation, NULL, |
| yyscanner); |
| n->initially_valid = !n->skip_validation; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_no_inherit: NO INHERIT { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| opt_column_list: |
| '(' columnList ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| columnList: |
| columnElem { $$ = list_make1($1); } |
| | columnList ',' columnElem { $$ = lappend($1, $3); } |
| ; |
| |
| columnElem: ColId |
| { |
| $$ = (Node *) makeString($1); |
| } |
| ; |
| |
| distributed_by_list: |
| distributed_by_elem { $$ = list_make1($1); } |
| | distributed_by_list ',' distributed_by_elem |
| { |
| DistributionKeyElem *newelem = $3; |
| ListCell *lc; |
| |
| foreach(lc, $1) |
| { |
| DistributionKeyElem *oldelem = (DistributionKeyElem *) lfirst(lc); |
| |
| if (strcmp(oldelem->name, newelem->name) == 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_DUPLICATE_COLUMN), |
| errmsg("duplicate column in DISTRIBUTED BY clause"), |
| parser_errposition(@3))); |
| } |
| |
| $$ = lappend($1, newelem); |
| } |
| ; |
| |
| distributed_by_elem: ColId opt_class |
| { |
| $$ = makeNode(DistributionKeyElem); |
| $$->name = $1; |
| $$->opclass = $2; |
| $$->location = @1; |
| } |
| ; |
| |
| opt_c_include: INCLUDE '(' columnList ')' { $$ = $3; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| key_match: MATCH FULL |
| { |
| $$ = FKCONSTR_MATCH_FULL; |
| } |
| | MATCH PARTIAL |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("MATCH PARTIAL not yet implemented"), |
| parser_errposition(@1))); |
| $$ = FKCONSTR_MATCH_PARTIAL; |
| } |
| | MATCH SIMPLE |
| { |
| $$ = FKCONSTR_MATCH_SIMPLE; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = FKCONSTR_MATCH_SIMPLE; |
| } |
| ; |
| |
| ExclusionConstraintList: |
| ExclusionConstraintElem { $$ = list_make1($1); } |
| | ExclusionConstraintList ',' ExclusionConstraintElem |
| { $$ = lappend($1, $3); } |
| ; |
| |
| ExclusionConstraintElem: index_elem WITH any_operator |
| { |
| $$ = list_make2($1, $3); |
| } |
| /* allow OPERATOR() decoration for the benefit of ruleutils.c */ |
| | index_elem WITH OPERATOR '(' any_operator ')' |
| { |
| $$ = list_make2($1, $5); |
| } |
| ; |
| |
| OptWhereClause: |
| WHERE '(' a_expr ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| key_actions: |
| key_update |
| { |
| KeyActions *n = palloc(sizeof(KeyActions)); |
| |
| n->updateAction = $1; |
| n->deleteAction = palloc(sizeof(KeyAction)); |
| n->deleteAction->action = FKCONSTR_ACTION_NOACTION; |
| n->deleteAction->cols = NIL; |
| $$ = n; |
| } |
| | key_delete |
| { |
| KeyActions *n = palloc(sizeof(KeyActions)); |
| |
| n->updateAction = palloc(sizeof(KeyAction)); |
| n->updateAction->action = FKCONSTR_ACTION_NOACTION; |
| n->updateAction->cols = NIL; |
| n->deleteAction = $1; |
| $$ = n; |
| } |
| | key_update key_delete |
| { |
| KeyActions *n = palloc(sizeof(KeyActions)); |
| |
| n->updateAction = $1; |
| n->deleteAction = $2; |
| $$ = n; |
| } |
| | key_delete key_update |
| { |
| KeyActions *n = palloc(sizeof(KeyActions)); |
| |
| n->updateAction = $2; |
| n->deleteAction = $1; |
| $$ = n; |
| } |
| | /*EMPTY*/ |
| { |
| KeyActions *n = palloc(sizeof(KeyActions)); |
| |
| n->updateAction = palloc(sizeof(KeyAction)); |
| n->updateAction->action = FKCONSTR_ACTION_NOACTION; |
| n->updateAction->cols = NIL; |
| n->deleteAction = palloc(sizeof(KeyAction)); |
| n->deleteAction->action = FKCONSTR_ACTION_NOACTION; |
| n->deleteAction->cols = NIL; |
| $$ = n; |
| } |
| ; |
| |
| key_update: ON UPDATE key_action |
| { |
| if (($3)->cols) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("a column list with %s is only supported for ON DELETE actions", |
| ($3)->action == FKCONSTR_ACTION_SETNULL ? "SET NULL" : "SET DEFAULT"), |
| parser_errposition(@1))); |
| $$ = $3; |
| } |
| ; |
| |
| key_delete: ON DELETE_P key_action |
| { |
| $$ = $3; |
| } |
| ; |
| |
| key_action: |
| NO ACTION |
| { |
| KeyAction *n = palloc(sizeof(KeyAction)); |
| |
| n->action = FKCONSTR_ACTION_NOACTION; |
| n->cols = NIL; |
| $$ = n; |
| } |
| | RESTRICT |
| { |
| KeyAction *n = palloc(sizeof(KeyAction)); |
| |
| n->action = FKCONSTR_ACTION_RESTRICT; |
| n->cols = NIL; |
| $$ = n; |
| } |
| | CASCADE |
| { |
| KeyAction *n = palloc(sizeof(KeyAction)); |
| |
| n->action = FKCONSTR_ACTION_CASCADE; |
| n->cols = NIL; |
| $$ = n; |
| } |
| | SET NULL_P opt_column_list |
| { |
| KeyAction *n = palloc(sizeof(KeyAction)); |
| |
| n->action = FKCONSTR_ACTION_SETNULL; |
| n->cols = $3; |
| $$ = n; |
| } |
| | SET DEFAULT opt_column_list |
| { |
| KeyAction *n = palloc(sizeof(KeyAction)); |
| |
| n->action = FKCONSTR_ACTION_SETDEFAULT; |
| n->cols = $3; |
| $$ = n; |
| } |
| ; |
| |
| OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /* |
| * For historical reasons, in GPDB the PARTITION BY clause can also be given |
| * at the end of CREATE TABLE. OptTailPartitionSpec is identical to |
| * OptPartitionSpec, but it's used at the end of CreateStmt rules, |
| * after all the other options. We have to play some bison tricks to avoid |
| * shift/reduce conflicts. |
| * |
| * The CREATE TABLE syntax looks like this: |
| * |
| * CREATE TABLE name (...) |
| * [PARTITION BY ...] [optional WITH/USING/INHERITS clauses] [PARTITION BY ...] |
| * |
| * This produces a shift/reduce conflict: if there are no WITH/USING/INHERITS |
| * options, it is ambiguous which [PARTITION BY ...] rule should capture the |
| * PARTITION BY clause. |
| * |
| * To work around that, we set the 'tail_partition_tie_in' flag before doing |
| * lookahead. It instructs the scanner to return the special PARTITION_TAIL |
| * token if the next word is "PARTITION", instead of the usual PARTITION |
| * token. This allows us to avoid ambiguity in the CreateStmt rules: as far |
| * as bison is concerned, "PARTITION BY" and "PARTITION_TAIL BY" look |
| * different, even though the actual user-visible syntax is the same. |
| * |
| * I think the proper way to solve this would be to play with %prec |
| * declarations. However, I couldn't get it to work. Furthermore, since this |
| * is a GPDB extension, it's good to avoid changing the upstream rules, |
| * because that always makes merging with upstream harder. This is a fairly |
| * isolated work-around, even if it's a bit ugly. |
| */ |
| |
| /* Optional partition key specification (at the position where PostgreSQL has it) */ |
| OptFirstPartitionSpec: PartitionSpec opt_list_subparts OptTabPartitionSpec |
| { |
| $1->gpPartDef = (GpPartitionDefinition *) $3; |
| $1->subPartSpec = (PartitionSpec *) $2; |
| /* |
| * Only if GPDB legacy partition syntax, check for expression in partition |
| * key. If gpPartDef is present then only its legacy syntax. |
| */ |
| if ($1->gpPartDef) |
| check_expressions_in_partition_key($1, yyscanner); |
| $$ = $1; |
| /* Do not allow SUBPARTITION BY clause for empty partition hierarchy */ |
| if (!$1->gpPartDef && $1->subPartSpec) |
| ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("SUBPARTITION BY clause is not allowed when no partitions specified at depth 1"))); |
| |
| pg_yyget_extra(yyscanner)->tail_partition_magic = true; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| |
| pg_yyget_extra(yyscanner)->tail_partition_magic = true; |
| } |
| ; |
| |
| OptSecondPartitionSpec: |
| PARTITION_TAIL BY ColId '(' part_params ')' opt_list_subparts OptTabPartitionSpec |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| |
| n->strategy = parsePartitionStrategy($3); |
| n->partParams = $5; |
| n->gpPartDef = (GpPartitionDefinition *) $8; |
| n->subPartSpec = (PartitionSpec *) $7; |
| n->location = @1; |
| /* |
| * Only if GPDB legacy partition syntax, check for expression in partition |
| * key. If gpPartDef is present then only its legacy syntax. |
| */ |
| if (n->gpPartDef) |
| check_expressions_in_partition_key(n, yyscanner); |
| |
| /* Do not allow SUBPARTITION BY clause for empty partition hierarchy */ |
| if (!n->gpPartDef && n->subPartSpec) |
| ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("SUBPARTITION BY clause is not allowed when no partitions specified at depth 1"))); |
| |
| $$ = n; |
| |
| pg_yyget_extra(yyscanner)->tail_partition_magic = false; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| |
| pg_yyget_extra(yyscanner)->tail_partition_magic = false; |
| } |
| ; |
| |
| PartitionSpec: PARTITION BY ColId '(' part_params ')' |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| |
| n->strategy = parsePartitionStrategy($3); |
| n->partParams = $5; |
| n->location = @1; |
| |
| $$ = n; |
| } |
| ; |
| |
| part_params: part_elem { $$ = list_make1($1); } |
| | part_params ',' part_elem { $$ = lappend($1, $3); } |
| ; |
| |
| part_elem: ColId opt_collate opt_qualified_name |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->name = $1; |
| n->expr = NULL; |
| n->collation = $2; |
| n->opclass = $3; |
| n->location = @1; |
| $$ = n; |
| } |
| | func_expr_windowless opt_collate opt_qualified_name |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->name = NULL; |
| n->expr = $1; |
| n->collation = $2; |
| n->opclass = $3; |
| n->location = @1; |
| $$ = n; |
| } |
| | '(' a_expr ')' opt_collate opt_qualified_name |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->name = NULL; |
| n->expr = $2; |
| n->collation = $4; |
| n->opclass = $5; |
| n->location = @1; |
| $$ = n; |
| } |
| ; |
| |
| table_access_method_clause: |
| USING name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* WITHOUT OIDS is legacy only */ |
| OptWith: |
| WITH reloptions { $$ = $2; } |
| | WITHOUT OIDS { $$ = NIL; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptWithLocation: |
| WITH LOCATION Sconst { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; } |
| | ON COMMIT DELETE_P ROWS { $$ = ONCOMMIT_DELETE_ROWS; } |
| | ON COMMIT PRESERVE ROWS { $$ = ONCOMMIT_PRESERVE_ROWS; } |
| | /*EMPTY*/ { $$ = ONCOMMIT_NOOP; } |
| ; |
| |
| OptTableSpace: TABLESPACE name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ExistingIndex: USING INDEX name { $$ = $3; } |
| ; |
| |
| DistributedBy: DISTRIBUTED BY '(' distributed_by_list ')' |
| { |
| DistributedBy *distributedBy = makeNode(DistributedBy); |
| distributedBy->ptype = POLICYTYPE_PARTITIONED; |
| distributedBy->numsegments = -1; |
| distributedBy->keyCols = $4; |
| $$ = (Node *)distributedBy; |
| } |
| | DISTRIBUTED RANDOMLY |
| { |
| DistributedBy *distributedBy = makeNode(DistributedBy); |
| distributedBy->ptype = POLICYTYPE_PARTITIONED; |
| distributedBy->numsegments = -1; |
| distributedBy->keyCols = NIL; |
| $$ = (Node *)distributedBy; |
| } |
| | DISTRIBUTED REPLICATED |
| { |
| DistributedBy *distributedBy = makeNode(DistributedBy); |
| distributedBy->ptype = POLICYTYPE_REPLICATED; |
| distributedBy->numsegments = -1; |
| distributedBy->keyCols = NIL; |
| $$ = (Node *)distributedBy; |
| } |
| ; |
| |
| OptDistributedBy: DistributedBy |
| { |
| /* |
| * In singlenode mode, distributed by clause has no real effect. |
| * We simply ignore it and issue a warning to ensure compatibility. |
| */ |
| if (IS_SINGLENODE()) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("DISTRIBUTED BY clause has no effect in singlenode mode"))); |
| $$ = NULL; |
| } |
| else |
| $$ = $1; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* START GPDB LEGACY PARTITION SYNTAX RULES */ |
| |
| OptTabPartitionColumnEncList: TabPartitionColumnEncList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| TabPartitionColumnEncList: |
| column_reference_storage_directive { $$ = list_make1($1); } |
| | TabPartitionColumnEncList column_reference_storage_directive |
| { |
| $$ = lappend($1, $2); |
| } |
| ; |
| |
| OptTabPartitionSpec: '(' TabPartitionElemList ')' |
| { |
| GpPartitionDefinition *n = makeNode(GpPartitionDefinition); |
| n->partDefElems = $2; |
| n->fromCatalog = false; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabSubPartitionSpec: |
| '(' TabSubPartitionElemList ')' |
| { |
| GpPartitionDefinition *n = makeNode(GpPartitionDefinition); |
| n->partDefElems = $2; |
| n->fromCatalog = false; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| TabPartitionElemList: |
| TabPartitionElem { $$ = list_make1($1); } |
| | TabPartitionElemList ',' |
| TabPartitionElem { $$ = lappend($1, $3); } |
| ; |
| TabSubPartitionElemList: |
| TabSubPartitionElem { $$ = list_make1($1); } |
| | TabSubPartitionElemList ',' |
| TabSubPartitionElem { $$ = lappend($1, $3); } |
| ; |
| |
| tab_part_val_no_paran: AexprConst { $$ = $1; } |
| | CAST '(' tab_part_val AS Typename ')' |
| { |
| $$ = makeTypeCast($3, $5, @4); |
| } |
| | tab_part_val_no_paran TYPECAST Typename |
| { |
| $$ = makeTypeCast($1, $3, @2); |
| } |
| | '-' tab_part_val_no_paran { $$ = doNegate($2, @1); } |
| ; |
| |
| tab_part_val: tab_part_val_no_paran { $$ = $1; } |
| | '(' tab_part_val_no_paran ')' { $$ = $2; } |
| | '(' tab_part_val_no_paran ')' TYPECAST Typename |
| { |
| $$ = makeTypeCast($2, $5, @4); |
| } |
| ; |
| |
| TabPartitionBoundarySpecValList: |
| tab_part_val { $$ = list_make1($1); } |
| | TabPartitionBoundarySpecValList ',' |
| tab_part_val { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * In PostgreSQL, the RANGE FROM is always inclusive and the RANGE TO |
| * exclusive, but the old Cloudberry syntax with START/END is more |
| * flexible. |
| */ |
| OptTabPartitionRangeInclusive: |
| INCLUSIVE { $$ = PART_EDGE_INCLUSIVE; } |
| | EXCLUSIVE { $$ = PART_EDGE_EXCLUSIVE; } |
| | /*EMPTY*/ { $$ = PART_EDGE_UNSPECIFIED; } |
| ; |
| |
| TabPartitionBoundarySpecStart: |
| START |
| '(' expr_list ')' |
| OptTabPartitionRangeInclusive |
| { |
| GpPartitionRangeItem *n = makeNode(GpPartitionRangeItem); |
| n->val = $3; |
| if (($5)) |
| n->edge = $5; |
| else |
| n->edge = PART_EDGE_INCLUSIVE; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| TabPartitionBoundarySpecEnd: |
| END_P |
| '(' expr_list ')' |
| OptTabPartitionRangeInclusive |
| { |
| GpPartitionRangeItem *n = makeNode(GpPartitionRangeItem); |
| n->val = $3; |
| if (($5)) |
| n->edge = $5; |
| else |
| n->edge = PART_EDGE_EXCLUSIVE; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptTabPartitionBoundarySpecEvery: |
| EVERY '(' expr_list ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabPartitionBoundarySpecEnd: |
| TabPartitionBoundarySpecEnd { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* VALUES for LIST, start..end for RANGE. */ |
| TabPartitionBoundarySpec: |
| part_values_clause |
| { |
| GpPartitionListSpec *n = makeNode(GpPartitionListSpec); |
| |
| n->partValues = $1; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecStart |
| OptTabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| GpPartitionRangeSpec *n = makeNode(GpPartitionRangeSpec); |
| n->partStart = (GpPartitionRangeItem *)$1; |
| n->partEnd = (GpPartitionRangeItem *)$2; |
| n->partEvery = $3; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| GpPartitionRangeSpec *n = makeNode(GpPartitionRangeSpec); |
| n->partStart = NULL; |
| n->partEnd = (GpPartitionRangeItem *)$1; |
| n->partEvery = $2; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptTabPartitionBoundarySpec: |
| TabPartitionBoundarySpec { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /* VALUES for LIST, start..end for RANGE. */ |
| TabAddPartitionBoundarySpec: |
| part_values_clause |
| { |
| GpPartitionListSpec *n = makeNode(GpPartitionListSpec); |
| |
| n->partValues = $1; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecStart |
| OptTabPartitionBoundarySpecEnd |
| { |
| GpPartitionRangeSpec *n = makeNode(GpPartitionRangeSpec); |
| n->partStart = (GpPartitionRangeItem *)$1; |
| n->partEnd = (GpPartitionRangeItem *)$2; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecEnd |
| { |
| GpPartitionRangeSpec *n = makeNode(GpPartitionRangeSpec); |
| n->partStart = NULL; |
| n->partEnd = (GpPartitionRangeItem *)$1; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptTabAddPartitionBoundarySpec: |
| TabAddPartitionBoundarySpec { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| multi_spec_value_list: '(' part_values_single ')' |
| { |
| ListCell *lc; |
| List *out = NIL; |
| |
| foreach(lc, $2) |
| out = lappend(out, linitial(lfirst(lc))); |
| |
| $$ = list_make1(out); |
| } |
| | multi_spec_value_list ',' '(' part_values_single ')' |
| { |
| ListCell *lc; |
| List *out = NIL; |
| |
| foreach(lc, $4) |
| out = lappend(out, linitial(lfirst(lc))); |
| |
| $$ = lappend($1, out); |
| } |
| ; |
| |
| part_values_single: tab_part_val_no_paran |
| { |
| $$ = list_make1(list_make1($1)); |
| } |
| | part_values_single ',' tab_part_val_no_paran |
| { |
| $$ = lappend($1, list_make1($3)); |
| } |
| ; |
| |
| part_values_clause: |
| VALUES '(' part_values_single ')' |
| { |
| $$ = $3; |
| } |
| | VALUES '(' multi_spec_value_list ')' |
| { |
| $$ = $3; |
| } |
| ; |
| |
| part_values_or_spec_list: TabPartitionBoundarySpecValList { $$ = $1; } |
| | part_values_clause { $$ = $1; } |
| ; |
| |
| /* a "Partition Element" closely corresponds to a "Partition Declaration" */ |
| TabPartitionElem: |
| TabPartitionNameDecl |
| OptTabPartitionBoundarySpec OptWith OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $6; |
| n->location = @1; |
| n->isDefault = 0; |
| n->options = $3; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $4; |
| n->colencs = $5; |
| $$ = (Node *)n; |
| } |
| |
| | TabPartitionDefaultNameDecl |
| OptWith |
| OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = $1; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = true; |
| n->options = $2; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $3; |
| n->colencs = $4; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpec |
| OptWith |
| OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = NULL; |
| n->boundSpec = $1; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = 0; |
| n->options = $2; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $3; |
| n->colencs = $4; |
| $$ = (Node *)n; |
| } |
| | column_reference_storage_directive |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| TabSubPartitionElem: |
| TabSubPartitionNameDecl OptTabPartitionBoundarySpec |
| OptWith |
| OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $6; |
| n->location = @1; |
| n->isDefault = 0; |
| n->options = $3; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $4; |
| n->colencs = $5; |
| $$ = (Node *)n; |
| } |
| |
| | TabSubPartitionDefaultNameDecl |
| OptWith |
| OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = $1; |
| n->boundSpec = NULL; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = true; |
| n->options = $2; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $3; |
| n->colencs = $4; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpec |
| OptWith |
| OptTableSpace |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| GpPartDefElem *n = makeNode(GpPartDefElem); |
| n->partName = NULL; |
| n->boundSpec = $1; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = false; |
| n->colencs = $4; |
| n->options = $2; |
| n->accessMethod = greenplumLegacyAOoptions(NULL, &n->options); |
| n->tablespacename = $3; |
| $$ = (Node *)n; |
| } |
| | column_reference_storage_directive |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| TabPartitionNameDecl: PARTITION PartitionColId |
| { |
| $$ = $2; |
| } |
| ; |
| TabPartitionDefaultNameDecl: DEFAULT PARTITION PartitionColId |
| { |
| $$ = $3; |
| } |
| ; |
| |
| TabSubPartitionNameDecl: SUBPARTITION PartitionColId |
| { |
| $$ = $2; |
| } |
| ; |
| |
| TabSubPartitionDefaultNameDecl: DEFAULT SUBPARTITION PartitionColId |
| { |
| $$ = $3; |
| } |
| ; |
| |
| TabSubPartitionTemplate: |
| SUBPARTITION TEMPLATE |
| '(' TabSubPartitionElemList ')' |
| { |
| GpPartitionDefinition *n = makeNode(GpPartitionDefinition); |
| n->partDefElems = $4; |
| n->isTemplate = true; |
| n->fromCatalog = false; |
| n->location = @3; |
| $$ = (Node *)n; |
| |
| /* a little (temporary?) syntax check on templates */ |
| if (n->partDefElems) |
| { |
| List *elems; |
| ListCell *lc; |
| Assert(IsA(n->partDefElems, List)); |
| |
| elems = (List *)n->partDefElems; |
| foreach(lc, elems) |
| { |
| GpPartDefElem *e = lfirst(lc); |
| |
| if (!IsA(e, GpPartDefElem)) continue; |
| |
| if (e->subSpec) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("template cannot contain specification for child partition"))); |
| } |
| } |
| } |
| ; |
| |
| opt_list_subparts: TabSubPartition { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| TabSubPartitionBy: SUBPARTITION BY |
| ColId '(' part_params ')' |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| |
| n->strategy = parsePartitionStrategy($3); |
| n->partParams = $5; |
| n->location = @1; |
| |
| check_expressions_in_partition_key(n, yyscanner); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| TabSubPartition: |
| TabSubPartitionBy TabSubPartitionTemplate |
| { |
| PartitionSpec *n = (PartitionSpec *) $1; |
| n->gpPartDef = (GpPartitionDefinition *) $2; |
| |
| $$ = $1; |
| } |
| | TabSubPartitionBy { $$ = $1; } |
| | TabSubPartitionBy TabSubPartition |
| { |
| PartitionSpec *n = (PartitionSpec *) $1; |
| n->subPartSpec = (PartitionSpec *) $2; |
| |
| $$ = $1; |
| } |
| | TabSubPartitionBy TabSubPartitionTemplate TabSubPartition |
| { |
| PartitionSpec *n = (PartitionSpec *) $1; |
| n->gpPartDef = (GpPartitionDefinition *) $2; |
| n->subPartSpec = (PartitionSpec *) $3; |
| |
| $$ = $1; |
| } |
| ; |
| /* END GPDB LEGACY PARTITION SYNTAX RULES */ |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE STATISTICS [[IF NOT EXISTS] stats_name] [(stat types)] |
| * ON expression-list FROM from_list |
| * |
| * Note: the expectation here is that the clauses after ON are a subset of |
| * SELECT syntax, allowing for expressions and joined tables, and probably |
| * someday a WHERE clause. Much less than that is currently implemented, |
| * but the grammar accepts it and then we'll throw FEATURE_NOT_SUPPORTED |
| * errors as necessary at execution. |
| * |
| * Statistics name is optional unless IF NOT EXISTS is specified. |
| * |
| *****************************************************************************/ |
| |
| CreateStatsStmt: |
| CREATE STATISTICS opt_qualified_name |
| opt_name_list ON stats_params FROM from_list |
| { |
| CreateStatsStmt *n = makeNode(CreateStatsStmt); |
| |
| n->defnames = $3; |
| n->stat_types = $4; |
| n->exprs = $6; |
| n->relations = $8; |
| n->stxcomment = NULL; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE STATISTICS IF_P NOT EXISTS any_name |
| opt_name_list ON stats_params FROM from_list |
| { |
| CreateStatsStmt *n = makeNode(CreateStatsStmt); |
| |
| n->defnames = $6; |
| n->stat_types = $7; |
| n->exprs = $9; |
| n->relations = $11; |
| n->stxcomment = NULL; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * Statistics attributes can be either simple column references, or arbitrary |
| * expressions in parens. For compatibility with index attributes permitted |
| * in CREATE INDEX, we allow an expression that's just a function call to be |
| * written without parens. |
| */ |
| |
| stats_params: stats_param { $$ = list_make1($1); } |
| | stats_params ',' stats_param { $$ = lappend($1, $3); } |
| ; |
| |
| stats_param: ColId |
| { |
| $$ = makeNode(StatsElem); |
| $$->name = $1; |
| $$->expr = NULL; |
| } |
| | func_expr_windowless |
| { |
| $$ = makeNode(StatsElem); |
| $$->name = NULL; |
| $$->expr = $1; |
| } |
| | '(' a_expr ')' |
| { |
| $$ = makeNode(StatsElem); |
| $$->name = NULL; |
| $$->expr = $2; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER STATISTICS [IF EXISTS] stats_name |
| * SET STATISTICS <SignedIconst> |
| * |
| *****************************************************************************/ |
| |
| AlterStatsStmt: |
| ALTER STATISTICS any_name SET STATISTICS SignedIconst |
| { |
| AlterStatsStmt *n = makeNode(AlterStatsStmt); |
| |
| n->defnames = $3; |
| n->missing_ok = false; |
| n->stxstattarget = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER STATISTICS IF_P EXISTS any_name SET STATISTICS SignedIconst |
| { |
| AlterStatsStmt *n = makeNode(AlterStatsStmt); |
| |
| n->defnames = $5; |
| n->missing_ok = true; |
| n->stxstattarget = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE TABLE relname AS SelectStmt [ WITH [NO] DATA ] |
| * |
| * |
| * Note: SELECT ... INTO is a now-deprecated alternative for this. |
| * |
| *****************************************************************************/ |
| |
| CreateAsStmt: |
| CREATE OptTemp TABLE create_as_target AS SelectStmt opt_with_data OptDistributedBy OptFirstPartitionSpec |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| |
| /* reset the hack set in OptFirstPartitionSpec */ |
| pg_yyget_extra(yyscanner)->tail_partition_magic = false; |
| |
| ctas->query = $6; |
| ctas->into = $4; |
| ctas->objtype = OBJECT_TABLE; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = false; |
| /* cram additional flags into the IntoClause */ |
| $4->rel->relpersistence = $2; |
| ctas->into->distributedBy = $8; |
| |
| if ($9) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("cannot create a partitioned table using CREATE TABLE AS SELECT"), |
| errhint("Use CREATE TABLE...LIKE (followed by INSERT...SELECT) instead."))); |
| |
| $4->skipData = !($7); |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS SelectStmt opt_with_data |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| |
| ctas->query = $9; |
| ctas->into = $7; |
| ctas->objtype = OBJECT_TABLE; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = true; |
| /* cram additional flags into the IntoClause */ |
| $7->rel->relpersistence = $2; |
| $7->skipData = !($10); |
| $$ = (Node *) ctas; |
| } |
| ; |
| |
| create_as_target: |
| qualified_name opt_column_list table_access_method_clause |
| OptWith OnCommitOption OptTableSpace |
| { |
| $$ = makeNode(IntoClause); |
| $$->rel = $1; |
| $$->colNames = $2; |
| $$->accessMethod = $3; |
| $$->options = $4; |
| $$->onCommit = $5; |
| $$->tableSpaceName = $6; |
| $$->viewQuery = NULL; |
| $$->skipData = false; /* might get changed later */ |
| |
| $$->accessMethod = greenplumLegacyAOoptions($$->accessMethod, &$$->options); |
| } |
| ; |
| |
| opt_with_data: |
| WITH DATA_P { $$ = true; } |
| | WITH NO DATA_P { $$ = false; } |
| | /*EMPTY*/ { $$ = true; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE EXTERNAL [WEB] TABLE relname |
| * |
| *****************************************************************************/ |
| |
| CreateExternalStmt: CREATE OptWritable EXTERNAL OptWeb OptTemp TABLE qualified_name '(' OptExtTableElementList ')' |
| ExtTypedesc FORMAT Sconst format_opt ext_options_opt ext_opt_encoding_list ExtSingleRowErrorHandling OptDistributedBy OptTagOptList |
| { |
| CreateExternalStmt *n = makeNode(CreateExternalStmt); |
| n->iswritable = $2; |
| n->isweb = $4; |
| $7->relpersistence = $5; |
| n->relation = $7; |
| n->tableElts = $9; |
| n->exttypedesc = (ExtTableTypeDesc *) $11; |
| n->format = $13; |
| n->formatOpts = $14; |
| n->extOptions = $15; |
| n->encoding = $16; |
| n->sreh = $17; |
| n->distributedBy = (DistributedBy *) $18; |
| n->tags = $19; |
| |
| /* various syntax checks for EXECUTE external table */ |
| if(((ExtTableTypeDesc *) n->exttypedesc)->exttabletype == EXTTBL_TYPE_EXECUTE) |
| { |
| ExtTableTypeDesc *extdesc = (ExtTableTypeDesc *) n->exttypedesc; |
| |
| if(!n->isweb) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("EXECUTE may not be used with a regular external table"), |
| errhint("Use CREATE EXTERNAL WEB TABLE instead."))); |
| |
| /* if no ON clause specified, default to "ON ALL" */ |
| if(extdesc->on_clause == NIL) |
| { |
| extdesc->on_clause = lappend(extdesc->on_clause, |
| makeDefElem("all", (Node *)makeInteger(true), @1)); |
| } |
| else if(n->iswritable) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("ON clause may not be used with a writable external table"))); |
| } |
| } |
| |
| if(n->sreh && n->iswritable) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("single row error handling may not be used with a writable external table"))); |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptWritable: WRITABLE { $$ = true; } |
| | READABLE { $$ = false; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| OptWeb: WEB { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| ExtTypedesc: |
| LOCATION '(' cdb_string_list ')' ext_on_clause_list |
| { |
| ExtTableTypeDesc *n = makeNode(ExtTableTypeDesc); |
| n->exttabletype = EXTTBL_TYPE_LOCATION; |
| n->location_list = $3; |
| n->on_clause = $5; |
| n->command_string = NULL; |
| $$ = (Node *)n; |
| |
| } |
| | EXECUTE Sconst ext_on_clause_list |
| { |
| ExtTableTypeDesc *n = makeNode(ExtTableTypeDesc); |
| n->exttabletype = EXTTBL_TYPE_EXECUTE; |
| n->location_list = NIL; |
| n->command_string = $2; |
| n->on_clause = $3; /* default will get set later if needed */ |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ext_on_clause_list: |
| ext_on_clause_list ext_on_clause_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ext_on_clause_item: |
| ON ALL |
| { |
| $$ = makeDefElem("all", (Node *)makeInteger(true), @1); |
| } |
| | ON HOST Sconst |
| { |
| $$ = makeDefElem("hostname", (Node *)makeString($3), @1); |
| } |
| | ON HOST |
| { |
| $$ = makeDefElem("eachhost", (Node *)makeInteger(true), @1); |
| } |
| | ON MASTER |
| { |
| $$ = makeDefElem("coordinator", (Node *)makeInteger(true), @1); |
| } |
| | ON COORDINATOR |
| { |
| $$ = makeDefElem("coordinator", (Node *)makeInteger(true), @1); |
| } |
| | ON SEGMENT Iconst |
| { |
| $$ = makeDefElem("segment", (Node *)makeInteger($3), @1); |
| } |
| | ON Iconst |
| { |
| $$ = makeDefElem("random", (Node *)makeInteger($2), @1); |
| } |
| ; |
| |
| format_opt: |
| '(' format_opt_list ')' { $$ = $2; } |
| | '(' format_def_list ')' { $$ = $2; } |
| | '(' ')' { $$ = NIL; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| format_opt_list: |
| format_opt_item |
| { |
| $$ = list_make1($1); |
| } |
| | format_opt_list format_opt_item |
| { |
| $$ = lappend($1, $2); |
| } |
| ; |
| |
| format_def_list: |
| format_def_item |
| { |
| $$ = list_make1($1); |
| } |
| | format_def_list ',' format_def_item |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| format_def_item: |
| ColLabel '=' def_arg |
| { |
| $$ = makeDefElem($1, $3, @1); |
| } |
| | ColLabel '=' '(' columnList ')' |
| { |
| $$ = makeDefElem($1, (Node *) $4, @1); |
| } |
| ; |
| |
| format_opt_item: |
| DELIMITER opt_as Sconst |
| { |
| $$ = makeDefElem("delimiter", (Node *)makeString($3), @1); |
| } |
| | NULL_P opt_as Sconst |
| { |
| $$ = makeDefElem("null", (Node *)makeString($3), @1); |
| } |
| | CSV |
| { |
| $$ = makeDefElem("csv", (Node *)makeInteger(true), @1); |
| } |
| | HEADER_P |
| { |
| $$ = makeDefElem("header", (Node *)makeInteger(true), @1); |
| } |
| | QUOTE opt_as Sconst |
| { |
| $$ = makeDefElem("quote", (Node *)makeString($3), @1); |
| } |
| | ESCAPE opt_as Sconst |
| { |
| $$ = makeDefElem("escape", (Node *)makeString($3), @1); |
| } |
| | FORCE NOT NULL_P columnList |
| { |
| $$ = makeDefElem("force_not_null", (Node *)$4, @1); |
| } |
| | FORCE QUOTE columnList |
| { |
| $$ = makeDefElem("force_quote", (Node *)$3, @1); |
| } |
| | FORCE QUOTE '*' |
| { |
| $$ = makeDefElem("force_quote", (Node *)makeNode(A_Star), @1); |
| } |
| | FILL MISSING FIELDS |
| { |
| $$ = makeDefElem("fill_missing_fields", (Node *)makeInteger(true), @1); |
| } |
| | NEWLINE opt_as Sconst |
| { |
| $$ = makeDefElem("newline", (Node *)makeString($3), @1); |
| } |
| ; |
| |
| ext_options_opt: |
| OPTIONS ext_options { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ext_options: |
| '(' ext_options_list ')' { $$ = $2; } |
| | '(' ')' { $$ = NIL; } |
| ; |
| |
| ext_options_list: |
| ext_options_item |
| { |
| $$ = list_make1($1); |
| } |
| | ext_options_list ',' ext_options_item |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| ext_options_item: |
| ColLabel Sconst |
| { |
| $$ = makeDefElem($1, (Node *)makeString($2), @1); |
| } |
| ; |
| |
| OptExtTableElementList: |
| ExtTableElementList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ExtTableElementList: |
| ExtTableElement |
| { |
| $$ = list_make1($1); |
| } |
| | ExtTableElementList ',' ExtTableElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| ExtTableElement: |
| ExtcolumnDef { $$ = $1; } |
| | TableLikeClause { $$ = $1; } |
| ; |
| |
| /* column def for ext table - doesn't have room for constraints */ |
| ExtcolumnDef: ColId Typename |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| n->colname = $1; |
| n->typeName = $2; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->constraints = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Single row error handling SQL |
| */ |
| OptSingleRowErrorHandling: |
| OptLogErrorTable SEGMENT REJECT_P LIMIT Iconst OptSrehLimitType |
| { |
| SingleRowErrorDesc *n = makeNode(SingleRowErrorDesc); |
| n->log_error_type = $1; |
| n->rejectlimit = $5; |
| n->is_limit_in_rows = $6; /* true for ROWS false for PERCENT */ |
| |
| /* PERCENT value check */ |
| if(!n->is_limit_in_rows && (n->rejectlimit < 1 || n->rejectlimit > 100)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid PERCENT value. Should be (1 - 100)"))); |
| |
| /* ROW values check */ |
| if(n->is_limit_in_rows && n->rejectlimit < 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid (ROWS) reject limit. Should be 2 or larger"))); |
| |
| $$ = lappend(NULL, makeDefElem("sreh", (Node *) n, @1)); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptLogErrorTable: |
| LOG_P ERRORS INTO qualified_name |
| { |
| if (gp_ignore_error_table) /* ignore the [INTO error-table] clause for backward compatibility */ |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("error table is not supported"), |
| errhint("Use gp_read_error_log() and gp_truncate_error_log() to view and manage the internal error log associated with your table."))); |
| } |
| else |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("error table is not supported"), |
| errhint("Set gp_ignore_error_table to ignore the [INTO error-table] clause for backward compatibility."), |
| parser_errposition(@3))); |
| } |
| $$ = 't'; |
| } |
| | LOG_P ERRORS { $$ = 't'; } |
| | /*EMPTY*/ { $$ = 'f'; } |
| ; |
| |
| /* |
| * External table Single row error handling SQL |
| */ |
| ExtSingleRowErrorHandling: |
| ExtLogErrorTable SEGMENT REJECT_P LIMIT Iconst OptSrehLimitType |
| { |
| SingleRowErrorDesc *n = makeNode(SingleRowErrorDesc); |
| n->log_error_type = $1; |
| n->rejectlimit = $5; |
| n->is_limit_in_rows = $6; /* true for ROWS false for PERCENT */ |
| |
| /* PERCENT value check */ |
| if(!n->is_limit_in_rows && (n->rejectlimit < 1 || n->rejectlimit > 100)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid PERCENT value. Should be (1 - 100)"))); |
| |
| /* ROW values check */ |
| if(n->is_limit_in_rows && n->rejectlimit < 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid (ROWS) reject limit. Should be 2 or larger"))); |
| |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ExtLogErrorTable: |
| OptLogErrorTable { $$ = $1; } |
| | LOG_P ERRORS PERSISTENTLY { $$ = 'p'; } |
| ; |
| |
| OptSrehLimitType: |
| ROWS { $$ = true; } |
| | PERCENT { $$ = false; } |
| | /* default is ROWS */ { $$ = true; } |
| ; |
| |
| /* |
| * ENCODING. (we cheat a little and use a list, even though it's 1 item max). |
| */ |
| ext_opt_encoding_list: |
| ext_opt_encoding_list ext_opt_encoding_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ext_opt_encoding_item: |
| ENCODING opt_equal Sconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeString($3), @1); |
| } |
| | ENCODING opt_equal Iconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeInteger($3), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE MATERIALIZED VIEW relname AS SelectStmt |
| * |
| *****************************************************************************/ |
| |
| CreateMatViewStmt: |
| CREATE OptNoLog incremental MATERIALIZED VIEW create_mv_target AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ctas->query = $8; |
| ctas->into = $6; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = false; |
| /* cram additional flags into the IntoClause */ |
| $6->rel->relpersistence = $2; |
| $6->skipData = !($9); |
| $6->ivm = $3; |
| ctas->into->distributedBy = $10; |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptNoLog incremental MATERIALIZED VIEW IF_P NOT EXISTS create_mv_target AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ctas->query = $11; |
| ctas->into = $9; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = true; |
| /* cram additional flags into the IntoClause */ |
| $9->rel->relpersistence = $2; |
| $9->skipData = !($12); |
| $9->ivm = $3; |
| ctas->into->distributedBy = $13; |
| $$ = (Node *) ctas; |
| } |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE DYNAMIC TABLE relname AS SelectStmt |
| * |
| *****************************************************************************/ |
| | CREATE OptNoLog DYNAMIC TABLE create_mv_target SCHEDULE task_schedule AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ctas->query = $9; |
| ctas->into = $5; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = false; |
| /* cram additional flags into the IntoClause */ |
| $5->rel->relpersistence = $2; |
| $5->skipData = !($10); |
| $5->dynamicTbl = true; |
| $5->schedule = $7; |
| ctas->into->distributedBy = $11; |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptNoLog DYNAMIC TABLE create_mv_target AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| |
| ctas->query = $7; |
| ctas->into = $5; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = false; |
| /* cram additional flags into the IntoClause */ |
| $5->rel->relpersistence = $2; |
| $5->skipData = !($8); |
| $5->dynamicTbl = true; |
| ctas->into->distributedBy = $9; |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptNoLog DYNAMIC TABLE create_mv_target IF_P NOT EXISTS SCHEDULE task_schedule AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| |
| ctas->query = $12; |
| ctas->into = $5; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = true; |
| /* cram additional flags into the IntoClause */ |
| $5->rel->relpersistence = $2; |
| $5->skipData = !($13); |
| $5->dynamicTbl = true; |
| $5->schedule = $10; |
| ctas->into->distributedBy = $14; |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptNoLog DYNAMIC TABLE create_mv_target IF_P NOT EXISTS AS SelectStmt opt_with_data OptDistributedBy |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ctas->query = $10; |
| ctas->into = $5; |
| ctas->objtype = OBJECT_MATVIEW; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = true; |
| /* cram additional flags into the IntoClause */ |
| $5->rel->relpersistence = $2; |
| $5->skipData = !($11); |
| $5->dynamicTbl = true; |
| ctas->into->distributedBy = $12; |
| $$ = (Node *) ctas; |
| } |
| ; |
| |
| create_mv_target: |
| qualified_name opt_column_list table_access_method_clause opt_reloptions OptTableSpace |
| { |
| $$ = makeNode(IntoClause); |
| $$->rel = $1; |
| $$->colNames = $2; |
| $$->accessMethod = $3; |
| $$->options = $4; |
| $$->onCommit = ONCOMMIT_NOOP; |
| $$->tableSpaceName = $5; |
| $$->viewQuery = NULL; /* filled at analysis time */ |
| $$->skipData = false; /* might get changed later */ |
| $$->ivm = false; |
| $$->dynamicTbl = false; |
| $$->schedule = NULL; |
| |
| $$->accessMethod = greenplumLegacyAOoptions($$->accessMethod, &$$->options); |
| } |
| ; |
| |
| incremental: INCREMENTAL { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| OptNoLog: UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; } |
| | /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * REFRESH MATERIALIZED VIEW qualified_name |
| * REFRESH DYNAMIC TABLE qualified_name |
| * |
| *****************************************************************************/ |
| |
| RefreshMatViewStmt: |
| REFRESH MATERIALIZED VIEW opt_concurrently qualified_name opt_with_data |
| { |
| RefreshMatViewStmt *n = makeNode(RefreshMatViewStmt); |
| |
| n->concurrent = $4; |
| n->relation = $5; |
| n->skipData = !($6); |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | REFRESH DYNAMIC TABLE opt_concurrently qualified_name opt_with_data |
| { |
| RefreshMatViewStmt *n = makeNode(RefreshMatViewStmt); |
| n->concurrent = $4; |
| n->relation = $5; |
| n->skipData = !($6); |
| n->isdynamic = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE SEQUENCE seqname |
| * ALTER SEQUENCE seqname |
| * |
| *****************************************************************************/ |
| |
| CreateSeqStmt: |
| CREATE OptTemp SEQUENCE qualified_name OptSeqOptList OptTagOptList |
| { |
| CreateSeqStmt *n = makeNode(CreateSeqStmt); |
| |
| $4->relpersistence = $2; |
| n->sequence = $4; |
| n->options = $5; |
| n->ownerId = InvalidOid; |
| n->if_not_exists = false; |
| n->tags = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList OptTagOptList |
| { |
| CreateSeqStmt *n = makeNode(CreateSeqStmt); |
| |
| $7->relpersistence = $2; |
| n->sequence = $7; |
| n->options = $8; |
| n->ownerId = InvalidOid; |
| n->if_not_exists = true; |
| n->tags = $9; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterSeqStmt: |
| ALTER SEQUENCE qualified_name SeqOptList |
| { |
| AlterSeqStmt *n = makeNode(AlterSeqStmt); |
| |
| n->sequence = $3; |
| n->options = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE IF_P EXISTS qualified_name SeqOptList |
| { |
| AlterSeqStmt *n = makeNode(AlterSeqStmt); |
| |
| n->sequence = $5; |
| n->options = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| |
| ; |
| |
| OptSeqOptList: SeqOptList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptParenthesizedSeqOptList: '(' SeqOptList ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| SeqOptList: SeqOptElem { $$ = list_make1($1); } |
| | SeqOptList SeqOptElem { $$ = lappend($1, $2); } |
| ; |
| |
| SeqOptElem: AS SimpleTypename |
| { |
| $$ = makeDefElem("as", (Node *) $2, @1); |
| } |
| | CACHE NumericOnly |
| { |
| $$ = makeDefElem("cache", (Node *) $2, @1); |
| } |
| | CYCLE |
| { |
| $$ = makeDefElem("cycle", (Node *) makeBoolean(true), @1); |
| } |
| | NO CYCLE |
| { |
| $$ = makeDefElem("cycle", (Node *) makeBoolean(false), @1); |
| } |
| | INCREMENT opt_by NumericOnly |
| { |
| $$ = makeDefElem("increment", (Node *) $3, @1); |
| } |
| | LOGGED |
| { |
| $$ = makeDefElem("logged", NULL, @1); |
| } |
| | MAXVALUE NumericOnly |
| { |
| $$ = makeDefElem("maxvalue", (Node *) $2, @1); |
| } |
| | MINVALUE NumericOnly |
| { |
| $$ = makeDefElem("minvalue", (Node *) $2, @1); |
| } |
| | NO MAXVALUE |
| { |
| $$ = makeDefElem("maxvalue", NULL, @1); |
| } |
| | NO MINVALUE |
| { |
| $$ = makeDefElem("minvalue", NULL, @1); |
| } |
| | OWNED BY any_name |
| { |
| $$ = makeDefElem("owned_by", (Node *) $3, @1); |
| } |
| | SEQUENCE NAME_P any_name |
| { |
| $$ = makeDefElem("sequence_name", (Node *) $3, @1); |
| } |
| | START opt_with NumericOnly |
| { |
| $$ = makeDefElem("start", (Node *) $3, @1); |
| } |
| | RESTART |
| { |
| $$ = makeDefElem("restart", NULL, @1); |
| } |
| | RESTART opt_with NumericOnly |
| { |
| $$ = makeDefElem("restart", (Node *) $3, @1); |
| } |
| | UNLOGGED |
| { |
| $$ = makeDefElem("unlogged", NULL, @1); |
| } |
| ; |
| |
| opt_by: BY |
| | /* EMPTY */ |
| ; |
| |
| NumericOnly: |
| FCONST { $$ = (Node *) makeFloat($1); } |
| | '+' FCONST { $$ = (Node *) makeFloat($2); } |
| | '-' FCONST |
| { |
| Float *f = makeFloat($2); |
| |
| doNegateFloat(f); |
| $$ = (Node *) f; |
| } |
| | SignedIconst { $$ = (Node *) makeInteger($1); } |
| ; |
| |
| NumericOnly_list: NumericOnly { $$ = list_make1($1); } |
| | NumericOnly_list ',' NumericOnly { $$ = lappend($1, $3); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE [OR REPLACE] [TRUSTED] [PROCEDURAL] LANGUAGE ... |
| * DROP [PROCEDURAL] LANGUAGE ... |
| * |
| *****************************************************************************/ |
| |
| CreatePLangStmt: |
| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE name |
| { |
| /* |
| * We now interpret parameterless CREATE LANGUAGE as |
| * CREATE EXTENSION. "OR REPLACE" is silently translated |
| * to "IF NOT EXISTS", which isn't quite the same, but |
| * seems more useful than throwing an error. We just |
| * ignore TRUSTED, as the previous code would have too. |
| */ |
| CreateExtensionStmt *n = makeNode(CreateExtensionStmt); |
| |
| n->if_not_exists = $2; |
| n->extname = $6; |
| n->options = NIL; |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE name |
| HANDLER handler_name opt_inline_handler opt_validator |
| { |
| CreatePLangStmt *n = makeNode(CreatePLangStmt); |
| |
| n->replace = $2; |
| n->plname = $6; |
| n->plhandler = $8; |
| n->plinline = $9; |
| n->plvalidator = $10; |
| n->pltrusted = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_trusted: |
| TRUSTED { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /* This ought to be just func_name, but that causes reduce/reduce conflicts |
| * (CREATE LANGUAGE is the only place where func_name isn't followed by '('). |
| * Work around by using simple names, instead. |
| */ |
| handler_name: |
| name { $$ = list_make1(makeString($1)); } |
| | name attrs { $$ = lcons(makeString($1), $2); } |
| ; |
| |
| opt_inline_handler: |
| INLINE_P handler_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| validator_clause: |
| VALIDATOR handler_name { $$ = $2; } |
| | NO VALIDATOR { $$ = NIL; } |
| ; |
| |
| opt_validator: |
| validator_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_procedural: |
| PROCEDURAL |
| | /*EMPTY*/ |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/' |
| * |
| *****************************************************************************/ |
| |
| CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions OptServer OptFileHandler OptTagOptList |
| { |
| CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); |
| List *fileHandler_list; |
| char *tmpfilehandler; |
| n->tablespacename = $3; |
| n->owner = $4; |
| n->location = $6; |
| n->options = $7; |
| |
| if ($8 != NULL) |
| { |
| n->options = lappend(n->options, $8); |
| n->options = lappend(n->options, |
| makeDefElem("path", (Node *)makeString($6), @6)); |
| } |
| n->filehandler = $9; |
| if (n->filehandler) |
| { |
| tmpfilehandler = pstrdup(n->filehandler); |
| if (tmpfilehandler && !SplitIdentifierString(tmpfilehandler, ',', &fileHandler_list)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid list syntax for \"handler\""), |
| parser_errposition(@9))); |
| if (tmpfilehandler && list_length(fileHandler_list) != 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid list syntax for \"handler\""), |
| parser_errposition(@9))); |
| } |
| n->tags = $10; |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; } |
| | /*EMPTY */ { $$ = NULL; } |
| ; |
| |
| OptServer: SERVER name { $$ = makeDefElem("server", (Node *)makeString($2), @1); } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| OptFileHandler: |
| HANDLER Sconst { $$ = $2; } |
| | HANDLER { $$ = NULL; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE TASK [IF NOT EXISTS] <name> SCHEDULE = '{ <num> SECONDS | <cron_expr> }' |
| * [ DATABASE <dbname>] |
| * [ USER <username>] |
| * AS |
| * <sql> |
| * |
| *****************************************************************************/ |
| |
| CreateTaskStmt: |
| CREATE TASK name SCHEDULE task_schedule OptTaskOptList AS task_command |
| { |
| CreateTaskStmt *n = makeNode(CreateTaskStmt); |
| n->taskname = $3; |
| n->schedule = $5; |
| n->options = $6; |
| n->sql = $8; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE TASK IF_P NOT EXISTS name SCHEDULE task_schedule OptTaskOptList AS task_command |
| { |
| CreateTaskStmt *n = makeNode(CreateTaskStmt); |
| n->taskname = $6; |
| n->schedule = $8; |
| n->options = $9; |
| n->sql = $11; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| OptTaskOptList: TaskOptList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TaskOptList: TaskOptElem { $$ = list_make1($1); } |
| | TaskOptList TaskOptElem { $$ = lappend($1, $2); } |
| ; |
| |
| TaskOptElem: DATABASE name |
| { |
| $$ = makeDefElem("dbname", (Node *)makeString($2), @1); |
| } |
| | USER name |
| { |
| $$ = makeDefElem("username", (Node *)makeString($2), @1); |
| } |
| ; |
| |
| task_schedule: |
| Sconst { $$ = $1; } |
| | NULL_P { $$ = NULL; } |
| ; |
| |
| task_command: |
| Sconst { $$ = $1; } |
| | NULL_P { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER TASK |
| * |
| *****************************************************************************/ |
| |
| AlterTaskStmt: |
| ALTER TASK name AlterTaskOptList |
| { |
| AlterTaskStmt *n = makeNode(AlterTaskStmt); |
| n->taskname = $3; |
| n->options = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TASK IF_P EXISTS name AlterTaskOptList |
| { |
| AlterTaskStmt *n = makeNode(AlterTaskStmt); |
| n->taskname = $5; |
| n->options = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterTaskOptList: AlterTaskElem { $$ = list_make1($1); } |
| | AlterTaskOptList AlterTaskElem { $$ = lappend($1, $2); } |
| ; |
| |
| AlterTaskElem: |
| SCHEDULE task_schedule |
| { |
| $$ = makeDefElem("schedule", (Node *)makeString($2), @1); |
| } |
| | DATABASE name |
| { |
| $$ = makeDefElem("dbname", (Node *)makeString($2), @1); |
| } |
| | USER name |
| { |
| $$ = makeDefElem("username", (Node *)makeString($2), @1); |
| } |
| | ACTIVE |
| { |
| $$ = makeDefElem("active", (Node *)makeInteger(true), @1); |
| } |
| | NOT ACTIVE |
| { |
| $$ = makeDefElem("active", (Node *)makeInteger(false), @1); |
| } |
| | AS task_command |
| { |
| $$ = makeDefElem("sql", (Node *)makeString($2), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * DROP TASK [ IF EXISTS ] <name> |
| * |
| *****************************************************************************/ |
| |
| DropTaskStmt: |
| DROP TASK name |
| { |
| DropTaskStmt *n = makeNode(DropTaskStmt); |
| n->taskname = $3; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP TASK IF_P EXISTS name |
| { |
| DropTaskStmt *n = makeNode(DropTaskStmt); |
| n->taskname = $5; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP TABLESPACE <tablespace> |
| * |
| * No need for drop behaviour as we cannot implement dependencies for |
| * objects in other databases; we can only support RESTRICT. |
| * |
| ****************************************************************************/ |
| |
| DropTableSpaceStmt: DROP TABLESPACE name |
| { |
| DropTableSpaceStmt *n = makeNode(DropTableSpaceStmt); |
| |
| n->tablespacename = $3; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP TABLESPACE IF_P EXISTS name |
| { |
| DropTableSpaceStmt *n = makeNode(DropTableSpaceStmt); |
| |
| n->tablespacename = $5; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE EXTENSION extension |
| * [ WITH ] [ SCHEMA schema ] [ VERSION version ] |
| * |
| *****************************************************************************/ |
| |
| CreateExtensionStmt: CREATE EXTENSION name opt_with create_extension_opt_list |
| { |
| CreateExtensionStmt *n = makeNode(CreateExtensionStmt); |
| |
| n->extname = $3; |
| n->if_not_exists = false; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | CREATE EXTENSION IF_P NOT EXISTS name opt_with create_extension_opt_list |
| { |
| CreateExtensionStmt *n = makeNode(CreateExtensionStmt); |
| |
| n->extname = $6; |
| n->if_not_exists = true; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| create_extension_opt_list: |
| create_extension_opt_list create_extension_opt_item |
| { $$ = lappend($1, $2); } |
| | /* EMPTY */ |
| { $$ = NIL; } |
| ; |
| |
| create_extension_opt_item: |
| SCHEMA name |
| { |
| $$ = makeDefElem("schema", (Node *) makeString($2), @1); |
| } |
| | VERSION_P NonReservedWord_or_Sconst |
| { |
| $$ = makeDefElem("new_version", (Node *) makeString($2), @1); |
| } |
| | FROM NonReservedWord_or_Sconst |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE EXTENSION ... FROM is no longer supported"), |
| parser_errposition(@1))); |
| } |
| | CASCADE |
| { |
| $$ = makeDefElem("cascade", (Node *) makeBoolean(true), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER EXTENSION name UPDATE [ TO version ] |
| * |
| *****************************************************************************/ |
| |
| AlterExtensionStmt: ALTER EXTENSION name UPDATE alter_extension_opt_list |
| { |
| AlterExtensionStmt *n = makeNode(AlterExtensionStmt); |
| |
| n->extname = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alter_extension_opt_list: |
| alter_extension_opt_list alter_extension_opt_item |
| { $$ = lappend($1, $2); } |
| | /* EMPTY */ |
| { $$ = NIL; } |
| ; |
| |
| alter_extension_opt_item: |
| TO NonReservedWord_or_Sconst |
| { |
| $$ = makeDefElem("new_version", (Node *) makeString($2), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER EXTENSION name ADD/DROP object-identifier |
| * |
| *****************************************************************************/ |
| |
| AlterExtensionContentsStmt: |
| ALTER EXTENSION name add_drop object_type_name name |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = $5; |
| n->object = (Node *) makeString($6); |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop object_type_any_name any_name |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = $5; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop AGGREGATE aggregate_with_argtypes |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_AGGREGATE; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')' |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_CAST; |
| n->object = (Node *) list_make2($7, $9); |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop DOMAIN_P Typename |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_DOMAIN; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop FUNCTION function_with_argtypes |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_FUNCTION; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop OPERATOR operator_with_argtypes |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_OPERATOR; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING name |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_OPCLASS; |
| n->object = (Node *) lcons(makeString($9), $7); |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING name |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_OPFAMILY; |
| n->object = (Node *) lcons(makeString($9), $7); |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop PROCEDURE function_with_argtypes |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_PROCEDURE; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop ROUTINE function_with_argtypes |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_ROUTINE; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop TRANSFORM FOR Typename LANGUAGE name |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_TRANSFORM; |
| n->object = (Node *) list_make2($7, makeString($9)); |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name add_drop TYPE_P Typename |
| { |
| AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); |
| |
| n->extname = $3; |
| n->action = $4; |
| n->objtype = OBJECT_TYPE; |
| n->object = (Node *) $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE FOREIGN DATA WRAPPER name options |
| * |
| *****************************************************************************/ |
| |
| CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options |
| { |
| CreateFdwStmt *n = makeNode(CreateFdwStmt); |
| |
| n->fdwname = $5; |
| n->func_options = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| fdw_option: |
| HANDLER handler_name { $$ = makeDefElem("handler", (Node *) $2, @1); } |
| | NO HANDLER { $$ = makeDefElem("handler", NULL, @1); } |
| | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *) $2, @1); } |
| | NO VALIDATOR { $$ = makeDefElem("validator", NULL, @1); } |
| ; |
| |
| fdw_options: |
| fdw_option { $$ = list_make1($1); } |
| | fdw_options fdw_option { $$ = lappend($1, $2); } |
| ; |
| |
| opt_fdw_options: |
| fdw_options { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER FOREIGN DATA WRAPPER name options |
| * |
| ****************************************************************************/ |
| |
| AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options |
| { |
| AlterFdwStmt *n = makeNode(AlterFdwStmt); |
| |
| n->fdwname = $5; |
| n->func_options = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name fdw_options |
| { |
| AlterFdwStmt *n = makeNode(AlterFdwStmt); |
| |
| n->fdwname = $5; |
| n->func_options = $6; |
| n->options = NIL; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* Options definition for CREATE FDW, SERVER, STORAGE SERVER and USER MAPPING */ |
| create_generic_options: |
| OPTIONS '(' generic_option_list ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| generic_option_list: |
| generic_option_elem |
| { |
| $$ = list_make1($1); |
| } |
| | generic_option_list ',' generic_option_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| /* Options definition for ALTER FDW, SERVER and USER MAPPING */ |
| alter_generic_options: |
| OPTIONS '(' alter_generic_option_list ')' { $$ = $3; } |
| ; |
| |
| alter_generic_option_list: |
| alter_generic_option_elem |
| { |
| $$ = list_make1($1); |
| } |
| | alter_generic_option_list ',' alter_generic_option_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| alter_generic_option_elem: |
| generic_option_elem |
| { |
| $$ = $1; |
| } |
| | SET generic_option_elem |
| { |
| $$ = $2; |
| $$->defaction = DEFELEM_SET; |
| } |
| | ADD_P generic_option_elem |
| { |
| $$ = $2; |
| $$->defaction = DEFELEM_ADD; |
| } |
| | DROP generic_option_name |
| { |
| $$ = makeDefElemExtended(NULL, $2, NULL, DEFELEM_DROP, @2); |
| } |
| ; |
| |
| generic_option_elem: |
| generic_option_name generic_option_arg |
| { |
| $$ = makeDefElem($1, $2, @1); |
| } |
| ; |
| |
| generic_option_name: |
| ColLabel { $$ = $1; } |
| ; |
| |
| /* We could use def_arg here, but the spec only requires string literals */ |
| generic_option_arg: |
| Sconst { $$ = (Node *) makeString($1); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE SERVER name [TYPE] [VERSION] [OPTIONS] |
| * |
| *****************************************************************************/ |
| |
| CreateForeignServerStmt: CREATE SERVER name opt_type opt_foreign_server_version |
| FOREIGN DATA_P WRAPPER name create_generic_options |
| { |
| CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt); |
| |
| n->servername = $3; |
| n->servertype = $4; |
| n->version = $5; |
| n->fdwname = $9; |
| n->options = $10; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE SERVER IF_P NOT EXISTS name opt_type opt_foreign_server_version |
| FOREIGN DATA_P WRAPPER name create_generic_options |
| { |
| CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt); |
| |
| n->servername = $6; |
| n->servertype = $7; |
| n->version = $8; |
| n->fdwname = $12; |
| n->options = $13; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_type: |
| TYPE_P Sconst { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| foreign_server_version: |
| VERSION_P Sconst { $$ = $2; } |
| | VERSION_P NULL_P { $$ = NULL; } |
| ; |
| |
| opt_foreign_server_version: |
| foreign_server_version { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER SERVER name [VERSION] [OPTIONS] |
| * |
| ****************************************************************************/ |
| |
| AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_options |
| { |
| AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt); |
| |
| n->servername = $3; |
| n->version = $4; |
| n->options = $5; |
| n->has_version = true; |
| $$ = (Node *) n; |
| } |
| | ALTER SERVER name foreign_server_version |
| { |
| AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt); |
| |
| n->servername = $3; |
| n->version = $4; |
| n->has_version = true; |
| $$ = (Node *) n; |
| } |
| | ALTER SERVER name alter_generic_options |
| { |
| AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt); |
| |
| n->servername = $3; |
| n->options = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE STORAGE SERVER name [OPTIONS] |
| * |
| *****************************************************************************/ |
| |
| CreateStorageServerStmt: |
| CREATE STORAGE SERVER name create_generic_options |
| { |
| CreateStorageServerStmt *n = makeNode(CreateStorageServerStmt); |
| n->servername = $4; |
| n->if_not_exists = false; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | CREATE STORAGE SERVER IF_P NOT EXISTS name create_generic_options |
| { |
| CreateStorageServerStmt *n = makeNode(CreateStorageServerStmt); |
| n->servername = $7; |
| n->if_not_exists = true; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER STORAGE SERVER name OPTIONS |
| * |
| ****************************************************************************/ |
| |
| AlterStorageServerStmt: |
| ALTER STORAGE SERVER name alter_generic_options |
| { |
| AlterStorageServerStmt *n = makeNode(AlterStorageServerStmt); |
| n->servername = $4; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP STORAGE SERVER name |
| * |
| ****************************************************************************/ |
| |
| DropStorageServerStmt: |
| DROP STORAGE SERVER name |
| { |
| DropStorageServerStmt *n = makeNode(DropStorageServerStmt); |
| n->servername = $4; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP STORAGE SERVER IF_P EXISTS name |
| { |
| DropStorageServerStmt *n = makeNode(DropStorageServerStmt); |
| n->servername = $6; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE FOREIGN TABLE relname (...) SERVER name (...) |
| * |
| *****************************************************************************/ |
| |
| CreateForeignTableStmt: |
| CREATE FOREIGN TABLE qualified_name |
| '(' OptTableElementList ')' |
| OptInherit SERVER name create_generic_options OptDistributedBy OptTagOptList |
| { |
| CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); |
| |
| $4->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $4; |
| n->base.tableElts = $6; |
| n->base.inhRelations = $8; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = false; |
| /* FDW-specific data */ |
| n->servername = $10; |
| n->options = $11; |
| n->distributedBy = (DistributedBy *) $12; |
| n->base.tags = $13; |
| if (strcmp(n->servername, GP_EXTTABLE_SERVER_NAME) != 0 && n->distributedBy) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("DISTRIBUTED BY clause is only supported by FOREIGN SERVER \"%s\"", GP_EXTTABLE_SERVER_NAME))); |
| } |
| $$ = (Node *) n; |
| } |
| | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name |
| '(' OptTableElementList ')' |
| OptInherit SERVER name create_generic_options OptTagOptList |
| { |
| CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); |
| |
| $7->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $7; |
| n->base.tableElts = $9; |
| n->base.inhRelations = $11; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = true; |
| /* FDW-specific data */ |
| n->servername = $13; |
| n->options = $14; |
| n->base.tags = $15; |
| $$ = (Node *) n; |
| } |
| | CREATE FOREIGN TABLE qualified_name |
| PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec |
| SERVER name create_generic_options OptTagOptList |
| { |
| CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); |
| |
| $4->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $4; |
| n->base.inhRelations = list_make1($7); |
| n->base.tableElts = $8; |
| n->base.partbound = $9; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = false; |
| /* FDW-specific data */ |
| n->servername = $11; |
| n->options = $12; |
| n->base.tags = $13; |
| $$ = (Node *) n; |
| } |
| | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name |
| PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec |
| SERVER name create_generic_options OptTagOptList |
| { |
| CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); |
| |
| $7->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $7; |
| n->base.inhRelations = list_make1($10); |
| n->base.tableElts = $11; |
| n->base.partbound = $12; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = true; |
| /* FDW-specific data */ |
| n->servername = $14; |
| n->options = $15; |
| n->base.tags = $16; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * IMPORT FOREIGN SCHEMA remote_schema |
| * [ { LIMIT TO | EXCEPT } ( table_list ) ] |
| * FROM SERVER server_name INTO local_schema [ OPTIONS (...) ] |
| * |
| ****************************************************************************/ |
| |
| ImportForeignSchemaStmt: |
| IMPORT_P FOREIGN SCHEMA name import_qualification |
| FROM SERVER name INTO name create_generic_options |
| { |
| ImportForeignSchemaStmt *n = makeNode(ImportForeignSchemaStmt); |
| |
| n->server_name = $8; |
| n->remote_schema = $4; |
| n->local_schema = $10; |
| n->list_type = $5->type; |
| n->table_list = $5->table_names; |
| n->options = $11; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| import_qualification_type: |
| LIMIT TO { $$ = FDW_IMPORT_SCHEMA_LIMIT_TO; } |
| | EXCEPT { $$ = FDW_IMPORT_SCHEMA_EXCEPT; } |
| ; |
| |
| import_qualification: |
| import_qualification_type '(' relation_expr_list ')' |
| { |
| ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual)); |
| |
| n->type = $1; |
| n->table_names = $3; |
| $$ = n; |
| } |
| | /*EMPTY*/ |
| { |
| ImportQual *n = (ImportQual *) palloc(sizeof(ImportQual)); |
| n->type = FDW_IMPORT_SCHEMA_ALL; |
| n->table_names = NIL; |
| $$ = n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * ADD SEG foreign_seg FROM SERVER server_name INTO foreign_table |
| * |
| *****************************************************************************/ |
| |
| AddForeignSegStmt: |
| ADD_P FOREIGN SEGMENT FROM SERVER name create_generic_options INTO name |
| { |
| AddForeignSegStmt *n = makeNode(AddForeignSegStmt); |
| n->servername = $6; |
| n->options = $7; |
| n->tablename = $9; |
| $$ = (Node *) n; |
| } |
| ; |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE USER MAPPING FOR auth_ident SERVER name [OPTIONS] |
| * |
| *****************************************************************************/ |
| |
| CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options |
| { |
| CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt); |
| |
| n->user = $5; |
| n->servername = $7; |
| n->options = $8; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE USER MAPPING IF_P NOT EXISTS FOR auth_ident SERVER name create_generic_options |
| { |
| CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt); |
| |
| n->user = $8; |
| n->servername = $10; |
| n->options = $11; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* User mapping authorization identifier */ |
| auth_ident: RoleSpec { $$ = $1; } |
| | USER { $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP USER MAPPING FOR auth_ident SERVER name |
| * |
| * XXX you'd think this should have a CASCADE/RESTRICT option, even if it's |
| * only pro forma; but the SQL standard doesn't show one. |
| ****************************************************************************/ |
| |
| DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name |
| { |
| DropUserMappingStmt *n = makeNode(DropUserMappingStmt); |
| |
| n->user = $5; |
| n->servername = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name |
| { |
| DropUserMappingStmt *n = makeNode(DropUserMappingStmt); |
| |
| n->user = $7; |
| n->servername = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER USER MAPPING FOR auth_ident SERVER name OPTIONS |
| * |
| ****************************************************************************/ |
| |
| AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options |
| { |
| AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt); |
| |
| n->user = $5; |
| n->servername = $7; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREAT STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name [OPTIONS] |
| * |
| *****************************************************************************/ |
| |
| CreateStorageUserMappingStmt: |
| CREATE STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name create_generic_options |
| { |
| CreateStorageUserMappingStmt *n = makeNode(CreateStorageUserMappingStmt); |
| n->user = $6; |
| n->servername = $9; |
| n->options = $10; |
| n->if_not_exists = false; |
| $$ = (Node *) n; |
| } |
| | CREATE STORAGE USER MAPPING IF_P NOT EXISTS FOR auth_ident |
| STORAGE SERVER name create_generic_options |
| { |
| CreateStorageUserMappingStmt *n = makeNode(CreateStorageUserMappingStmt); |
| n->user = $9; |
| n->servername = $12; |
| n->options = $13; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name |
| * |
| * XXX you'd think this should have a CASCADE/RESTRICT option, even if it's |
| * only pro forma; but the SQL standard doesn't show one. |
| ****************************************************************************/ |
| |
| DropStorageUserMappingStmt: |
| DROP STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name |
| { |
| DropStorageUserMappingStmt *n = makeNode(DropStorageUserMappingStmt); |
| n->user = $6; |
| n->servername = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP STORAGE USER MAPPING IF_P EXISTS FOR auth_ident STORAGE SERVER name |
| { |
| DropStorageUserMappingStmt *n = makeNode(DropStorageUserMappingStmt); |
| n->user = $8; |
| n->servername = $11; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name OPTIONS |
| * |
| ****************************************************************************/ |
| |
| AlterStorageUserMappingStmt: |
| ALTER STORAGE USER MAPPING FOR auth_ident STORAGE SERVER name alter_generic_options |
| { |
| AlterStorageUserMappingStmt *n = makeNode(AlterStorageUserMappingStmt); |
| n->user = $6; |
| n->servername = $9; |
| n->options = $10; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE DIRECTORY TABLE relname SERVER name (...) |
| * |
| *****************************************************************************/ |
| |
| CreateDirectoryTableStmt: |
| CREATE DIRECTORY TABLE qualified_name |
| table_access_method_clause OptTableSpace OptWithLocation OptTagOptList |
| { |
| CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); |
| $4->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $4; |
| n->base.inhRelations = NIL; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| /* TODO: support tablespace for data table ? */ |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = false; |
| n->base.distributedBy = GetDirectoryTableDistributedBy(); |
| n->base.relKind = RELKIND_DIRECTORY_TABLE; |
| n->tablespacename = $6; |
| n->location = $7; |
| n->base.tags = $8; |
| |
| $$ = (Node *) n; |
| } |
| | CREATE DIRECTORY TABLE IF_P NOT EXISTS qualified_name |
| table_access_method_clause OptTableSpace OptWithLocation OptTagOptList |
| { |
| CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); |
| $7->relpersistence = RELPERSISTENCE_PERMANENT; |
| n->base.relation = $7; |
| n->base.inhRelations = NIL; |
| n->base.ofTypename = NULL; |
| n->base.constraints = NIL; |
| n->base.options = NIL; |
| n->base.oncommit = ONCOMMIT_NOOP; |
| /* TODO: support tablespace for data table? */ |
| n->base.tablespacename = NULL; |
| n->base.if_not_exists = true; |
| n->base.distributedBy = GetDirectoryTableDistributedBy(); |
| n->base.relKind = RELKIND_DIRECTORY_TABLE; |
| n->tablespacename = $9; |
| n->location = $10; |
| n->base.tags = $11; |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * ALTER DIRECTORY TABLE relname TAG (tagname = tagvalue, ...) |
| * ALTER DIRECTORY TABLE relname UNSET TAG (tagname_list) |
| * |
| *****************************************************************************/ |
| |
| AlterDirectoryTableStmt: |
| ALTER DIRECTORY TABLE qualified_name TAG '(' TagOptList ')' |
| { |
| AlterDirectoryTableStmt *n = makeNode(AlterDirectoryTableStmt); |
| n->relation = $4; |
| n->tags = $7; |
| |
| $$ = (Node *)n; |
| } |
| | ALTER DIRECTORY TABLE qualified_name UNSET_P TAG '(' name_list ')' |
| { |
| AlterDirectoryTableStmt *n = makeNode(AlterDirectoryTableStmt); |
| n->relation = $4; |
| n->tags = $8; |
| n->unsettag = true; |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP DIRECTORY TABLE [ IF EXISTS ] tablename [, tablename ...] |
| * [ RESTRICT | CASCADE ] [WITH CONTENT] |
| * |
| *****************************************************************************/ |
| |
| DropDirectoryTableStmt: |
| DROP DIRECTORY TABLE IF_P EXISTS any_name_list opt_drop_behavior opt_drop_directory_table_behavior |
| { |
| DropDirectoryTableStmt *n = makeNode(DropDirectoryTableStmt); |
| n->base.removeType = OBJECT_DIRECTORY_TABLE; |
| n->base.missing_ok = true; |
| n->base.objects = $6; |
| n->base.behavior = $7; |
| n->base.concurrent = false; |
| n->with_content = $8; |
| $$ = (Node *)n; |
| } |
| | DROP DIRECTORY TABLE any_name_list opt_drop_behavior opt_drop_directory_table_behavior |
| { |
| DropDirectoryTableStmt *n = makeNode(DropDirectoryTableStmt); |
| n->base.removeType = OBJECT_DIRECTORY_TABLE; |
| n->base.missing_ok = true; |
| n->base.objects = $4; |
| n->base.behavior = $5; |
| n->base.concurrent = false; |
| n->with_content = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERIES: |
| * CREATE POLICY name ON table |
| * [AS { PERMISSIVE | RESTRICTIVE } ] |
| * [FOR { SELECT | INSERT | UPDATE | DELETE } ] |
| * [TO role, ...] |
| * [USING (qual)] [WITH CHECK (with check qual)] |
| * ALTER POLICY name ON table [TO role, ...] |
| * [USING (qual)] [WITH CHECK (with check qual)] |
| * |
| *****************************************************************************/ |
| |
| CreatePolicyStmt: |
| CREATE POLICY name ON qualified_name RowSecurityDefaultPermissive |
| RowSecurityDefaultForCmd RowSecurityDefaultToRole |
| RowSecurityOptionalExpr RowSecurityOptionalWithCheck |
| { |
| CreatePolicyStmt *n = makeNode(CreatePolicyStmt); |
| |
| n->policy_name = $3; |
| n->table = $5; |
| n->permissive = $6; |
| n->cmd_name = $7; |
| n->roles = $8; |
| n->qual = $9; |
| n->with_check = $10; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterPolicyStmt: |
| ALTER POLICY name ON qualified_name RowSecurityOptionalToRole |
| RowSecurityOptionalExpr RowSecurityOptionalWithCheck |
| { |
| AlterPolicyStmt *n = makeNode(AlterPolicyStmt); |
| |
| n->policy_name = $3; |
| n->table = $5; |
| n->roles = $6; |
| n->qual = $7; |
| n->with_check = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RowSecurityOptionalExpr: |
| USING '(' a_expr ')' { $$ = $3; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| RowSecurityOptionalWithCheck: |
| WITH CHECK '(' a_expr ')' { $$ = $4; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| RowSecurityDefaultToRole: |
| TO role_list { $$ = $2; } |
| | /* EMPTY */ { $$ = list_make1(makeRoleSpec(ROLESPEC_PUBLIC, -1)); } |
| ; |
| |
| RowSecurityOptionalToRole: |
| TO role_list { $$ = $2; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| RowSecurityDefaultPermissive: |
| AS IDENT |
| { |
| if (strcmp($2, "permissive") == 0) |
| $$ = true; |
| else if (strcmp($2, "restrictive") == 0) |
| $$ = false; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("unrecognized row security option \"%s\"", $2), |
| errhint("Only PERMISSIVE or RESTRICTIVE policies are supported currently."), |
| parser_errposition(@2))); |
| |
| } |
| | /* EMPTY */ { $$ = true; } |
| ; |
| |
| RowSecurityDefaultForCmd: |
| FOR row_security_cmd { $$ = $2; } |
| | /* EMPTY */ { $$ = "all"; } |
| ; |
| |
| row_security_cmd: |
| ALL { $$ = "all"; } |
| | SELECT { $$ = "select"; } |
| | INSERT { $$ = "insert"; } |
| | UPDATE { $$ = "update"; } |
| | DELETE_P { $$ = "delete"; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE ACCESS METHOD name HANDLER handler_name |
| * |
| *****************************************************************************/ |
| |
| CreateAmStmt: CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name |
| { |
| CreateAmStmt *n = makeNode(CreateAmStmt); |
| |
| n->amname = $4; |
| n->handler_name = $8; |
| n->amtype = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| am_type: |
| INDEX { $$ = AMTYPE_INDEX; } |
| | TABLE { $$ = AMTYPE_TABLE; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE TRIGGER ... |
| * |
| *****************************************************************************/ |
| |
| CreateTrigStmt: |
| CREATE opt_or_replace TRIGGER name TriggerActionTime TriggerEvents ON |
| qualified_name TriggerReferencing TriggerForSpec TriggerWhen |
| EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')' |
| { |
| CreateTrigStmt *n = makeNode(CreateTrigStmt); |
| |
| n->replace = $2; |
| n->isconstraint = false; |
| n->trigname = $4; |
| n->relation = $8; |
| n->funcname = $14; |
| n->args = $16; |
| n->row = $10; |
| n->timing = $5; |
| n->events = intVal(linitial($6)); |
| n->columns = (List *) lsecond($6); |
| n->whenClause = $11; |
| n->transitionRels = $9; |
| n->deferrable = false; |
| n->initdeferred = false; |
| n->constrrel = NULL; |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace CONSTRAINT TRIGGER name AFTER TriggerEvents ON |
| qualified_name OptConstrFromTable ConstraintAttributeSpec |
| FOR EACH ROW TriggerWhen |
| EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')' |
| { |
| CreateTrigStmt *n = makeNode(CreateTrigStmt); |
| |
| n->replace = $2; |
| if (n->replace) /* not supported, see CreateTrigger */ |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"))); |
| n->isconstraint = true; |
| n->trigname = $5; |
| n->relation = $9; |
| n->funcname = $18; |
| n->args = $20; |
| n->row = true; |
| n->timing = TRIGGER_TYPE_AFTER; |
| n->events = intVal(linitial($7)); |
| n->columns = (List *) lsecond($7); |
| n->whenClause = $15; |
| n->transitionRels = NIL; |
| processCASbits($11, @11, "TRIGGER", |
| &n->deferrable, &n->initdeferred, NULL, |
| NULL, yyscanner); |
| n->constrrel = $10; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| TriggerActionTime: |
| BEFORE { $$ = TRIGGER_TYPE_BEFORE; } |
| | AFTER { $$ = TRIGGER_TYPE_AFTER; } |
| | INSTEAD OF { $$ = TRIGGER_TYPE_INSTEAD; } |
| ; |
| |
| TriggerEvents: |
| TriggerOneEvent |
| { $$ = $1; } |
| | TriggerEvents OR TriggerOneEvent |
| { |
| int events1 = intVal(linitial($1)); |
| int events2 = intVal(linitial($3)); |
| List *columns1 = (List *) lsecond($1); |
| List *columns2 = (List *) lsecond($3); |
| |
| if (events1 & events2) |
| parser_yyerror("duplicate trigger events specified"); |
| /* |
| * concat'ing the columns lists loses information about |
| * which columns went with which event, but so long as |
| * only UPDATE carries columns and we disallow multiple |
| * UPDATE items, it doesn't matter. Command execution |
| * should just ignore the columns for non-UPDATE events. |
| */ |
| $$ = list_make2(makeInteger(events1 | events2), |
| list_concat(columns1, columns2)); |
| } |
| ; |
| |
| TriggerOneEvent: |
| INSERT |
| { $$ = list_make2(makeInteger(TRIGGER_TYPE_INSERT), NIL); } |
| | DELETE_P |
| { $$ = list_make2(makeInteger(TRIGGER_TYPE_DELETE), NIL); } |
| | UPDATE |
| { $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), NIL); } |
| | UPDATE OF columnList |
| { $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), $3); } |
| | TRUNCATE |
| { $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); } |
| ; |
| |
| TriggerReferencing: |
| REFERENCING TriggerTransitions { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TriggerTransitions: |
| TriggerTransition { $$ = list_make1($1); } |
| | TriggerTransitions TriggerTransition { $$ = lappend($1, $2); } |
| ; |
| |
| TriggerTransition: |
| TransitionOldOrNew TransitionRowOrTable opt_as TransitionRelName |
| { |
| TriggerTransition *n = makeNode(TriggerTransition); |
| |
| n->name = $4; |
| n->isNew = $1; |
| n->isTable = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| TransitionOldOrNew: |
| NEW { $$ = true; } |
| | OLD { $$ = false; } |
| ; |
| |
| TransitionRowOrTable: |
| TABLE { $$ = true; } |
| /* |
| * According to the standard, lack of a keyword here implies ROW. |
| * Support for that would require prohibiting ROW entirely here, |
| * reserving the keyword ROW, and/or requiring AS (instead of |
| * allowing it to be optional, as the standard specifies) as the |
| * next token. Requiring ROW seems cleanest and easiest to |
| * explain. |
| */ |
| | ROW { $$ = false; } |
| ; |
| |
| TransitionRelName: |
| ColId { $$ = $1; } |
| ; |
| |
| TriggerForSpec: |
| FOR TriggerForOptEach TriggerForType |
| { |
| $$ = $3; |
| } |
| | /* EMPTY */ |
| { |
| /* let creation of triggers go through for pg_restore when upgrading from GP6 to GP7 */ |
| if (!gp_enable_statement_trigger) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("Triggers for statements are not yet supported"))); |
| } |
| $$ = false; |
| } |
| ; |
| |
| TriggerForOptEach: |
| EACH |
| | /*EMPTY*/ |
| ; |
| |
| TriggerForType: |
| ROW { $$ = true; } |
| | STATEMENT |
| { |
| /* let creation of triggers go through for pg_restore when upgrading from GP6 to GP7 */ |
| if (!gp_enable_statement_trigger) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("Triggers for statements are not yet supported"))); |
| } |
| $$ = false; |
| } |
| ; |
| |
| TriggerWhen: |
| WHEN '(' a_expr ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| FUNCTION_or_PROCEDURE: |
| FUNCTION |
| | PROCEDURE |
| ; |
| |
| TriggerFuncArgs: |
| TriggerFuncArg { $$ = list_make1($1); } |
| | TriggerFuncArgs ',' TriggerFuncArg { $$ = lappend($1, $3); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TriggerFuncArg: |
| Iconst |
| { |
| $$ = (Node *) makeString(psprintf("%d", $1)); |
| } |
| | FCONST { $$ = (Node *) makeString($1); } |
| | Sconst { $$ = (Node *) makeString($1); } |
| | ColLabel { $$ = (Node *) makeString($1); } |
| ; |
| |
| OptConstrFromTable: |
| FROM qualified_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ConstraintAttributeSpec: |
| /*EMPTY*/ |
| { $$ = 0; } |
| | ConstraintAttributeSpec ConstraintAttributeElem |
| { |
| /* |
| * We must complain about conflicting options. |
| * We could, but choose not to, complain about redundant |
| * options (ie, where $2's bit is already set in $1). |
| */ |
| int newspec = $1 | $2; |
| |
| /* special message for this case */ |
| if ((newspec & (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) == (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), |
| parser_errposition(@2))); |
| /* generic message for other conflicts */ |
| if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || |
| (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("conflicting constraint properties"), |
| parser_errposition(@2))); |
| $$ = newspec; |
| } |
| ; |
| |
| ConstraintAttributeElem: |
| NOT DEFERRABLE { $$ = CAS_NOT_DEFERRABLE; } |
| | DEFERRABLE { $$ = CAS_DEFERRABLE; } |
| | INITIALLY IMMEDIATE { $$ = CAS_INITIALLY_IMMEDIATE; } |
| | INITIALLY DEFERRED { $$ = CAS_INITIALLY_DEFERRED; } |
| | NOT VALID { $$ = CAS_NOT_VALID; } |
| | NO INHERIT { $$ = CAS_NO_INHERIT; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE EVENT TRIGGER ... |
| * ALTER EVENT TRIGGER ... |
| * |
| *****************************************************************************/ |
| |
| CreateEventTrigStmt: |
| CREATE EVENT TRIGGER name ON ColLabel |
| EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')' |
| { |
| CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt); |
| |
| n->trigname = $4; |
| n->eventname = $6; |
| n->whenclause = NULL; |
| n->funcname = $9; |
| $$ = (Node *) n; |
| } |
| | CREATE EVENT TRIGGER name ON ColLabel |
| WHEN event_trigger_when_list |
| EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')' |
| { |
| CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt); |
| |
| n->trigname = $4; |
| n->eventname = $6; |
| n->whenclause = $8; |
| n->funcname = $11; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| event_trigger_when_list: |
| event_trigger_when_item |
| { $$ = list_make1($1); } |
| | event_trigger_when_list AND event_trigger_when_item |
| { $$ = lappend($1, $3); } |
| ; |
| |
| event_trigger_when_item: |
| ColId IN_P '(' event_trigger_value_list ')' |
| { $$ = makeDefElem($1, (Node *) $4, @1); } |
| ; |
| |
| event_trigger_value_list: |
| SCONST |
| { $$ = list_make1(makeString($1)); } |
| | event_trigger_value_list ',' SCONST |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| AlterEventTrigStmt: |
| ALTER EVENT TRIGGER name enable_trigger |
| { |
| AlterEventTrigStmt *n = makeNode(AlterEventTrigStmt); |
| |
| n->trigname = $4; |
| n->tgenabled = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| enable_trigger: |
| ENABLE_P { $$ = TRIGGER_FIRES_ON_ORIGIN; } |
| | ENABLE_P REPLICA { $$ = TRIGGER_FIRES_ON_REPLICA; } |
| | ENABLE_P ALWAYS { $$ = TRIGGER_FIRES_ALWAYS; } |
| | DISABLE_P { $$ = TRIGGER_DISABLED; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE ASSERTION ... |
| * |
| *****************************************************************************/ |
| |
| CreateAssertionStmt: |
| CREATE ASSERTION any_name CHECK '(' a_expr ')' ConstraintAttributeSpec |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE ASSERTION is not yet implemented"))); |
| |
| $$ = NULL; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * define (aggregate,operator,type) |
| * |
| *****************************************************************************/ |
| |
| DefineStmt: |
| CREATE opt_or_replace opt_ordered AGGREGATE func_name aggr_args definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_AGGREGATE; |
| n->oldstyle = false; |
| n->replace = $2; |
| n->defnames = $5; |
| n->args = $6; |
| n->definition = $7; |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace opt_ordered AGGREGATE func_name old_aggr_definition |
| { |
| /* old-style (pre-8.2) syntax for CREATE AGGREGATE */ |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_AGGREGATE; |
| n->oldstyle = true; |
| n->replace = $2; |
| n->defnames = $5; |
| n->args = NIL; |
| n->definition = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE OPERATOR any_operator definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_OPERATOR; |
| n->oldstyle = false; |
| n->defnames = $3; |
| n->args = NIL; |
| n->definition = $4; |
| $$ = (Node *) n; |
| } |
| | CREATE TYPE_P any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TYPE; |
| n->oldstyle = false; |
| n->defnames = $3; |
| n->args = NIL; |
| n->definition = $4; |
| $$ = (Node *) n; |
| } |
| | CREATE TYPE_P any_name |
| { |
| /* Shell type (identified by lack of definition) */ |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TYPE; |
| n->oldstyle = false; |
| n->defnames = $3; |
| n->args = NIL; |
| n->definition = NIL; |
| $$ = (Node *) n; |
| } |
| | CREATE TYPE_P any_name AS '(' OptTableFuncElementList ')' |
| { |
| CompositeTypeStmt *n = makeNode(CompositeTypeStmt); |
| |
| /* can't use qualified_name, sigh */ |
| n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner); |
| n->coldeflist = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace opt_trusted PROTOCOL name definition |
| { |
| /* |
| * The opt_or_replace is here just to avoid a grammar conflict. |
| * It's not actually supported. |
| */ |
| if ($2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("syntax error"), |
| parser_errposition(@2))); |
| |
| DefineStmt *n = makeNode(DefineStmt); |
| n->kind = OBJECT_EXTPROTOCOL; |
| n->oldstyle = false; |
| n->trusted = $3; |
| n->defnames = list_make1(makeString($5)); |
| n->args = NIL; |
| n->definition = $6; |
| $$ = (Node *)n; |
| } |
| | CREATE TYPE_P any_name AS ENUM_P '(' opt_enum_val_list ')' |
| { |
| CreateEnumStmt *n = makeNode(CreateEnumStmt); |
| |
| n->typeName = $3; |
| n->vals = $7; |
| $$ = (Node *) n; |
| } |
| | CREATE TYPE_P any_name AS RANGE definition |
| { |
| CreateRangeStmt *n = makeNode(CreateRangeStmt); |
| |
| n->typeName = $3; |
| n->params = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE TEXT_P SEARCH PARSER any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TSPARSER; |
| n->args = NIL; |
| n->defnames = $5; |
| n->definition = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE TEXT_P SEARCH DICTIONARY any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TSDICTIONARY; |
| n->args = NIL; |
| n->defnames = $5; |
| n->definition = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE TEXT_P SEARCH TEMPLATE any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TSTEMPLATE; |
| n->args = NIL; |
| n->defnames = $5; |
| n->definition = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE TEXT_P SEARCH CONFIGURATION any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_TSCONFIGURATION; |
| n->args = NIL; |
| n->defnames = $5; |
| n->definition = $6; |
| $$ = (Node *) n; |
| } |
| | CREATE COLLATION any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_COLLATION; |
| n->args = NIL; |
| n->defnames = $3; |
| n->definition = $4; |
| $$ = (Node *) n; |
| } |
| | CREATE COLLATION IF_P NOT EXISTS any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_COLLATION; |
| n->args = NIL; |
| n->defnames = $6; |
| n->definition = $7; |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| | CREATE COLLATION any_name FROM any_name |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_COLLATION; |
| n->args = NIL; |
| n->defnames = $3; |
| n->definition = list_make1(makeDefElem("from", (Node *) $5, @5)); |
| $$ = (Node *) n; |
| } |
| | CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| |
| n->kind = OBJECT_COLLATION; |
| n->args = NIL; |
| n->defnames = $6; |
| n->definition = list_make1(makeDefElem("from", (Node *) $8, @8)); |
| n->if_not_exists = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_ordered: ORDERED |
| | /*EMPTY*/ |
| ; |
| |
| definition: '(' def_list ')' { $$ = $2; } |
| ; |
| |
| def_list: def_elem { $$ = list_make1($1); } |
| | def_list ',' def_elem { $$ = lappend($1, $3); } |
| ; |
| |
| def_elem: ColLabel '=' def_arg |
| { |
| $$ = makeDefElem($1, (Node *) $3, @1); |
| } |
| | ColLabel |
| { |
| $$ = makeDefElem($1, NULL, @1); |
| } |
| ; |
| |
| /* Note: any simple identifier will be returned as a type name! */ |
| def_arg: func_type { $$ = (Node *)$1; } |
| /* MPP-6685: allow unquoted ROW keyword as "orientation" option */ |
| | ROW { $$ = (Node *)makeString(pstrdup("row")); } |
| | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); } |
| | qual_all_Op { $$ = (Node *)$1; } |
| | NumericOnly { $$ = (Node *)$1; } |
| | Sconst { $$ = (Node *)makeString($1); } |
| | NONE { $$ = (Node *)makeString(pstrdup($1)); } |
| ; |
| |
| old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; } |
| ; |
| |
| old_aggr_list: old_aggr_elem { $$ = list_make1($1); } |
| | old_aggr_list ',' old_aggr_elem { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * Must use IDENT here to avoid reduce/reduce conflicts; fortunately none of |
| * the item names needed in old aggregate definitions are likely to become |
| * SQL keywords. |
| */ |
| old_aggr_elem: IDENT '=' def_arg |
| { |
| $$ = makeDefElem($1, (Node *) $3, @1); |
| } |
| ; |
| |
| opt_enum_val_list: |
| enum_val_list { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| enum_val_list: Sconst |
| { $$ = list_make1(makeString($1)); } |
| | enum_val_list ',' Sconst |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER TYPE enumtype ADD ... |
| * |
| *****************************************************************************/ |
| |
| AlterEnumStmt: |
| ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst |
| { |
| AlterEnumStmt *n = makeNode(AlterEnumStmt); |
| |
| n->typeName = $3; |
| n->oldVal = NULL; |
| n->newVal = $7; |
| n->newValNeighbor = NULL; |
| n->newValIsAfter = true; |
| n->skipIfNewValExists = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst BEFORE Sconst |
| { |
| AlterEnumStmt *n = makeNode(AlterEnumStmt); |
| |
| n->typeName = $3; |
| n->oldVal = NULL; |
| n->newVal = $7; |
| n->newValNeighbor = $9; |
| n->newValIsAfter = false; |
| n->skipIfNewValExists = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst AFTER Sconst |
| { |
| AlterEnumStmt *n = makeNode(AlterEnumStmt); |
| |
| n->typeName = $3; |
| n->oldVal = NULL; |
| n->newVal = $7; |
| n->newValNeighbor = $9; |
| n->newValIsAfter = true; |
| n->skipIfNewValExists = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name RENAME VALUE_P Sconst TO Sconst |
| { |
| AlterEnumStmt *n = makeNode(AlterEnumStmt); |
| |
| n->typeName = $3; |
| n->oldVal = $6; |
| n->newVal = $8; |
| n->newValNeighbor = NULL; |
| n->newValIsAfter = false; |
| n->skipIfNewValExists = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_if_not_exists: IF_P NOT EXISTS { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE OPERATOR CLASS ... |
| * CREATE OPERATOR FAMILY ... |
| * ALTER OPERATOR FAMILY ... |
| * DROP OPERATOR CLASS ... |
| * DROP OPERATOR FAMILY ... |
| * |
| *****************************************************************************/ |
| |
| CreateOpClassStmt: |
| CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename |
| USING name opt_opfamily AS opclass_item_list |
| { |
| CreateOpClassStmt *n = makeNode(CreateOpClassStmt); |
| |
| n->opclassname = $4; |
| n->isDefault = $5; |
| n->datatype = $8; |
| n->amname = $10; |
| n->opfamilyname = $11; |
| n->items = $13; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opclass_item_list: |
| opclass_item { $$ = list_make1($1); } |
| | opclass_item_list ',' opclass_item { $$ = lappend($1, $3); } |
| ; |
| |
| opclass_item: |
| OPERATOR Iconst any_operator opclass_purpose opt_recheck |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| ObjectWithArgs *owa = makeNode(ObjectWithArgs); |
| |
| owa->objname = $3; |
| owa->objargs = NIL; |
| n->itemtype = OPCLASS_ITEM_OPERATOR; |
| n->name = owa; |
| n->number = $2; |
| n->order_family = $4; |
| $$ = (Node *) n; |
| } |
| | OPERATOR Iconst operator_with_argtypes opclass_purpose |
| opt_recheck |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_OPERATOR; |
| n->name = $3; |
| n->number = $2; |
| n->order_family = $4; |
| $$ = (Node *) n; |
| } |
| | FUNCTION Iconst function_with_argtypes |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_FUNCTION; |
| n->name = $3; |
| n->number = $2; |
| $$ = (Node *) n; |
| } |
| | FUNCTION Iconst '(' type_list ')' function_with_argtypes |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_FUNCTION; |
| n->name = $6; |
| n->number = $2; |
| n->class_args = $4; |
| $$ = (Node *) n; |
| } |
| | STORAGE Typename |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_STORAGETYPE; |
| n->storedtype = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_default: DEFAULT { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_opfamily: FAMILY any_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opclass_purpose: FOR SEARCH { $$ = NIL; } |
| | FOR ORDER BY any_name { $$ = $4; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_recheck: RECHECK |
| { |
| /* |
| * RECHECK no longer does anything in opclass definitions, |
| * but we still accept it to ease porting of old database |
| * dumps. |
| */ |
| ereport(NOTICE, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("RECHECK is no longer required"), |
| errhint("Update your data type."), |
| parser_errposition(@1))); |
| $$ = true; |
| } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| |
| CreateOpFamilyStmt: |
| CREATE OPERATOR FAMILY any_name USING name |
| { |
| CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt); |
| |
| n->opfamilyname = $4; |
| n->amname = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterOpFamilyStmt: |
| ALTER OPERATOR FAMILY any_name USING name ADD_P opclass_item_list |
| { |
| AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt); |
| |
| n->opfamilyname = $4; |
| n->amname = $6; |
| n->isDrop = false; |
| n->items = $8; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR FAMILY any_name USING name DROP opclass_drop_list |
| { |
| AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt); |
| |
| n->opfamilyname = $4; |
| n->amname = $6; |
| n->isDrop = true; |
| n->items = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opclass_drop_list: |
| opclass_drop { $$ = list_make1($1); } |
| | opclass_drop_list ',' opclass_drop { $$ = lappend($1, $3); } |
| ; |
| |
| opclass_drop: |
| OPERATOR Iconst '(' type_list ')' |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_OPERATOR; |
| n->number = $2; |
| n->class_args = $4; |
| $$ = (Node *) n; |
| } |
| | FUNCTION Iconst '(' type_list ')' |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| |
| n->itemtype = OPCLASS_ITEM_FUNCTION; |
| n->number = $2; |
| n->class_args = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| DropOpClassStmt: |
| DROP OPERATOR CLASS any_name USING name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->objects = list_make1(lcons(makeString($6), $4)); |
| n->removeType = OBJECT_OPCLASS; |
| n->behavior = $7; |
| n->missing_ok = false; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP OPERATOR CLASS IF_P EXISTS any_name USING name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->objects = list_make1(lcons(makeString($8), $6)); |
| n->removeType = OBJECT_OPCLASS; |
| n->behavior = $9; |
| n->missing_ok = true; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| DropOpFamilyStmt: |
| DROP OPERATOR FAMILY any_name USING name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->objects = list_make1(lcons(makeString($6), $4)); |
| n->removeType = OBJECT_OPFAMILY; |
| n->behavior = $7; |
| n->missing_ok = false; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP OPERATOR FAMILY IF_P EXISTS any_name USING name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->objects = list_make1(lcons(makeString($8), $6)); |
| n->removeType = OBJECT_OPFAMILY; |
| n->behavior = $9; |
| n->missing_ok = true; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ] |
| * REASSIGN OWNED BY username [, username ...] TO username |
| * |
| *****************************************************************************/ |
| DropOwnedStmt: |
| DROP OWNED BY role_list opt_drop_behavior |
| { |
| DropOwnedStmt *n = makeNode(DropOwnedStmt); |
| |
| n->roles = $4; |
| n->behavior = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| ReassignOwnedStmt: |
| REASSIGN OWNED BY role_list TO RoleSpec |
| { |
| ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt); |
| |
| n->roles = $4; |
| n->newrole = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] |
| * [ RESTRICT | CASCADE ] |
| * |
| *****************************************************************************/ |
| |
| DropStmt: DROP object_type_any_name IF_P EXISTS any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->missing_ok = true; |
| n->objects = $5; |
| n->behavior = $6; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP object_type_any_name any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->missing_ok = false; |
| n->objects = $3; |
| n->behavior = $4; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP drop_type_name IF_P EXISTS name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->missing_ok = true; |
| n->objects = $5; |
| n->behavior = $6; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP drop_type_name name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->missing_ok = false; |
| n->objects = $3; |
| n->behavior = $4; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP object_type_name_on_any_name name ON any_name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->objects = list_make1(lappend($5, makeString($3))); |
| n->behavior = $6; |
| n->missing_ok = false; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP object_type_name_on_any_name IF_P EXISTS name ON any_name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = $2; |
| n->objects = list_make1(lappend($7, makeString($5))); |
| n->behavior = $8; |
| n->missing_ok = true; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP TYPE_P type_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_TYPE; |
| n->missing_ok = false; |
| n->objects = $3; |
| n->behavior = $4; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP TYPE_P IF_P EXISTS type_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_TYPE; |
| n->missing_ok = true; |
| n->objects = $5; |
| n->behavior = $6; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP DOMAIN_P type_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_DOMAIN; |
| n->missing_ok = false; |
| n->objects = $3; |
| n->behavior = $4; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP DOMAIN_P IF_P EXISTS type_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_DOMAIN; |
| n->missing_ok = true; |
| n->objects = $5; |
| n->behavior = $6; |
| n->concurrent = false; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_INDEX; |
| n->missing_ok = false; |
| n->objects = $4; |
| n->behavior = $5; |
| n->concurrent = true; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| | DROP INDEX CONCURRENTLY IF_P EXISTS any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_INDEX; |
| n->missing_ok = true; |
| n->objects = $6; |
| n->behavior = $7; |
| n->concurrent = true; |
| n->isdynamic = false; |
| $$ = (Node *) n; |
| } |
| /* DROP DYNAMIC TABLE */ |
| | DROP DYNAMIC TABLE IF_P EXISTS any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| n->removeType = OBJECT_MATVIEW; |
| n->missing_ok = true; |
| n->objects = $6; |
| n->behavior = $7; |
| n->concurrent = false; |
| n->isdynamic = true; |
| $$ = (Node *)n; |
| } |
| | DROP DYNAMIC TABLE any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| n->removeType = OBJECT_MATVIEW; |
| n->missing_ok = false; |
| n->objects = $4; |
| n->behavior = $5; |
| n->concurrent = false; |
| n->isdynamic = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* object types taking any_name/any_name_list */ |
| object_type_any_name: |
| TABLE { $$ = OBJECT_TABLE; } |
| | SEQUENCE { $$ = OBJECT_SEQUENCE; } |
| | VIEW { $$ = OBJECT_VIEW; } |
| | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } |
| | INDEX { $$ = OBJECT_INDEX; } |
| | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } |
| | EXTERNAL TABLE { $$ = OBJECT_FOREIGN_TABLE; } |
| | EXTERNAL WEB TABLE { $$ = OBJECT_FOREIGN_TABLE; } |
| | COLLATION { $$ = OBJECT_COLLATION; } |
| | CONVERSION_P { $$ = OBJECT_CONVERSION; } |
| | STATISTICS { $$ = OBJECT_STATISTIC_EXT; } |
| | TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; } |
| | TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; } |
| | TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; } |
| | TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; } |
| ; |
| |
| /* |
| * object types taking name/name_list |
| * |
| * DROP handles some of them separately |
| */ |
| |
| object_type_name: |
| drop_type_name { $$ = $1; } |
| | DATABASE { $$ = OBJECT_DATABASE; } |
| | ROLE { $$ = OBJECT_ROLE; } |
| | PROFILE { $$ = OBJECT_PROFILE; } |
| | SUBSCRIPTION { $$ = OBJECT_SUBSCRIPTION; } |
| | TABLESPACE { $$ = OBJECT_TABLESPACE; } |
| | RESOURCE QUEUE { $$ = OBJECT_RESQUEUE; } |
| | RESOURCE GROUP_P { $$ = OBJECT_RESGROUP; } |
| ; |
| |
| drop_type_name: |
| ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; } |
| | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } |
| | EXTENSION { $$ = OBJECT_EXTENSION; } |
| | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; } |
| | opt_procedural LANGUAGE { $$ = OBJECT_LANGUAGE; } |
| | PUBLICATION { $$ = OBJECT_PUBLICATION; } |
| | SCHEMA { $$ = OBJECT_SCHEMA; } |
| | SERVER { $$ = OBJECT_FOREIGN_SERVER; } |
| | PROTOCOL { $$ = OBJECT_EXTPROTOCOL; } |
| ; |
| |
| /* object types attached to a table */ |
| object_type_name_on_any_name: |
| POLICY { $$ = OBJECT_POLICY; } |
| | RULE { $$ = OBJECT_RULE; } |
| | TRIGGER { $$ = OBJECT_TRIGGER; } |
| ; |
| |
| any_name_list: |
| any_name { $$ = list_make1($1); } |
| | any_name_list ',' any_name { $$ = lappend($1, $3); } |
| ; |
| |
| any_name: ColId { $$ = list_make1(makeString($1)); } |
| | ColId attrs { $$ = lcons(makeString($1), $2); } |
| ; |
| |
| attrs: '.' attr_name |
| { $$ = list_make1(makeString($2)); } |
| | attrs '.' attr_name |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| type_name_list: |
| Typename { $$ = list_make1($1); } |
| | type_name_list ',' Typename { $$ = lappend($1, $3); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * truncate table relname1, relname2, ... |
| * |
| *****************************************************************************/ |
| |
| TruncateStmt: |
| TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior |
| { |
| TruncateStmt *n = makeNode(TruncateStmt); |
| |
| n->relations = $3; |
| n->restart_seqs = $4; |
| n->behavior = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_restart_seqs: |
| CONTINUE_P IDENTITY_P { $$ = false; } |
| | RESTART IDENTITY_P { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * COMMENT ON <object> IS <text> |
| * |
| *****************************************************************************/ |
| |
| CommentStmt: |
| COMMENT ON object_type_any_name any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = $3; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON COLUMN any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_COLUMN; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON object_type_name name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = $3; |
| n->object = (Node *) makeString($4); |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON TYPE_P Typename IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_TYPE; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON DOMAIN_P Typename IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_DOMAIN; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON AGGREGATE aggregate_with_argtypes IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_AGGREGATE; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON FUNCTION function_with_argtypes IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_FUNCTION; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON OPERATOR operator_with_argtypes IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_OPERATOR; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON CONSTRAINT name ON any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_TABCONSTRAINT; |
| n->object = (Node *) lappend($6, makeString($4)); |
| n->comment = $8; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_DOMCONSTRAINT; |
| /* |
| * should use Typename not any_name in the production, but |
| * there's a shift/reduce conflict if we do that, so fix it |
| * up here. |
| */ |
| n->object = (Node *) list_make2(makeTypeNameFromNameList($7), makeString($4)); |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON object_type_name_on_any_name name ON any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = $3; |
| n->object = (Node *) lappend($6, makeString($4)); |
| n->comment = $8; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON PROCEDURE function_with_argtypes IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_PROCEDURE; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON ROUTINE function_with_argtypes IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_ROUTINE; |
| n->object = (Node *) $4; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON TRANSFORM FOR Typename LANGUAGE name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_TRANSFORM; |
| n->object = (Node *) list_make2($5, makeString($7)); |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON OPERATOR CLASS any_name USING name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_OPCLASS; |
| n->object = (Node *) lcons(makeString($7), $5); |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON OPERATOR FAMILY any_name USING name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_OPFAMILY; |
| n->object = (Node *) lcons(makeString($7), $5); |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_LARGEOBJECT; |
| n->object = (Node *) $5; |
| n->comment = $7; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| |
| n->objtype = OBJECT_CAST; |
| n->object = (Node *) list_make2($5, $7); |
| n->comment = $10; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON TAG name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_TAG; |
| n->object = (Node *) makeString($4); |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| comment_text: |
| Sconst { $$ = $1; } |
| | NULL_P { $$ = NULL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * SECURITY LABEL [FOR <provider>] ON <object> IS <label> |
| * |
| * As with COMMENT ON, <object> can refer to various types of database |
| * objects (e.g. TABLE, COLUMN, etc.). |
| * |
| *****************************************************************************/ |
| |
| SecLabelStmt: |
| SECURITY LABEL opt_provider ON object_type_any_name any_name |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = $5; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON COLUMN any_name |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_COLUMN; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON object_type_name name |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = $5; |
| n->object = (Node *) makeString($6); |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON TYPE_P Typename |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_TYPE; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON DOMAIN_P Typename |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_DOMAIN; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON AGGREGATE aggregate_with_argtypes |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_AGGREGATE; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON FUNCTION function_with_argtypes |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_FUNCTION; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON LARGE_P OBJECT_P NumericOnly |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_LARGEOBJECT; |
| n->object = (Node *) $7; |
| n->label = $9; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON PROCEDURE function_with_argtypes |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_PROCEDURE; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| | SECURITY LABEL opt_provider ON ROUTINE function_with_argtypes |
| IS security_label |
| { |
| SecLabelStmt *n = makeNode(SecLabelStmt); |
| |
| n->provider = $3; |
| n->objtype = OBJECT_ROUTINE; |
| n->object = (Node *) $6; |
| n->label = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_provider: FOR NonReservedWord_or_Sconst { $$ = $2; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| security_label: Sconst { $$ = $1; } |
| | NULL_P { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * fetch/move |
| * |
| *****************************************************************************/ |
| |
| FetchStmt: FETCH fetch_args |
| { |
| FetchStmt *n = (FetchStmt *) $2; |
| |
| n->ismove = false; |
| $$ = (Node *) n; |
| } |
| | MOVE fetch_args |
| { |
| FetchStmt *n = (FetchStmt *) $2; |
| |
| n->ismove = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| fetch_args: cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $1; |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $2; |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | NEXT opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | PRIOR opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_BACKWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | FIRST_P opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | LAST_P opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = -1; |
| $$ = (Node *) n; |
| } |
| | ABSOLUTE_P SignedIconst opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = $2; |
| $$ = (Node *) n; |
| } |
| | RELATIVE_P SignedIconst opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_RELATIVE; |
| n->howMany = $2; |
| $$ = (Node *) n; |
| } |
| | SignedIconst opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_FORWARD; |
| n->howMany = $1; |
| $$ = (Node *) n; |
| } |
| | ALL opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_FORWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *) n; |
| } |
| | FORWARD opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | FORWARD SignedIconst opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_FORWARD; |
| n->howMany = $2; |
| $$ = (Node *) n; |
| } |
| | FORWARD ALL opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_FORWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *) n; |
| } |
| | BACKWARD opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $3; |
| n->direction = FETCH_BACKWARD; |
| n->howMany = 1; |
| $$ = (Node *) n; |
| } |
| | BACKWARD SignedIconst opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_BACKWARD; |
| n->howMany = $2; |
| $$ = (Node *) n; |
| } |
| | BACKWARD ALL opt_from_in cursor_name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| |
| n->portalname = $4; |
| n->direction = FETCH_BACKWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| from_in: FROM |
| | IN_P |
| ; |
| |
| opt_from_in: from_in |
| | /* EMPTY */ |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * GRANT and REVOKE statements |
| * |
| *****************************************************************************/ |
| |
| GrantStmt: GRANT privileges ON privilege_target TO grantee_list |
| opt_grant_grant_option opt_granted_by |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = true; |
| n->privileges = $2; |
| n->targtype = ($4)->targtype; |
| n->objtype = ($4)->objtype; |
| n->objects = ($4)->objs; |
| n->grantees = $6; |
| n->grant_option = $7; |
| n->grantor = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RevokeStmt: |
| REVOKE privileges ON privilege_target |
| FROM grantee_list opt_granted_by opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = false; |
| n->grant_option = false; |
| n->privileges = $2; |
| n->targtype = ($4)->targtype; |
| n->objtype = ($4)->objtype; |
| n->objects = ($4)->objs; |
| n->grantees = $6; |
| n->grantor = $7; |
| n->behavior = $8; |
| $$ = (Node *) n; |
| } |
| | REVOKE GRANT OPTION FOR privileges ON privilege_target |
| FROM grantee_list opt_granted_by opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = false; |
| n->grant_option = true; |
| n->privileges = $5; |
| n->targtype = ($7)->targtype; |
| n->objtype = ($7)->objtype; |
| n->objects = ($7)->objs; |
| n->grantees = $9; |
| n->grantor = $10; |
| n->behavior = $11; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /* |
| * Privilege names are represented as strings; the validity of the privilege |
| * names gets checked at execution. This is a bit annoying but we have little |
| * choice because of the syntactic conflict with lists of role names in |
| * GRANT/REVOKE. What's more, we have to call out in the "privilege" |
| * production any reserved keywords that need to be usable as privilege names. |
| */ |
| |
| /* either ALL [PRIVILEGES] or a list of individual privileges */ |
| privileges: privilege_list |
| { $$ = $1; } |
| | ALL |
| { $$ = NIL; } |
| | ALL PRIVILEGES |
| { $$ = NIL; } |
| | ALL '(' columnList ')' |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = NULL; |
| n->cols = $3; |
| $$ = list_make1(n); |
| } |
| | ALL PRIVILEGES '(' columnList ')' |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = NULL; |
| n->cols = $4; |
| $$ = list_make1(n); |
| } |
| ; |
| |
| privilege_list: privilege { $$ = list_make1($1); } |
| | privilege_list ',' privilege { $$ = lappend($1, $3); } |
| ; |
| |
| privilege: SELECT opt_column_list |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = pstrdup($1); |
| n->cols = $2; |
| $$ = n; |
| } |
| | REFERENCES opt_column_list |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = pstrdup($1); |
| n->cols = $2; |
| $$ = n; |
| } |
| | CREATE opt_column_list |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = pstrdup($1); |
| n->cols = $2; |
| $$ = n; |
| } |
| | ALTER SYSTEM_P |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| n->priv_name = pstrdup("alter system"); |
| n->cols = NIL; |
| $$ = n; |
| } |
| | ColId opt_column_list |
| { |
| AccessPriv *n = makeNode(AccessPriv); |
| |
| n->priv_name = $1; |
| n->cols = $2; |
| $$ = n; |
| } |
| ; |
| |
| parameter_name_list: |
| parameter_name |
| { |
| $$ = list_make1(makeString($1)); |
| } |
| | parameter_name_list ',' parameter_name |
| { |
| $$ = lappend($1, makeString($3)); |
| } |
| ; |
| |
| parameter_name: |
| ColId |
| { |
| $$ = $1; |
| } |
| | parameter_name '.' ColId |
| { |
| $$ = psprintf("%s.%s", $1, $3); |
| } |
| ; |
| |
| |
| /* Don't bother trying to fold the first two rules into one using |
| * opt_table. You're going to get conflicts. |
| */ |
| privilege_target: |
| qualified_name_list_with_only |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_TABLE; |
| n->objs = $1; |
| $$ = n; |
| } |
| | TABLE qualified_name_list_with_only |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_TABLE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | SEQUENCE qualified_name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_SEQUENCE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | FOREIGN DATA_P WRAPPER name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_FDW; |
| n->objs = $4; |
| $$ = n; |
| } |
| | FOREIGN SERVER name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_FOREIGN_SERVER; |
| n->objs = $3; |
| $$ = n; |
| } |
| | FUNCTION function_with_argtypes_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_FUNCTION; |
| n->objs = $2; |
| $$ = n; |
| } |
| | PROCEDURE function_with_argtypes_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_PROCEDURE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | ROUTINE function_with_argtypes_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_ROUTINE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | DATABASE name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_DATABASE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | DOMAIN_P any_name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_DOMAIN; |
| n->objs = $2; |
| $$ = n; |
| } |
| | LANGUAGE name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_LANGUAGE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | LARGE_P OBJECT_P NumericOnly_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_LARGEOBJECT; |
| n->objs = $3; |
| $$ = n; |
| } |
| | PARAMETER parameter_name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_PARAMETER_ACL; |
| n->objs = $2; |
| $$ = n; |
| } |
| | SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_SCHEMA; |
| n->objs = $2; |
| $$ = n; |
| } |
| | TABLESPACE name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_TABLESPACE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | PROTOCOL name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_EXTPROTOCOL; |
| n->objs = $2; |
| $$ = n; |
| } |
| | TYPE_P any_name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_OBJECT; |
| n->objtype = OBJECT_TYPE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | ALL TABLES IN_P SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_ALL_IN_SCHEMA; |
| n->objtype = OBJECT_TABLE; |
| n->objs = $5; |
| $$ = n; |
| } |
| | ALL SEQUENCES IN_P SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_ALL_IN_SCHEMA; |
| n->objtype = OBJECT_SEQUENCE; |
| n->objs = $5; |
| $$ = n; |
| } |
| | ALL FUNCTIONS IN_P SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_ALL_IN_SCHEMA; |
| n->objtype = OBJECT_FUNCTION; |
| n->objs = $5; |
| $$ = n; |
| } |
| | ALL PROCEDURES IN_P SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_ALL_IN_SCHEMA; |
| n->objtype = OBJECT_PROCEDURE; |
| n->objs = $5; |
| $$ = n; |
| } |
| | ALL ROUTINES IN_P SCHEMA name_list |
| { |
| PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); |
| |
| n->targtype = ACL_TARGET_ALL_IN_SCHEMA; |
| n->objtype = OBJECT_ROUTINE; |
| n->objs = $5; |
| $$ = n; |
| } |
| ; |
| |
| |
| grantee_list: |
| grantee { $$ = list_make1($1); } |
| | grantee_list ',' grantee { $$ = lappend($1, $3); } |
| ; |
| |
| grantee: |
| RoleSpec { $$ = $1; } |
| | GROUP_P RoleSpec { $$ = $2; } |
| ; |
| |
| |
| opt_grant_grant_option: |
| WITH GRANT OPTION { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * GRANT and REVOKE ROLE statements |
| * |
| *****************************************************************************/ |
| |
| GrantRoleStmt: |
| GRANT privilege_list TO role_list opt_granted_by |
| { |
| GrantRoleStmt *n = makeNode(GrantRoleStmt); |
| |
| n->is_grant = true; |
| n->granted_roles = $2; |
| n->grantee_roles = $4; |
| n->opt = NIL; |
| n->grantor = $5; |
| $$ = (Node *) n; |
| } |
| | GRANT privilege_list TO role_list WITH grant_role_opt_list opt_granted_by |
| { |
| GrantRoleStmt *n = makeNode(GrantRoleStmt); |
| |
| n->is_grant = true; |
| n->granted_roles = $2; |
| n->grantee_roles = $4; |
| n->opt = $6; |
| n->grantor = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RevokeRoleStmt: |
| REVOKE privilege_list FROM role_list opt_granted_by opt_drop_behavior |
| { |
| GrantRoleStmt *n = makeNode(GrantRoleStmt); |
| |
| n->is_grant = false; |
| n->opt = NIL; |
| n->granted_roles = $2; |
| n->grantee_roles = $4; |
| n->grantor = $5; |
| n->behavior = $6; |
| $$ = (Node *) n; |
| } |
| | REVOKE ColId OPTION FOR privilege_list FROM role_list opt_granted_by opt_drop_behavior |
| { |
| GrantRoleStmt *n = makeNode(GrantRoleStmt); |
| DefElem *opt; |
| |
| opt = makeDefElem(pstrdup($2), |
| (Node *) makeBoolean(false), @2); |
| n->is_grant = false; |
| n->opt = list_make1(opt); |
| n->granted_roles = $5; |
| n->grantee_roles = $7; |
| n->grantor = $8; |
| n->behavior = $9; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| grant_role_opt_list: |
| grant_role_opt_list ',' grant_role_opt { $$ = lappend($1, $3); } |
| | grant_role_opt { $$ = list_make1($1); } |
| ; |
| |
| grant_role_opt: |
| ColLabel grant_role_opt_value |
| { |
| $$ = makeDefElem(pstrdup($1), $2, @1); |
| } |
| ; |
| |
| grant_role_opt_value: |
| OPTION { $$ = (Node *) makeBoolean(true); } |
| | TRUE_P { $$ = (Node *) makeBoolean(true); } |
| | FALSE_P { $$ = (Node *) makeBoolean(false); } |
| ; |
| |
| opt_granted_by: GRANTED BY RoleSpec { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER DEFAULT PRIVILEGES statement |
| * |
| *****************************************************************************/ |
| |
| AlterDefaultPrivilegesStmt: |
| ALTER DEFAULT PRIVILEGES DefACLOptionList DefACLAction |
| { |
| AlterDefaultPrivilegesStmt *n = makeNode(AlterDefaultPrivilegesStmt); |
| |
| n->options = $4; |
| n->action = (GrantStmt *) $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| DefACLOptionList: |
| DefACLOptionList DefACLOption { $$ = lappend($1, $2); } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| DefACLOption: |
| IN_P SCHEMA name_list |
| { |
| $$ = makeDefElem("schemas", (Node *) $3, @1); |
| } |
| | FOR ROLE role_list |
| { |
| $$ = makeDefElem("roles", (Node *) $3, @1); |
| } |
| | FOR USER role_list |
| { |
| $$ = makeDefElem("roles", (Node *) $3, @1); |
| } |
| ; |
| |
| /* |
| * This should match GRANT/REVOKE, except that individual target objects |
| * are not mentioned and we only allow a subset of object types. |
| */ |
| DefACLAction: |
| GRANT privileges ON defacl_privilege_target TO grantee_list |
| opt_grant_grant_option |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = true; |
| n->privileges = $2; |
| n->targtype = ACL_TARGET_DEFAULTS; |
| n->objtype = $4; |
| n->objects = NIL; |
| n->grantees = $6; |
| n->grant_option = $7; |
| $$ = (Node *) n; |
| } |
| | REVOKE privileges ON defacl_privilege_target |
| FROM grantee_list opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = false; |
| n->grant_option = false; |
| n->privileges = $2; |
| n->targtype = ACL_TARGET_DEFAULTS; |
| n->objtype = $4; |
| n->objects = NIL; |
| n->grantees = $6; |
| n->behavior = $7; |
| $$ = (Node *) n; |
| } |
| | REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target |
| FROM grantee_list opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| |
| n->is_grant = false; |
| n->grant_option = true; |
| n->privileges = $5; |
| n->targtype = ACL_TARGET_DEFAULTS; |
| n->objtype = $7; |
| n->objects = NIL; |
| n->grantees = $9; |
| n->behavior = $10; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| defacl_privilege_target: |
| TABLES { $$ = OBJECT_TABLE; } |
| | FUNCTIONS { $$ = OBJECT_FUNCTION; } |
| | ROUTINES { $$ = OBJECT_FUNCTION; } |
| | SEQUENCES { $$ = OBJECT_SEQUENCE; } |
| | TYPES_P { $$ = OBJECT_TYPE; } |
| | SCHEMAS { $$ = OBJECT_SCHEMA; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: CREATE INDEX |
| * |
| * Note: we cannot put TABLESPACE clause after WHERE clause unless we are |
| * willing to make TABLESPACE a fully reserved word. |
| *****************************************************************************/ |
| |
| IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_single_name |
| ON relation_expr access_method_clause '(' index_params ')' |
| opt_include opt_unique_null_treatment opt_reloptions OptTableSpace where_clause OptTagOptList |
| { |
| IndexStmt *n = makeNode(IndexStmt); |
| |
| n->unique = $2; |
| n->concurrent = $4; |
| n->idxname = $5; |
| n->relation = $7; |
| n->accessMethod = $8; |
| n->indexParams = $10; |
| n->indexIncludingParams = $12; |
| n->nulls_not_distinct = !$13; |
| n->options = $14; |
| n->tableSpace = $15; |
| n->whereClause = $16; |
| n->excludeOpNames = NIL; |
| n->idxcomment = NULL; |
| n->indexOid = InvalidOid; |
| n->oldNumber = InvalidRelFileNumber; |
| n->oldCreateSubid = InvalidSubTransactionId; |
| n->oldFirstRelfilelocatorSubid = InvalidSubTransactionId; |
| n->primary = false; |
| n->isconstraint = false; |
| n->deferrable = false; |
| n->initdeferred = false; |
| n->transformed = false; |
| n->if_not_exists = false; |
| n->reset_default_tblspc = false; |
| n->tags = $17; |
| |
| $$ = (Node *) n; |
| } |
| | CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS name |
| ON relation_expr access_method_clause '(' index_params ')' |
| opt_include opt_unique_null_treatment opt_reloptions OptTableSpace where_clause OptTagOptList |
| { |
| IndexStmt *n = makeNode(IndexStmt); |
| |
| n->unique = $2; |
| n->concurrent = $4; |
| n->idxname = $8; |
| n->relation = $10; |
| n->accessMethod = $11; |
| n->indexParams = $13; |
| n->indexIncludingParams = $15; |
| n->nulls_not_distinct = !$16; |
| n->options = $17; |
| n->tableSpace = $18; |
| n->whereClause = $19; |
| n->excludeOpNames = NIL; |
| n->idxcomment = NULL; |
| n->indexOid = InvalidOid; |
| n->oldNumber = InvalidRelFileNumber; |
| n->oldCreateSubid = InvalidSubTransactionId; |
| n->oldFirstRelfilelocatorSubid = InvalidSubTransactionId; |
| n->primary = false; |
| n->isconstraint = false; |
| n->deferrable = false; |
| n->initdeferred = false; |
| n->transformed = false; |
| n->if_not_exists = true; |
| n->reset_default_tblspc = false; |
| n->tags = $20; |
| |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_unique: |
| UNIQUE { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| access_method_clause: |
| USING name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| index_params: index_elem { $$ = list_make1($1); } |
| | index_params ',' index_elem { $$ = lappend($1, $3); } |
| ; |
| |
| |
| index_elem_options: |
| opt_collate opt_qualified_name opt_asc_desc opt_nulls_order |
| { |
| $$ = makeNode(IndexElem); |
| $$->name = NULL; |
| $$->expr = NULL; |
| $$->indexcolname = NULL; |
| $$->collation = $1; |
| $$->opclass = $2; |
| $$->opclassopts = NIL; |
| $$->ordering = $3; |
| $$->nulls_ordering = $4; |
| } |
| | opt_collate any_name reloptions opt_asc_desc opt_nulls_order |
| { |
| $$ = makeNode(IndexElem); |
| $$->name = NULL; |
| $$->expr = NULL; |
| $$->indexcolname = NULL; |
| $$->collation = $1; |
| $$->opclass = $2; |
| $$->opclassopts = $3; |
| $$->ordering = $4; |
| $$->nulls_ordering = $5; |
| } |
| ; |
| |
| /* |
| * Index attributes can be either simple column references, or arbitrary |
| * expressions in parens. For backwards-compatibility reasons, we allow |
| * an expression that's just a function call to be written without parens. |
| */ |
| index_elem: ColId index_elem_options |
| { |
| $$ = $2; |
| $$->name = $1; |
| } |
| | func_expr_windowless index_elem_options |
| { |
| $$ = $2; |
| $$->expr = $1; |
| } |
| | '(' a_expr ')' index_elem_options |
| { |
| $$ = $4; |
| $$->expr = $2; |
| } |
| ; |
| |
| opt_include: INCLUDE '(' index_including_params ')' { $$ = $3; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| index_including_params: index_elem { $$ = list_make1($1); } |
| | index_including_params ',' index_elem { $$ = lappend($1, $3); } |
| ; |
| |
| opt_collate: COLLATE any_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_class: any_name { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| opt_asc_desc: ASC { $$ = SORTBY_ASC; } |
| | DESC { $$ = SORTBY_DESC; } |
| | /*EMPTY*/ { $$ = SORTBY_DEFAULT; } |
| ; |
| |
| opt_nulls_order: NULLS_LA FIRST_P { $$ = SORTBY_NULLS_FIRST; } |
| | NULLS_LA LAST_P { $$ = SORTBY_NULLS_LAST; } |
| | /*EMPTY*/ { $$ = SORTBY_NULLS_DEFAULT; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * create [or replace] function <fname> |
| * [(<type-1> { , <type-n>})] |
| * returns <type-r> |
| * as <filename or code in language as appropriate> |
| * language <lang> [with parameters] |
| * |
| *****************************************************************************/ |
| |
| CreateFunctionStmt: |
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults |
| RETURNS func_return opt_createfunc_opt_list opt_routine_body opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| |
| n->is_procedure = false; |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = $5; |
| n->returnType = $7; |
| n->options = $8; |
| n->sql_body = $9; |
| n->options = list_concat(n->options, $10); |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults |
| RETURNS TABLE '(' table_func_column_list ')' opt_createfunc_opt_list opt_routine_body |
| opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| |
| n->is_procedure = false; |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = mergeTableFuncParameters($5, $9); |
| n->returnType = TableFuncTypeName($9); |
| n->returnType->location = @7; |
| n->options = $11; |
| n->sql_body = $12; |
| n->options = list_concat(n->options, $13); |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults |
| opt_createfunc_opt_list opt_routine_body opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| |
| n->is_procedure = false; |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = $5; |
| n->returnType = NULL; |
| n->options = $6; |
| n->sql_body = $7; |
| n->options = list_concat(n->options, $8); |
| $$ = (Node *) n; |
| } |
| | CREATE opt_or_replace PROCEDURE func_name func_args_with_defaults |
| opt_createfunc_opt_list opt_routine_body |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| |
| n->is_procedure = true; |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = $5; |
| n->returnType = NULL; |
| n->options = $6; |
| n->sql_body = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_or_replace: |
| OR REPLACE { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| func_args: '(' func_args_list ')' { $$ = $2; } |
| | '(' ')' { $$ = NIL; } |
| ; |
| |
| func_args_list: |
| func_arg { $$ = list_make1($1); } |
| | func_args_list ',' func_arg { $$ = lappend($1, $3); } |
| ; |
| |
| function_with_argtypes_list: |
| function_with_argtypes { $$ = list_make1($1); } |
| | function_with_argtypes_list ',' function_with_argtypes |
| { $$ = lappend($1, $3); } |
| ; |
| |
| function_with_argtypes: |
| func_name func_args |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = $1; |
| n->objargs = extractArgTypes($2); |
| n->objfuncargs = $2; |
| $$ = n; |
| } |
| /* |
| * Because of reduce/reduce conflicts, we can't use func_name |
| * below, but we can write it out the long way, which actually |
| * allows more cases. |
| */ |
| | type_func_name_keyword |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = list_make1(makeString(pstrdup($1))); |
| n->args_unspecified = true; |
| $$ = n; |
| } |
| | ColId |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = list_make1(makeString($1)); |
| n->args_unspecified = true; |
| $$ = n; |
| } |
| | ColId indirection |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = check_func_name(lcons(makeString($1), $2), |
| yyscanner); |
| n->args_unspecified = true; |
| $$ = n; |
| } |
| ; |
| |
| /* |
| * func_args_with_defaults is separate because we only want to accept |
| * defaults in CREATE FUNCTION, not in ALTER etc. |
| */ |
| func_args_with_defaults: |
| '(' func_args_with_defaults_list ')' { $$ = $2; } |
| | '(' ')' { $$ = NIL; } |
| ; |
| |
| func_args_with_defaults_list: |
| func_arg_with_default { $$ = list_make1($1); } |
| | func_args_with_defaults_list ',' func_arg_with_default |
| { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * The style with arg_class first is SQL99 standard, but Oracle puts |
| * param_name first; accept both since it's likely people will try both |
| * anyway. Don't bother trying to save productions by letting arg_class |
| * have an empty alternative ... you'll get shift/reduce conflicts. |
| * |
| * We can catch over-specified arguments here if we want to, |
| * but for now better to silently swallow typmod, etc. |
| * - thomas 2000-03-22 |
| */ |
| func_arg: |
| arg_class param_name func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = $2; |
| n->argType = $3; |
| n->mode = $1; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| | param_name arg_class func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = $1; |
| n->argType = $3; |
| n->mode = $2; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| | param_name func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = $1; |
| n->argType = $2; |
| n->mode = FUNC_PARAM_DEFAULT; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| | arg_class func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = NULL; |
| n->argType = $2; |
| n->mode = $1; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| | func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = NULL; |
| n->argType = $1; |
| n->mode = FUNC_PARAM_DEFAULT; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| ; |
| |
| /* INOUT is SQL99 standard, IN OUT is for Oracle compatibility */ |
| arg_class: IN_P { $$ = FUNC_PARAM_IN; } |
| | OUT_P { $$ = FUNC_PARAM_OUT; } |
| | INOUT { $$ = FUNC_PARAM_INOUT; } |
| | IN_P OUT_P { $$ = FUNC_PARAM_INOUT; } |
| | VARIADIC { $$ = FUNC_PARAM_VARIADIC; } |
| ; |
| |
| /* |
| * Ideally param_name should be ColId, but that causes too many conflicts. |
| */ |
| param_name: type_function_name |
| ; |
| |
| func_return: |
| func_type |
| { |
| /* We can catch over-specified results here if we want to, |
| * but for now better to silently swallow typmod, etc. |
| * - thomas 2000-03-22 |
| */ |
| $$ = $1; |
| } |
| ; |
| |
| /* |
| * We would like to make the %TYPE productions here be ColId attrs etc, |
| * but that causes reduce/reduce conflicts. type_function_name |
| * is next best choice. |
| */ |
| func_type: Typename { $$ = $1; } |
| | type_function_name attrs '%' TYPE_P |
| { |
| $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); |
| $$->pct_type = true; |
| $$->location = @1; |
| } |
| | SETOF type_function_name attrs '%' TYPE_P |
| { |
| $$ = makeTypeNameFromNameList(lcons(makeString($2), $3)); |
| $$->pct_type = true; |
| $$->setof = true; |
| $$->location = @2; |
| } |
| ; |
| |
| func_arg_with_default: |
| func_arg |
| { |
| $$ = $1; |
| } |
| | func_arg DEFAULT a_expr |
| { |
| $$ = $1; |
| $$->defexpr = $3; |
| } |
| | func_arg '=' a_expr |
| { |
| $$ = $1; |
| $$->defexpr = $3; |
| } |
| ; |
| |
| /* Aggregate args can be most things that function args can be */ |
| aggr_arg: func_arg |
| { |
| if (!($1->mode == FUNC_PARAM_DEFAULT || |
| $1->mode == FUNC_PARAM_IN || |
| $1->mode == FUNC_PARAM_VARIADIC)) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("aggregates cannot have output arguments"), |
| parser_errposition(@1))); |
| $$ = $1; |
| } |
| ; |
| |
| /* |
| * The SQL standard offers no guidance on how to declare aggregate argument |
| * lists, since it doesn't have CREATE AGGREGATE etc. We accept these cases: |
| * |
| * (*) - normal agg with no args |
| * (aggr_arg,...) - normal agg with args |
| * (ORDER BY aggr_arg,...) - ordered-set agg with no direct args |
| * (aggr_arg,... ORDER BY aggr_arg,...) - ordered-set agg with direct args |
| * |
| * The zero-argument case is spelled with '*' for consistency with COUNT(*). |
| * |
| * An additional restriction is that if the direct-args list ends in a |
| * VARIADIC item, the ordered-args list must contain exactly one item that |
| * is also VARIADIC with the same type. This allows us to collapse the two |
| * VARIADIC items into one, which is necessary to represent the aggregate in |
| * pg_proc. We check this at the grammar stage so that we can return a list |
| * in which the second VARIADIC item is already discarded, avoiding extra work |
| * in cases such as DROP AGGREGATE. |
| * |
| * The return value of this production is a two-element list, in which the |
| * first item is a sublist of FunctionParameter nodes (with any duplicate |
| * VARIADIC item already dropped, as per above) and the second is an Integer |
| * node, containing -1 if there was no ORDER BY and otherwise the number |
| * of argument declarations before the ORDER BY. (If this number is equal |
| * to the first sublist's length, then we dropped a duplicate VARIADIC item.) |
| * This representation is passed as-is to CREATE AGGREGATE; for operations |
| * on existing aggregates, we can just apply extractArgTypes to the first |
| * sublist. |
| */ |
| aggr_args: '(' '*' ')' |
| { |
| $$ = list_make2(NIL, makeInteger(-1)); |
| } |
| | '(' aggr_args_list ')' |
| { |
| $$ = list_make2($2, makeInteger(-1)); |
| } |
| | '(' ORDER BY aggr_args_list ')' |
| { |
| $$ = list_make2($4, makeInteger(0)); |
| } |
| | '(' aggr_args_list ORDER BY aggr_args_list ')' |
| { |
| /* this is the only case requiring consistency checking */ |
| $$ = makeOrderedSetArgs($2, $5, yyscanner); |
| } |
| ; |
| |
| aggr_args_list: |
| aggr_arg { $$ = list_make1($1); } |
| | aggr_args_list ',' aggr_arg { $$ = lappend($1, $3); } |
| ; |
| |
| aggregate_with_argtypes: |
| func_name aggr_args |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = $1; |
| n->objargs = extractAggrArgTypes($2); |
| n->objfuncargs = (List *) linitial($2); |
| $$ = n; |
| } |
| ; |
| |
| aggregate_with_argtypes_list: |
| aggregate_with_argtypes { $$ = list_make1($1); } |
| | aggregate_with_argtypes_list ',' aggregate_with_argtypes |
| { $$ = lappend($1, $3); } |
| ; |
| |
| opt_createfunc_opt_list: |
| createfunc_opt_list |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| createfunc_opt_list: |
| /* Must be at least one to prevent conflict */ |
| createfunc_opt_item { $$ = list_make1($1); } |
| | createfunc_opt_list createfunc_opt_item { $$ = lappend($1, $2); } |
| ; |
| |
| /* |
| * Options common to both CREATE FUNCTION and ALTER FUNCTION |
| */ |
| common_func_opt_item: |
| CALLED ON NULL_P INPUT_P |
| { |
| $$ = makeDefElem("strict", (Node *) makeBoolean(false), @1); |
| } |
| | RETURNS NULL_P ON NULL_P INPUT_P |
| { |
| $$ = makeDefElem("strict", (Node *) makeBoolean(true), @1); |
| } |
| | STRICT_P |
| { |
| $$ = makeDefElem("strict", (Node *) makeBoolean(true), @1); |
| } |
| | IMMUTABLE |
| { |
| $$ = makeDefElem("volatility", (Node *) makeString("immutable"), @1); |
| } |
| | STABLE |
| { |
| $$ = makeDefElem("volatility", (Node *) makeString("stable"), @1); |
| } |
| | VOLATILE |
| { |
| $$ = makeDefElem("volatility", (Node *) makeString("volatile"), @1); |
| } |
| | EXTERNAL SECURITY DEFINER |
| { |
| $$ = makeDefElem("security", (Node *) makeBoolean(true), @1); |
| } |
| | EXTERNAL SECURITY INVOKER |
| { |
| $$ = makeDefElem("security", (Node *) makeBoolean(false), @1); |
| } |
| | SECURITY DEFINER |
| { |
| $$ = makeDefElem("security", (Node *) makeBoolean(true), @1); |
| } |
| | SECURITY INVOKER |
| { |
| $$ = makeDefElem("security", (Node *) makeBoolean(false), @1); |
| } |
| | LEAKPROOF |
| { |
| $$ = makeDefElem("leakproof", (Node *) makeBoolean(true), @1); |
| } |
| | NOT LEAKPROOF |
| { |
| $$ = makeDefElem("leakproof", (Node *) makeBoolean(false), @1); |
| } |
| | COST NumericOnly |
| { |
| $$ = makeDefElem("cost", (Node *) $2, @1); |
| } |
| | ROWS NumericOnly |
| { |
| $$ = makeDefElem("rows", (Node *) $2, @1); |
| } |
| | SUPPORT any_name |
| { |
| $$ = makeDefElem("support", (Node *) $2, @1); |
| } |
| | FunctionSetResetClause |
| { |
| /* we abuse the normal content of a DefElem here */ |
| $$ = makeDefElem("set", (Node *) $1, @1); |
| } |
| | PARALLEL ColId |
| { |
| $$ = makeDefElem("parallel", (Node *) makeString($2), @1); |
| } |
| | NO SQL_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("none"), @1); |
| } |
| | CONTAINS SQL_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("contains"), @1); |
| } |
| | READS SQL_P DATA_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("reads"), @1); |
| } |
| | MODIFIES SQL_P DATA_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("modifies"), @1); |
| } |
| | EXECUTE ON ANY |
| { |
| $$ = makeDefElem("exec_location", (Node *)makeString("any"), @1); |
| } |
| | EXECUTE ON MASTER |
| { |
| $$ = makeDefElem("exec_location", (Node *)makeString("coordinator"), @1); |
| } |
| | EXECUTE ON COORDINATOR |
| { |
| $$ = makeDefElem("exec_location", (Node *)makeString("coordinator"), @1); |
| } |
| | EXECUTE ON INITPLAN |
| { |
| $$ = makeDefElem("exec_location", (Node *)makeString("initplan"), @1); |
| } |
| | EXECUTE ON ALL SEGMENTS |
| { |
| $$ = makeDefElem("exec_location", (Node *)makeString("all_segments"), @1); |
| } |
| ; |
| |
| createfunc_opt_item: |
| AS func_as |
| { |
| $$ = makeDefElem("as", (Node *) $2, @1); |
| } |
| | LANGUAGE NonReservedWord_or_Sconst |
| { |
| $$ = makeDefElem("language", (Node *) makeString($2), @1); |
| } |
| | TRANSFORM transform_type_list |
| { |
| $$ = makeDefElem("transform", (Node *) $2, @1); |
| } |
| | WINDOW |
| { |
| $$ = makeDefElem("window", (Node *) makeBoolean(true), @1); |
| } |
| | common_func_opt_item |
| { |
| $$ = $1; |
| } |
| ; |
| |
| func_as: Sconst { $$ = list_make1(makeString($1)); } |
| | Sconst ',' Sconst |
| { |
| $$ = list_make2(makeString($1), makeString($3)); |
| } |
| ; |
| |
| ReturnStmt: RETURN a_expr |
| { |
| ReturnStmt *r = makeNode(ReturnStmt); |
| |
| r->returnval = (Node *) $2; |
| $$ = (Node *) r; |
| } |
| ; |
| |
| opt_routine_body: |
| ReturnStmt |
| { |
| $$ = $1; |
| } |
| | BEGIN_P ATOMIC routine_body_stmt_list END_P |
| { |
| /* |
| * A compound statement is stored as a single-item list |
| * containing the list of statements as its member. That |
| * way, the parse analysis code can tell apart an empty |
| * body from no body at all. |
| */ |
| $$ = (Node *) list_make1($3); |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| routine_body_stmt_list: |
| routine_body_stmt_list routine_body_stmt ';' |
| { |
| /* As in stmtmulti, discard empty statements */ |
| if ($2 != NULL) |
| $$ = lappend($1, $2); |
| else |
| $$ = $1; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NIL; |
| } |
| ; |
| |
| routine_body_stmt: |
| stmt |
| | ReturnStmt |
| ; |
| |
| transform_type_list: |
| FOR TYPE_P Typename { $$ = list_make1($3); } |
| | transform_type_list ',' FOR TYPE_P Typename { $$ = lappend($1, $5); } |
| ; |
| |
| opt_definition: |
| WITH definition { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| table_func_column: param_name func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| |
| n->name = $1; |
| n->argType = $2; |
| n->mode = FUNC_PARAM_TABLE; |
| n->defexpr = NULL; |
| $$ = n; |
| } |
| ; |
| |
| table_func_column_list: |
| table_func_column |
| { |
| $$ = list_make1($1); |
| } |
| | table_func_column_list ',' table_func_column |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| /***************************************************************************** |
| * ALTER FUNCTION / ALTER PROCEDURE / ALTER ROUTINE |
| * |
| * RENAME and OWNER subcommands are already provided by the generic |
| * ALTER infrastructure, here we just specify alterations that can |
| * only be applied to functions. |
| * |
| *****************************************************************************/ |
| AlterFunctionStmt: |
| ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict |
| { |
| AlterFunctionStmt *n = makeNode(AlterFunctionStmt); |
| |
| n->objtype = OBJECT_FUNCTION; |
| n->func = $3; |
| n->actions = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER PROCEDURE function_with_argtypes alterfunc_opt_list opt_restrict |
| { |
| AlterFunctionStmt *n = makeNode(AlterFunctionStmt); |
| |
| n->objtype = OBJECT_PROCEDURE; |
| n->func = $3; |
| n->actions = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER ROUTINE function_with_argtypes alterfunc_opt_list opt_restrict |
| { |
| AlterFunctionStmt *n = makeNode(AlterFunctionStmt); |
| |
| n->objtype = OBJECT_ROUTINE; |
| n->func = $3; |
| n->actions = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| alterfunc_opt_list: |
| /* At least one option must be specified */ |
| common_func_opt_item { $$ = list_make1($1); } |
| | alterfunc_opt_list common_func_opt_item { $$ = lappend($1, $2); } |
| ; |
| |
| /* Ignored, merely for SQL compliance */ |
| opt_restrict: |
| RESTRICT |
| | /* EMPTY */ |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP FUNCTION funcname (arg1, arg2, ...) [ RESTRICT | CASCADE ] |
| * DROP PROCEDURE procname (arg1, arg2, ...) [ RESTRICT | CASCADE ] |
| * DROP ROUTINE routname (arg1, arg2, ...) [ RESTRICT | CASCADE ] |
| * DROP AGGREGATE aggname (arg1, ...) [ RESTRICT | CASCADE ] |
| * DROP OPERATOR opname (leftoperand_typ, rightoperand_typ) [ RESTRICT | CASCADE ] |
| * |
| *****************************************************************************/ |
| |
| RemoveFuncStmt: |
| DROP FUNCTION function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_FUNCTION; |
| n->objects = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP FUNCTION IF_P EXISTS function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_FUNCTION; |
| n->objects = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP PROCEDURE function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_PROCEDURE; |
| n->objects = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP PROCEDURE IF_P EXISTS function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_PROCEDURE; |
| n->objects = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP ROUTINE function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_ROUTINE; |
| n->objects = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP ROUTINE IF_P EXISTS function_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_ROUTINE; |
| n->objects = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RemoveAggrStmt: |
| DROP AGGREGATE aggregate_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_AGGREGATE; |
| n->objects = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_AGGREGATE; |
| n->objects = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RemoveOperStmt: |
| DROP OPERATOR operator_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_OPERATOR; |
| n->objects = $3; |
| n->behavior = $4; |
| n->missing_ok = false; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| | DROP OPERATOR IF_P EXISTS operator_with_argtypes_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_OPERATOR; |
| n->objects = $5; |
| n->behavior = $6; |
| n->missing_ok = true; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| oper_argtypes: |
| '(' Typename ')' |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("missing argument"), |
| errhint("Use NONE to denote the missing argument of a unary operator."), |
| parser_errposition(@3))); |
| } |
| | '(' Typename ',' Typename ')' |
| { $$ = list_make2($2, $4); } |
| | '(' NONE ',' Typename ')' /* left unary */ |
| { $$ = list_make2(NULL, $4); } |
| | '(' Typename ',' NONE ')' /* right unary */ |
| { $$ = list_make2($2, NULL); } |
| ; |
| |
| any_operator: |
| all_Op |
| { $$ = list_make1(makeString($1)); } |
| | ColId '.' any_operator |
| { $$ = lcons(makeString($1), $3); } |
| ; |
| |
| operator_with_argtypes_list: |
| operator_with_argtypes { $$ = list_make1($1); } |
| | operator_with_argtypes_list ',' operator_with_argtypes |
| { $$ = lappend($1, $3); } |
| ; |
| |
| operator_with_argtypes: |
| any_operator oper_argtypes |
| { |
| ObjectWithArgs *n = makeNode(ObjectWithArgs); |
| |
| n->objname = $1; |
| n->objargs = $2; |
| $$ = n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * DO <anonymous code block> [ LANGUAGE language ] |
| * |
| * We use a DefElem list for future extensibility, and to allow flexibility |
| * in the clause order. |
| * |
| *****************************************************************************/ |
| |
| DoStmt: DO dostmt_opt_list |
| { |
| DoStmt *n = makeNode(DoStmt); |
| |
| n->args = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| dostmt_opt_list: |
| dostmt_opt_item { $$ = list_make1($1); } |
| | dostmt_opt_list dostmt_opt_item { $$ = lappend($1, $2); } |
| ; |
| |
| dostmt_opt_item: |
| Sconst |
| { |
| $$ = makeDefElem("as", (Node *) makeString($1), @1); |
| } |
| | LANGUAGE NonReservedWord_or_Sconst |
| { |
| $$ = makeDefElem("language", (Node *) makeString($2), @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * CREATE CAST / DROP CAST |
| * |
| *****************************************************************************/ |
| |
| CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' |
| WITH FUNCTION function_with_argtypes cast_context |
| { |
| CreateCastStmt *n = makeNode(CreateCastStmt); |
| |
| n->sourcetype = $4; |
| n->targettype = $6; |
| n->func = $10; |
| n->context = (CoercionContext) $11; |
| n->inout = false; |
| $$ = (Node *) n; |
| } |
| | CREATE CAST '(' Typename AS Typename ')' |
| WITHOUT FUNCTION cast_context |
| { |
| CreateCastStmt *n = makeNode(CreateCastStmt); |
| |
| n->sourcetype = $4; |
| n->targettype = $6; |
| n->func = NULL; |
| n->context = (CoercionContext) $10; |
| n->inout = false; |
| $$ = (Node *) n; |
| } |
| | CREATE CAST '(' Typename AS Typename ')' |
| WITH INOUT cast_context |
| { |
| CreateCastStmt *n = makeNode(CreateCastStmt); |
| |
| n->sourcetype = $4; |
| n->targettype = $6; |
| n->func = NULL; |
| n->context = (CoercionContext) $10; |
| n->inout = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| cast_context: AS IMPLICIT_P { $$ = COERCION_IMPLICIT; } |
| | AS ASSIGNMENT { $$ = COERCION_ASSIGNMENT; } |
| | /*EMPTY*/ { $$ = COERCION_EXPLICIT; } |
| ; |
| |
| |
| DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_CAST; |
| n->objects = list_make1(list_make2($5, $7)); |
| n->behavior = $9; |
| n->missing_ok = $3; |
| n->concurrent = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_if_exists: IF_P EXISTS { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * CREATE TRANSFORM / DROP TRANSFORM |
| * |
| *****************************************************************************/ |
| |
| CreateTransformStmt: CREATE opt_or_replace TRANSFORM FOR Typename LANGUAGE name '(' transform_element_list ')' |
| { |
| CreateTransformStmt *n = makeNode(CreateTransformStmt); |
| |
| n->replace = $2; |
| n->type_name = $5; |
| n->lang = $7; |
| n->fromsql = linitial($9); |
| n->tosql = lsecond($9); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| transform_element_list: FROM SQL_P WITH FUNCTION function_with_argtypes ',' TO SQL_P WITH FUNCTION function_with_argtypes |
| { |
| $$ = list_make2($5, $11); |
| } |
| | TO SQL_P WITH FUNCTION function_with_argtypes ',' FROM SQL_P WITH FUNCTION function_with_argtypes |
| { |
| $$ = list_make2($11, $5); |
| } |
| | FROM SQL_P WITH FUNCTION function_with_argtypes |
| { |
| $$ = list_make2($5, NULL); |
| } |
| | TO SQL_P WITH FUNCTION function_with_argtypes |
| { |
| $$ = list_make2(NULL, $5); |
| } |
| ; |
| |
| |
| DropTransformStmt: DROP TRANSFORM opt_if_exists FOR Typename LANGUAGE name opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| |
| n->removeType = OBJECT_TRANSFORM; |
| n->objects = list_make1(list_make2($5, makeString($7))); |
| n->behavior = $8; |
| n->missing_ok = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * REINDEX [ (options) ] {INDEX | TABLE | SCHEMA} [CONCURRENTLY] <name> |
| * REINDEX [ (options) ] {DATABASE | SYSTEM} [CONCURRENTLY] [<name>] |
| *****************************************************************************/ |
| |
| ReindexStmt: |
| REINDEX opt_reindex_option_list reindex_target_relation opt_concurrently qualified_name |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| |
| n->kind = $3; |
| n->relation = $5; |
| n->name = NULL; |
| n->params = $2; |
| if ($4) |
| n->params = lappend(n->params, |
| makeDefElem("concurrently", NULL, @4)); |
| $$ = (Node *) n; |
| } |
| | REINDEX opt_reindex_option_list SCHEMA opt_concurrently name |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| |
| n->kind = REINDEX_OBJECT_SCHEMA; |
| n->relation = NULL; |
| n->name = $5; |
| n->params = $2; |
| if ($4) |
| n->params = lappend(n->params, |
| makeDefElem("concurrently", NULL, @4)); |
| $$ = (Node *) n; |
| } |
| | REINDEX opt_reindex_option_list reindex_target_all opt_concurrently opt_single_name |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| n->kind = $3; |
| n->relation = NULL; |
| n->name = $5; |
| n->params = $2; |
| if ($4) |
| n->params = lappend(n->params, |
| makeDefElem("concurrently", NULL, @4)); |
| $$ = (Node *) n; |
| } |
| ; |
| reindex_target_relation: |
| INDEX { $$ = REINDEX_OBJECT_INDEX; } |
| | TABLE { $$ = REINDEX_OBJECT_TABLE; } |
| ; |
| reindex_target_all: |
| SYSTEM_P { $$ = REINDEX_OBJECT_SYSTEM; } |
| | DATABASE { $$ = REINDEX_OBJECT_DATABASE; } |
| ; |
| opt_reindex_option_list: |
| '(' utility_option_list ')' { $$ = $2; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER TABLESPACE |
| * |
| *****************************************************************************/ |
| |
| AlterTblSpcStmt: |
| ALTER TABLESPACE name SET reloptions |
| { |
| AlterTableSpaceOptionsStmt *n = |
| makeNode(AlterTableSpaceOptionsStmt); |
| |
| n->tablespacename = $3; |
| n->options = $5; |
| n->isReset = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLESPACE name RESET reloptions |
| { |
| AlterTableSpaceOptionsStmt *n = |
| makeNode(AlterTableSpaceOptionsStmt); |
| |
| n->tablespacename = $3; |
| n->options = $5; |
| n->isReset = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLESPACE name TAG '(' TagOptList ')' |
| { |
| AlterTableSpaceOptionsStmt *n = makeNode(AlterTableSpaceOptionsStmt); |
| n->tablespacename = $3; |
| n->tags = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TABLESPACE name UNSET_P TAG '(' name_list ')' |
| { |
| AlterTableSpaceOptionsStmt *n = makeNode(AlterTableSpaceOptionsStmt); |
| n->tablespacename = $3; |
| n->tags = $7; |
| n->unsettag = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name RENAME TO newname |
| * |
| *****************************************************************************/ |
| |
| RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_AGGREGATE; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER COLLATION any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLLATION; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER CONVERSION_P any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_CONVERSION; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_DATABASE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER DOMAIN_P any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_DOMAIN; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_DOMCONSTRAINT; |
| n->object = (Node *) $3; |
| n->subname = $6; |
| n->newname = $8; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_FDW; |
| n->object = (Node *) makeString($5); |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FUNCTION function_with_argtypes RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_FUNCTION; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER GROUP_P RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER opt_procedural LANGUAGE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_LANGUAGE; |
| n->object = (Node *) makeString($4); |
| n->newname = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR CLASS any_name USING name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_OPCLASS; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newname = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR FAMILY any_name USING name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_OPFAMILY; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newname = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER POLICY name ON qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_POLICY; |
| n->relation = $5; |
| n->subname = $3; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER POLICY IF_P EXISTS name ON qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_POLICY; |
| n->relation = $7; |
| n->subname = $5; |
| n->newname = $10; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER PROCEDURE function_with_argtypes RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_PROCEDURE; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER PUBLICATION name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_PUBLICATION; |
| n->object = (Node *) makeString($3); |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER ROUTINE function_with_argtypes RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_ROUTINE; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SCHEMA name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_SCHEMA; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SERVER name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_FOREIGN_SERVER; |
| n->object = (Node *) makeString($3); |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_SUBSCRIPTION; |
| n->object = (Node *) makeString($3); |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TABLE; |
| n->relation = $3; |
| n->subname = NULL; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TABLE; |
| n->relation = $5; |
| n->subname = NULL; |
| n->newname = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_SEQUENCE; |
| n->relation = $3; |
| n->subname = NULL; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE IF_P EXISTS qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_SEQUENCE; |
| n->relation = $5; |
| n->subname = NULL; |
| n->newname = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_VIEW; |
| n->relation = $3; |
| n->subname = NULL; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW IF_P EXISTS qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_VIEW; |
| n->relation = $5; |
| n->subname = NULL; |
| n->newname = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_MATVIEW; |
| n->relation = $4; |
| n->subname = NULL; |
| n->newname = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_MATVIEW; |
| n->relation = $6; |
| n->subname = NULL; |
| n->newname = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_INDEX; |
| n->relation = $3; |
| n->subname = NULL; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX IF_P EXISTS qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_INDEX; |
| n->relation = $5; |
| n->subname = NULL; |
| n->newname = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_FOREIGN_TABLE; |
| n->relation = $4; |
| n->subname = NULL; |
| n->newname = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_FOREIGN_TABLE; |
| n->relation = $6; |
| n->subname = NULL; |
| n->newname = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE relation_expr RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_TABLE; |
| n->relation = $3; |
| n->subname = $6; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_TABLE; |
| n->relation = $5; |
| n->subname = $8; |
| n->newname = $10; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW qualified_name RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_VIEW; |
| n->relation = $3; |
| n->subname = $6; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_VIEW; |
| n->relation = $5; |
| n->subname = $8; |
| n->newname = $10; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW qualified_name RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_MATVIEW; |
| n->relation = $4; |
| n->subname = $7; |
| n->newname = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_MATVIEW; |
| n->relation = $6; |
| n->subname = $9; |
| n->newname = $11; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TABCONSTRAINT; |
| n->relation = $3; |
| n->subname = $6; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TABCONSTRAINT; |
| n->relation = $5; |
| n->subname = $8; |
| n->newname = $10; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE relation_expr RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_FOREIGN_TABLE; |
| n->relation = $4; |
| n->subname = $7; |
| n->newname = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_COLUMN; |
| n->relationType = OBJECT_FOREIGN_TABLE; |
| n->relation = $6; |
| n->subname = $9; |
| n->newname = $11; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER RULE name ON qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_RULE; |
| n->relation = $5; |
| n->subname = $3; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TRIGGER name ON qualified_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TRIGGER; |
| n->relation = $5; |
| n->subname = $3; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER EVENT TRIGGER name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_EVENT_TRIGGER; |
| n->object = (Node *) makeString($4); |
| n->newname = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER ROLE RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER USER RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLESPACE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TABLESPACE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER STATISTICS any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_STATISTIC_EXT; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TSPARSER; |
| n->object = (Node *) $5; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TSDICTIONARY; |
| n->object = (Node *) $5; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TSTEMPLATE; |
| n->object = (Node *) $5; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TSCONFIGURATION; |
| n->object = (Node *) $5; |
| n->newname = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_TYPE; |
| n->object = (Node *) $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| |
| n->renameType = OBJECT_ATTRIBUTE; |
| n->relationType = OBJECT_TYPE; |
| n->relation = makeRangeVarFromAnyName($3, @3, yyscanner); |
| n->subname = $6; |
| n->newname = $8; |
| n->behavior = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER PROTOCOL name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_EXTPROTOCOL; |
| n->object = (Node *) makeString($3); |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | ALTER PROFILE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_PROFILE; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | ALTER TAG name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_TAG; |
| n->subname = $3; |
| n->newname = $6; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | ALTER TAG IF_P EXISTS name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_TAG; |
| n->subname = $5; |
| n->newname = $8; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_column: COLUMN |
| | /*EMPTY*/ |
| ; |
| |
| opt_set_data: SET DATA_P { $$ = 1; } |
| | /*EMPTY*/ { $$ = 0; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name DEPENDS ON EXTENSION name |
| * |
| *****************************************************************************/ |
| |
| AlterObjectDependsStmt: |
| ALTER FUNCTION function_with_argtypes opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_FUNCTION; |
| n->object = (Node *) $3; |
| n->extname = makeString($8); |
| n->remove = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER PROCEDURE function_with_argtypes opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_PROCEDURE; |
| n->object = (Node *) $3; |
| n->extname = makeString($8); |
| n->remove = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER ROUTINE function_with_argtypes opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_ROUTINE; |
| n->object = (Node *) $3; |
| n->extname = makeString($8); |
| n->remove = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER TRIGGER name ON qualified_name opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_TRIGGER; |
| n->relation = $5; |
| n->object = (Node *) list_make1(makeString($3)); |
| n->extname = makeString($10); |
| n->remove = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW qualified_name opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_MATVIEW; |
| n->relation = $4; |
| n->extname = makeString($9); |
| n->remove = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER INDEX qualified_name opt_no DEPENDS ON EXTENSION name |
| { |
| AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); |
| |
| n->objectType = OBJECT_INDEX; |
| n->relation = $3; |
| n->extname = makeString($8); |
| n->remove = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_no: NO { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name SET SCHEMA name |
| * |
| *****************************************************************************/ |
| |
| AlterObjectSchemaStmt: |
| ALTER AGGREGATE aggregate_with_argtypes SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_AGGREGATE; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER COLLATION any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_COLLATION; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER CONVERSION_P any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_CONVERSION; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER DOMAIN_P any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_DOMAIN; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER EXTENSION name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_EXTENSION; |
| n->object = (Node *) makeString($3); |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FUNCTION function_with_argtypes SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_FUNCTION; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR operator_with_argtypes SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_OPERATOR; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR CLASS any_name USING name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_OPCLASS; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newschema = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR FAMILY any_name USING name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_OPFAMILY; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newschema = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER PROCEDURE function_with_argtypes SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_PROCEDURE; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER ROUTINE function_with_argtypes SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_ROUTINE; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TABLE; |
| n->relation = $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLE IF_P EXISTS relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TABLE; |
| n->relation = $5; |
| n->newschema = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER STATISTICS any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_STATISTIC_EXT; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TSPARSER; |
| n->object = (Node *) $5; |
| n->newschema = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TSDICTIONARY; |
| n->object = (Node *) $5; |
| n->newschema = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TSTEMPLATE; |
| n->object = (Node *) $5; |
| n->newschema = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TSCONFIGURATION; |
| n->object = (Node *) $5; |
| n->newschema = $8; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_SEQUENCE; |
| n->relation = $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_SEQUENCE; |
| n->relation = $5; |
| n->newschema = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_VIEW; |
| n->relation = $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER VIEW IF_P EXISTS qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_VIEW; |
| n->relation = $5; |
| n->newschema = $8; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_MATVIEW; |
| n->relation = $4; |
| n->newschema = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_MATVIEW; |
| n->relation = $6; |
| n->newschema = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_FOREIGN_TABLE; |
| n->relation = $4; |
| n->newschema = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN TABLE IF_P EXISTS relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_FOREIGN_TABLE; |
| n->relation = $6; |
| n->newschema = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| |
| n->objectType = OBJECT_TYPE; |
| n->object = (Node *) $3; |
| n->newschema = $6; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER OPERATOR name SET define |
| * |
| *****************************************************************************/ |
| |
| AlterOperatorStmt: |
| ALTER OPERATOR operator_with_argtypes SET '(' operator_def_list ')' |
| { |
| AlterOperatorStmt *n = makeNode(AlterOperatorStmt); |
| |
| n->opername = $3; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| operator_def_list: operator_def_elem { $$ = list_make1($1); } |
| | operator_def_list ',' operator_def_elem { $$ = lappend($1, $3); } |
| ; |
| |
| operator_def_elem: ColLabel '=' NONE |
| { $$ = makeDefElem($1, NULL, @1); } |
| | ColLabel '=' operator_def_arg |
| { $$ = makeDefElem($1, (Node *) $3, @1); } |
| ; |
| |
| /* must be similar enough to def_arg to avoid reduce/reduce conflicts */ |
| operator_def_arg: |
| func_type { $$ = (Node *) $1; } |
| | reserved_keyword { $$ = (Node *) makeString(pstrdup($1)); } |
| | qual_all_Op { $$ = (Node *) $1; } |
| | NumericOnly { $$ = (Node *) $1; } |
| | Sconst { $$ = (Node *) makeString($1); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER TYPE name SET define |
| * |
| * We repurpose ALTER OPERATOR's version of "definition" here |
| * |
| *****************************************************************************/ |
| |
| AlterTypeStmt: |
| ALTER TYPE_P any_name SET '(' operator_def_list ')' |
| { |
| AlterTypeStmt *n = makeNode(AlterTypeStmt); |
| |
| n->typeName = $3; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name SET DEFAULT ENCODING definition |
| { |
| AlterTypeStmt *n = makeNode(AlterTypeStmt); |
| |
| n->typeName = $3; |
| n->options = $7; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name OWNER TO newname |
| * |
| *****************************************************************************/ |
| |
| AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_AGGREGATE; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER COLLATION any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_COLLATION; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER CONVERSION_P any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_CONVERSION; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_DATABASE; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER DOMAIN_P any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_DOMAIN; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_FUNCTION; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_LANGUAGE; |
| n->object = (Node *) makeString($4); |
| n->newowner = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_LARGEOBJECT; |
| n->object = (Node *) $4; |
| n->newowner = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR operator_with_argtypes OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_OPERATOR; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR CLASS any_name USING name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_OPCLASS; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newowner = $9; |
| $$ = (Node *) n; |
| } |
| | ALTER OPERATOR FAMILY any_name USING name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_OPFAMILY; |
| n->object = (Node *) lcons(makeString($6), $4); |
| n->newowner = $9; |
| $$ = (Node *) n; |
| } |
| | ALTER PROCEDURE function_with_argtypes OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_PROCEDURE; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER ROUTINE function_with_argtypes OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_ROUTINE; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER SCHEMA name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_SCHEMA; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TYPE_P any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_TYPE; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TABLESPACE name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_TABLESPACE; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER STATISTICS any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_STATISTIC_EXT; |
| n->object = (Node *) $3; |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER PROTOCOL name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_EXTPROTOCOL; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_TSDICTIONARY; |
| n->object = (Node *) $5; |
| n->newowner = $8; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_TSCONFIGURATION; |
| n->object = (Node *) $5; |
| n->newowner = $8; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_FDW; |
| n->object = (Node *) makeString($5); |
| n->newowner = $8; |
| $$ = (Node *) n; |
| } |
| | ALTER SERVER name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_FOREIGN_SERVER; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER EVENT TRIGGER name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_EVENT_TRIGGER; |
| n->object = (Node *) makeString($4); |
| n->newowner = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER PUBLICATION name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_PUBLICATION; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| |
| n->objectType = OBJECT_SUBSCRIPTION; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER TAG name OWNER TO RoleSpec |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_TAG; |
| n->object = (Node *) makeString($3); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * CREATE PUBLICATION name [WITH options] |
| * |
| * CREATE PUBLICATION FOR ALL TABLES [WITH options] |
| * |
| * CREATE PUBLICATION FOR pub_obj [, ...] [WITH options] |
| * |
| * pub_obj is one of: |
| * |
| * TABLE table [, ...] |
| * TABLES IN SCHEMA schema [, ...] |
| * |
| *****************************************************************************/ |
| |
| CreatePublicationStmt: |
| CREATE PUBLICATION name opt_definition |
| { |
| CreatePublicationStmt *n = makeNode(CreatePublicationStmt); |
| |
| n->pubname = $3; |
| n->options = $4; |
| $$ = (Node *) n; |
| } |
| | CREATE PUBLICATION name FOR ALL TABLES opt_definition |
| { |
| CreatePublicationStmt *n = makeNode(CreatePublicationStmt); |
| |
| n->pubname = $3; |
| n->options = $7; |
| n->for_all_tables = true; |
| $$ = (Node *) n; |
| } |
| | CREATE PUBLICATION name FOR pub_obj_list opt_definition |
| { |
| CreatePublicationStmt *n = makeNode(CreatePublicationStmt); |
| |
| n->pubname = $3; |
| n->options = $6; |
| n->pubobjects = (List *) $5; |
| preprocess_pubobj_list(n->pubobjects, yyscanner); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * FOR TABLE and FOR TABLES IN SCHEMA specifications |
| * |
| * This rule parses publication objects with and without keyword prefixes. |
| * |
| * The actual type of the object without keyword prefix depends on the previous |
| * one with keyword prefix. It will be preprocessed in preprocess_pubobj_list(). |
| * |
| * For the object without keyword prefix, we cannot just use relation_expr here, |
| * because some extended expressions in relation_expr cannot be used as a |
| * schemaname and we cannot differentiate it. So, we extract the rules from |
| * relation_expr here. |
| */ |
| PublicationObjSpec: |
| TABLE relation_expr opt_column_list OptWhereClause |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_TABLE; |
| $$->pubtable = makeNode(PublicationTable); |
| $$->pubtable->relation = $2; |
| $$->pubtable->columns = $3; |
| $$->pubtable->whereClause = $4; |
| } |
| | TABLES IN_P SCHEMA ColId |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA; |
| $$->name = $4; |
| $$->location = @4; |
| } |
| | TABLES IN_P SCHEMA CURRENT_SCHEMA |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA; |
| $$->location = @4; |
| } |
| | ColId opt_column_list OptWhereClause |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_CONTINUATION; |
| /* |
| * If either a row filter or column list is specified, create |
| * a PublicationTable object. |
| */ |
| if ($2 || $3) |
| { |
| /* |
| * The OptWhereClause must be stored here but it is |
| * valid only for tables. For non-table objects, an |
| * error will be thrown later via |
| * preprocess_pubobj_list(). |
| */ |
| $$->pubtable = makeNode(PublicationTable); |
| $$->pubtable->relation = makeRangeVar(NULL, $1, @1); |
| $$->pubtable->columns = $2; |
| $$->pubtable->whereClause = $3; |
| } |
| else |
| { |
| $$->name = $1; |
| } |
| $$->location = @1; |
| } |
| | ColId indirection opt_column_list OptWhereClause |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_CONTINUATION; |
| $$->pubtable = makeNode(PublicationTable); |
| $$->pubtable->relation = makeRangeVarFromQualifiedName($1, $2, @1, yyscanner); |
| $$->pubtable->columns = $3; |
| $$->pubtable->whereClause = $4; |
| $$->location = @1; |
| } |
| /* grammar like tablename * , ONLY tablename, ONLY ( tablename ) */ |
| | extended_relation_expr opt_column_list OptWhereClause |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_CONTINUATION; |
| $$->pubtable = makeNode(PublicationTable); |
| $$->pubtable->relation = $1; |
| $$->pubtable->columns = $2; |
| $$->pubtable->whereClause = $3; |
| } |
| | CURRENT_SCHEMA |
| { |
| $$ = makeNode(PublicationObjSpec); |
| $$->pubobjtype = PUBLICATIONOBJ_CONTINUATION; |
| $$->location = @1; |
| } |
| ; |
| |
| pub_obj_list: PublicationObjSpec |
| { $$ = list_make1($1); } |
| | pub_obj_list ',' PublicationObjSpec |
| { $$ = lappend($1, $3); } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE WAREHOUSE name |
| * [WAREHOUSE_SIZE <warehouse_size>] |
| * |
| *****************************************************************************/ |
| |
| CreateWarehouseStmt: CREATE WAREHOUSE name OptWarehouseOptList OptTagOptList |
| { |
| CreateWarehouseStmt *n = makeNode(CreateWarehouseStmt); |
| n->whname = $3; |
| n->options = $4; |
| n->tags = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| OptWarehouseOptList: WarehouseOptList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| WarehouseOptList: WarehouseOptElem { $$ = list_make1($1); } |
| | WarehouseOptList WarehouseOptElem { $$ = lappend($1, $2); } |
| ; |
| |
| WarehouseOptElem: |
| WAREHOUSE_SIZE SignedIconst |
| { |
| $$ = makeDefElem("warehouse_size", (Node *)makeInteger($2), @1); |
| } |
| ; |
| |
| |
| DropWarehouseStmt: DROP WAREHOUSE name |
| { |
| DropWarehouseStmt *n = makeNode(DropWarehouseStmt); |
| n->whname = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER PUBLICATION name SET ( options ) |
| * |
| * ALTER PUBLICATION name ADD pub_obj [, ...] |
| * |
| * ALTER PUBLICATION name DROP pub_obj [, ...] |
| * |
| * ALTER PUBLICATION name SET pub_obj [, ...] |
| * |
| * pub_obj is one of: |
| * |
| * TABLE table_name [, ...] |
| * TABLES IN SCHEMA schema_name [, ...] |
| * |
| *****************************************************************************/ |
| |
| AlterPublicationStmt: |
| ALTER PUBLICATION name SET definition |
| { |
| AlterPublicationStmt *n = makeNode(AlterPublicationStmt); |
| |
| n->pubname = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER PUBLICATION name ADD_P pub_obj_list |
| { |
| AlterPublicationStmt *n = makeNode(AlterPublicationStmt); |
| |
| n->pubname = $3; |
| n->pubobjects = $5; |
| preprocess_pubobj_list(n->pubobjects, yyscanner); |
| n->action = AP_AddObjects; |
| $$ = (Node *) n; |
| } |
| | ALTER PUBLICATION name SET pub_obj_list |
| { |
| AlterPublicationStmt *n = makeNode(AlterPublicationStmt); |
| |
| n->pubname = $3; |
| n->pubobjects = $5; |
| preprocess_pubobj_list(n->pubobjects, yyscanner); |
| n->action = AP_SetObjects; |
| $$ = (Node *) n; |
| } |
| | ALTER PUBLICATION name DROP pub_obj_list |
| { |
| AlterPublicationStmt *n = makeNode(AlterPublicationStmt); |
| |
| n->pubname = $3; |
| n->pubobjects = $5; |
| preprocess_pubobj_list(n->pubobjects, yyscanner); |
| n->action = AP_DropObjects; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * CREATE SUBSCRIPTION name ... |
| * |
| *****************************************************************************/ |
| |
| CreateSubscriptionStmt: |
| CREATE SUBSCRIPTION name CONNECTION Sconst PUBLICATION name_list opt_definition |
| { |
| CreateSubscriptionStmt *n = |
| makeNode(CreateSubscriptionStmt); |
| n->subname = $3; |
| n->conninfo = $5; |
| n->publication = $7; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER SUBSCRIPTION name ... |
| * |
| *****************************************************************************/ |
| |
| AlterSubscriptionStmt: |
| ALTER SUBSCRIPTION name SET definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_OPTIONS; |
| n->subname = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name CONNECTION Sconst |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_CONNECTION; |
| n->subname = $3; |
| n->conninfo = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name REFRESH PUBLICATION opt_definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_REFRESH; |
| n->subname = $3; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name ADD_P PUBLICATION name_list opt_definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_ADD_PUBLICATION; |
| n->subname = $3; |
| n->publication = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name DROP PUBLICATION name_list opt_definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_DROP_PUBLICATION; |
| n->subname = $3; |
| n->publication = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name SET PUBLICATION name_list opt_definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_SET_PUBLICATION; |
| n->subname = $3; |
| n->publication = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name ENABLE_P |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_ENABLED; |
| n->subname = $3; |
| n->options = list_make1(makeDefElem("enabled", |
| (Node *) makeBoolean(true), @1)); |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name DISABLE_P |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_ENABLED; |
| n->subname = $3; |
| n->options = list_make1(makeDefElem("enabled", |
| (Node *) makeBoolean(false), @1)); |
| $$ = (Node *) n; |
| } |
| | ALTER SUBSCRIPTION name SKIP definition |
| { |
| AlterSubscriptionStmt *n = |
| makeNode(AlterSubscriptionStmt); |
| |
| n->kind = ALTER_SUBSCRIPTION_SKIP; |
| n->subname = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * DROP SUBSCRIPTION [ IF EXISTS ] name |
| * |
| *****************************************************************************/ |
| |
| DropSubscriptionStmt: DROP SUBSCRIPTION name opt_drop_behavior |
| { |
| DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt); |
| |
| n->subname = $3; |
| n->missing_ok = false; |
| n->behavior = $4; |
| $$ = (Node *) n; |
| } |
| | DROP SUBSCRIPTION IF_P EXISTS name opt_drop_behavior |
| { |
| DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt); |
| |
| n->subname = $5; |
| n->missing_ok = true; |
| n->behavior = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: Define Rewrite Rule |
| * |
| *****************************************************************************/ |
| |
| RuleStmt: CREATE opt_or_replace RULE name AS |
| ON event TO qualified_name where_clause |
| DO opt_instead RuleActionList |
| { |
| RuleStmt *n = makeNode(RuleStmt); |
| |
| n->replace = $2; |
| n->relation = $9; |
| n->rulename = $4; |
| n->whereClause = $10; |
| n->event = $7; |
| n->instead = $12; |
| n->actions = $13; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| RuleActionList: |
| NOTHING { $$ = NIL; } |
| | RuleActionStmt { $$ = list_make1($1); } |
| | '(' RuleActionMulti ')' { $$ = $2; } |
| ; |
| |
| /* the thrashing around here is to discard "empty" statements... */ |
| RuleActionMulti: |
| RuleActionMulti ';' RuleActionStmtOrEmpty |
| { if ($3 != NULL) |
| $$ = lappend($1, $3); |
| else |
| $$ = $1; |
| } |
| | RuleActionStmtOrEmpty |
| { if ($1 != NULL) |
| $$ = list_make1($1); |
| else |
| $$ = NIL; |
| } |
| ; |
| |
| RuleActionStmt: |
| SelectStmt |
| | InsertStmt |
| | UpdateStmt |
| | DeleteStmt |
| | NotifyStmt |
| ; |
| |
| RuleActionStmtOrEmpty: |
| RuleActionStmt { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| event: SELECT { $$ = CMD_SELECT; } |
| | UPDATE { $$ = CMD_UPDATE; } |
| | DELETE_P { $$ = CMD_DELETE; } |
| | INSERT { $$ = CMD_INSERT; } |
| ; |
| |
| opt_instead: |
| INSTEAD { $$ = true; } |
| | ALSO { $$ = false; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * NOTIFY <identifier> can appear both in rule bodies and |
| * as a query-level command |
| * |
| *****************************************************************************/ |
| |
| NotifyStmt: NOTIFY ColId notify_payload |
| { |
| NotifyStmt *n = makeNode(NotifyStmt); |
| |
| n->conditionname = $2; |
| n->payload = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| notify_payload: |
| ',' Sconst { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ListenStmt: LISTEN ColId |
| { |
| ListenStmt *n = makeNode(ListenStmt); |
| |
| n->conditionname = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| UnlistenStmt: |
| UNLISTEN ColId |
| { |
| UnlistenStmt *n = makeNode(UnlistenStmt); |
| |
| n->conditionname = $2; |
| $$ = (Node *) n; |
| } |
| | UNLISTEN '*' |
| { |
| UnlistenStmt *n = makeNode(UnlistenStmt); |
| |
| n->conditionname = NULL; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Transactions: |
| * |
| * BEGIN / COMMIT / ROLLBACK |
| * (also older versions END / ABORT) |
| * |
| *****************************************************************************/ |
| |
| TransactionStmt: |
| ABORT_P opt_transaction opt_transaction_chain |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_ROLLBACK; |
| n->options = NIL; |
| n->chain = $3; |
| $$ = (Node *) n; |
| } |
| | START TRANSACTION transaction_mode_list_or_empty |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_START; |
| n->options = $3; |
| $$ = (Node *) n; |
| } |
| | COMMIT opt_transaction opt_transaction_chain |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_COMMIT; |
| n->options = NIL; |
| n->chain = $3; |
| $$ = (Node *) n; |
| } |
| | ROLLBACK opt_transaction opt_transaction_chain |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_ROLLBACK; |
| n->options = NIL; |
| n->chain = $3; |
| $$ = (Node *) n; |
| } |
| | SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_SAVEPOINT; |
| n->savepoint_name = $2; |
| $$ = (Node *) n; |
| } |
| | RELEASE SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_RELEASE; |
| n->savepoint_name = $3; |
| $$ = (Node *) n; |
| } |
| | RELEASE ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_RELEASE; |
| n->savepoint_name = $2; |
| $$ = (Node *) n; |
| } |
| | ROLLBACK opt_transaction TO SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_ROLLBACK_TO; |
| n->savepoint_name = $5; |
| $$ = (Node *) n; |
| } |
| | ROLLBACK opt_transaction TO ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_ROLLBACK_TO; |
| n->savepoint_name = $4; |
| $$ = (Node *) n; |
| } |
| | PREPARE TRANSACTION Sconst |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_PREPARE; |
| n->gid = $3; |
| $$ = (Node *) n; |
| } |
| | COMMIT PREPARED Sconst |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_COMMIT_PREPARED; |
| n->gid = $3; |
| $$ = (Node *) n; |
| } |
| | ROLLBACK PREPARED Sconst |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_ROLLBACK_PREPARED; |
| n->gid = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| TransactionStmtLegacy: |
| BEGIN_P opt_transaction transaction_mode_list_or_empty |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_BEGIN; |
| n->options = $3; |
| $$ = (Node *) n; |
| } |
| | END_P opt_transaction opt_transaction_chain |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| |
| n->kind = TRANS_STMT_COMMIT; |
| n->options = NIL; |
| n->chain = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_transaction: WORK |
| | TRANSACTION |
| | /*EMPTY*/ |
| ; |
| |
| transaction_mode_item: |
| ISOLATION LEVEL iso_level |
| { $$ = makeDefElem("transaction_isolation", |
| makeStringConst($3, @3), @1); } |
| | READ ONLY |
| { $$ = makeDefElem("transaction_read_only", |
| makeIntConst(true, @1), @1); } |
| | READ WRITE |
| { $$ = makeDefElem("transaction_read_only", |
| makeIntConst(false, @1), @1); } |
| | DEFERRABLE |
| { $$ = makeDefElem("transaction_deferrable", |
| makeIntConst(true, @1), @1); } |
| | NOT DEFERRABLE |
| { $$ = makeDefElem("transaction_deferrable", |
| makeIntConst(false, @1), @1); } |
| ; |
| |
| /* Syntax with commas is SQL-spec, without commas is Postgres historical */ |
| transaction_mode_list: |
| transaction_mode_item |
| { $$ = list_make1($1); } |
| | transaction_mode_list ',' transaction_mode_item |
| { $$ = lappend($1, $3); } |
| | transaction_mode_list transaction_mode_item |
| { $$ = lappend($1, $2); } |
| ; |
| |
| transaction_mode_list_or_empty: |
| transaction_mode_list |
| | /* EMPTY */ |
| { $$ = NIL; } |
| ; |
| |
| opt_transaction_chain: |
| AND CHAIN { $$ = true; } |
| | AND NO CHAIN { $$ = false; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')' |
| * AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ] |
| * |
| *****************************************************************************/ |
| |
| ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions OptTagOptList |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| |
| n->view = $4; |
| n->view->relpersistence = $2; |
| n->aliases = $5; |
| n->query = $9; |
| n->replace = false; |
| n->options = $6; |
| n->withCheckOption = $10; |
| n->tags = $7; |
| $$ = (Node *) n; |
| } |
| | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list opt_reloptions OptTagOptList |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| |
| n->view = $6; |
| n->view->relpersistence = $4; |
| n->aliases = $7; |
| n->query = $11; |
| n->replace = true; |
| n->options = $8; |
| n->withCheckOption = $12; |
| n->tags = $9; |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions OptTagOptList |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| |
| n->view = $5; |
| n->view->relpersistence = $2; |
| n->aliases = $7; |
| n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $12); |
| n->replace = false; |
| n->options = $9; |
| n->withCheckOption = $13; |
| n->tags = $10; |
| if (n->withCheckOption != NO_CHECK_OPTION) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("WITH CHECK OPTION not supported on recursive views"), |
| parser_errposition(@12))); |
| $$ = (Node *) n; |
| } |
| | CREATE OR REPLACE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions OptTagOptList |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| |
| n->view = $7; |
| n->view->relpersistence = $4; |
| n->aliases = $9; |
| n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $14); |
| n->replace = true; |
| n->options = $11; |
| n->withCheckOption = $15; |
| n->tags = $12; |
| if (n->withCheckOption != NO_CHECK_OPTION) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("WITH CHECK OPTION not supported on recursive views"), |
| parser_errposition(@14))); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_check_option: |
| WITH CHECK OPTION { $$ = CASCADED_CHECK_OPTION; } |
| | WITH CASCADED CHECK OPTION { $$ = CASCADED_CHECK_OPTION; } |
| | WITH LOCAL CHECK OPTION { $$ = LOCAL_CHECK_OPTION; } |
| | /* EMPTY */ { $$ = NO_CHECK_OPTION; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * LOAD "filename" |
| * |
| *****************************************************************************/ |
| |
| LoadStmt: LOAD file_name |
| { |
| LoadStmt *n = makeNode(LoadStmt); |
| |
| n->filename = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * CREATE DATABASE |
| * |
| *****************************************************************************/ |
| |
| CreatedbStmt: |
| CREATE DATABASE name opt_with createdb_opt_list OptTagOptList |
| { |
| CreatedbStmt *n = makeNode(CreatedbStmt); |
| |
| n->dbname = $3; |
| n->options = $5; |
| n->tags = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| createdb_opt_list: |
| createdb_opt_items { $$ = $1; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| createdb_opt_items: |
| createdb_opt_item { $$ = list_make1($1); } |
| | createdb_opt_items createdb_opt_item { $$ = lappend($1, $2); } |
| ; |
| |
| createdb_opt_item: |
| createdb_opt_name opt_equal NumericOnly |
| { |
| $$ = makeDefElem($1, $3, @1); |
| } |
| | createdb_opt_name opt_equal opt_boolean_or_string |
| { |
| $$ = makeDefElem($1, (Node *) makeString($3), @1); |
| } |
| | createdb_opt_name opt_equal DEFAULT |
| { |
| $$ = makeDefElem($1, NULL, @1); |
| } |
| ; |
| |
| /* |
| * Ideally we'd use ColId here, but that causes shift/reduce conflicts against |
| * the ALTER DATABASE SET/RESET syntaxes. Instead call out specific keywords |
| * we need, and allow IDENT so that database option names don't have to be |
| * parser keywords unless they are already keywords for other reasons. |
| * |
| * XXX this coding technique is fragile since if someone makes a formerly |
| * non-keyword option name into a keyword and forgets to add it here, the |
| * option will silently break. Best defense is to provide a regression test |
| * exercising every such option, at least at the syntax level. |
| */ |
| createdb_opt_name: |
| IDENT { $$ = $1; } |
| | CONNECTION LIMIT { $$ = pstrdup("connection_limit"); } |
| | ENCODING { $$ = pstrdup($1); } |
| | LOCATION { $$ = pstrdup($1); } |
| | OWNER { $$ = pstrdup($1); } |
| | TABLESPACE { $$ = pstrdup($1); } |
| | TEMPLATE { $$ = pstrdup($1); } |
| ; |
| |
| /* |
| * Though the equals sign doesn't match other WITH options, pg_dump uses |
| * equals for backward compatibility, and it doesn't seem worth removing it. |
| */ |
| opt_equal: '=' |
| | /*EMPTY*/ |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER DATABASE |
| * |
| *****************************************************************************/ |
| |
| AlterDatabaseStmt: |
| ALTER DATABASE name WITH createdb_opt_list |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| |
| n->dbname = $3; |
| n->options = $5; |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name createdb_opt_list |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| |
| n->dbname = $3; |
| n->options = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name SET TABLESPACE name |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| |
| n->dbname = $3; |
| n->options = list_make1(makeDefElem("tablespace", |
| (Node *) makeString($6), @6)); |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name REFRESH COLLATION VERSION_P |
| { |
| AlterDatabaseRefreshCollStmt *n = makeNode(AlterDatabaseRefreshCollStmt); |
| |
| n->dbname = $3; |
| $$ = (Node *) n; |
| } |
| | ALTER DATABASE name TAG '(' TagOptList ')' |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| n->dbname = $3; |
| n->tags = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER DATABASE name UNSET_P TAG '(' name_list ')' |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| n->dbname = $3; |
| n->tags = $7; |
| n->unsettag = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| AlterDatabaseSetStmt: |
| ALTER DATABASE name SetResetClause |
| { |
| AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); |
| |
| n->dbname = $3; |
| n->setstmt = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * DROP DATABASE [ IF EXISTS ] dbname [ [ WITH ] ( options ) ] |
| * |
| * This is implicitly CASCADE, no need for drop behavior |
| *****************************************************************************/ |
| |
| DropdbStmt: DROP DATABASE name |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| |
| n->dbname = $3; |
| n->missing_ok = false; |
| n->options = NULL; |
| $$ = (Node *) n; |
| } |
| | DROP DATABASE IF_P EXISTS name |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| |
| n->dbname = $5; |
| n->missing_ok = true; |
| n->options = NULL; |
| $$ = (Node *) n; |
| } |
| | DROP DATABASE name opt_with '(' drop_option_list ')' |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| |
| n->dbname = $3; |
| n->missing_ok = false; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| | DROP DATABASE IF_P EXISTS name opt_with '(' drop_option_list ')' |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| |
| n->dbname = $5; |
| n->missing_ok = true; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| drop_option_list: |
| drop_option |
| { |
| $$ = list_make1((Node *) $1); |
| } |
| | drop_option_list ',' drop_option |
| { |
| $$ = lappend($1, (Node *) $3); |
| } |
| ; |
| |
| /* |
| * Currently only the FORCE option is supported, but the syntax is designed |
| * to be extensible so that we can add more options in the future if required. |
| */ |
| drop_option: |
| FORCE |
| { |
| $$ = makeDefElem("force", NULL, @1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER COLLATION |
| * |
| *****************************************************************************/ |
| |
| AlterCollationStmt: ALTER COLLATION any_name REFRESH VERSION_P |
| { |
| AlterCollationStmt *n = makeNode(AlterCollationStmt); |
| |
| n->collname = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * ALTER SYSTEM |
| * |
| * This is used to change configuration parameters persistently. |
| *****************************************************************************/ |
| |
| AlterSystemStmt: |
| ALTER SYSTEM_P SET generic_set |
| { |
| AlterSystemStmt *n = makeNode(AlterSystemStmt); |
| |
| n->setstmt = $4; |
| $$ = (Node *) n; |
| } |
| | ALTER SYSTEM_P RESET generic_reset |
| { |
| AlterSystemStmt *n = makeNode(AlterSystemStmt); |
| |
| n->setstmt = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a domain |
| * |
| *****************************************************************************/ |
| |
| CreateDomainStmt: |
| CREATE DOMAIN_P any_name opt_as Typename ColQualList |
| { |
| CreateDomainStmt *n = makeNode(CreateDomainStmt); |
| |
| n->domainname = $3; |
| n->typeName = $5; |
| SplitColQualList($6, &n->constraints, &n->collClause, |
| yyscanner); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterDomainStmt: |
| /* ALTER DOMAIN <domain> {SET DEFAULT <expr>|DROP DEFAULT} */ |
| ALTER DOMAIN_P any_name alter_column_default |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'T'; |
| n->typeName = $3; |
| n->def = $4; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> DROP NOT NULL */ |
| | ALTER DOMAIN_P any_name DROP NOT NULL_P |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'N'; |
| n->typeName = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> SET NOT NULL */ |
| | ALTER DOMAIN_P any_name SET NOT NULL_P |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'O'; |
| n->typeName = $3; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> ADD CONSTRAINT ... */ |
| | ALTER DOMAIN_P any_name ADD_P TableConstraint |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'C'; |
| n->typeName = $3; |
| n->def = $5; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */ |
| | ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'X'; |
| n->typeName = $3; |
| n->name = $6; |
| n->behavior = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */ |
| | ALTER DOMAIN_P any_name DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'X'; |
| n->typeName = $3; |
| n->name = $8; |
| n->behavior = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| /* ALTER DOMAIN <domain> VALIDATE CONSTRAINT <name> */ |
| | ALTER DOMAIN_P any_name VALIDATE CONSTRAINT name |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| |
| n->subtype = 'V'; |
| n->typeName = $3; |
| n->name = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_as: AS |
| | /* EMPTY */ |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a text search dictionary or configuration |
| * |
| *****************************************************************************/ |
| |
| AlterTSDictionaryStmt: |
| ALTER TEXT_P SEARCH DICTIONARY any_name definition |
| { |
| AlterTSDictionaryStmt *n = makeNode(AlterTSDictionaryStmt); |
| |
| n->dictname = $5; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AlterTSConfigurationStmt: |
| ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list any_with any_name_list |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_ADD_MAPPING; |
| n->cfgname = $5; |
| n->tokentype = $9; |
| n->dicts = $11; |
| n->override = false; |
| n->replace = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list any_with any_name_list |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN; |
| n->cfgname = $5; |
| n->tokentype = $9; |
| n->dicts = $11; |
| n->override = true; |
| n->replace = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name any_with any_name |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_REPLACE_DICT; |
| n->cfgname = $5; |
| n->tokentype = NIL; |
| n->dicts = list_make2($9,$11); |
| n->override = false; |
| n->replace = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name any_with any_name |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN; |
| n->cfgname = $5; |
| n->tokentype = $9; |
| n->dicts = list_make2($11,$13); |
| n->override = false; |
| n->replace = true; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_DROP_MAPPING; |
| n->cfgname = $5; |
| n->tokentype = $9; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list |
| { |
| AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); |
| |
| n->kind = ALTER_TSCONFIG_DROP_MAPPING; |
| n->cfgname = $5; |
| n->tokentype = $11; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* Use this if TIME or ORDINALITY after WITH should be taken as an identifier */ |
| any_with: WITH |
| | WITH_LA |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a conversion |
| * |
| * CREATE [DEFAULT] CONVERSION <conversion_name> |
| * FOR <encoding_name> TO <encoding_name> FROM <func_name> |
| * |
| *****************************************************************************/ |
| |
| CreateConversionStmt: |
| CREATE opt_default CONVERSION_P any_name FOR Sconst |
| TO Sconst FROM any_name |
| { |
| CreateConversionStmt *n = makeNode(CreateConversionStmt); |
| |
| n->conversion_name = $4; |
| n->for_encoding_name = $6; |
| n->to_encoding_name = $8; |
| n->func_name = $10; |
| n->def = $2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CLUSTER [VERBOSE] <qualified_name> [ USING <index_name> ] |
| * CLUSTER [ (options) ] <qualified_name> [ USING <index_name> ] |
| * CLUSTER [VERBOSE] |
| * CLUSTER [VERBOSE] <index_name> ON <qualified_name> (for pre-8.3) |
| * |
| *****************************************************************************/ |
| |
| ClusterStmt: |
| CLUSTER opt_verbose qualified_name cluster_index_specification |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| |
| n->relation = $3; |
| n->indexname = $4; |
| n->params = NIL; |
| if ($2) |
| n->params = lappend(n->params, makeDefElem("verbose", NULL, @2)); |
| $$ = (Node *) n; |
| } |
| |
| | CLUSTER '(' utility_option_list ')' qualified_name cluster_index_specification |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| |
| n->relation = $5; |
| n->indexname = $6; |
| n->params = $3; |
| $$ = (Node *) n; |
| } |
| | CLUSTER opt_verbose |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| |
| n->relation = NULL; |
| n->indexname = NULL; |
| n->params = NIL; |
| if ($2) |
| n->params = lappend(n->params, makeDefElem("verbose", NULL, @2)); |
| $$ = (Node *) n; |
| } |
| /* kept for pre-8.3 compatibility */ |
| | CLUSTER opt_verbose name ON qualified_name |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| |
| n->relation = $5; |
| n->indexname = $3; |
| n->params = NIL; |
| if ($2) |
| n->params = lappend(n->params, makeDefElem("verbose", NULL, @2)); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| cluster_index_specification: |
| USING name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * VACUUM |
| * ANALYZE |
| * |
| *****************************************************************************/ |
| |
| VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_ao_aux_only opt_vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| |
| n->options = NIL; |
| if ($2) |
| n->options = lappend(n->options, |
| makeDefElem("full", NULL, @2)); |
| if ($3) |
| n->options = lappend(n->options, |
| makeDefElem("freeze", NULL, @3)); |
| if ($4) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @4)); |
| if ($5) |
| n->options = lappend(n->options, |
| makeDefElem("analyze", NULL, @5)); |
| if ($6) |
| n->options = lappend(n->options, |
| makeDefElem("ao_aux_only", NULL, @6)); |
| n->rels = $7; |
| n->is_vacuumcmd = true; |
| $$ = (Node *) n; |
| } |
| | VACUUM '(' utility_option_list ')' opt_vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| |
| n->options = $3; |
| n->rels = $5; |
| n->is_vacuumcmd = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| |
| n->options = NIL; |
| if ($2) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @2)); |
| n->rels = $3; |
| n->is_vacuumcmd = false; |
| $$ = (Node *) n; |
| } |
| | analyze_keyword '(' utility_option_list ')' opt_vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| |
| n->options = $3; |
| n->rels = $5; |
| n->is_vacuumcmd = false; |
| $$ = (Node *) n; |
| } |
| /* |
| * GPDB-specific ROOTPARTITION / FULLSCAN options. |
| * These cannot be rolled into the above rules without making |
| * ROOTPARTITION and FULLSCAN keywords reserved, because it is |
| * ambiguous whether "ANALYZE ROOTPARTITION" means "all relations |
| * with ROOTPARTITION option", or "one relation called |
| * ROOTPARTITION". So with these options, you must specify a |
| * relation name/list. For database-wide operation, you can do |
| * ANALYZE ROOTPARTITION ALL, which is special cased here. There is |
| * not ANALYZE FULLSCAN ALL, though. |
| * |
| * The modern syntax with parens doesn't have these problems, so |
| * you can do "ANALYZE (FULLSCAN)". |
| */ |
| | analyze_keyword opt_verbose ROOTPARTITION vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->options = NIL; |
| if ($2) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @2)); |
| n->options = lappend(n->options, |
| makeDefElem("rootpartition", NULL, @3)); |
| n->rels = $4; |
| n->is_vacuumcmd = false; |
| $$ = (Node *)n; |
| } |
| | analyze_keyword opt_verbose ROOTPARTITION ALL |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->options = NIL; |
| if ($2) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @2)); |
| n->options = lappend(n->options, |
| makeDefElem("rootpartition", NULL, @3)); |
| n->rels = NIL; |
| n->is_vacuumcmd = false; |
| $$ = (Node *)n; |
| } |
| | analyze_keyword opt_verbose FULLSCAN vacuum_relation_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->options = NIL; |
| if ($2) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @2)); |
| n->options = lappend(n->options, |
| makeDefElem("fullscan", NULL, @3)); |
| n->rels = $4; |
| n->is_vacuumcmd = false; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| utility_option_list: |
| utility_option_elem |
| { |
| $$ = list_make1($1); |
| } |
| | utility_option_list ',' utility_option_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| analyze_keyword: |
| ANALYZE |
| | ANALYSE /* British */ |
| ; |
| |
| utility_option_elem: |
| utility_option_name utility_option_arg |
| { |
| $$ = makeDefElem($1, $2, @1); |
| } |
| ; |
| |
| utility_option_name: |
| NonReservedWord { $$ = $1; } |
| | analyze_keyword { $$ = "analyze"; } |
| | FORMAT_LA { $$ = "format"; } |
| ; |
| |
| utility_option_arg: |
| opt_boolean_or_string { $$ = (Node *) makeString($1); } |
| | NumericOnly { $$ = (Node *) $1; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| opt_analyze: |
| analyze_keyword { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_verbose: |
| VERBOSE { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_full: FULL { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_freeze: FREEZE { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_name_list: |
| '(' name_list ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| vacuum_relation: |
| qualified_name opt_name_list |
| { |
| $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2); |
| } |
| ; |
| |
| vacuum_relation_list: |
| vacuum_relation |
| { $$ = list_make1($1); } |
| | vacuum_relation_list ',' vacuum_relation |
| { $$ = lappend($1, $3); } |
| ; |
| |
| opt_vacuum_relation_list: |
| vacuum_relation_list { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /*GPDB: only vacuum supporting heap tables of given AO table*/ |
| opt_ao_aux_only: AO_AUX_ONLY { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * EXPLAIN [ANALYZE] [VERBOSE] query |
| * EXPLAIN ( options ) query |
| * |
| *****************************************************************************/ |
| |
| ExplainStmt: |
| EXPLAIN ExplainableStmt |
| { |
| ExplainStmt *n = makeNode(ExplainStmt); |
| |
| n->query = $2; |
| n->options = NIL; |
| $$ = (Node *) n; |
| } |
| | EXPLAIN analyze_keyword opt_verbose opt_dxl ExplainableStmt |
| { |
| ExplainStmt *n = makeNode(ExplainStmt); |
| n->query = $5; |
| n->options = list_make1(makeDefElem("analyze", NULL, @2)); |
| if ($3) |
| n->options = lappend(n->options, |
| makeDefElem("verbose", NULL, @3)); |
| if ($4) |
| n->options = lappend(n->options, |
| makeDefElem("dxl", NULL, @4)); |
| $$ = (Node *) n; |
| } |
| | EXPLAIN VERBOSE opt_dxl ExplainableStmt |
| { |
| ExplainStmt *n = makeNode(ExplainStmt); |
| n->query = $4; |
| n->options = list_make1(makeDefElem("verbose", NULL, @2)); |
| if ($3) |
| n->options = lappend(n->options, |
| makeDefElem("dxl", NULL, @3)); |
| $$ = (Node *) n; |
| } |
| | EXPLAIN '(' utility_option_list ')' ExplainableStmt |
| { |
| ExplainStmt *n = makeNode(ExplainStmt); |
| |
| n->query = $5; |
| n->options = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| ExplainableStmt: |
| SelectStmt |
| | InsertStmt |
| | UpdateStmt |
| | DeleteStmt |
| | MergeStmt |
| | DeclareCursorStmt |
| | CreateAsStmt |
| | CreateMatViewStmt |
| | RefreshMatViewStmt |
| | ExecuteStmt /* by default all are $$=$1 */ |
| | CreateStmt |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("cannot EXPLAIN CREATE TABLE without AS " |
| "clause"))); |
| } |
| ; |
| |
| opt_dxl: DXL { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * PREPARE <plan_name> [(args, ...)] AS <query> |
| * |
| *****************************************************************************/ |
| |
| PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt |
| { |
| PrepareStmt *n = makeNode(PrepareStmt); |
| |
| n->name = $2; |
| n->argtypes = $3; |
| n->query = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| prep_type_clause: '(' type_list ')' { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| PreparableStmt: |
| SelectStmt |
| | InsertStmt |
| | UpdateStmt |
| | DeleteStmt |
| | MergeStmt /* by default all are $$=$1 */ |
| ; |
| |
| /***************************************************************************** |
| * |
| * EXECUTE <plan_name> [(params, ...)] |
| * CREATE TABLE <name> AS EXECUTE <plan_name> [(params, ...)] |
| * |
| *****************************************************************************/ |
| |
| ExecuteStmt: EXECUTE name execute_param_clause |
| { |
| ExecuteStmt *n = makeNode(ExecuteStmt); |
| |
| n->name = $2; |
| n->params = $3; |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE create_as_target AS |
| EXECUTE name execute_param_clause opt_with_data |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ExecuteStmt *n = makeNode(ExecuteStmt); |
| |
| n->name = $7; |
| n->params = $8; |
| ctas->query = (Node *) n; |
| ctas->into = $4; |
| ctas->objtype = OBJECT_TABLE; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = false; |
| /* cram additional flags into the IntoClause */ |
| $4->rel->relpersistence = $2; |
| $4->skipData = !($9); |
| $$ = (Node *) ctas; |
| } |
| | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS |
| EXECUTE name execute_param_clause opt_with_data |
| { |
| CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); |
| ExecuteStmt *n = makeNode(ExecuteStmt); |
| |
| n->name = $10; |
| n->params = $11; |
| ctas->query = (Node *) n; |
| ctas->into = $7; |
| ctas->objtype = OBJECT_TABLE; |
| ctas->is_select_into = false; |
| ctas->if_not_exists = true; |
| /* cram additional flags into the IntoClause */ |
| $7->rel->relpersistence = $2; |
| $7->skipData = !($12); |
| $$ = (Node *) ctas; |
| } |
| ; |
| |
| execute_param_clause: '(' expr_list ')' { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * DEALLOCATE [PREPARE] <plan_name> |
| * |
| *****************************************************************************/ |
| |
| DeallocateStmt: DEALLOCATE name |
| { |
| DeallocateStmt *n = makeNode(DeallocateStmt); |
| |
| n->name = $2; |
| $$ = (Node *) n; |
| } |
| | DEALLOCATE PREPARE name |
| { |
| DeallocateStmt *n = makeNode(DeallocateStmt); |
| |
| n->name = $3; |
| $$ = (Node *) n; |
| } |
| | DEALLOCATE ALL |
| { |
| DeallocateStmt *n = makeNode(DeallocateStmt); |
| |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| | DEALLOCATE PREPARE ALL |
| { |
| DeallocateStmt *n = makeNode(DeallocateStmt); |
| |
| n->name = NULL; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| */ |
| |
| |
| |
| |
| cdb_string_list: |
| cdb_string { $$ = list_make1($1); } |
| | cdb_string_list ',' cdb_string |
| { |
| if (list_member($1, $3)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_TABLE_DEFINITION), |
| errmsg("duplicate location uri"), |
| parser_errposition(@3))); |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| |
| cdb_string: |
| Sconst |
| { |
| $$ = (Node *) makeString($1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * INSERT STATEMENTS |
| * |
| *****************************************************************************/ |
| |
| InsertStmt: |
| opt_with_clause INSERT INTO insert_target insert_rest |
| opt_on_conflict returning_clause |
| { |
| $5->relation = $4; |
| $5->onConflictClause = $6; |
| $5->returningList = $7; |
| $5->withClause = $1; |
| $$ = (Node *) $5; |
| } |
| ; |
| |
| /* |
| * Can't easily make AS optional here, because VALUES in insert_rest would |
| * have a shift/reduce conflict with VALUES as an optional alias. We could |
| * easily allow unreserved_keywords as optional aliases, but that'd be an odd |
| * divergence from other places. So just require AS for now. |
| */ |
| insert_target: |
| qualified_name |
| { |
| $$ = $1; |
| } |
| | qualified_name AS ColId |
| { |
| $1->alias = makeAlias($3, NIL); |
| $$ = $1; |
| } |
| ; |
| |
| insert_rest: |
| SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = NIL; |
| $$->selectStmt = $1; |
| } |
| | OVERRIDING override_kind VALUE_P SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = NIL; |
| $$->override = $2; |
| $$->selectStmt = $4; |
| } |
| | '(' insert_column_list ')' SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = $2; |
| $$->selectStmt = $4; |
| } |
| | '(' insert_column_list ')' OVERRIDING override_kind VALUE_P SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = $2; |
| $$->override = $5; |
| $$->selectStmt = $7; |
| } |
| | DEFAULT VALUES |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = NIL; |
| $$->selectStmt = NULL; |
| } |
| ; |
| |
| override_kind: |
| USER { $$ = OVERRIDING_USER_VALUE; } |
| | SYSTEM_P { $$ = OVERRIDING_SYSTEM_VALUE; } |
| ; |
| |
| insert_column_list: |
| insert_column_item |
| { $$ = list_make1($1); } |
| | insert_column_list ',' insert_column_item |
| { $$ = lappend($1, $3); } |
| ; |
| |
| insert_column_item: |
| ColId opt_indirection |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $1; |
| $$->indirection = check_indirection($2, yyscanner); |
| $$->val = NULL; |
| $$->location = @1; |
| } |
| ; |
| |
| opt_on_conflict: |
| ON CONFLICT opt_conf_expr DO UPDATE SET set_clause_list where_clause |
| { |
| $$ = makeNode(OnConflictClause); |
| $$->action = ONCONFLICT_UPDATE; |
| $$->infer = $3; |
| $$->targetList = $7; |
| $$->whereClause = $8; |
| $$->location = @1; |
| } |
| | |
| ON CONFLICT opt_conf_expr DO NOTHING |
| { |
| $$ = makeNode(OnConflictClause); |
| $$->action = ONCONFLICT_NOTHING; |
| $$->infer = $3; |
| $$->targetList = NIL; |
| $$->whereClause = NULL; |
| $$->location = @1; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| opt_conf_expr: |
| '(' index_params ')' where_clause |
| { |
| $$ = makeNode(InferClause); |
| $$->indexElems = $2; |
| $$->whereClause = $4; |
| $$->conname = NULL; |
| $$->location = @1; |
| } |
| | |
| ON CONSTRAINT name |
| { |
| $$ = makeNode(InferClause); |
| $$->indexElems = NIL; |
| $$->whereClause = NULL; |
| $$->conname = $3; |
| $$->location = @1; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| returning_clause: |
| RETURNING target_list { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * DELETE STATEMENTS |
| * |
| *****************************************************************************/ |
| |
| DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias |
| using_clause where_or_current_clause returning_clause |
| { |
| DeleteStmt *n = makeNode(DeleteStmt); |
| |
| n->relation = $4; |
| n->usingClause = $5; |
| n->whereClause = $6; |
| n->returningList = $7; |
| n->withClause = $1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| using_clause: |
| USING from_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * LOCK TABLE |
| * |
| *****************************************************************************/ |
| |
| LockStmt: LOCK_P opt_table relation_expr_list opt_lock opt_nowait |
| { |
| LockStmt *n = makeNode(LockStmt); |
| |
| n->relations = $3; |
| n->mode = $4; |
| n->nowait = $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_lock: IN_P lock_type MODE { $$ = $2; } |
| | /*EMPTY*/ { $$ = AccessExclusiveLock; } |
| ; |
| |
| lock_type: ACCESS SHARE { $$ = AccessShareLock; } |
| | ROW SHARE { $$ = RowShareLock; } |
| | ROW EXCLUSIVE { $$ = RowExclusiveLock; } |
| | SHARE UPDATE EXCLUSIVE { $$ = ShareUpdateExclusiveLock; } |
| | SHARE { $$ = ShareLock; } |
| | SHARE ROW EXCLUSIVE { $$ = ShareRowExclusiveLock; } |
| | EXCLUSIVE { $$ = ExclusiveLock; } |
| | ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; } |
| ; |
| |
| opt_nowait: NOWAIT { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_nowait_or_skip: |
| NOWAIT { $$ = LockWaitError; } |
| | SKIP LOCKED { $$ = LockWaitSkip; } |
| | /*EMPTY*/ { $$ = LockWaitBlock; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * UpdateStmt (UPDATE) |
| * |
| *****************************************************************************/ |
| |
| UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias |
| SET set_clause_list |
| from_clause |
| where_or_current_clause |
| returning_clause |
| { |
| UpdateStmt *n = makeNode(UpdateStmt); |
| |
| n->relation = $3; |
| n->targetList = $5; |
| n->fromClause = $6; |
| n->whereClause = $7; |
| n->returningList = $8; |
| n->withClause = $1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| set_clause_list: |
| set_clause { $$ = $1; } |
| | set_clause_list ',' set_clause { $$ = list_concat($1,$3); } |
| ; |
| |
| set_clause: |
| set_target '=' a_expr |
| { |
| $1->val = (Node *) $3; |
| $$ = list_make1($1); |
| } |
| | '(' set_target_list ')' '=' a_expr |
| { |
| int ncolumns = list_length($2); |
| int i = 1; |
| ListCell *col_cell; |
| |
| /* Create a MultiAssignRef source for each target */ |
| foreach(col_cell, $2) |
| { |
| ResTarget *res_col = (ResTarget *) lfirst(col_cell); |
| MultiAssignRef *r = makeNode(MultiAssignRef); |
| |
| r->source = (Node *) $5; |
| r->colno = i; |
| r->ncolumns = ncolumns; |
| res_col->val = (Node *) r; |
| i++; |
| } |
| |
| $$ = $2; |
| } |
| ; |
| |
| set_target: |
| ColId opt_indirection |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $1; |
| $$->indirection = check_indirection($2, yyscanner); |
| $$->val = NULL; /* upper production sets this */ |
| $$->location = @1; |
| } |
| ; |
| |
| set_target_list: |
| set_target { $$ = list_make1($1); } |
| | set_target_list ',' set_target { $$ = lappend($1,$3); } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * MERGE |
| * |
| *****************************************************************************/ |
| |
| MergeStmt: |
| opt_with_clause MERGE INTO relation_expr_opt_alias |
| USING table_ref |
| ON a_expr |
| merge_when_list |
| { |
| MergeStmt *m = makeNode(MergeStmt); |
| |
| m->withClause = $1; |
| m->relation = $4; |
| m->sourceRelation = $6; |
| m->joinCondition = $8; |
| m->mergeWhenClauses = $9; |
| |
| $$ = (Node *) m; |
| } |
| ; |
| |
| merge_when_list: |
| merge_when_clause { $$ = list_make1($1); } |
| | merge_when_list merge_when_clause { $$ = lappend($1,$2); } |
| ; |
| |
| merge_when_clause: |
| WHEN MATCHED opt_merge_when_condition THEN merge_update |
| { |
| $5->matched = true; |
| $5->condition = $3; |
| |
| $$ = (Node *) $5; |
| } |
| | WHEN MATCHED opt_merge_when_condition THEN merge_delete |
| { |
| $5->matched = true; |
| $5->condition = $3; |
| |
| $$ = (Node *) $5; |
| } |
| | WHEN NOT MATCHED opt_merge_when_condition THEN merge_insert |
| { |
| $6->matched = false; |
| $6->condition = $4; |
| |
| $$ = (Node *) $6; |
| } |
| | WHEN MATCHED opt_merge_when_condition THEN DO NOTHING |
| { |
| MergeWhenClause *m = makeNode(MergeWhenClause); |
| |
| m->matched = true; |
| m->commandType = CMD_NOTHING; |
| m->condition = $3; |
| |
| $$ = (Node *) m; |
| } |
| | WHEN NOT MATCHED opt_merge_when_condition THEN DO NOTHING |
| { |
| MergeWhenClause *m = makeNode(MergeWhenClause); |
| |
| m->matched = false; |
| m->commandType = CMD_NOTHING; |
| m->condition = $4; |
| |
| $$ = (Node *) m; |
| } |
| ; |
| |
| opt_merge_when_condition: |
| AND a_expr { $$ = $2; } |
| | { $$ = NULL; } |
| ; |
| |
| merge_update: |
| UPDATE SET set_clause_list |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_UPDATE; |
| n->override = OVERRIDING_NOT_SET; |
| n->targetList = $3; |
| n->values = NIL; |
| |
| $$ = n; |
| } |
| ; |
| |
| merge_delete: |
| DELETE_P |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_DELETE; |
| n->override = OVERRIDING_NOT_SET; |
| n->targetList = NIL; |
| n->values = NIL; |
| |
| $$ = n; |
| } |
| ; |
| |
| merge_insert: |
| INSERT merge_values_clause |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_INSERT; |
| n->override = OVERRIDING_NOT_SET; |
| n->targetList = NIL; |
| n->values = $2; |
| $$ = n; |
| } |
| | INSERT OVERRIDING override_kind VALUE_P merge_values_clause |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_INSERT; |
| n->override = $3; |
| n->targetList = NIL; |
| n->values = $5; |
| $$ = n; |
| } |
| | INSERT '(' insert_column_list ')' merge_values_clause |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_INSERT; |
| n->override = OVERRIDING_NOT_SET; |
| n->targetList = $3; |
| n->values = $5; |
| $$ = n; |
| } |
| | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P merge_values_clause |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_INSERT; |
| n->override = $6; |
| n->targetList = $3; |
| n->values = $8; |
| $$ = n; |
| } |
| | INSERT DEFAULT VALUES |
| { |
| MergeWhenClause *n = makeNode(MergeWhenClause); |
| n->commandType = CMD_INSERT; |
| n->override = OVERRIDING_NOT_SET; |
| n->targetList = NIL; |
| n->values = NIL; |
| $$ = n; |
| } |
| ; |
| |
| merge_values_clause: |
| VALUES '(' expr_list ')' |
| { |
| $$ = $3; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CURSOR STATEMENTS |
| * |
| *****************************************************************************/ |
| DeclareCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR SelectStmt |
| { |
| DeclareCursorStmt *n = makeNode(DeclareCursorStmt); |
| |
| n->portalname = $2; |
| /* currently we always set FAST_PLAN option */ |
| n->options = $3 | $5 | CURSOR_OPT_FAST_PLAN; |
| n->query = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| cursor_name: name { $$ = $1; } |
| ; |
| |
| cursor_options: /*EMPTY*/ { $$ = 0; } |
| | cursor_options NO SCROLL { $$ = $1 | CURSOR_OPT_NO_SCROLL; } |
| | cursor_options SCROLL { $$ = $1 | CURSOR_OPT_SCROLL; } |
| | cursor_options BINARY { $$ = $1 | CURSOR_OPT_BINARY; } |
| | cursor_options ASENSITIVE { $$ = $1 | CURSOR_OPT_ASENSITIVE; } |
| | cursor_options INSENSITIVE { $$ = $1 | CURSOR_OPT_INSENSITIVE; } |
| | cursor_options PARALLEL RETRIEVE { $$ = $1 | CURSOR_OPT_PARALLEL_RETRIEVE; } |
| ; |
| |
| opt_hold: /* EMPTY */ { $$ = 0; } |
| | WITH HOLD { $$ = CURSOR_OPT_HOLD; } |
| | WITHOUT HOLD { $$ = 0; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * SELECT STATEMENTS |
| * |
| *****************************************************************************/ |
| |
| /* A complete SELECT statement looks like this. |
| * |
| * The rule returns either a single SelectStmt node or a tree of them, |
| * representing a set-operation tree. |
| * |
| * There is an ambiguity when a sub-SELECT is within an a_expr and there |
| * are excess parentheses: do the parentheses belong to the sub-SELECT or |
| * to the surrounding a_expr? We don't really care, but bison wants to know. |
| * To resolve the ambiguity, we are careful to define the grammar so that |
| * the decision is staved off as long as possible: as long as we can keep |
| * absorbing parentheses into the sub-SELECT, we will do so, and only when |
| * it's no longer possible to do that will we decide that parens belong to |
| * the expression. For example, in "SELECT (((SELECT 2)) + 3)" the extra |
| * parentheses are treated as part of the sub-select. The necessity of doing |
| * it that way is shown by "SELECT (((SELECT 2)) UNION SELECT 2)". Had we |
| * parsed "((SELECT 2))" as an a_expr, it'd be too late to go back to the |
| * SELECT viewpoint when we see the UNION. |
| * |
| * This approach is implemented by defining a nonterminal select_with_parens, |
| * which represents a SELECT with at least one outer layer of parentheses, |
| * and being careful to use select_with_parens, never '(' SelectStmt ')', |
| * in the expression grammar. We will then have shift-reduce conflicts |
| * which we can resolve in favor of always treating '(' <select> ')' as |
| * a select_with_parens. To resolve the conflicts, the productions that |
| * conflict with the select_with_parens productions are manually given |
| * precedences lower than the precedence of ')', thereby ensuring that we |
| * shift ')' (and then reduce to select_with_parens) rather than trying to |
| * reduce the inner <select> nonterminal to something else. We use UMINUS |
| * precedence for this, which is a fairly arbitrary choice. |
| * |
| * To be able to define select_with_parens itself without ambiguity, we need |
| * a nonterminal select_no_parens that represents a SELECT structure with no |
| * outermost parentheses. This is a little bit tedious, but it works. |
| * |
| * In non-expression contexts, we use SelectStmt which can represent a SELECT |
| * with or without outer parentheses. |
| */ |
| |
| SelectStmt: select_no_parens %prec UMINUS |
| | select_with_parens %prec UMINUS |
| ; |
| |
| RetrieveStmt: |
| RETRIEVE SignedIconst FROM ENDPOINT name |
| { |
| RetrieveStmt *n = makeNode(RetrieveStmt); |
| n->endpoint_name = $5; |
| n->count = $2; |
| $$ = (Node *)n; |
| } |
| | RETRIEVE ALL FROM ENDPOINT name |
| { |
| RetrieveStmt *n = makeNode(RetrieveStmt); |
| n->endpoint_name = $5; |
| n->count = -1; |
| n->is_all = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| select_with_parens: |
| '(' select_no_parens ')' { $$ = $2; } |
| | '(' select_with_parens ')' { $$ = $2; } |
| ; |
| |
| /* |
| * This rule parses the equivalent of the standard's <query expression>. |
| * The duplicative productions are annoying, but hard to get rid of without |
| * creating shift/reduce conflicts. |
| * |
| * The locking clause (FOR UPDATE etc) may be before or after LIMIT/OFFSET. |
| * In <=7.2.X, LIMIT/OFFSET had to be after FOR UPDATE |
| * We now support both orderings, but prefer LIMIT/OFFSET before the locking |
| * clause. |
| * 2002-08-28 bjm |
| */ |
| select_no_parens: |
| simple_select { $$ = $1; } |
| | select_clause sort_clause |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, NIL, |
| NULL, NULL, |
| yyscanner); |
| $$ = $1; |
| } |
| | select_clause opt_sort_clause for_locking_clause opt_select_limit |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, $3, |
| $4, |
| NULL, |
| yyscanner); |
| $$ = $1; |
| } |
| | select_clause opt_sort_clause select_limit opt_for_locking_clause |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, $4, |
| $3, |
| NULL, |
| yyscanner); |
| $$ = $1; |
| } |
| | with_clause select_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, NULL, NIL, |
| NULL, |
| $1, |
| yyscanner); |
| $$ = $2; |
| } |
| | with_clause select_clause sort_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, NIL, |
| NULL, |
| $1, |
| yyscanner); |
| $$ = $2; |
| } |
| | with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, $4, |
| $5, |
| $1, |
| yyscanner); |
| $$ = $2; |
| } |
| | with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, $5, |
| $4, |
| $1, |
| yyscanner); |
| $$ = $2; |
| } |
| ; |
| |
| select_clause: |
| simple_select { $$ = $1; } |
| | select_with_parens { $$ = $1; } |
| ; |
| |
| /* |
| * This rule parses SELECT statements that can appear within set operations, |
| * including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify |
| * the ordering of the set operations. Without '(' and ')' we want the |
| * operations to be ordered per the precedence specs at the head of this file. |
| * |
| * As with select_no_parens, simple_select cannot have outer parentheses, |
| * but can have parenthesized subclauses. |
| * |
| * It might appear that we could fold the first two alternatives into one |
| * by using opt_distinct_clause. However, that causes a shift/reduce conflict |
| * against INSERT ... SELECT ... ON CONFLICT. We avoid the ambiguity by |
| * requiring SELECT DISTINCT [ON] to be followed by a non-empty target_list. |
| * |
| * Note that sort clauses cannot be included at this level --- SQL requires |
| * SELECT foo UNION SELECT bar ORDER BY baz |
| * to be parsed as |
| * (SELECT foo UNION SELECT bar) ORDER BY baz |
| * not |
| * SELECT foo UNION (SELECT bar ORDER BY baz) |
| * Likewise for WITH, FOR UPDATE and LIMIT. Therefore, those clauses are |
| * described as part of the select_no_parens production, not simple_select. |
| * This does not limit functionality, because you can reintroduce these |
| * clauses inside parentheses. |
| * |
| * NOTE: only the leftmost component SelectStmt should have INTO. |
| * However, this is not checked by the grammar; parse analysis must check it. |
| */ |
| simple_select: |
| SELECT opt_all_clause opt_target_list |
| into_clause from_clause where_clause |
| group_clause having_clause window_clause |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| n->targetList = $3; |
| n->intoClause = $4; |
| n->fromClause = $5; |
| n->whereClause = $6; |
| n->groupClause = ($7)->list; |
| n->groupDistinct = ($7)->distinct; |
| n->havingClause = $8; |
| n->windowClause = $9; |
| $$ = (Node *) n; |
| } |
| | SELECT distinct_clause target_list |
| into_clause from_clause where_clause |
| group_clause having_clause window_clause |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| n->distinctClause = $2; |
| n->targetList = $3; |
| n->intoClause = $4; |
| n->fromClause = $5; |
| n->whereClause = $6; |
| n->groupClause = ($7)->list; |
| n->groupDistinct = ($7)->distinct; |
| n->havingClause = $8; |
| n->windowClause = $9; |
| $$ = (Node *) n; |
| } |
| | values_clause { $$ = $1; } |
| | TABLE relation_expr |
| { |
| /* same as SELECT * FROM relation_expr */ |
| ColumnRef *cr = makeNode(ColumnRef); |
| ResTarget *rt = makeNode(ResTarget); |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| cr->fields = list_make1(makeNode(A_Star)); |
| cr->location = -1; |
| |
| rt->name = NULL; |
| rt->indirection = NIL; |
| rt->val = (Node *) cr; |
| rt->location = -1; |
| |
| n->targetList = list_make1(rt); |
| n->fromClause = list_make1($2); |
| $$ = (Node *) n; |
| } |
| | select_clause UNION set_quantifier select_clause |
| { |
| $$ = makeSetOp(SETOP_UNION, $3 == SET_QUANTIFIER_ALL, $1, $4); |
| } |
| | select_clause INTERSECT set_quantifier select_clause |
| { |
| $$ = makeSetOp(SETOP_INTERSECT, $3 == SET_QUANTIFIER_ALL, $1, $4); |
| } |
| | select_clause EXCEPT set_quantifier select_clause |
| { |
| $$ = makeSetOp(SETOP_EXCEPT, $3 == SET_QUANTIFIER_ALL, $1, $4); |
| } |
| ; |
| |
| /* |
| * SQL standard WITH clause looks like: |
| * |
| * WITH [ RECURSIVE ] <query name> [ (<column>,...) ] |
| * AS (query) [ SEARCH or CYCLE clause ] |
| * |
| * Recognizing WITH_LA here allows a CTE to be named TIME or ORDINALITY. |
| */ |
| with_clause: |
| WITH cte_list |
| { |
| $$ = makeNode(WithClause); |
| $$->ctes = $2; |
| $$->recursive = false; |
| $$->location = @1; |
| } |
| | WITH_LA cte_list |
| { |
| $$ = makeNode(WithClause); |
| $$->ctes = $2; |
| $$->recursive = false; |
| $$->location = @1; |
| } |
| | WITH RECURSIVE cte_list |
| { |
| $$ = makeNode(WithClause); |
| $$->ctes = $3; |
| $$->recursive = true; |
| $$->location = @1; |
| } |
| ; |
| |
| cte_list: |
| common_table_expr { $$ = list_make1($1); } |
| | cte_list ',' common_table_expr { $$ = lappend($1, $3); } |
| ; |
| |
| common_table_expr: name opt_name_list AS opt_materialized '(' PreparableStmt ')' opt_search_clause opt_cycle_clause |
| { |
| CommonTableExpr *n = makeNode(CommonTableExpr); |
| |
| n->ctename = $1; |
| n->aliascolnames = $2; |
| n->ctematerialized = $4; |
| n->ctequery = $6; |
| n->search_clause = castNode(CTESearchClause, $8); |
| n->cycle_clause = castNode(CTECycleClause, $9); |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_materialized: |
| MATERIALIZED { $$ = CTEMaterializeAlways; } |
| | NOT MATERIALIZED { $$ = CTEMaterializeNever; } |
| | /*EMPTY*/ { $$ = CTEMaterializeDefault; } |
| ; |
| |
| opt_search_clause: |
| SEARCH DEPTH FIRST_P BY columnList SET ColId |
| { |
| CTESearchClause *n = makeNode(CTESearchClause); |
| |
| n->search_col_list = $5; |
| n->search_breadth_first = false; |
| n->search_seq_column = $7; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | SEARCH BREADTH FIRST_P BY columnList SET ColId |
| { |
| CTESearchClause *n = makeNode(CTESearchClause); |
| |
| n->search_col_list = $5; |
| n->search_breadth_first = true; |
| n->search_seq_column = $7; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| opt_cycle_clause: |
| CYCLE columnList SET ColId TO AexprConst DEFAULT AexprConst USING ColId |
| { |
| CTECycleClause *n = makeNode(CTECycleClause); |
| |
| n->cycle_col_list = $2; |
| n->cycle_mark_column = $4; |
| n->cycle_mark_value = $6; |
| n->cycle_mark_default = $8; |
| n->cycle_path_column = $10; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | CYCLE columnList SET ColId USING ColId |
| { |
| CTECycleClause *n = makeNode(CTECycleClause); |
| |
| n->cycle_col_list = $2; |
| n->cycle_mark_column = $4; |
| n->cycle_mark_value = makeBoolAConst(true, -1); |
| n->cycle_mark_default = makeBoolAConst(false, -1); |
| n->cycle_path_column = $6; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = NULL; |
| } |
| ; |
| |
| opt_with_clause: |
| with_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| into_clause: |
| INTO OptTempTableName |
| { |
| $$ = makeNode(IntoClause); |
| $$->rel = $2; |
| $$->colNames = NIL; |
| $$->options = NIL; |
| $$->onCommit = ONCOMMIT_NOOP; |
| $$->tableSpaceName = NULL; |
| $$->viewQuery = NULL; |
| $$->skipData = false; |
| } |
| | /*EMPTY*/ |
| { $$ = NULL; } |
| ; |
| |
| /* |
| * Redundancy here is needed to avoid shift/reduce conflicts, |
| * since TEMP is not a reserved word. See also OptTemp. |
| */ |
| OptTempTableName: |
| TEMPORARY opt_table qualified_name |
| { |
| $$ = $3; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | TEMP opt_table qualified_name |
| { |
| $$ = $3; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | LOCAL TEMPORARY opt_table qualified_name |
| { |
| $$ = $4; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | LOCAL TEMP opt_table qualified_name |
| { |
| $$ = $4; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | GLOBAL TEMPORARY opt_table qualified_name |
| { |
| ereport(WARNING, |
| (errmsg("GLOBAL is deprecated in temporary table creation"), |
| parser_errposition(@1))); |
| $$ = $4; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | GLOBAL TEMP opt_table qualified_name |
| { |
| ereport(WARNING, |
| (errmsg("GLOBAL is deprecated in temporary table creation"), |
| parser_errposition(@1))); |
| $$ = $4; |
| $$->relpersistence = RELPERSISTENCE_TEMP; |
| } |
| | UNLOGGED opt_table qualified_name |
| { |
| $$ = $3; |
| $$->relpersistence = RELPERSISTENCE_UNLOGGED; |
| } |
| | TABLE qualified_name |
| { |
| $$ = $2; |
| $$->relpersistence = RELPERSISTENCE_PERMANENT; |
| } |
| | qualified_name |
| { |
| $$ = $1; |
| $$->relpersistence = RELPERSISTENCE_PERMANENT; |
| } |
| ; |
| |
| opt_table: TABLE |
| | /*EMPTY*/ |
| ; |
| |
| set_quantifier: |
| ALL { $$ = SET_QUANTIFIER_ALL; } |
| | DISTINCT { $$ = SET_QUANTIFIER_DISTINCT; } |
| | /*EMPTY*/ { $$ = SET_QUANTIFIER_DEFAULT; } |
| ; |
| |
| /* We use (NIL) as a placeholder to indicate that all target expressions |
| * should be placed in the DISTINCT list during parsetree analysis. |
| */ |
| distinct_clause: |
| DISTINCT { $$ = list_make1(NIL); } |
| | DISTINCT ON '(' expr_list ')' { $$ = $4; } |
| ; |
| |
| opt_all_clause: |
| ALL |
| | /*EMPTY*/ |
| ; |
| |
| opt_distinct_clause: |
| distinct_clause { $$ = $1; } |
| | opt_all_clause { $$ = NIL; } |
| ; |
| |
| opt_sort_clause: |
| sort_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| sort_clause: |
| ORDER BY sortby_list { $$ = $3; } |
| ; |
| |
| sortby_list: |
| sortby { $$ = list_make1($1); } |
| | sortby_list ',' sortby { $$ = lappend($1, $3); } |
| ; |
| |
| sortby: a_expr USING qual_all_Op opt_nulls_order |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_dir = SORTBY_USING; |
| $$->sortby_nulls = $4; |
| $$->useOp = $3; |
| $$->location = @3; |
| } |
| | a_expr opt_asc_desc opt_nulls_order |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_dir = $2; |
| $$->sortby_nulls = $3; |
| $$->useOp = NIL; |
| $$->location = -1; /* no operator */ |
| } |
| ; |
| |
| |
| select_limit: |
| limit_clause offset_clause |
| { |
| $$ = $1; |
| ($$)->limitOffset = $2; |
| } |
| | offset_clause limit_clause |
| { |
| $$ = $2; |
| ($$)->limitOffset = $1; |
| } |
| | limit_clause |
| { |
| $$ = $1; |
| } |
| | offset_clause |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = $1; |
| n->limitCount = NULL; |
| n->limitOption = LIMIT_OPTION_COUNT; |
| $$ = n; |
| } |
| ; |
| |
| opt_select_limit: |
| select_limit { $$ = $1; } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| limit_clause: |
| LIMIT select_limit_value |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = NULL; |
| n->limitCount = $2; |
| n->limitOption = LIMIT_OPTION_COUNT; |
| $$ = n; |
| } |
| | LIMIT select_limit_value ',' select_offset_value |
| { |
| /* Disabled because it was too confusing, bjm 2002-02-18 */ |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("LIMIT #,# syntax is not supported"), |
| errhint("Use separate LIMIT and OFFSET clauses."), |
| parser_errposition(@1))); |
| } |
| /* SQL:2008 syntax */ |
| /* to avoid shift/reduce conflicts, handle the optional value with |
| * a separate production rather than an opt_ expression. The fact |
| * that ONLY is fully reserved means that this way, we defer any |
| * decision about what rule reduces ROW or ROWS to the point where |
| * we can see the ONLY token in the lookahead slot. |
| */ |
| | FETCH first_or_next select_fetch_first_value row_or_rows ONLY |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = NULL; |
| n->limitCount = $3; |
| n->limitOption = LIMIT_OPTION_COUNT; |
| $$ = n; |
| } |
| | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = NULL; |
| n->limitCount = $3; |
| n->limitOption = LIMIT_OPTION_WITH_TIES; |
| $$ = n; |
| } |
| | FETCH first_or_next row_or_rows ONLY |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = NULL; |
| n->limitCount = makeIntConst(1, -1); |
| n->limitOption = LIMIT_OPTION_COUNT; |
| $$ = n; |
| } |
| | FETCH first_or_next row_or_rows WITH TIES |
| { |
| SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit)); |
| |
| n->limitOffset = NULL; |
| n->limitCount = makeIntConst(1, -1); |
| n->limitOption = LIMIT_OPTION_WITH_TIES; |
| $$ = n; |
| } |
| ; |
| |
| offset_clause: |
| OFFSET select_offset_value |
| { $$ = $2; } |
| /* SQL:2008 syntax */ |
| | OFFSET select_fetch_first_value row_or_rows |
| { $$ = $2; } |
| ; |
| |
| select_limit_value: |
| a_expr { $$ = $1; } |
| | ALL |
| { |
| /* LIMIT ALL is represented as a NULL constant */ |
| $$ = makeNullAConst(@1); |
| } |
| ; |
| |
| select_offset_value: |
| a_expr { $$ = $1; } |
| ; |
| |
| /* |
| * Allowing full expressions without parentheses causes various parsing |
| * problems with the trailing ROW/ROWS key words. SQL spec only calls for |
| * <simple value specification>, which is either a literal or a parameter (but |
| * an <SQL parameter reference> could be an identifier, bringing up conflicts |
| * with ROW/ROWS). We solve this by leveraging the presence of ONLY (see above) |
| * to determine whether the expression is missing rather than trying to make it |
| * optional in this rule. |
| * |
| * c_expr covers almost all the spec-required cases (and more), but it doesn't |
| * cover signed numeric literals, which are allowed by the spec. So we include |
| * those here explicitly. We need FCONST as well as ICONST because values that |
| * don't fit in the platform's "long", but do fit in bigint, should still be |
| * accepted here. (This is possible in 64-bit Windows as well as all 32-bit |
| * builds.) |
| */ |
| select_fetch_first_value: |
| c_expr { $$ = $1; } |
| | '+' I_or_F_const |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } |
| | '-' I_or_F_const |
| { $$ = doNegate($2, @1); } |
| ; |
| |
| I_or_F_const: |
| Iconst { $$ = makeIntConst($1,@1); } |
| | FCONST { $$ = makeFloatConst($1,@1); } |
| ; |
| |
| /* noise words */ |
| row_or_rows: ROW { $$ = 0; } |
| | ROWS { $$ = 0; } |
| ; |
| |
| first_or_next: FIRST_P { $$ = 0; } |
| | NEXT { $$ = 0; } |
| ; |
| |
| |
| /* |
| * This syntax for group_clause tries to follow the spec quite closely. |
| * However, the spec allows only column references, not expressions, |
| * which introduces an ambiguity between implicit row constructors |
| * (a,b) and lists of column references. |
| * |
| * We handle this by using the a_expr production for what the spec calls |
| * <ordinary grouping set>, which in the spec represents either one column |
| * reference or a parenthesized list of column references. Then, we check the |
| * top node of the a_expr to see if it's an implicit RowExpr, and if so, just |
| * grab and use the list, discarding the node. (this is done in parse analysis, |
| * not here) |
| * |
| * (we abuse the row_format field of RowExpr to distinguish implicit and |
| * explicit row constructors; it's debatable if anyone sanely wants to use them |
| * in a group clause, but if they have a reason to, we make it possible.) |
| * |
| * Each item in the group_clause list is either an expression tree or a |
| * GroupingSet node of some type. |
| */ |
| group_clause: |
| GROUP_P BY set_quantifier group_by_list |
| { |
| GroupClause *n = (GroupClause *) palloc(sizeof(GroupClause)); |
| |
| n->distinct = $3 == SET_QUANTIFIER_DISTINCT; |
| n->list = $4; |
| $$ = n; |
| } |
| | /*EMPTY*/ |
| { |
| GroupClause *n = (GroupClause *) palloc(sizeof(GroupClause)); |
| |
| n->distinct = false; |
| n->list = NIL; |
| $$ = n; |
| } |
| ; |
| |
| group_by_list: |
| group_by_item { $$ = list_make1($1); } |
| | group_by_list ',' group_by_item { $$ = lappend($1,$3); } |
| ; |
| |
| group_by_item: |
| a_expr { $$ = $1; } |
| | empty_grouping_set { $$ = $1; } |
| | cube_clause { $$ = $1; } |
| | rollup_clause { $$ = $1; } |
| | grouping_sets_clause { $$ = $1; } |
| ; |
| |
| empty_grouping_set: |
| '(' ')' |
| { |
| $$ = (Node *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, @1); |
| } |
| ; |
| |
| /* |
| * These hacks rely on setting precedence of CUBE and ROLLUP below that of '(', |
| * so that they shift in these rules rather than reducing the conflicting |
| * unreserved_keyword rule. |
| */ |
| |
| rollup_clause: |
| ROLLUP '(' expr_list ')' |
| { |
| $$ = (Node *) makeGroupingSet(GROUPING_SET_ROLLUP, $3, @1); |
| } |
| ; |
| |
| cube_clause: |
| CUBE '(' expr_list ')' |
| { |
| $$ = (Node *) makeGroupingSet(GROUPING_SET_CUBE, $3, @1); |
| } |
| ; |
| |
| grouping_sets_clause: |
| GROUPING SETS '(' group_by_list ')' |
| { |
| $$ = (Node *) makeGroupingSet(GROUPING_SET_SETS, $4, @1); |
| } |
| ; |
| |
| having_clause: |
| HAVING a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| for_locking_clause: |
| for_locking_items { $$ = $1; } |
| | FOR READ ONLY { $$ = NIL; } |
| ; |
| |
| opt_for_locking_clause: |
| for_locking_clause { $$ = $1; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| for_locking_items: |
| for_locking_item { $$ = list_make1($1); } |
| | for_locking_items for_locking_item { $$ = lappend($1, $2); } |
| ; |
| |
| for_locking_item: |
| for_locking_strength locked_rels_list opt_nowait_or_skip |
| { |
| LockingClause *n = makeNode(LockingClause); |
| |
| n->lockedRels = $2; |
| n->strength = $1; |
| n->waitPolicy = $3; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| for_locking_strength: |
| FOR UPDATE { $$ = LCS_FORUPDATE; } |
| | FOR NO KEY UPDATE { $$ = LCS_FORNOKEYUPDATE; } |
| | FOR SHARE { $$ = LCS_FORSHARE; } |
| | FOR KEY SHARE { $$ = LCS_FORKEYSHARE; } |
| ; |
| |
| locked_rels_list: |
| OF qualified_name_list { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| |
| /* |
| * We should allow ROW '(' expr_list ')' too, but that seems to require |
| * making VALUES a fully reserved word, which will probably break more apps |
| * than allowing the noise-word is worth. |
| */ |
| values_clause: |
| VALUES '(' expr_list ')' |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| n->valuesLists = list_make1($3); |
| $$ = (Node *) n; |
| } |
| | values_clause ',' '(' expr_list ')' |
| { |
| SelectStmt *n = (SelectStmt *) $1; |
| |
| n->valuesLists = lappend(n->valuesLists, $4); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * clauses common to all Optimizable Stmts: |
| * from_clause - allow list of both JOIN expressions and table names |
| * where_clause - qualifications for joins or restrictions |
| * |
| *****************************************************************************/ |
| |
| from_clause: |
| FROM from_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| from_list: |
| table_ref { $$ = list_make1($1); } |
| | from_list ',' table_ref { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * table_ref is where an alias clause can be attached. |
| */ |
| table_ref: relation_expr opt_alias_clause |
| { |
| $1->alias = $2; |
| $$ = (Node *) $1; |
| } |
| | relation_expr opt_alias_clause tablesample_clause |
| { |
| RangeTableSample *n = (RangeTableSample *) $3; |
| |
| $1->alias = $2; |
| /* relation_expr goes inside the RangeTableSample node */ |
| n->relation = (Node *) $1; |
| $$ = (Node *) n; |
| } |
| | func_table func_alias_clause |
| { |
| RangeFunction *n = (RangeFunction *) $1; |
| |
| n->alias = linitial($2); |
| n->coldeflist = lsecond($2); |
| $$ = (Node *) n; |
| } |
| | LATERAL_P func_table func_alias_clause |
| { |
| RangeFunction *n = (RangeFunction *) $2; |
| |
| n->lateral = true; |
| n->alias = linitial($3); |
| n->coldeflist = lsecond($3); |
| $$ = (Node *) n; |
| } |
| | xmltable opt_alias_clause |
| { |
| RangeTableFunc *n = (RangeTableFunc *) $1; |
| |
| n->alias = $2; |
| $$ = (Node *) n; |
| } |
| | LATERAL_P xmltable opt_alias_clause |
| { |
| RangeTableFunc *n = (RangeTableFunc *) $2; |
| |
| n->lateral = true; |
| n->alias = $3; |
| $$ = (Node *) n; |
| } |
| | select_with_parens opt_alias_clause |
| { |
| RangeSubselect *n = makeNode(RangeSubselect); |
| |
| n->lateral = false; |
| n->subquery = $1; |
| n->alias = $2; |
| $$ = (Node *) n; |
| } |
| | LATERAL_P select_with_parens opt_alias_clause |
| { |
| RangeSubselect *n = makeNode(RangeSubselect); |
| |
| n->lateral = true; |
| n->subquery = $2; |
| n->alias = $3; |
| $$ = (Node *) n; |
| } |
| | joined_table |
| { |
| $$ = (Node *) $1; |
| } |
| | '(' joined_table ')' alias_clause |
| { |
| $2->alias = $4; |
| $$ = (Node *) $2; |
| } |
| ; |
| |
| |
| /* |
| * It may seem silly to separate joined_table from table_ref, but there is |
| * method in SQL's madness: if you don't do it this way you get reduce- |
| * reduce conflicts, because it's not clear to the parser generator whether |
| * to expect alias_clause after ')' or not. For the same reason we must |
| * treat 'JOIN' and 'join_type JOIN' separately, rather than allowing |
| * join_type to expand to empty; if we try it, the parser generator can't |
| * figure out when to reduce an empty join_type right after table_ref. |
| * |
| * Note that a CROSS JOIN is the same as an unqualified |
| * INNER JOIN, and an INNER JOIN/ON has the same shape |
| * but a qualification expression to limit membership. |
| * A NATURAL JOIN implicitly matches column names between |
| * tables and the shape is determined by which columns are |
| * in common. We'll collect columns during the later transformations. |
| */ |
| |
| joined_table: |
| '(' joined_table ')' |
| { |
| $$ = $2; |
| } |
| | table_ref CROSS JOIN table_ref |
| { |
| /* CROSS JOIN is same as unqualified inner join */ |
| JoinExpr *n = makeNode(JoinExpr); |
| |
| n->jointype = JOIN_INNER; |
| n->isNatural = false; |
| n->larg = $1; |
| n->rarg = $4; |
| n->usingClause = NIL; |
| n->join_using_alias = NULL; |
| n->quals = NULL; |
| $$ = n; |
| } |
| | table_ref join_type JOIN table_ref join_qual |
| { |
| JoinExpr *n = makeNode(JoinExpr); |
| |
| n->jointype = $2; |
| n->isNatural = false; |
| n->larg = $1; |
| n->rarg = $4; |
| if ($5 != NULL && IsA($5, List)) |
| { |
| /* USING clause */ |
| n->usingClause = linitial_node(List, castNode(List, $5)); |
| n->join_using_alias = lsecond_node(Alias, castNode(List, $5)); |
| } |
| else |
| { |
| /* ON clause */ |
| n->quals = $5; |
| } |
| $$ = n; |
| } |
| | table_ref JOIN table_ref join_qual |
| { |
| /* letting join_type reduce to empty doesn't work */ |
| JoinExpr *n = makeNode(JoinExpr); |
| |
| n->jointype = JOIN_INNER; |
| n->isNatural = false; |
| n->larg = $1; |
| n->rarg = $3; |
| if ($4 != NULL && IsA($4, List)) |
| { |
| /* USING clause */ |
| n->usingClause = linitial_node(List, castNode(List, $4)); |
| n->join_using_alias = lsecond_node(Alias, castNode(List, $4)); |
| } |
| else |
| { |
| /* ON clause */ |
| n->quals = $4; |
| } |
| $$ = n; |
| } |
| | table_ref NATURAL join_type JOIN table_ref |
| { |
| JoinExpr *n = makeNode(JoinExpr); |
| |
| n->jointype = $3; |
| n->isNatural = true; |
| n->larg = $1; |
| n->rarg = $5; |
| n->usingClause = NIL; /* figure out which columns later... */ |
| n->join_using_alias = NULL; |
| n->quals = NULL; /* fill later */ |
| $$ = n; |
| } |
| | table_ref NATURAL JOIN table_ref |
| { |
| /* letting join_type reduce to empty doesn't work */ |
| JoinExpr *n = makeNode(JoinExpr); |
| |
| n->jointype = JOIN_INNER; |
| n->isNatural = true; |
| n->larg = $1; |
| n->rarg = $4; |
| n->usingClause = NIL; /* figure out which columns later... */ |
| n->join_using_alias = NULL; |
| n->quals = NULL; /* fill later */ |
| $$ = n; |
| } |
| ; |
| |
| alias_clause: |
| AS ColId '(' name_list ')' |
| { |
| $$ = makeNode(Alias); |
| $$->aliasname = $2; |
| $$->colnames = $4; |
| } |
| | AS ColId |
| { |
| $$ = makeNode(Alias); |
| $$->aliasname = $2; |
| } |
| | ColId '(' name_list ')' |
| { |
| $$ = makeNode(Alias); |
| $$->aliasname = $1; |
| $$->colnames = $3; |
| } |
| | ColId |
| { |
| $$ = makeNode(Alias); |
| $$->aliasname = $1; |
| } |
| ; |
| |
| opt_alias_clause: alias_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* |
| * The alias clause after JOIN ... USING only accepts the AS ColId spelling, |
| * per SQL standard. (The grammar could parse the other variants, but they |
| * don't seem to be useful, and it might lead to parser problems in the |
| * future.) |
| */ |
| opt_alias_clause_for_join_using: |
| AS ColId |
| { |
| $$ = makeNode(Alias); |
| $$->aliasname = $2; |
| /* the column name list will be inserted later */ |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* |
| * func_alias_clause can include both an Alias and a coldeflist, so we make it |
| * return a 2-element list that gets disassembled by calling production. |
| */ |
| func_alias_clause: |
| alias_clause |
| { |
| $$ = list_make2($1, NIL); |
| } |
| | AS '(' TableFuncElementList ')' |
| { |
| $$ = list_make2(NULL, $3); |
| } |
| | AS ColId '(' TableFuncElementList ')' |
| { |
| Alias *a = makeNode(Alias); |
| |
| a->aliasname = $2; |
| $$ = list_make2(a, $4); |
| } |
| | ColId '(' TableFuncElementList ')' |
| { |
| Alias *a = makeNode(Alias); |
| |
| a->aliasname = $1; |
| $$ = list_make2(a, $3); |
| } |
| | /*EMPTY*/ |
| { |
| $$ = list_make2(NULL, NIL); |
| } |
| ; |
| |
| join_type: FULL opt_outer { $$ = JOIN_FULL; } |
| | LEFT opt_outer { $$ = JOIN_LEFT; } |
| | RIGHT opt_outer { $$ = JOIN_RIGHT; } |
| | INNER_P { $$ = JOIN_INNER; } |
| ; |
| |
| /* OUTER is just noise... */ |
| opt_outer: OUTER_P |
| | /*EMPTY*/ |
| ; |
| |
| /* JOIN qualification clauses |
| * Possibilities are: |
| * USING ( column list ) [ AS alias ] |
| * allows only unqualified column names, |
| * which must match between tables. |
| * ON expr allows more general qualifications. |
| * |
| * We return USING as a two-element List (the first item being a sub-List |
| * of the common column names, and the second either an Alias item or NULL). |
| * An ON-expr will not be a List, so it can be told apart that way. |
| */ |
| |
| join_qual: USING '(' name_list ')' opt_alias_clause_for_join_using |
| { |
| $$ = (Node *) list_make2($3, $5); |
| } |
| | ON a_expr |
| { |
| $$ = $2; |
| } |
| ; |
| |
| |
| relation_expr: |
| qualified_name |
| { |
| /* inheritance query, implicitly */ |
| $$ = $1; |
| $$->inh = true; |
| $$->alias = NULL; |
| } |
| | extended_relation_expr |
| { |
| $$ = $1; |
| } |
| ; |
| |
| extended_relation_expr: |
| qualified_name '*' |
| { |
| /* inheritance query, explicitly */ |
| $$ = $1; |
| $$->inh = true; |
| $$->alias = NULL; |
| } |
| | ONLY qualified_name |
| { |
| /* no inheritance */ |
| $$ = $2; |
| $$->inh = false; |
| $$->alias = NULL; |
| } |
| | ONLY '(' qualified_name ')' |
| { |
| /* no inheritance, SQL99-style syntax */ |
| $$ = $3; |
| $$->inh = false; |
| $$->alias = NULL; |
| } |
| ; |
| |
| |
| relation_expr_list: |
| relation_expr { $$ = list_make1($1); } |
| | relation_expr_list ',' relation_expr { $$ = lappend($1, $3); } |
| ; |
| |
| |
| /* |
| * Given "UPDATE foo set set ...", we have to decide without looking any |
| * further ahead whether the first "set" is an alias or the UPDATE's SET |
| * keyword. Since "set" is allowed as a column name both interpretations |
| * are feasible. We resolve the shift/reduce conflict by giving the first |
| * relation_expr_opt_alias production a higher precedence than the SET token |
| * has, causing the parser to prefer to reduce, in effect assuming that the |
| * SET is not an alias. |
| */ |
| relation_expr_opt_alias: relation_expr %prec UMINUS |
| { |
| $$ = $1; |
| } |
| | relation_expr ColId |
| { |
| Alias *alias = makeNode(Alias); |
| |
| alias->aliasname = $2; |
| $1->alias = alias; |
| $$ = $1; |
| } |
| | relation_expr AS ColId |
| { |
| Alias *alias = makeNode(Alias); |
| |
| alias->aliasname = $3; |
| $1->alias = alias; |
| $$ = $1; |
| } |
| ; |
| |
| /* |
| * TABLESAMPLE decoration in a FROM item |
| */ |
| tablesample_clause: |
| TABLESAMPLE func_name '(' expr_list ')' opt_repeatable_clause |
| { |
| RangeTableSample *n = makeNode(RangeTableSample); |
| |
| /* n->relation will be filled in later */ |
| n->method = $2; |
| n->args = $4; |
| n->repeatable = $6; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opt_repeatable_clause: |
| REPEATABLE '(' a_expr ')' { $$ = (Node *) $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* |
| * func_table represents a function invocation in a FROM list. It can be |
| * a plain function call, like "foo(...)", or a ROWS FROM expression with |
| * one or more function calls, "ROWS FROM (foo(...), bar(...))", |
| * optionally with WITH ORDINALITY attached. |
| * In the ROWS FROM syntax, a column definition list can be given for each |
| * function, for example: |
| * ROWS FROM (foo() AS (foo_res_a text, foo_res_b text), |
| * bar() AS (bar_res_a text, bar_res_b text)) |
| * It's also possible to attach a column definition list to the RangeFunction |
| * as a whole, but that's handled by the table_ref production. |
| */ |
| func_table: func_expr_windowless opt_ordinality |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| |
| n->lateral = false; |
| n->ordinality = $2; |
| n->is_rowsfrom = false; |
| n->functions = list_make1(list_make2($1, NIL)); |
| /* alias and coldeflist are set by table_ref production */ |
| $$ = (Node *) n; |
| } |
| | ROWS FROM '(' rowsfrom_list ')' opt_ordinality |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| |
| n->lateral = false; |
| n->ordinality = $6; |
| n->is_rowsfrom = true; |
| n->functions = $4; |
| /* alias and coldeflist are set by table_ref production */ |
| $$ = (Node *) n; |
| } |
| ; |
| |
| rowsfrom_item: func_expr_windowless opt_col_def_list |
| { $$ = list_make2($1, $2); } |
| ; |
| |
| rowsfrom_list: |
| rowsfrom_item { $$ = list_make1($1); } |
| | rowsfrom_list ',' rowsfrom_item { $$ = lappend($1, $3); } |
| ; |
| |
| opt_col_def_list: AS '(' TableFuncElementList ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_ordinality: WITH_LA ORDINALITY { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| |
| where_clause: |
| WHERE a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* variant for UPDATE and DELETE */ |
| where_or_current_clause: |
| WHERE a_expr { $$ = $2; } |
| | WHERE CURRENT_P OF cursor_name |
| { |
| CurrentOfExpr *n = makeNode(CurrentOfExpr); |
| |
| /* cvarno is filled in by parse analysis */ |
| n->cursor_name = $4; |
| n->cursor_param = 0; |
| $$ = (Node *) n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| OptTableFuncElementList: |
| TableFuncElementList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TableFuncElementList: |
| TableFuncElement |
| { |
| $$ = list_make1($1); |
| } |
| | TableFuncElementList ',' TableFuncElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| TableFuncElement: ColId Typename opt_collate_clause |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| |
| n->colname = $1; |
| n->typeName = $2; |
| n->inhcount = 0; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->is_from_type = false; |
| n->storage = 0; |
| n->raw_default = NULL; |
| n->cooked_default = NULL; |
| n->collClause = (CollateClause *) $3; |
| n->collOid = InvalidOid; |
| n->constraints = NIL; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * XMLTABLE |
| */ |
| xmltable: |
| XMLTABLE '(' c_expr xmlexists_argument COLUMNS xmltable_column_list ')' |
| { |
| RangeTableFunc *n = makeNode(RangeTableFunc); |
| |
| n->rowexpr = $3; |
| n->docexpr = $4; |
| n->columns = $6; |
| n->namespaces = NIL; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | XMLTABLE '(' XMLNAMESPACES '(' xml_namespace_list ')' ',' |
| c_expr xmlexists_argument COLUMNS xmltable_column_list ')' |
| { |
| RangeTableFunc *n = makeNode(RangeTableFunc); |
| |
| n->rowexpr = $8; |
| n->docexpr = $9; |
| n->columns = $11; |
| n->namespaces = $5; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| xmltable_column_list: xmltable_column_el { $$ = list_make1($1); } |
| | xmltable_column_list ',' xmltable_column_el { $$ = lappend($1, $3); } |
| ; |
| |
| xmltable_column_el: |
| ColId Typename |
| { |
| RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); |
| |
| fc->colname = $1; |
| fc->for_ordinality = false; |
| fc->typeName = $2; |
| fc->is_not_null = false; |
| fc->colexpr = NULL; |
| fc->coldefexpr = NULL; |
| fc->location = @1; |
| |
| $$ = (Node *) fc; |
| } |
| | ColId Typename xmltable_column_option_list |
| { |
| RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); |
| ListCell *option; |
| bool nullability_seen = false; |
| |
| fc->colname = $1; |
| fc->typeName = $2; |
| fc->for_ordinality = false; |
| fc->is_not_null = false; |
| fc->colexpr = NULL; |
| fc->coldefexpr = NULL; |
| fc->location = @1; |
| |
| foreach(option, $3) |
| { |
| DefElem *defel = (DefElem *) lfirst(option); |
| |
| if (strcmp(defel->defname, "default") == 0) |
| { |
| if (fc->coldefexpr != NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one DEFAULT value is allowed"), |
| parser_errposition(defel->location))); |
| fc->coldefexpr = defel->arg; |
| } |
| else if (strcmp(defel->defname, "path") == 0) |
| { |
| if (fc->colexpr != NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("only one PATH value per column is allowed"), |
| parser_errposition(defel->location))); |
| fc->colexpr = defel->arg; |
| } |
| else if (strcmp(defel->defname, "is_not_null") == 0) |
| { |
| if (nullability_seen) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("conflicting or redundant NULL / NOT NULL declarations for column \"%s\"", fc->colname), |
| parser_errposition(defel->location))); |
| fc->is_not_null = boolVal(defel->arg); |
| nullability_seen = true; |
| } |
| else |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("unrecognized column option \"%s\"", |
| defel->defname), |
| parser_errposition(defel->location))); |
| } |
| } |
| $$ = (Node *) fc; |
| } |
| | ColId FOR ORDINALITY |
| { |
| RangeTableFuncCol *fc = makeNode(RangeTableFuncCol); |
| |
| fc->colname = $1; |
| fc->for_ordinality = true; |
| /* other fields are ignored, initialized by makeNode */ |
| fc->location = @1; |
| |
| $$ = (Node *) fc; |
| } |
| ; |
| |
| xmltable_column_option_list: |
| xmltable_column_option_el |
| { $$ = list_make1($1); } |
| | xmltable_column_option_list xmltable_column_option_el |
| { $$ = lappend($1, $2); } |
| ; |
| |
| xmltable_column_option_el: |
| IDENT b_expr |
| { $$ = makeDefElem($1, $2, @1); } |
| | DEFAULT b_expr |
| { $$ = makeDefElem("default", $2, @1); } |
| | NOT NULL_P |
| { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } |
| | NULL_P |
| { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } |
| ; |
| |
| xml_namespace_list: |
| xml_namespace_el |
| { $$ = list_make1($1); } |
| | xml_namespace_list ',' xml_namespace_el |
| { $$ = lappend($1, $3); } |
| ; |
| |
| xml_namespace_el: |
| b_expr AS ColLabel |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $3; |
| $$->indirection = NIL; |
| $$->val = $1; |
| $$->location = @1; |
| } |
| | DEFAULT b_expr |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = NULL; |
| $$->indirection = NIL; |
| $$->val = $2; |
| $$->location = @1; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Type syntax |
| * SQL introduces a large amount of type-specific syntax. |
| * Define individual clauses to handle these cases, and use |
| * the generic case to handle regular type-extensible Postgres syntax. |
| * - thomas 1997-10-10 |
| * |
| *****************************************************************************/ |
| |
| Typename: SimpleTypename opt_array_bounds |
| { |
| $$ = $1; |
| $$->arrayBounds = $2; |
| } |
| | SETOF SimpleTypename opt_array_bounds |
| { |
| $$ = $2; |
| $$->arrayBounds = $3; |
| $$->setof = true; |
| } |
| /* SQL standard syntax, currently only one-dimensional */ |
| | SimpleTypename ARRAY '[' Iconst ']' |
| { |
| $$ = $1; |
| $$->arrayBounds = list_make1(makeInteger($4)); |
| } |
| | SETOF SimpleTypename ARRAY '[' Iconst ']' |
| { |
| $$ = $2; |
| $$->arrayBounds = list_make1(makeInteger($5)); |
| $$->setof = true; |
| } |
| | SimpleTypename ARRAY |
| { |
| $$ = $1; |
| $$->arrayBounds = list_make1(makeInteger(-1)); |
| } |
| | SETOF SimpleTypename ARRAY |
| { |
| $$ = $2; |
| $$->arrayBounds = list_make1(makeInteger(-1)); |
| $$->setof = true; |
| } |
| ; |
| |
| opt_array_bounds: |
| opt_array_bounds '[' ']' |
| { $$ = lappend($1, makeInteger(-1)); } |
| | opt_array_bounds '[' Iconst ']' |
| { $$ = lappend($1, makeInteger($3)); } |
| | /*EMPTY*/ |
| { $$ = NIL; } |
| ; |
| |
| SimpleTypename: |
| GenericType { $$ = $1; } |
| | Numeric { $$ = $1; } |
| | Bit { $$ = $1; } |
| | Character { $$ = $1; } |
| | ConstDatetime { $$ = $1; } |
| | ConstInterval opt_interval |
| { |
| $$ = $1; |
| $$->typmods = $2; |
| } |
| | ConstInterval '(' Iconst ')' |
| { |
| $$ = $1; |
| $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), |
| makeIntConst($3, @3)); |
| } |
| ; |
| |
| /* We have a separate ConstTypename to allow defaulting fixed-length |
| * types such as CHAR() and BIT() to an unspecified length. |
| * SQL9x requires that these default to a length of one, but this |
| * makes no sense for constructs like CHAR 'hi' and BIT '0101', |
| * where there is an obvious better choice to make. |
| * Note that ConstInterval is not included here since it must |
| * be pushed up higher in the rules to accommodate the postfix |
| * options (e.g. INTERVAL '1' YEAR). Likewise, we have to handle |
| * the generic-type-name case in AexprConst to avoid premature |
| * reduce/reduce conflicts against function names. |
| */ |
| ConstTypename: |
| Numeric { $$ = $1; } |
| | ConstBit { $$ = $1; } |
| | ConstCharacter { $$ = $1; } |
| | ConstDatetime { $$ = $1; } |
| ; |
| |
| /* |
| * GenericType covers all type names that don't have special syntax mandated |
| * by the standard, including qualified names. We also allow type modifiers. |
| * To avoid parsing conflicts against function invocations, the modifiers |
| * have to be shown as expr_list here, but parse analysis will only accept |
| * constants for them. |
| */ |
| GenericType: |
| type_function_name opt_type_modifiers |
| { |
| $$ = makeTypeName($1); |
| $$->typmods = $2; |
| $$->location = @1; |
| } |
| | type_function_name attrs opt_type_modifiers |
| { |
| $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); |
| $$->typmods = $3; |
| $$->location = @1; |
| } |
| ; |
| |
| opt_type_modifiers: '(' expr_list ')' { $$ = $2; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| /* |
| * SQL numeric data types |
| */ |
| Numeric: INT_P |
| { |
| $$ = SystemTypeName("int4"); |
| $$->location = @1; |
| } |
| | INTEGER |
| { |
| $$ = SystemTypeName("int4"); |
| $$->location = @1; |
| } |
| | SMALLINT |
| { |
| $$ = SystemTypeName("int2"); |
| $$->location = @1; |
| } |
| | BIGINT |
| { |
| $$ = SystemTypeName("int8"); |
| $$->location = @1; |
| } |
| | REAL |
| { |
| $$ = SystemTypeName("float4"); |
| $$->location = @1; |
| } |
| | FLOAT_P opt_float |
| { |
| $$ = $2; |
| $$->location = @1; |
| } |
| | DOUBLE_P PRECISION |
| { |
| $$ = SystemTypeName("float8"); |
| $$->location = @1; |
| } |
| | DECIMAL_P opt_type_modifiers |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmods = $2; |
| $$->location = @1; |
| } |
| | DEC opt_type_modifiers |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmods = $2; |
| $$->location = @1; |
| } |
| | NUMERIC opt_type_modifiers |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmods = $2; |
| $$->location = @1; |
| } |
| | BOOLEAN_P |
| { |
| $$ = SystemTypeName("bool"); |
| $$->location = @1; |
| } |
| ; |
| |
| opt_float: '(' Iconst ')' |
| { |
| /* |
| * Check FLOAT() precision limits assuming IEEE floating |
| * types - thomas 1997-09-18 |
| */ |
| if ($2 < 1) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("precision for type float must be at least 1 bit"), |
| parser_errposition(@2))); |
| else if ($2 <= 24) |
| $$ = SystemTypeName("float4"); |
| else if ($2 <= 53) |
| $$ = SystemTypeName("float8"); |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("precision for type float must be less than 54 bits"), |
| parser_errposition(@2))); |
| } |
| | /*EMPTY*/ |
| { |
| $$ = SystemTypeName("float8"); |
| } |
| ; |
| |
| /* |
| * SQL bit-field data types |
| * The following implements BIT() and BIT VARYING(). |
| */ |
| Bit: BitWithLength |
| { |
| $$ = $1; |
| } |
| | BitWithoutLength |
| { |
| $$ = $1; |
| } |
| ; |
| |
| /* ConstBit is like Bit except "BIT" defaults to unspecified length */ |
| /* See notes for ConstCharacter, which addresses same issue for "CHAR" */ |
| ConstBit: BitWithLength |
| { |
| $$ = $1; |
| } |
| | BitWithoutLength |
| { |
| $$ = $1; |
| $$->typmods = NIL; |
| } |
| ; |
| |
| BitWithLength: |
| BIT opt_varying '(' expr_list ')' |
| { |
| char *typname; |
| |
| typname = $2 ? "varbit" : "bit"; |
| $$ = SystemTypeName(typname); |
| $$->typmods = $4; |
| $$->location = @1; |
| } |
| ; |
| |
| BitWithoutLength: |
| BIT opt_varying |
| { |
| /* bit defaults to bit(1), varbit to no limit */ |
| if ($2) |
| { |
| $$ = SystemTypeName("varbit"); |
| } |
| else |
| { |
| $$ = SystemTypeName("bit"); |
| $$->typmods = list_make1(makeIntConst(1, -1)); |
| } |
| $$->location = @1; |
| } |
| ; |
| |
| |
| /* |
| * SQL character data types |
| * The following implements CHAR() and VARCHAR(). |
| */ |
| Character: CharacterWithLength |
| { |
| $$ = $1; |
| } |
| | CharacterWithoutLength |
| { |
| $$ = $1; |
| } |
| ; |
| |
| ConstCharacter: CharacterWithLength |
| { |
| $$ = $1; |
| } |
| | CharacterWithoutLength |
| { |
| /* Length was not specified so allow to be unrestricted. |
| * This handles problems with fixed-length (bpchar) strings |
| * which in column definitions must default to a length |
| * of one, but should not be constrained if the length |
| * was not specified. |
| */ |
| $$ = $1; |
| $$->typmods = NIL; |
| } |
| ; |
| |
| CharacterWithLength: character '(' Iconst ')' |
| { |
| $$ = SystemTypeName($1); |
| $$->typmods = list_make1(makeIntConst($3, @3)); |
| $$->location = @1; |
| } |
| ; |
| |
| CharacterWithoutLength: character |
| { |
| $$ = SystemTypeName($1); |
| /* char defaults to char(1), varchar to no limit */ |
| if (strcmp($1, "bpchar") == 0) |
| $$->typmods = list_make1(makeIntConst(1, -1)); |
| $$->location = @1; |
| } |
| ; |
| |
| character: CHARACTER opt_varying |
| { $$ = $2 ? "varchar": "bpchar"; } |
| | CHAR_P opt_varying |
| { $$ = $2 ? "varchar": "bpchar"; } |
| | VARCHAR |
| { $$ = "varchar"; } |
| | NATIONAL CHARACTER opt_varying |
| { $$ = $3 ? "varchar": "bpchar"; } |
| | NATIONAL CHAR_P opt_varying |
| { $$ = $3 ? "varchar": "bpchar"; } |
| | NCHAR opt_varying |
| { $$ = $2 ? "varchar": "bpchar"; } |
| ; |
| |
| opt_varying: |
| VARYING { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /* |
| * SQL date/time types |
| */ |
| ConstDatetime: |
| TIMESTAMP '(' Iconst ')' opt_timezone |
| { |
| if ($5) |
| $$ = SystemTypeName("timestamptz"); |
| else |
| $$ = SystemTypeName("timestamp"); |
| $$->typmods = list_make1(makeIntConst($3, @3)); |
| $$->location = @1; |
| } |
| | TIMESTAMP opt_timezone |
| { |
| if ($2) |
| $$ = SystemTypeName("timestamptz"); |
| else |
| $$ = SystemTypeName("timestamp"); |
| $$->location = @1; |
| } |
| | TIME '(' Iconst ')' opt_timezone |
| { |
| if ($5) |
| $$ = SystemTypeName("timetz"); |
| else |
| $$ = SystemTypeName("time"); |
| $$->typmods = list_make1(makeIntConst($3, @3)); |
| $$->location = @1; |
| } |
| | TIME opt_timezone |
| { |
| if ($2) |
| $$ = SystemTypeName("timetz"); |
| else |
| $$ = SystemTypeName("time"); |
| $$->location = @1; |
| } |
| ; |
| |
| ConstInterval: |
| INTERVAL |
| { |
| $$ = SystemTypeName("interval"); |
| $$->location = @1; |
| } |
| ; |
| |
| opt_timezone: |
| WITH_LA TIME ZONE { $$ = true; } |
| | WITHOUT_LA TIME ZONE { $$ = false; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| opt_interval: |
| YEAR_P |
| { $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); } |
| | MONTH_P |
| { $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); } |
| | DAY_P |
| { $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1)); } |
| | HOUR_P |
| { $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); } |
| | MINUTE_P |
| { $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); } |
| | interval_second |
| { $$ = $1; } |
| | YEAR_P TO MONTH_P |
| { |
| $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) | |
| INTERVAL_MASK(MONTH), @1)); |
| } |
| | DAY_P TO HOUR_P |
| { |
| $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) | |
| INTERVAL_MASK(HOUR), @1)); |
| } |
| | DAY_P TO MINUTE_P |
| { |
| $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) | |
| INTERVAL_MASK(HOUR) | |
| INTERVAL_MASK(MINUTE), @1)); |
| } |
| | DAY_P TO interval_second |
| { |
| $$ = $3; |
| linitial($$) = makeIntConst(INTERVAL_MASK(DAY) | |
| INTERVAL_MASK(HOUR) | |
| INTERVAL_MASK(MINUTE) | |
| INTERVAL_MASK(SECOND), @1); |
| } |
| | HOUR_P TO MINUTE_P |
| { |
| $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | |
| INTERVAL_MASK(MINUTE), @1)); |
| } |
| | HOUR_P TO interval_second |
| { |
| $$ = $3; |
| linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) | |
| INTERVAL_MASK(MINUTE) | |
| INTERVAL_MASK(SECOND), @1); |
| } |
| | MINUTE_P TO interval_second |
| { |
| $$ = $3; |
| linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) | |
| INTERVAL_MASK(SECOND), @1); |
| } |
| | /*EMPTY*/ |
| { $$ = NIL; } |
| ; |
| |
| interval_second: |
| SECOND_P |
| { |
| $$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1)); |
| } |
| | SECOND_P '(' Iconst ')' |
| { |
| $$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1), |
| makeIntConst($3, @3)); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * expression grammar |
| * |
| *****************************************************************************/ |
| |
| /* |
| * General expressions |
| * This is the heart of the expression syntax. |
| * |
| * We have two expression types: a_expr is the unrestricted kind, and |
| * b_expr is a subset that must be used in some places to avoid shift/reduce |
| * conflicts. For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr" |
| * because that use of AND conflicts with AND as a boolean operator. So, |
| * b_expr is used in BETWEEN and we remove boolean keywords from b_expr. |
| * |
| * Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can |
| * always be used by surrounding it with parens. |
| * |
| * c_expr is all the productions that are common to a_expr and b_expr; |
| * it's factored out just to eliminate redundant coding. |
| * |
| * Be careful of productions involving more than one terminal token. |
| * By default, bison will assign such productions the precedence of their |
| * last terminal, but in nearly all cases you want it to be the precedence |
| * of the first terminal instead; otherwise you will not get the behavior |
| * you expect! So we use %prec annotations freely to set precedences. |
| */ |
| a_expr: c_expr { $$ = $1; } |
| | a_expr TYPECAST Typename |
| { $$ = makeTypeCast($1, $3, @2); } |
| | a_expr COLLATE any_name |
| { |
| CollateClause *n = makeNode(CollateClause); |
| |
| n->arg = $1; |
| n->collname = $3; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | a_expr AT TIME ZONE a_expr %prec AT |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("timezone"), |
| list_make2($5, $1), |
| COERCE_SQL_SYNTAX, |
| @2); |
| } |
| /* |
| * These operators must be called out explicitly in order to make use |
| * of bison's automatic operator-precedence handling. All other |
| * operator names are handled by the generic productions using "Op", |
| * below; and all those operators will have the same precedence. |
| * |
| * If you add more explicitly-known operators, be sure to add them |
| * also to b_expr and to the MathOp list below. |
| */ |
| | '+' a_expr %prec UMINUS |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } |
| | '-' a_expr %prec UMINUS |
| { $$ = doNegate($2, @1); } |
| | 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 '*' a_expr |
| { $$ = (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 '^' a_expr |
| { $$ = (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 '=' a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); } |
| | a_expr LESS_EQUALS a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); } |
| | a_expr GREATER_EQUALS a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); } |
| | a_expr NOT_EQUALS a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); } |
| |
| | a_expr qual_Op a_expr %prec Op |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); } |
| | qual_Op a_expr %prec Op |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); } |
| |
| | a_expr AND a_expr |
| { $$ = makeAndExpr($1, $3, @2); } |
| | a_expr OR a_expr |
| { $$ = makeOrExpr($1, $3, @2); } |
| | NOT a_expr |
| { $$ = makeNotExpr($2, @1); } |
| | NOT_LA a_expr %prec NOT |
| { $$ = makeNotExpr($2, @1); } |
| |
| | a_expr LIKE a_expr |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~", |
| $1, $3, @2); |
| } |
| | a_expr LIKE a_expr ESCAPE a_expr %prec LIKE |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), |
| list_make2($3, $5), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~", |
| $1, (Node *) n, @2); |
| } |
| | a_expr NOT_LA LIKE a_expr %prec NOT_LA |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~", |
| $1, $4, @2); |
| } |
| | a_expr NOT_LA LIKE a_expr ESCAPE a_expr %prec NOT_LA |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), |
| list_make2($4, $6), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~", |
| $1, (Node *) n, @2); |
| } |
| | a_expr ILIKE a_expr |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*", |
| $1, $3, @2); |
| } |
| | a_expr ILIKE a_expr ESCAPE a_expr %prec ILIKE |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), |
| list_make2($3, $5), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*", |
| $1, (Node *) n, @2); |
| } |
| | a_expr NOT_LA ILIKE a_expr %prec NOT_LA |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*", |
| $1, $4, @2); |
| } |
| | a_expr NOT_LA ILIKE a_expr ESCAPE a_expr %prec NOT_LA |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("like_escape"), |
| list_make2($4, $6), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*", |
| $1, (Node *) n, @2); |
| } |
| |
| | a_expr SIMILAR TO a_expr %prec SIMILAR |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), |
| list_make1($4), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~", |
| $1, (Node *) n, @2); |
| } |
| | a_expr SIMILAR TO a_expr ESCAPE a_expr %prec SIMILAR |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), |
| list_make2($4, $6), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~", |
| $1, (Node *) n, @2); |
| } |
| | a_expr NOT_LA SIMILAR TO a_expr %prec NOT_LA |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), |
| list_make1($5), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~", |
| $1, (Node *) n, @2); |
| } |
| | a_expr NOT_LA SIMILAR TO a_expr ESCAPE a_expr %prec NOT_LA |
| { |
| FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"), |
| list_make2($5, $7), |
| COERCE_EXPLICIT_CALL, |
| @2); |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~", |
| $1, (Node *) n, @2); |
| } |
| |
| /* NullTest clause |
| * Define SQL-style Null test clause. |
| * Allow two forms described in the standard: |
| * a IS NULL |
| * a IS NOT NULL |
| * Allow two SQL extensions |
| * a ISNULL |
| * a NOTNULL |
| */ |
| | a_expr IS NULL_P %prec IS |
| { |
| NullTest *n = makeNode(NullTest); |
| |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NULL; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | a_expr ISNULL |
| { |
| NullTest *n = makeNode(NullTest); |
| |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NULL; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | a_expr IS NOT NULL_P %prec IS |
| { |
| NullTest *n = makeNode(NullTest); |
| |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NOT_NULL; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | a_expr NOTNULL |
| { |
| NullTest *n = makeNode(NullTest); |
| |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NOT_NULL; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | row OVERLAPS row |
| { |
| if (list_length($1) != 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("wrong number of parameters on left side of OVERLAPS expression"), |
| parser_errposition(@1))); |
| if (list_length($3) != 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("wrong number of parameters on right side of OVERLAPS expression"), |
| parser_errposition(@3))); |
| $$ = (Node *) makeFuncCall(SystemFuncName("overlaps"), |
| list_concat($1, $3), |
| COERCE_SQL_SYNTAX, |
| @2); |
| } |
| | a_expr IS TRUE_P %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_TRUE; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS NOT TRUE_P %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_TRUE; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS FALSE_P %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_FALSE; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS NOT FALSE_P %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_FALSE; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS UNKNOWN %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_UNKNOWN; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS NOT UNKNOWN %prec IS |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_UNKNOWN; |
| b->location = @2; |
| $$ = (Node *) b; |
| } |
| | a_expr IS DISTINCT FROM a_expr %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2); |
| } |
| | a_expr IS NOT DISTINCT FROM a_expr %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2); |
| } |
| | a_expr BETWEEN opt_asymmetric b_expr AND a_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN, |
| "BETWEEN", |
| $1, |
| (Node *) list_make2($4, $6), |
| @2); |
| } |
| | a_expr NOT_LA BETWEEN opt_asymmetric b_expr AND a_expr %prec NOT_LA |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN, |
| "NOT BETWEEN", |
| $1, |
| (Node *) list_make2($5, $7), |
| @2); |
| } |
| | a_expr BETWEEN SYMMETRIC b_expr AND a_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN_SYM, |
| "BETWEEN SYMMETRIC", |
| $1, |
| (Node *) list_make2($4, $6), |
| @2); |
| } |
| | a_expr NOT_LA BETWEEN SYMMETRIC b_expr AND a_expr %prec NOT_LA |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN_SYM, |
| "NOT BETWEEN SYMMETRIC", |
| $1, |
| (Node *) list_make2($5, $7), |
| @2); |
| } |
| | a_expr IN_P in_expr |
| { |
| /* in_expr returns a SubLink or a list of a_exprs */ |
| if (IsA($3, SubLink)) |
| { |
| /* generate foo = ANY (subquery) */ |
| SubLink *n = (SubLink *) $3; |
| |
| n->subLinkType = ANY_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = $1; |
| n->operName = NIL; /* show it's IN not = ANY */ |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| else |
| { |
| /* generate scalar IN expression */ |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2); |
| } |
| } |
| | a_expr NOT_LA IN_P in_expr %prec NOT_LA |
| { |
| /* in_expr returns a SubLink or a list of a_exprs */ |
| if (IsA($4, SubLink)) |
| { |
| /* generate NOT (foo = ANY (subquery)) */ |
| /* Make an = ANY node */ |
| SubLink *n = (SubLink *) $4; |
| |
| n->subLinkType = ANY_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = $1; |
| n->operName = NIL; /* show it's IN not = ANY */ |
| n->location = @2; |
| /* Stick a NOT on top; must have same parse location */ |
| $$ = makeNotExpr((Node *) n, @2); |
| } |
| else |
| { |
| /* generate scalar NOT IN expression */ |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2); |
| } |
| } |
| | a_expr subquery_Op sub_type select_with_parens %prec Op |
| { |
| SubLink *n = makeNode(SubLink); |
| |
| n->subLinkType = $3; |
| n->subLinkId = 0; |
| n->testexpr = $1; |
| n->operName = $2; |
| n->subselect = $4; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| | a_expr subquery_Op sub_type '(' a_expr ')' %prec Op |
| { |
| if ($3 == ANY_SUBLINK) |
| $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2); |
| else |
| $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2); |
| } |
| | UNIQUE opt_unique_null_treatment select_with_parens |
| { |
| /* Not sure how to get rid of the parentheses |
| * but there are lots of shift/reduce errors without them. |
| * |
| * Should be able to implement this by plopping the entire |
| * select into a node, then transforming the target expressions |
| * from whatever they are into count(*), and testing the |
| * entire result equal to one. |
| * But, will probably implement a separate node in the executor. |
| */ |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("UNIQUE predicate is not yet implemented"), |
| parser_errposition(@1))); |
| } |
| | a_expr IS DOCUMENT_P %prec IS |
| { |
| $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, |
| list_make1($1), @2); |
| } |
| | a_expr IS NOT DOCUMENT_P %prec IS |
| { |
| $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, |
| list_make1($1), @2), |
| @2); |
| } |
| | a_expr IS NORMALIZED %prec IS |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("is_normalized"), |
| list_make1($1), |
| COERCE_SQL_SYNTAX, |
| @2); |
| } |
| | a_expr IS unicode_normal_form NORMALIZED %prec IS |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("is_normalized"), |
| list_make2($1, makeStringConst($3, @3)), |
| COERCE_SQL_SYNTAX, |
| @2); |
| } |
| | a_expr IS NOT NORMALIZED %prec IS |
| { |
| $$ = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"), |
| list_make1($1), |
| COERCE_SQL_SYNTAX, |
| @2), |
| @2); |
| } |
| | a_expr IS NOT unicode_normal_form NORMALIZED %prec IS |
| { |
| $$ = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"), |
| list_make2($1, makeStringConst($4, @4)), |
| COERCE_SQL_SYNTAX, |
| @2), |
| @2); |
| } |
| | a_expr IS json_predicate_type_constraint |
| json_key_uniqueness_constraint_opt %prec IS |
| { |
| JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); |
| |
| $$ = makeJsonIsPredicate($1, format, $3, $4, @1); |
| } |
| /* |
| * Required by SQL/JSON, but there are conflicts |
| | a_expr |
| FORMAT_LA JSON json_encoding_clause_opt |
| IS json_predicate_type_constraint |
| json_key_uniqueness_constraint_opt %prec IS |
| { |
| $3.location = @2; |
| $$ = makeJsonIsPredicate($1, $3, $5, $6, @1); |
| } |
| */ |
| | a_expr IS NOT |
| json_predicate_type_constraint |
| json_key_uniqueness_constraint_opt %prec IS |
| { |
| JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); |
| |
| $$ = makeNotExpr(makeJsonIsPredicate($1, format, $4, $5, @1), @1); |
| } |
| /* |
| * Required by SQL/JSON, but there are conflicts |
| | a_expr |
| FORMAT_LA JSON json_encoding_clause_opt |
| IS NOT |
| json_predicate_type_constraint |
| json_key_uniqueness_constraint_opt %prec IS |
| { |
| $3.location = @2; |
| $$ = makeNotExpr(makeJsonIsPredicate($1, $3, $6, $7, @1), @1); |
| } |
| */ |
| | DEFAULT |
| { |
| /* |
| * The SQL spec only allows DEFAULT in "contextually typed |
| * expressions", but for us, it's easier to allow it in |
| * any a_expr and then throw error during parse analysis |
| * if it's in an inappropriate context. This way also |
| * lets us say something smarter than "syntax error". |
| */ |
| SetToDefault *n = makeNode(SetToDefault); |
| |
| /* parse analysis will fill in the rest */ |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * Restricted expressions |
| * |
| * b_expr is a subset of the complete expression syntax defined by a_expr. |
| * |
| * Presently, AND, NOT, IS, and IN are the a_expr keywords that would |
| * cause trouble in the places where b_expr is used. For simplicity, we |
| * just eliminate all the boolean-keyword-operator productions from b_expr. |
| */ |
| b_expr: c_expr |
| { $$ = $1; } |
| | b_expr TYPECAST Typename |
| { $$ = makeTypeCast($1, $3, @2); } |
| | '+' b_expr %prec UMINUS |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); } |
| | '-' b_expr %prec UMINUS |
| { $$ = doNegate($2, @1); } |
| | 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 '*' b_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 '^' b_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 '=' b_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); } |
| | b_expr LESS_EQUALS b_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); } |
| | b_expr GREATER_EQUALS b_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); } |
| | b_expr NOT_EQUALS b_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); } |
| | b_expr qual_Op b_expr %prec Op |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); } |
| | qual_Op b_expr %prec Op |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); } |
| | b_expr IS DISTINCT FROM b_expr %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2); |
| } |
| | b_expr IS NOT DISTINCT FROM b_expr %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2); |
| } |
| | b_expr IS DOCUMENT_P %prec IS |
| { |
| $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, |
| list_make1($1), @2); |
| } |
| | b_expr IS NOT DOCUMENT_P %prec IS |
| { |
| $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, |
| list_make1($1), @2), |
| @2); |
| } |
| ; |
| |
| /* |
| * Productions that can be used in both a_expr and b_expr. |
| * |
| * Note: productions that refer recursively to a_expr or b_expr mostly |
| * cannot appear here. However, it's OK to refer to a_exprs that occur |
| * inside parentheses, such as function arguments; that cannot introduce |
| * ambiguity to the b_expr syntax. |
| */ |
| c_expr: columnref { $$ = $1; } |
| | AexprConst { $$ = $1; } |
| | PARAM opt_indirection |
| { |
| ParamRef *p = makeNode(ParamRef); |
| |
| p->number = $1; |
| p->location = @1; |
| if ($2) |
| { |
| A_Indirection *n = makeNode(A_Indirection); |
| |
| n->arg = (Node *) p; |
| n->indirection = check_indirection($2, yyscanner); |
| $$ = (Node *) n; |
| } |
| else |
| $$ = (Node *) p; |
| } |
| | '(' a_expr ')' opt_indirection |
| { |
| if ($4) |
| { |
| A_Indirection *n = makeNode(A_Indirection); |
| |
| n->arg = $2; |
| n->indirection = check_indirection($4, yyscanner); |
| $$ = (Node *) n; |
| } |
| else |
| $$ = $2; |
| } |
| | case_expr |
| { $$ = $1; } |
| | func_expr |
| { $$ = $1; } |
| | decode_expr |
| { $$ = $1; } |
| | select_with_parens %prec UMINUS |
| { |
| SubLink *n = makeNode(SubLink); |
| |
| n->subLinkType = EXPR_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $1; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | select_with_parens indirection |
| { |
| /* |
| * Because the select_with_parens nonterminal is designed |
| * to "eat" as many levels of parens as possible, the |
| * '(' a_expr ')' opt_indirection production above will |
| * fail to match a sub-SELECT with indirection decoration; |
| * the sub-SELECT won't be regarded as an a_expr as long |
| * as there are parens around it. To support applying |
| * subscripting or field selection to a sub-SELECT result, |
| * we need this redundant-looking production. |
| */ |
| SubLink *n = makeNode(SubLink); |
| A_Indirection *a = makeNode(A_Indirection); |
| |
| n->subLinkType = EXPR_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $1; |
| n->location = @1; |
| a->arg = (Node *) n; |
| a->indirection = check_indirection($2, yyscanner); |
| $$ = (Node *) a; |
| } |
| | EXISTS select_with_parens |
| { |
| SubLink *n = makeNode(SubLink); |
| |
| n->subLinkType = EXISTS_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | ARRAY select_with_parens |
| { |
| SubLink *n = makeNode(SubLink); |
| |
| n->subLinkType = ARRAY_SUBLINK; |
| n->subLinkId = 0; |
| n->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $2; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | ARRAY array_expr |
| { |
| A_ArrayExpr *n = castNode(A_ArrayExpr, $2); |
| |
| /* point outermost A_ArrayExpr to the ARRAY keyword */ |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | TABLE '(' table_value_select_clause ')' |
| { |
| TableValueExpr *n = makeNode(TableValueExpr); |
| n->subquery = $3; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | explicit_row |
| { |
| RowExpr *r = makeNode(RowExpr); |
| |
| r->args = $1; |
| r->row_typeid = InvalidOid; /* not analyzed yet */ |
| r->colnames = NIL; /* to be filled in during analysis */ |
| r->row_format = COERCE_EXPLICIT_CALL; /* abuse */ |
| r->location = @1; |
| $$ = (Node *) r; |
| } |
| | implicit_row |
| { |
| RowExpr *r = makeNode(RowExpr); |
| |
| r->args = $1; |
| r->row_typeid = InvalidOid; /* not analyzed yet */ |
| r->colnames = NIL; /* to be filled in during analysis */ |
| r->row_format = COERCE_IMPLICIT_CAST; /* abuse */ |
| r->location = @1; |
| $$ = (Node *) r; |
| } |
| | GROUPING '(' expr_list ')' |
| { |
| GroupingFunc *g = makeNode(GroupingFunc); |
| |
| g->args = $3; |
| g->location = @1; |
| $$ = (Node *) g; |
| } |
| | GROUP_ID '(' ')' |
| { |
| GroupId *g = makeNode(GroupId); |
| g->location = @1; |
| $$ = (Node *)g; |
| } |
| ; |
| |
| scatter_clause: |
| /* EMPTY */ { $$ = NIL; } |
| | SCATTER RANDOMLY { $$ = list_make1(NULL); } |
| | SCATTER BY expr_list { $$ = $3; } |
| ; |
| |
| table_value_select_clause: |
| SelectStmt scatter_clause |
| { |
| SelectStmt *s = (SelectStmt *) $1; |
| /* |
| * In singlenode mode, scatter clause has no real effect. |
| * We simply ignore it and issue a warning to ensure compatibility. |
| */ |
| if (IS_SINGLENODE()) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("SCATTER BY clause has no effect in singlenode mode"))); |
| s->scatterClause = NIL; |
| } |
| else |
| s->scatterClause = $2; |
| $$ = (Node *) s; |
| } |
| ; |
| |
| func_application: func_name '(' ')' |
| { |
| $$ = (Node *) makeFuncCall($1, NIL, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| } |
| | func_name '(' func_arg_list opt_sort_clause ')' |
| { |
| FuncCall *n = makeFuncCall($1, $3, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->agg_order = $4; |
| $$ = (Node *) n; |
| } |
| | func_name '(' VARIADIC func_arg_expr opt_sort_clause ')' |
| { |
| FuncCall *n = makeFuncCall($1, list_make1($4), |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->func_variadic = true; |
| n->agg_order = $5; |
| $$ = (Node *) n; |
| } |
| | func_name '(' func_arg_list ',' VARIADIC func_arg_expr opt_sort_clause ')' |
| { |
| FuncCall *n = makeFuncCall($1, lappend($3, $6), |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->func_variadic = true; |
| n->agg_order = $7; |
| $$ = (Node *) n; |
| } |
| | func_name '(' ALL func_arg_list opt_sort_clause ')' |
| { |
| FuncCall *n = makeFuncCall($1, $4, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->agg_order = $5; |
| /* Ideally we'd mark the FuncCall node to indicate |
| * "must be an aggregate", but there's no provision |
| * for that in FuncCall at the moment. |
| */ |
| n->func_variadic = false; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *) n; |
| } |
| | func_name '(' DISTINCT func_arg_list opt_sort_clause ')' |
| { |
| FuncCall *n = makeFuncCall($1, $4, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->agg_order = $5; |
| n->agg_distinct = true; |
| $$ = (Node *) n; |
| } |
| | func_name '(' '*' ')' |
| { |
| /* |
| * We consider AGGREGATE(*) to invoke a parameterless |
| * aggregate. This does the right thing for COUNT(*), |
| * and there are no other aggregates in SQL that accept |
| * '*' as parameter. |
| * |
| * The FuncCall node is also marked agg_star = true, |
| * so that later processing can detect what the argument |
| * really was. |
| */ |
| FuncCall *n = makeFuncCall($1, NIL, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| |
| n->agg_star = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /* |
| * func_expr and its cousin func_expr_windowless are split out from c_expr just |
| * so that we have classifications for "everything that is a function call or |
| * looks like one". This isn't very important, but it saves us having to |
| * document which variants are legal in places like "FROM function()" or the |
| * backwards-compatible functional-index syntax for CREATE INDEX. |
| * (Note that many of the special SQL functions wouldn't actually make any |
| * sense as functional index entries, but we ignore that consideration here.) |
| */ |
| func_expr: func_application within_group_clause filter_clause over_clause |
| { |
| FuncCall *n = (FuncCall *) $1; |
| |
| /* |
| * The order clause for WITHIN GROUP and the one for |
| * plain-aggregate ORDER BY share a field, so we have to |
| * check here that at most one is present. We also check |
| * for DISTINCT and VARIADIC here to give a better error |
| * location. Other consistency checks are deferred to |
| * parse analysis. |
| */ |
| if ($2 != NIL) |
| { |
| if (n->agg_order != NIL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("cannot use multiple ORDER BY clauses with WITHIN GROUP"), |
| parser_errposition(@2))); |
| if (n->agg_distinct) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("cannot use DISTINCT with WITHIN GROUP"), |
| parser_errposition(@2))); |
| if (n->func_variadic) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("cannot use VARIADIC with WITHIN GROUP"), |
| parser_errposition(@2))); |
| n->agg_order = $2; |
| n->agg_within_group = true; |
| } |
| n->agg_filter = $3; |
| n->over = $4; |
| $$ = (Node *) n; |
| } |
| | json_aggregate_func filter_clause over_clause |
| { |
| JsonAggConstructor *n = IsA($1, JsonObjectAgg) ? |
| ((JsonObjectAgg *) $1)->constructor : |
| ((JsonArrayAgg *) $1)->constructor; |
| |
| n->agg_filter = $2; |
| n->over = $3; |
| $$ = (Node *) $1; |
| } |
| | func_expr_common_subexpr |
| { $$ = $1; } |
| ; |
| |
| /* |
| * As func_expr but does not accept WINDOW functions directly |
| * (but they can still be contained in arguments for functions etc). |
| * Use this when window expressions are not allowed, where needed to |
| * disambiguate the grammar (e.g. in CREATE INDEX). |
| */ |
| func_expr_windowless: |
| func_application { $$ = $1; } |
| | func_expr_common_subexpr { $$ = $1; } |
| | json_aggregate_func { $$ = $1; } |
| ; |
| |
| /* |
| * Special expressions that are considered to be functions. |
| */ |
| func_expr_common_subexpr: |
| COLLATION FOR '(' a_expr ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("pg_collation_for"), |
| list_make1($4), |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | CURRENT_DATE |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1); |
| } |
| | CURRENT_TIME |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1); |
| } |
| | CURRENT_TIME '(' Iconst ')' |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1); |
| } |
| | CURRENT_TIMESTAMP |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1); |
| } |
| | CURRENT_TIMESTAMP '(' Iconst ')' |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1); |
| } |
| | LOCALTIME |
| { |
| $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1); |
| } |
| | LOCALTIME '(' Iconst ')' |
| { |
| $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1); |
| } |
| | LOCALTIMESTAMP |
| { |
| $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1); |
| } |
| | LOCALTIMESTAMP '(' Iconst ')' |
| { |
| $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1); |
| } |
| | CURRENT_ROLE |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1); |
| } |
| | CURRENT_USER |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1); |
| } |
| | SESSION_USER |
| { |
| $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1); |
| } |
| | SYSTEM_USER |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("system_user"), |
| NIL, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | USER |
| { |
| $$ = makeSQLValueFunction(SVFOP_USER, -1, @1); |
| } |
| | CURRENT_CATALOG |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1); |
| } |
| | CURRENT_SCHEMA |
| { |
| $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1); |
| } |
| | CAST '(' a_expr AS Typename ')' |
| { $$ = makeTypeCast($3, $5, @1); } |
| | EXTRACT '(' extract_list ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("extract"), |
| $3, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | NORMALIZE '(' a_expr ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("normalize"), |
| list_make1($3), |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | NORMALIZE '(' a_expr ',' unicode_normal_form ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("normalize"), |
| list_make2($3, makeStringConst($5, @5)), |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | OVERLAY '(' overlay_list ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("overlay"), |
| $3, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | OVERLAY '(' func_arg_list_opt ')' |
| { |
| /* |
| * allow functions named overlay() to be called without |
| * special syntax |
| */ |
| $$ = (Node *) makeFuncCall(list_make1(makeString("overlay")), |
| $3, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| } |
| | POSITION '(' position_list ')' |
| { |
| /* |
| * position(A in B) is converted to position(B, A) |
| * |
| * We deliberately don't offer a "plain syntax" option |
| * for position(), because the reversal of the arguments |
| * creates too much risk of confusion. |
| */ |
| $$ = (Node *) makeFuncCall(SystemFuncName("position"), |
| $3, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | SUBSTRING '(' substr_list ')' |
| { |
| /* substring(A from B for C) is converted to |
| * substring(A, B, C) - thomas 2000-11-28 |
| */ |
| $$ = (Node *) makeFuncCall(SystemFuncName("substring"), |
| $3, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | SUBSTRING '(' func_arg_list_opt ')' |
| { |
| /* |
| * allow functions named substring() to be called without |
| * special syntax |
| */ |
| $$ = (Node *) makeFuncCall(list_make1(makeString("substring")), |
| $3, |
| COERCE_EXPLICIT_CALL, |
| @1); |
| } |
| | TREAT '(' a_expr AS Typename ')' |
| { |
| /* TREAT(expr AS target) converts expr of a particular type to target, |
| * which is defined to be a subtype of the original expression. |
| * In SQL99, this is intended for use with structured UDTs, |
| * but let's make this a generally useful form allowing stronger |
| * coercions than are handled by implicit casting. |
| * |
| * Convert SystemTypeName() to SystemFuncName() even though |
| * at the moment they result in the same thing. |
| */ |
| $$ = (Node *) makeFuncCall(SystemFuncName(strVal(llast($5->names))), |
| list_make1($3), |
| COERCE_EXPLICIT_CALL, |
| @1); |
| } |
| | TRIM '(' BOTH trim_list ')' |
| { |
| /* various trim expressions are defined in SQL |
| * - thomas 1997-07-19 |
| */ |
| $$ = (Node *) makeFuncCall(SystemFuncName("btrim"), |
| $4, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | TRIM '(' LEADING trim_list ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("ltrim"), |
| $4, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | TRIM '(' TRAILING trim_list ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("rtrim"), |
| $4, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | TRIM '(' trim_list ')' |
| { |
| $$ = (Node *) makeFuncCall(SystemFuncName("btrim"), |
| $3, |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| | NULLIF '(' a_expr ',' a_expr ')' |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1); |
| } |
| | COALESCE '(' expr_list ')' |
| { |
| CoalesceExpr *c = makeNode(CoalesceExpr); |
| |
| c->args = $3; |
| c->location = @1; |
| $$ = (Node *) c; |
| } |
| | GREATEST '(' expr_list ')' |
| { |
| MinMaxExpr *v = makeNode(MinMaxExpr); |
| |
| v->args = $3; |
| v->op = IS_GREATEST; |
| v->location = @1; |
| $$ = (Node *) v; |
| } |
| | LEAST '(' expr_list ')' |
| { |
| MinMaxExpr *v = makeNode(MinMaxExpr); |
| |
| v->args = $3; |
| v->op = IS_LEAST; |
| v->location = @1; |
| $$ = (Node *) v; |
| } |
| | MEDIAN '(' a_expr ')' |
| { |
| /* |
| * MEDIAN is parsed as an alias to percentile_cont(0.5). |
| * We keep track of original expression to deparse |
| * it later in views, etc. |
| */ |
| FuncCall *n; |
| SortBy *sortby; |
| |
| n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("median"); |
| n->args = list_make1(makeAConst((Node*) makeFloat(pstrdup("0.5")), @1)); |
| |
| sortby = makeNode(SortBy); |
| sortby->node = $3; |
| sortby->sortby_dir = SORTBY_DEFAULT; |
| sortby->sortby_nulls = SORTBY_NULLS_DEFAULT; |
| sortby->useOp = NIL; |
| sortby->location = -1; /* no operator */ |
| n->agg_order = list_make1(sortby); |
| |
| n->agg_within_group = true; |
| n->agg_filter = NULL; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | DECODE '(' a_expr ',' a_expr ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = list_make1(makeString("decode")); |
| n->args = list_make2($3, $5); |
| n->agg_order = NIL; |
| n->agg_star = false; |
| n->agg_distinct = false; |
| n->func_variadic = false; |
| n->agg_filter = NULL; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *)n; |
| } |
| | XMLCONCAT '(' expr_list ')' |
| { |
| $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1); |
| } |
| | XMLELEMENT '(' NAME_P ColLabel ')' |
| { |
| $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1); |
| } |
| | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')' |
| { |
| $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1); |
| } |
| | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')' |
| { |
| $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1); |
| } |
| | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')' |
| { |
| $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1); |
| } |
| | XMLEXISTS '(' c_expr xmlexists_argument ')' |
| { |
| /* xmlexists(A PASSING [BY REF] B [BY REF]) is |
| * converted to xmlexists(A, B)*/ |
| $$ = (Node *) makeFuncCall(SystemFuncName("xmlexists"), |
| list_make2($3, $4), |
| COERCE_SQL_SYNTAX, |
| @1); |
| } |
| /* |
| * GPDB: In versions 4.3 of GPDB, we had the xmlexists(text, xml) |
| * function, but not this syntactic sugar, and XMLEXISTS was not |
| * a keyword. So there might be applications out there calling |
| * it like "SELECT xmlexists(foo, bar)", which will fail in |
| * PostgreSQL because XMLEXISTS is a keyword. Support that |
| * old syntax, for backwards-compatibiltiy. |
| */ |
| | XMLEXISTS '(' a_expr ',' a_expr ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("xmlexists"); |
| n->args = list_make2($3, $5); |
| n->agg_order = NIL; |
| n->agg_star = false; |
| n->agg_distinct = false; |
| n->func_variadic = false; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | XMLFOREST '(' xml_attribute_list ')' |
| { |
| $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1); |
| } |
| | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')' |
| { |
| XmlExpr *x = (XmlExpr *) |
| makeXmlExpr(IS_XMLPARSE, NULL, NIL, |
| list_make2($4, makeBoolAConst($5, -1)), |
| @1); |
| |
| x->xmloption = $3; |
| $$ = (Node *) x; |
| } |
| | XMLPI '(' NAME_P ColLabel ')' |
| { |
| $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1); |
| } |
| | XMLPI '(' NAME_P ColLabel ',' a_expr ')' |
| { |
| $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1); |
| } |
| | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')' |
| { |
| $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL, |
| list_make3($3, $5, $6), @1); |
| } |
| | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')' |
| { |
| XmlSerialize *n = makeNode(XmlSerialize); |
| |
| n->xmloption = $3; |
| n->expr = $4; |
| n->typeName = $6; |
| n->indent = $7; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_OBJECT '(' func_arg_list ')' |
| { |
| /* Support for legacy (non-standard) json_object() */ |
| $$ = (Node *) makeFuncCall(SystemFuncName("json_object"), |
| $3, COERCE_EXPLICIT_CALL, @1); |
| } |
| | JSON_OBJECT '(' json_name_and_value_list |
| json_object_constructor_null_clause_opt |
| json_key_uniqueness_constraint_opt |
| json_output_clause_opt ')' |
| { |
| JsonObjectConstructor *n = makeNode(JsonObjectConstructor); |
| |
| n->exprs = $3; |
| n->absent_on_null = $4; |
| n->unique = $5; |
| n->output = (JsonOutput *) $6; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_OBJECT '(' json_output_clause_opt ')' |
| { |
| JsonObjectConstructor *n = makeNode(JsonObjectConstructor); |
| |
| n->exprs = NULL; |
| n->absent_on_null = false; |
| n->unique = false; |
| n->output = (JsonOutput *) $3; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_ARRAY '(' |
| json_value_expr_list |
| json_array_constructor_null_clause_opt |
| json_output_clause_opt |
| ')' |
| { |
| JsonArrayConstructor *n = makeNode(JsonArrayConstructor); |
| |
| n->exprs = $3; |
| n->absent_on_null = $4; |
| n->output = (JsonOutput *) $5; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_ARRAY '(' |
| select_no_parens |
| json_format_clause_opt |
| /* json_array_constructor_null_clause_opt */ |
| json_output_clause_opt |
| ')' |
| { |
| JsonArrayQueryConstructor *n = makeNode(JsonArrayQueryConstructor); |
| |
| n->query = $3; |
| n->format = (JsonFormat *) $4; |
| n->absent_on_null = true; /* XXX */ |
| n->output = (JsonOutput *) $5; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_ARRAY '(' |
| json_output_clause_opt |
| ')' |
| { |
| JsonArrayConstructor *n = makeNode(JsonArrayConstructor); |
| |
| n->exprs = NIL; |
| n->absent_on_null = true; |
| n->output = (JsonOutput *) $3; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * SQL/XML support |
| */ |
| xml_root_version: VERSION_P a_expr |
| { $$ = $2; } |
| | VERSION_P NO VALUE_P |
| { $$ = makeNullAConst(-1); } |
| ; |
| |
| opt_xml_root_standalone: ',' STANDALONE_P YES_P |
| { $$ = makeIntConst(XML_STANDALONE_YES, -1); } |
| | ',' STANDALONE_P NO |
| { $$ = makeIntConst(XML_STANDALONE_NO, -1); } |
| | ',' STANDALONE_P NO VALUE_P |
| { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); } |
| | /*EMPTY*/ |
| { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); } |
| ; |
| |
| xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; } |
| ; |
| |
| xml_attribute_list: xml_attribute_el { $$ = list_make1($1); } |
| | xml_attribute_list ',' xml_attribute_el { $$ = lappend($1, $3); } |
| ; |
| |
| xml_attribute_el: a_expr AS ColLabel |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $3; |
| $$->indirection = NIL; |
| $$->val = (Node *) $1; |
| $$->location = @1; |
| } |
| | a_expr |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = NULL; |
| $$->indirection = NIL; |
| $$->val = (Node *) $1; |
| $$->location = @1; |
| } |
| ; |
| |
| document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; } |
| | CONTENT_P { $$ = XMLOPTION_CONTENT; } |
| ; |
| |
| xml_indent_option: INDENT { $$ = true; } |
| | NO INDENT { $$ = false; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; } |
| | STRIP_P WHITESPACE_P { $$ = false; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| /* We allow several variants for SQL and other compatibility. */ |
| xmlexists_argument: |
| PASSING c_expr |
| { |
| $$ = $2; |
| } |
| | PASSING c_expr xml_passing_mech |
| { |
| $$ = $2; |
| } |
| | PASSING xml_passing_mech c_expr |
| { |
| $$ = $3; |
| } |
| | PASSING xml_passing_mech c_expr xml_passing_mech |
| { |
| $$ = $3; |
| } |
| ; |
| |
| xml_passing_mech: |
| BY REF_P |
| | BY VALUE_P |
| ; |
| |
| |
| /* |
| * Aggregate decoration clauses |
| */ |
| within_group_clause: |
| WITHIN GROUP_P '(' sort_clause ')' { $$ = $4; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| filter_clause: |
| FILTER '(' WHERE a_expr ')' { $$ = $4; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /* |
| * Window Definitions |
| */ |
| window_clause: |
| WINDOW window_definition_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| window_definition_list: |
| window_definition { $$ = list_make1($1); } |
| | window_definition_list ',' window_definition |
| { $$ = lappend($1, $3); } |
| ; |
| |
| window_definition: |
| ColId AS window_specification |
| { |
| WindowDef *n = $3; |
| |
| n->name = $1; |
| $$ = n; |
| } |
| ; |
| |
| over_clause: OVER window_specification |
| { $$ = $2; } |
| | OVER ColId |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->name = $2; |
| n->refname = NULL; |
| n->partitionClause = NIL; |
| n->orderClause = NIL; |
| n->frameOptions = FRAMEOPTION_DEFAULTS; |
| n->startOffset = NULL; |
| n->endOffset = NULL; |
| n->location = @2; |
| $$ = n; |
| } |
| | /*EMPTY*/ |
| { $$ = NULL; } |
| ; |
| |
| window_specification: '(' opt_existing_window_name opt_partition_clause |
| opt_sort_clause opt_frame_clause ')' |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->name = NULL; |
| n->refname = $2; |
| n->partitionClause = $3; |
| n->orderClause = $4; |
| /* copy relevant fields of opt_frame_clause */ |
| n->frameOptions = $5->frameOptions; |
| n->startOffset = $5->startOffset; |
| n->endOffset = $5->endOffset; |
| n->location = @1; |
| $$ = n; |
| } |
| ; |
| |
| /* |
| * If we see PARTITION, RANGE, ROWS or GROUPS as the first token after the '(' |
| * of a window_specification, we want the assumption to be that there is |
| * no existing_window_name; but those keywords are unreserved and so could |
| * be ColIds. We fix this by making them have the same precedence as IDENT |
| * and giving the empty production here a slightly higher precedence, so |
| * that the shift/reduce conflict is resolved in favor of reducing the rule. |
| * These keywords are thus precluded from being an existing_window_name but |
| * are not reserved for any other purpose. |
| */ |
| opt_existing_window_name: ColId { $$ = $1; } |
| | /*EMPTY*/ %prec Op { $$ = NULL; } |
| ; |
| |
| opt_partition_clause: PARTITION BY expr_list { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /* |
| * For frame clauses, we return a WindowDef, but only some fields are used: |
| * frameOptions, startOffset, and endOffset. |
| */ |
| opt_frame_clause: |
| RANGE frame_extent opt_window_exclusion_clause |
| { |
| WindowDef *n = $2; |
| |
| n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_RANGE; |
| n->frameOptions |= $3; |
| $$ = n; |
| } |
| | ROWS frame_extent opt_window_exclusion_clause |
| { |
| WindowDef *n = $2; |
| |
| n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS; |
| n->frameOptions |= $3; |
| $$ = n; |
| } |
| | GROUPS frame_extent opt_window_exclusion_clause |
| { |
| WindowDef *n = $2; |
| |
| n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_GROUPS; |
| n->frameOptions |= $3; |
| $$ = n; |
| } |
| | /*EMPTY*/ |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_DEFAULTS; |
| n->startOffset = NULL; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| ; |
| |
| frame_extent: frame_bound |
| { |
| WindowDef *n = $1; |
| |
| /* reject invalid cases */ |
| if (n->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame start cannot be UNBOUNDED FOLLOWING"), |
| parser_errposition(@1))); |
| if (n->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame starting from following row cannot end with current row"), |
| parser_errposition(@1))); |
| n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW; |
| $$ = n; |
| } |
| | BETWEEN frame_bound AND frame_bound |
| { |
| WindowDef *n1 = $2; |
| WindowDef *n2 = $4; |
| |
| /* form merged options */ |
| int frameOptions = n1->frameOptions; |
| /* shift converts START_ options to END_ options */ |
| frameOptions |= n2->frameOptions << 1; |
| frameOptions |= FRAMEOPTION_BETWEEN; |
| /* reject invalid cases */ |
| if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame start cannot be UNBOUNDED FOLLOWING"), |
| parser_errposition(@2))); |
| if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame end cannot be UNBOUNDED PRECEDING"), |
| parser_errposition(@4))); |
| if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) && |
| (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame starting from current row cannot have preceding rows"), |
| parser_errposition(@4))); |
| if ((frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) && |
| (frameOptions & (FRAMEOPTION_END_OFFSET_PRECEDING | |
| FRAMEOPTION_END_CURRENT_ROW))) |
| ereport(ERROR, |
| (errcode(ERRCODE_WINDOWING_ERROR), |
| errmsg("frame starting from following row cannot have preceding rows"), |
| parser_errposition(@4))); |
| n1->frameOptions = frameOptions; |
| n1->endOffset = n2->startOffset; |
| $$ = n1; |
| } |
| ; |
| |
| /* |
| * This is used for both frame start and frame end, with output set up on |
| * the assumption it's frame start; the frame_extent productions must reject |
| * invalid cases. |
| */ |
| frame_bound: |
| UNBOUNDED PRECEDING |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_START_UNBOUNDED_PRECEDING; |
| n->startOffset = NULL; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| | UNBOUNDED FOLLOWING |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_START_UNBOUNDED_FOLLOWING; |
| n->startOffset = NULL; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| | CURRENT_P ROW |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_START_CURRENT_ROW; |
| n->startOffset = NULL; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| | a_expr PRECEDING |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_START_OFFSET_PRECEDING; |
| n->startOffset = $1; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| | a_expr FOLLOWING |
| { |
| WindowDef *n = makeNode(WindowDef); |
| |
| n->frameOptions = FRAMEOPTION_START_OFFSET_FOLLOWING; |
| n->startOffset = $1; |
| n->endOffset = NULL; |
| $$ = n; |
| } |
| ; |
| |
| opt_window_exclusion_clause: |
| EXCLUDE CURRENT_P ROW { $$ = FRAMEOPTION_EXCLUDE_CURRENT_ROW; } |
| | EXCLUDE GROUP_P { $$ = FRAMEOPTION_EXCLUDE_GROUP; } |
| | EXCLUDE TIES { $$ = FRAMEOPTION_EXCLUDE_TIES; } |
| | EXCLUDE NO OTHERS { $$ = 0; } |
| | /*EMPTY*/ { $$ = 0; } |
| ; |
| |
| |
| /* |
| * Supporting nonterminals for expressions. |
| */ |
| |
| /* Explicit row production. |
| * |
| * SQL99 allows an optional ROW keyword, so we can now do single-element rows |
| * without conflicting with the parenthesized a_expr production. Without the |
| * ROW keyword, there must be more than one a_expr inside the parens. |
| */ |
| row: ROW '(' expr_list ')' { $$ = $3; } |
| | ROW '(' ')' { $$ = NIL; } |
| | '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); } |
| ; |
| |
| explicit_row: ROW '(' expr_list ')' { $$ = $3; } |
| | ROW '(' ')' { $$ = NIL; } |
| ; |
| |
| implicit_row: '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); } |
| ; |
| |
| sub_type: ANY { $$ = ANY_SUBLINK; } |
| | SOME { $$ = ANY_SUBLINK; } |
| | ALL { $$ = ALL_SUBLINK; } |
| ; |
| |
| all_Op: Op { $$ = $1; } |
| | MathOp { $$ = $1; } |
| ; |
| |
| MathOp: '+' { $$ = "+"; } |
| | '-' { $$ = "-"; } |
| | '*' { $$ = "*"; } |
| | '/' { $$ = "/"; } |
| | '%' { $$ = "%"; } |
| | '^' { $$ = "^"; } |
| | '<' { $$ = "<"; } |
| | '>' { $$ = ">"; } |
| | '=' { $$ = "="; } |
| | LESS_EQUALS { $$ = "<="; } |
| | GREATER_EQUALS { $$ = ">="; } |
| | NOT_EQUALS { $$ = "<>"; } |
| ; |
| |
| qual_Op: Op |
| { $$ = list_make1(makeString($1)); } |
| | OPERATOR '(' any_operator ')' |
| { $$ = $3; } |
| ; |
| |
| qual_all_Op: |
| all_Op |
| { $$ = list_make1(makeString($1)); } |
| | OPERATOR '(' any_operator ')' |
| { $$ = $3; } |
| ; |
| |
| subquery_Op: |
| all_Op |
| { $$ = list_make1(makeString($1)); } |
| | OPERATOR '(' any_operator ')' |
| { $$ = $3; } |
| | LIKE |
| { $$ = list_make1(makeString("~~")); } |
| | NOT_LA LIKE |
| { $$ = list_make1(makeString("!~~")); } |
| | ILIKE |
| { $$ = list_make1(makeString("~~*")); } |
| | NOT_LA ILIKE |
| { $$ = list_make1(makeString("!~~*")); } |
| /* cannot put SIMILAR TO here, because SIMILAR TO is a hack. |
| * the regular expression is preprocessed by a function (similar_to_escape), |
| * and the ~ operator for posix regular expressions is used. |
| * x SIMILAR TO y -> x ~ similar_to_escape(y) |
| * this transformation is made on the fly by the parser upwards. |
| * however the SubLink structure which handles any/some/all stuff |
| * is not ready for such a thing. |
| */ |
| ; |
| |
| expr_list: a_expr |
| { |
| $$ = list_make1($1); |
| } |
| | expr_list ',' a_expr |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| /* function arguments can have names */ |
| func_arg_list: func_arg_expr |
| { |
| $$ = list_make1($1); |
| } |
| | func_arg_list ',' func_arg_expr |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| func_arg_expr: a_expr |
| { |
| $$ = $1; |
| } |
| | param_name COLON_EQUALS a_expr |
| { |
| NamedArgExpr *na = makeNode(NamedArgExpr); |
| |
| na->name = $1; |
| na->arg = (Expr *) $3; |
| na->argnumber = -1; /* until determined */ |
| na->location = @1; |
| $$ = (Node *) na; |
| } |
| | param_name EQUALS_GREATER a_expr |
| { |
| NamedArgExpr *na = makeNode(NamedArgExpr); |
| |
| na->name = $1; |
| na->arg = (Expr *) $3; |
| na->argnumber = -1; /* until determined */ |
| na->location = @1; |
| $$ = (Node *) na; |
| } |
| ; |
| |
| func_arg_list_opt: func_arg_list { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| type_list: Typename { $$ = list_make1($1); } |
| | type_list ',' Typename { $$ = lappend($1, $3); } |
| ; |
| |
| array_expr: '[' expr_list ']' |
| { |
| $$ = makeAArrayExpr($2, @1); |
| } |
| | '[' array_expr_list ']' |
| { |
| $$ = makeAArrayExpr($2, @1); |
| } |
| | '[' ']' |
| { |
| $$ = makeAArrayExpr(NIL, @1); |
| } |
| ; |
| |
| array_expr_list: array_expr { $$ = list_make1($1); } |
| | array_expr_list ',' array_expr { $$ = lappend($1, $3); } |
| ; |
| |
| |
| extract_list: |
| extract_arg FROM a_expr |
| { |
| $$ = list_make2(makeStringConst($1, @1), $3); |
| } |
| ; |
| |
| /* Allow delimited string Sconst in extract_arg as an SQL extension. |
| * - thomas 2001-04-12 |
| */ |
| extract_arg: |
| IDENT { $$ = $1; } |
| | YEAR_P { $$ = "year"; } |
| | MONTH_P { $$ = "month"; } |
| | DAY_P { $$ = "day"; } |
| | HOUR_P { $$ = "hour"; } |
| | MINUTE_P { $$ = "minute"; } |
| | SECOND_P { $$ = "second"; } |
| | Sconst { $$ = $1; } |
| ; |
| |
| unicode_normal_form: |
| NFC { $$ = "NFC"; } |
| | NFD { $$ = "NFD"; } |
| | NFKC { $$ = "NFKC"; } |
| | NFKD { $$ = "NFKD"; } |
| ; |
| |
| /* OVERLAY() arguments */ |
| overlay_list: |
| a_expr PLACING a_expr FROM a_expr FOR a_expr |
| { |
| /* overlay(A PLACING B FROM C FOR D) is converted to overlay(A, B, C, D) */ |
| $$ = list_make4($1, $3, $5, $7); |
| } |
| | a_expr PLACING a_expr FROM a_expr |
| { |
| /* overlay(A PLACING B FROM C) is converted to overlay(A, B, C) */ |
| $$ = list_make3($1, $3, $5); |
| } |
| ; |
| |
| /* position_list uses b_expr not a_expr to avoid conflict with general IN */ |
| position_list: |
| b_expr IN_P b_expr { $$ = list_make2($3, $1); } |
| ; |
| |
| /* |
| * SUBSTRING() arguments |
| * |
| * Note that SQL:1999 has both |
| * text FROM int FOR int |
| * and |
| * text FROM pattern FOR escape |
| * |
| * In the parser we map them both to a call to the substring() function and |
| * rely on type resolution to pick the right one. |
| * |
| * In SQL:2003, the second variant was changed to |
| * text SIMILAR pattern ESCAPE escape |
| * We could in theory map that to a different function internally, but |
| * since we still support the SQL:1999 version, we don't. However, |
| * ruleutils.c will reverse-list the call in the newer style. |
| */ |
| substr_list: |
| a_expr FROM a_expr FOR a_expr |
| { |
| $$ = list_make3($1, $3, $5); |
| } |
| | a_expr FOR a_expr FROM a_expr |
| { |
| /* not legal per SQL, but might as well allow it */ |
| $$ = list_make3($1, $5, $3); |
| } |
| | a_expr FROM a_expr |
| { |
| /* |
| * Because we aren't restricting data types here, this |
| * syntax can end up resolving to textregexsubstr(). |
| * We've historically allowed that to happen, so continue |
| * to accept it. However, ruleutils.c will reverse-list |
| * such a call in regular function call syntax. |
| */ |
| $$ = list_make2($1, $3); |
| } |
| | a_expr FOR a_expr |
| { |
| /* not legal per SQL */ |
| |
| /* |
| * Since there are no cases where this syntax allows |
| * a textual FOR value, we forcibly cast the argument |
| * to int4. The possible matches in pg_proc are |
| * substring(text,int4) and substring(text,text), |
| * and we don't want the parser to choose the latter, |
| * which it is likely to do if the second argument |
| * is unknown or doesn't have an implicit cast to int4. |
| */ |
| $$ = list_make3($1, makeIntConst(1, -1), |
| makeTypeCast($3, |
| SystemTypeName("int4"), -1)); |
| } |
| | a_expr SIMILAR a_expr ESCAPE a_expr |
| { |
| $$ = list_make3($1, $3, $5); |
| } |
| ; |
| |
| trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } |
| | FROM expr_list { $$ = $2; } |
| | expr_list { $$ = $1; } |
| ; |
| |
| in_expr: select_with_parens |
| { |
| SubLink *n = makeNode(SubLink); |
| |
| n->subselect = $1; |
| /* other fields will be filled later */ |
| $$ = (Node *) n; |
| } |
| | '(' expr_list ')' { $$ = (Node *) $2; } |
| ; |
| |
| /* |
| * Define SQL-style CASE clause. |
| * - Full specification |
| * CASE WHEN a = b THEN c ... ELSE d END |
| * - Implicit argument |
| * CASE a WHEN b THEN c ... ELSE d END |
| */ |
| case_expr: CASE case_arg when_clause_list case_default END_P |
| { |
| CaseExpr *c = makeNode(CaseExpr); |
| |
| c->casetype = InvalidOid; /* not analyzed yet */ |
| c->arg = (Expr *) $2; |
| c->args = $3; |
| c->defresult = (Expr *) $4; |
| c->location = @1; |
| $$ = (Node *) c; |
| } |
| ; |
| |
| when_clause_list: |
| /* There must be at least one */ |
| when_clause { $$ = list_make1($1); } |
| | when_clause_list when_clause { $$ = lappend($1, $2); } |
| ; |
| |
| when_clause: |
| WHEN when_operand THEN a_expr |
| { |
| CaseWhen *w = makeNode(CaseWhen); |
| |
| w->expr = (Expr *) $2; |
| w->result = (Expr *) $4; |
| w->location = @1; |
| $$ = (Node *) w; |
| } |
| ; |
| |
| when_operand: |
| a_expr { $$ = $1; } |
| | IS NOT DISTINCT FROM a_expr { $$ = makeIsNotDistinctFromNode($5,@2); } |
| ; |
| |
| case_default: |
| ELSE a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| case_arg: a_expr { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /* |
| * Oracle-compatible DECODE function: |
| * DECODE(lhs, rhs, res [, rhs2, res2 ]... [, def_res]): |
| * returns resX if lhs = rhsX, or def_res if no match found |
| * It is transformed into: |
| * CASE lhs WHEN IS NOT DISTINCT FROM rhs THEN res |
| * [WHEN IS NOT DISTINCT FROM rhs2 THEN res2] ... |
| * ELSE def_res END |
| */ |
| decode_expr: |
| DECODE '(' a_expr search_result_list decode_default ')' |
| { |
| CaseExpr *c = makeNode(CaseExpr); |
| c->casetype = InvalidOid; /* not analyzed yet */ |
| c->arg = (Expr *) $3; |
| c->args = $4; |
| c->defresult = (Expr *) $5; |
| $$ = (Node *) c; |
| } |
| ; |
| |
| search_result_list: |
| search_result { $$ = list_make1($1); } |
| | search_result_list search_result { $$ = lappend($1, $2); } |
| ; |
| |
| search_result: |
| ',' a_expr ',' a_expr |
| { |
| Node *n = makeIsNotDistinctFromNode($2,@2); |
| CaseWhen *w = makeNode(CaseWhen); |
| w->expr = (Expr *) n; |
| w->result = (Expr *) $4; |
| $$ = (Node *) w; |
| } |
| ; |
| |
| decode_default: |
| ',' a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| columnref: ColId |
| { |
| $$ = makeColumnRef($1, NIL, @1, yyscanner); |
| } |
| | ColId indirection |
| { |
| $$ = makeColumnRef($1, $2, @1, yyscanner); |
| } |
| ; |
| |
| indirection_el: |
| '.' attr_name |
| { |
| $$ = (Node *) makeString($2); |
| } |
| | '.' '*' |
| { |
| $$ = (Node *) makeNode(A_Star); |
| } |
| | '[' a_expr ']' |
| { |
| A_Indices *ai = makeNode(A_Indices); |
| |
| ai->is_slice = false; |
| ai->lidx = NULL; |
| ai->uidx = $2; |
| $$ = (Node *) ai; |
| } |
| | '[' opt_slice_bound ':' opt_slice_bound ']' |
| { |
| A_Indices *ai = makeNode(A_Indices); |
| |
| ai->is_slice = true; |
| ai->lidx = $2; |
| ai->uidx = $4; |
| $$ = (Node *) ai; |
| } |
| ; |
| |
| opt_slice_bound: |
| a_expr { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| indirection: |
| indirection_el { $$ = list_make1($1); } |
| | indirection indirection_el { $$ = lappend($1, $2); } |
| ; |
| |
| opt_indirection: |
| /*EMPTY*/ { $$ = NIL; } |
| | opt_indirection indirection_el { $$ = lappend($1, $2); } |
| ; |
| |
| opt_asymmetric: ASYMMETRIC |
| | /*EMPTY*/ |
| ; |
| |
| /* SQL/JSON support */ |
| json_value_expr: |
| a_expr json_format_clause_opt |
| { |
| /* formatted_expr will be set during parse-analysis. */ |
| $$ = (Node *) makeJsonValueExpr((Expr *) $1, NULL, |
| castNode(JsonFormat, $2)); |
| } |
| ; |
| |
| json_format_clause_opt: |
| FORMAT_LA JSON json_encoding_clause_opt |
| { |
| $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, $3, @1); |
| } |
| | /* EMPTY */ |
| { |
| $$ = (Node *) makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1); |
| } |
| ; |
| |
| json_encoding_clause_opt: |
| ENCODING name { $$ = makeJsonEncoding($2); } |
| | /* EMPTY */ { $$ = JS_ENC_DEFAULT; } |
| ; |
| |
| json_output_clause_opt: |
| RETURNING Typename json_format_clause_opt |
| { |
| JsonOutput *n = makeNode(JsonOutput); |
| |
| n->typeName = $2; |
| n->returning = makeNode(JsonReturning); |
| n->returning->format = (JsonFormat *) $3; |
| $$ = (Node *) n; |
| } |
| | /* EMPTY */ { $$ = NULL; } |
| ; |
| |
| json_predicate_type_constraint: |
| JSON { $$ = JS_TYPE_ANY; } |
| | JSON VALUE_P { $$ = JS_TYPE_ANY; } |
| | JSON ARRAY { $$ = JS_TYPE_ARRAY; } |
| | JSON OBJECT_P { $$ = JS_TYPE_OBJECT; } |
| | JSON SCALAR { $$ = JS_TYPE_SCALAR; } |
| ; |
| |
| /* KEYS is a noise word here */ |
| json_key_uniqueness_constraint_opt: |
| WITH UNIQUE KEYS { $$ = true; } |
| | WITH UNIQUE { $$ = true; } |
| | WITHOUT UNIQUE KEYS { $$ = false; } |
| | WITHOUT UNIQUE { $$ = false; } |
| | /* EMPTY */ %prec KEYS { $$ = false; } |
| ; |
| |
| json_name_and_value_list: |
| json_name_and_value |
| { $$ = list_make1($1); } |
| | json_name_and_value_list ',' json_name_and_value |
| { $$ = lappend($1, $3); } |
| ; |
| |
| json_name_and_value: |
| /* Supporting this syntax seems to require major surgery |
| KEY c_expr VALUE_P json_value_expr |
| { $$ = makeJsonKeyValue($2, $4); } |
| | |
| */ |
| c_expr VALUE_P json_value_expr |
| { $$ = makeJsonKeyValue($1, $3); } |
| | |
| a_expr ':' json_value_expr |
| { $$ = makeJsonKeyValue($1, $3); } |
| ; |
| |
| /* empty means false for objects, true for arrays */ |
| json_object_constructor_null_clause_opt: |
| NULL_P ON NULL_P { $$ = false; } |
| | ABSENT ON NULL_P { $$ = true; } |
| | /* EMPTY */ { $$ = false; } |
| ; |
| |
| json_array_constructor_null_clause_opt: |
| NULL_P ON NULL_P { $$ = false; } |
| | ABSENT ON NULL_P { $$ = true; } |
| | /* EMPTY */ { $$ = true; } |
| ; |
| |
| json_value_expr_list: |
| json_value_expr { $$ = list_make1($1); } |
| | json_value_expr_list ',' json_value_expr { $$ = lappend($1, $3);} |
| ; |
| |
| json_aggregate_func: |
| JSON_OBJECTAGG '(' |
| json_name_and_value |
| json_object_constructor_null_clause_opt |
| json_key_uniqueness_constraint_opt |
| json_output_clause_opt |
| ')' |
| { |
| JsonObjectAgg *n = makeNode(JsonObjectAgg); |
| |
| n->arg = (JsonKeyValue *) $3; |
| n->absent_on_null = $4; |
| n->unique = $5; |
| n->constructor = makeNode(JsonAggConstructor); |
| n->constructor->output = (JsonOutput *) $6; |
| n->constructor->agg_order = NULL; |
| n->constructor->location = @1; |
| $$ = (Node *) n; |
| } |
| | JSON_ARRAYAGG '(' |
| json_value_expr |
| json_array_aggregate_order_by_clause_opt |
| json_array_constructor_null_clause_opt |
| json_output_clause_opt |
| ')' |
| { |
| JsonArrayAgg *n = makeNode(JsonArrayAgg); |
| |
| n->arg = (JsonValueExpr *) $3; |
| n->absent_on_null = $5; |
| n->constructor = makeNode(JsonAggConstructor); |
| n->constructor->agg_order = $4; |
| n->constructor->output = (JsonOutput *) $6; |
| n->constructor->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| json_array_aggregate_order_by_clause_opt: |
| ORDER BY sortby_list { $$ = $3; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * target list for SELECT |
| * |
| *****************************************************************************/ |
| |
| opt_target_list: target_list { $$ = $1; } |
| | /* EMPTY */ { $$ = NIL; } |
| ; |
| |
| target_list: |
| target_el { $$ = list_make1($1); } |
| | target_list ',' target_el { $$ = lappend($1, $3); } |
| ; |
| |
| target_el: a_expr AS ColLabel |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $3; |
| $$->indirection = NIL; |
| $$->val = (Node *) $1; |
| $$->location = @1; |
| } |
| /* |
| * Postgres supports omitting AS only for column labels that aren't |
| * any known keyword. There is an ambiguity against postfix |
| * operators: is "a ! b" an infix expression, or a postfix |
| * expression and a column label? We prefer to resolve this |
| * as an infix expression, which we accomplish by assigning |
| * IDENT a precedence higher than POSTFIXOP. |
| * |
| * In GPDB, we extend this to allow most unreserved_keywords by |
| * also assigning them a precedence. There are certain keywords |
| * that can't work without the as: reserved_keywords, the date |
| * modifier suffixes (DAY, MONTH, YEAR, etc) and a few other |
| * obscure cases. |
| */ |
| | a_expr BareColLabel |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $2; |
| $$->indirection = NIL; |
| $$->val = (Node *) $1; |
| $$->location = @1; |
| } |
| | a_expr |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = NULL; |
| $$->indirection = NIL; |
| $$->val = (Node *) $1; |
| $$->location = @1; |
| } |
| | '*' |
| { |
| ColumnRef *n = makeNode(ColumnRef); |
| |
| n->fields = list_make1(makeNode(A_Star)); |
| n->location = @1; |
| |
| $$ = makeNode(ResTarget); |
| $$->name = NULL; |
| $$->indirection = NIL; |
| $$->val = (Node *) n; |
| $$->location = @1; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Names and constants |
| * |
| *****************************************************************************/ |
| |
| qualified_name_list: |
| qualified_name { $$ = list_make1($1); } |
| | qualified_name_list ',' qualified_name { $$ = lappend($1, $3); } |
| ; |
| |
| qualified_name_list_with_only: |
| qualified_name |
| { |
| $$ = list_make1($1); |
| } |
| | ONLY qualified_name |
| { |
| $2->inh = false; |
| $$ = list_make1($2); |
| } |
| | qualified_name_list_with_only ',' qualified_name |
| { |
| $$ = lappend($1, $3); |
| } |
| | qualified_name_list_with_only ',' ONLY qualified_name |
| { |
| $4->inh = false; |
| $$ = lappend($1, $4); |
| } |
| ; |
| |
| /* |
| * The production for a qualified relation name has to exactly match the |
| * production for a qualified func_name, because in a FROM clause we cannot |
| * tell which we are parsing until we see what comes after it ('(' for a |
| * func_name, something else for a relation). Therefore we allow 'indirection' |
| * which may contain subscripts, and reject that case in the C code. |
| */ |
| qualified_name: |
| ColId |
| { |
| $$ = makeRangeVar(NULL, $1, @1); |
| } |
| | ColId indirection |
| { |
| $$ = makeRangeVarFromQualifiedName($1, $2, @1, yyscanner); |
| } |
| ; |
| |
| name_list: name |
| { $$ = list_make1(makeString($1)); } |
| | name_list ',' name |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| |
| name: ColId { $$ = $1; }; |
| |
| attr_name: ColLabel { $$ = $1; }; |
| |
| file_name: Sconst { $$ = $1; }; |
| |
| /* |
| * The production for a qualified func_name has to exactly match the |
| * production for a qualified columnref, because we cannot tell which we |
| * are parsing until we see what comes after it ('(' or Sconst for a func_name, |
| * anything else for a columnref). Therefore we allow 'indirection' which |
| * may contain subscripts, and reject that case in the C code. (If we |
| * ever implement SQL99-like methods, such syntax may actually become legal!) |
| */ |
| func_name: type_function_name |
| { $$ = list_make1(makeString($1)); } |
| | ColId indirection |
| { |
| $$ = check_func_name(lcons(makeString($1), $2), |
| yyscanner); |
| } |
| ; |
| |
| |
| /* |
| * Constants |
| */ |
| AexprConst: Iconst |
| { |
| $$ = makeIntConst($1, @1); |
| } |
| | FCONST |
| { |
| $$ = makeFloatConst($1, @1); |
| } |
| | Sconst |
| { |
| $$ = makeStringConst($1, @1); |
| } |
| | BCONST |
| { |
| $$ = makeBitStringConst($1, @1); |
| } |
| | XCONST |
| { |
| /* This is a bit constant per SQL99: |
| * Without Feature F511, "BIT data type", |
| * a <general literal> shall not be a |
| * <bit string literal> or a <hex string literal>. |
| */ |
| $$ = makeBitStringConst($1, @1); |
| } |
| | func_name Sconst |
| { |
| /* generic type 'literal' syntax */ |
| TypeName *t = makeTypeNameFromNameList($1); |
| |
| t->location = @1; |
| $$ = makeStringConstCast($2, @2, t); |
| } |
| | func_name '(' func_arg_list opt_sort_clause ')' Sconst |
| { |
| /* generic syntax with a type modifier */ |
| TypeName *t = makeTypeNameFromNameList($1); |
| ListCell *lc; |
| |
| /* |
| * We must use func_arg_list and opt_sort_clause in the |
| * production to avoid reduce/reduce conflicts, but we |
| * don't actually wish to allow NamedArgExpr in this |
| * context, nor ORDER BY. |
| */ |
| foreach(lc, $3) |
| { |
| NamedArgExpr *arg = (NamedArgExpr *) lfirst(lc); |
| |
| if (IsA(arg, NamedArgExpr)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("type modifier cannot have parameter name"), |
| parser_errposition(arg->location))); |
| } |
| if ($4 != NIL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("type modifier cannot have ORDER BY"), |
| parser_errposition(@4))); |
| |
| t->typmods = $3; |
| t->location = @1; |
| $$ = makeStringConstCast($6, @6, t); |
| } |
| | ConstTypename Sconst |
| { |
| $$ = makeStringConstCast($2, @2, $1); |
| } |
| | ConstInterval Sconst opt_interval |
| { |
| TypeName *t = $1; |
| |
| t->typmods = $3; |
| $$ = makeStringConstCast($2, @2, t); |
| } |
| | ConstInterval '(' Iconst ')' Sconst |
| { |
| TypeName *t = $1; |
| |
| t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), |
| makeIntConst($3, @3)); |
| $$ = makeStringConstCast($5, @5, t); |
| } |
| | TRUE_P |
| { |
| $$ = makeBoolAConst(true, @1); |
| } |
| | FALSE_P |
| { |
| $$ = makeBoolAConst(false, @1); |
| } |
| | NULL_P |
| { |
| $$ = makeNullAConst(@1); |
| } |
| ; |
| |
| Iconst: ICONST { $$ = $1; }; |
| Sconst: SCONST { $$ = $1; }; |
| |
| SignedIconst: Iconst { $$ = $1; } |
| | '+' Iconst { $$ = + $2; } |
| | '-' Iconst { $$ = - $2; } |
| ; |
| |
| QueueId: NonReservedWord { $$ = $1; }; |
| |
| /* Role specifications */ |
| RoleId: RoleSpec |
| { |
| RoleSpec *spc = (RoleSpec *) $1; |
| |
| switch (spc->roletype) |
| { |
| case ROLESPEC_CSTRING: |
| $$ = spc->rolename; |
| break; |
| case ROLESPEC_PUBLIC: |
| ereport(ERROR, |
| (errcode(ERRCODE_RESERVED_NAME), |
| errmsg("role name \"%s\" is reserved", |
| "public"), |
| parser_errposition(@1))); |
| break; |
| case ROLESPEC_SESSION_USER: |
| ereport(ERROR, |
| (errcode(ERRCODE_RESERVED_NAME), |
| errmsg("%s cannot be used as a role name here", |
| "SESSION_USER"), |
| parser_errposition(@1))); |
| break; |
| case ROLESPEC_CURRENT_USER: |
| ereport(ERROR, |
| (errcode(ERRCODE_RESERVED_NAME), |
| errmsg("%s cannot be used as a role name here", |
| "CURRENT_USER"), |
| parser_errposition(@1))); |
| break; |
| case ROLESPEC_CURRENT_ROLE: |
| ereport(ERROR, |
| (errcode(ERRCODE_RESERVED_NAME), |
| errmsg("%s cannot be used as a role name here", |
| "CURRENT_ROLE"), |
| parser_errposition(@1))); |
| break; |
| } |
| } |
| ; |
| |
| RoleSpec: NonReservedWord |
| { |
| /* |
| * "public" and "none" are not keywords, but they must |
| * be treated specially here. |
| */ |
| RoleSpec *n; |
| |
| if (strcmp($1, "public") == 0) |
| { |
| n = (RoleSpec *) makeRoleSpec(ROLESPEC_PUBLIC, @1); |
| n->roletype = ROLESPEC_PUBLIC; |
| } |
| else if (strcmp($1, "none") == 0) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_RESERVED_NAME), |
| errmsg("role name \"%s\" is reserved", |
| "none"), |
| parser_errposition(@1))); |
| } |
| else |
| { |
| n = makeRoleSpec(ROLESPEC_CSTRING, @1); |
| n->rolename = pstrdup($1); |
| } |
| $$ = n; |
| } |
| | CURRENT_ROLE |
| { |
| $$ = makeRoleSpec(ROLESPEC_CURRENT_ROLE, @1); |
| } |
| | CURRENT_USER |
| { |
| $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1); |
| } |
| | SESSION_USER |
| { |
| $$ = makeRoleSpec(ROLESPEC_SESSION_USER, @1); |
| } |
| ; |
| |
| role_list: RoleSpec |
| { $$ = list_make1($1); } |
| | role_list ',' RoleSpec |
| { $$ = lappend($1, $3); } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * PL/pgSQL extensions |
| * |
| * You'd think a PL/pgSQL "expression" should be just an a_expr, but |
| * historically it can include just about anything that can follow SELECT. |
| * Therefore the returned struct is a SelectStmt. |
| *****************************************************************************/ |
| |
| PLpgSQL_Expr: opt_distinct_clause opt_target_list |
| from_clause where_clause |
| group_clause having_clause window_clause |
| opt_sort_clause opt_select_limit opt_for_locking_clause |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| n->distinctClause = $1; |
| n->targetList = $2; |
| n->fromClause = $3; |
| n->whereClause = $4; |
| n->groupClause = ($5)->list; |
| n->groupDistinct = ($5)->distinct; |
| n->havingClause = $6; |
| n->windowClause = $7; |
| n->sortClause = $8; |
| if ($9) |
| { |
| n->limitOffset = $9->limitOffset; |
| n->limitCount = $9->limitCount; |
| if (!n->sortClause && |
| $9->limitOption == LIMIT_OPTION_WITH_TIES) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("WITH TIES cannot be specified without ORDER BY clause"))); |
| n->limitOption = $9->limitOption; |
| } |
| n->lockingClause = $10; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * PL/pgSQL Assignment statement: name opt_indirection := PLpgSQL_Expr |
| */ |
| |
| PLAssignStmt: plassign_target opt_indirection plassign_equals PLpgSQL_Expr |
| { |
| PLAssignStmt *n = makeNode(PLAssignStmt); |
| |
| n->name = $1; |
| n->indirection = check_indirection($2, yyscanner); |
| /* nnames will be filled by calling production */ |
| n->val = (SelectStmt *) $4; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| plassign_target: ColId { $$ = $1; } |
| | PARAM { $$ = psprintf("$%d", $1); } |
| ; |
| |
| plassign_equals: COLON_EQUALS |
| | '=' |
| ; |
| |
| |
| /* |
| * Name classification hierarchy. |
| * |
| * IDENT is the lexeme returned by the lexer for identifiers that match |
| * no known keyword. In most cases, we can accept certain keywords as |
| * names, not only IDENTs. We prefer to accept as many such keywords |
| * as possible to minimize the impact of "reserved words" on programmers. |
| * So, we divide names into several possible classes. The classification |
| * is chosen in part to make keywords acceptable as names wherever possible. |
| */ |
| |
| /* Column identifier --- names that can be column, table, etc names. |
| */ |
| ColId: IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| | col_name_keyword { $$ = pstrdup($1); } |
| ; |
| |
| /* Type/function identifier --- names that can be type or function names. |
| */ |
| type_function_name: IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| | type_func_name_keyword { $$ = pstrdup($1); } |
| ; |
| |
| /* Any not-fully-reserved word --- these names can be, eg, role names. |
| */ |
| NonReservedWord: IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| | col_name_keyword { $$ = pstrdup($1); } |
| | type_func_name_keyword { $$ = pstrdup($1); } |
| ; |
| |
| /* Column label --- allowed labels in "AS" clauses. |
| * This presently includes *all* Postgres keywords. |
| */ |
| ColLabel: IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| | col_name_keyword { $$ = pstrdup($1); } |
| | type_func_name_keyword { $$ = pstrdup($1); } |
| | reserved_keyword { $$ = pstrdup($1); } |
| ; |
| |
| |
| /* |
| * Keyword category lists. Generally, every keyword present in |
| * the Postgres grammar should appear in exactly one of these lists. |
| * |
| * Put a new keyword into the first list that it can go into without causing |
| * shift or reduce conflicts. The earlier lists define "less reserved" |
| * categories of keywords. |
| * |
| * Make sure that each keyword's category in kwlist.h matches where |
| * it is listed here. (Someday we may be able to generate these lists and |
| * kwlist.h's table from a common master list.) |
| */ |
| |
| /* "Unreserved" keywords --- available for use as any kind of name. |
| */ |
| unreserved_keyword: |
| ABORT_P |
| | ABSENT |
| | ABSOLUTE_P |
| | ACCESS |
| | ACCOUNT |
| | ACTION |
| | ACTIVE |
| | ADD_P |
| | ADMIN |
| | AFTER |
| | AGGREGATE |
| | ALLOWED_VALUES |
| | ALSO |
| | ALTER |
| | ALWAYS |
| | ASENSITIVE |
| | ASSERTION |
| | ASSIGNMENT |
| | AT |
| | ATOMIC |
| | ATTACH |
| | ATTRIBUTE |
| | BACKWARD |
| | BEFORE |
| | BEGIN_P |
| | BREADTH |
| | BY |
| | CACHE |
| | CALL |
| | CALLED |
| | CASCADE |
| | CASCADED |
| | CATALOG_P |
| | CHAIN |
| | CHARACTERISTICS |
| | CHECKPOINT |
| | CLASS |
| | CLOSE |
| | CLUSTER |
| | COLUMNS |
| | COMMENT |
| | COMMENTS |
| | COMMIT |
| | COMMITTED |
| | COMPRESSION |
| | CONCURRENCY |
| | CONFIGURATION |
| | CONFLICT |
| | CONNECTION |
| | CONSTRAINTS |
| | CONTAINS |
| | CONTENT_P |
| | CONTINUE_P |
| | CONVERSION_P |
| | COORDINATOR |
| | COPY |
| | COST |
| | CPUSET |
| | CPU_MAX_PERCENT |
| | CPU_WEIGHT |
| | CREATEEXTTABLE |
| | CSV |
| | CUBE |
| | CURRENT_P |
| | CURSOR |
| | CYCLE |
| | DATA_P |
| | DATABASE |
| | DAY_P |
| | DEALLOCATE |
| | DECLARE |
| | DEFAULTS |
| | DEFERRED |
| | DEFINER |
| | DELETE_P |
| | DELIMITER |
| | DELIMITERS |
| | DENY |
| | DEPENDS |
| | DEPTH |
| | DETACH |
| | DICTIONARY |
| | DISABLE_P |
| | DISCARD |
| | DOCUMENT_P |
| | DOMAIN_P |
| | DOUBLE_P |
| | DROP |
| | DXL |
| | DYNAMIC |
| | EACH |
| | ENABLE_P |
| | ENCODING |
| | ENCRYPTED |
| | ENDPOINT |
| | ENUM_P |
| | ERRORS |
| | ESCAPE |
| | EVENT |
| | EVERY |
| | EXCHANGE |
| | EXCLUDING |
| | EXCLUSIVE |
| | EXECUTE |
| | EXPAND |
| | EXPLAIN |
| | EXPRESSION |
| | EXTENSION |
| | EXTERNAL |
| | FAILED_LOGIN_ATTEMPTS |
| | FAMILY |
| | FIELDS |
| | FILL |
| | FILTER |
| | FINALIZE |
| | FIRST_P |
| | FOLLOWING |
| | FORCE |
| | FORMAT |
| | FORWARD |
| | FULLSCAN |
| | FUNCTION |
| | FUNCTIONS |
| | GENERATED |
| | GLOBAL |
| | GRANTED |
| | GROUPS |
| | HANDLER |
| | HASH |
| | HEADER_P |
| | HOLD |
| | HOST |
| | HOUR_P |
| | IDENTITY_P |
| | IF_P |
| | IGNORE_P |
| | IMMEDIATE |
| | IMMUTABLE |
| | IMPLICIT_P |
| | IMPORT_P |
| | INCLUDE |
| | INCLUDING |
| | INCLUSIVE |
| | INCREMENT |
| | INCREMENTAL |
| | INDENT |
| | INDEX |
| | INDEXES |
| | INHERIT |
| | INHERITS |
| | INITPLAN |
| | INLINE_P |
| | INPUT_P |
| | INSENSITIVE |
| | INSERT |
| | INSTEAD |
| | INVOKER |
| | IO_LIMIT |
| | ISOLATION |
| | JSON |
| | KEY |
| | KEYS |
| | LABEL |
| | LANGUAGE |
| | LARGE_P |
| | LAST_P |
| | LEAKPROOF |
| | LEVEL |
| | LIST |
| | LISTEN |
| | LOAD |
| | LOCAL |
| | LOCATION |
| | LOCK_P |
| | LOCKED |
| | LOCUS |
| | LOG_P |
| | LOGGED |
| | MAPPING |
| | MASTER |
| | MATCH |
| | MATCHED |
| | MATERIALIZED |
| | MAXVALUE |
| | MEMORY_QUOTA |
| | MERGE |
| | METHOD |
| | MINUTE_P |
| | MINVALUE |
| | MIN_COST |
| | MISSING |
| | MODE |
| | MODIFIES |
| | MONTH_P |
| | MOVE |
| | NAME_P |
| | NAMES |
| | NEW |
| | NEWLINE |
| | NEXT |
| | NFC |
| | NFD |
| | NFKC |
| | NFKD |
| | NO |
| | NOCREATEEXTTABLE |
| | NOOVERCOMMIT |
| | NORMALIZED |
| | NOTHING |
| | NOTIFY |
| | NOWAIT |
| | NULLS_P |
| | OBJECT_P |
| | OF |
| | OFF |
| | OIDS |
| | OLD |
| | OPERATOR |
| | OPTION |
| | OPTIONS |
| | ORDERED |
| | ORDINALITY |
| | OTHERS |
| | OVER |
| | OVERCOMMIT |
| | OVERRIDING |
| | OWNED |
| | OWNER |
| | PARALLEL |
| | PARAMETER |
| | PARSER |
| | PARTIAL |
| | PARTITIONS |
| | PASSING |
| | PASSWORD |
| | PASSWORD_LOCK_TIME |
| | PASSWORD_REUSE_MAX |
| | PERCENT |
| | PERSISTENTLY |
| | PLANS |
| | POLICY |
| | PRECEDING |
| | PREPARE |
| | PREPARED |
| | PRESERVE |
| | PRIOR |
| | PRIVILEGES |
| | PROCEDURAL |
| | PROCEDURE |
| | PROCEDURES |
| | PROFILE |
| | PROGRAM |
| | PROTOCOL |
| | PUBLICATION |
| | QUEUE |
| | QUOTE |
| | RANDOMLY /* gp */ |
| | RANGE |
| | READ |
| | READABLE |
| | READS |
| | REASSIGN |
| | RECHECK |
| | RECURSIVE |
| | REF_P |
| | REFERENCING |
| | REFRESH |
| | REINDEX |
| | REJECT_P /* gp */ |
| | RELATIVE_P |
| | RELEASE |
| | RENAME |
| | REPEATABLE |
| | REPLACE |
| | REPLICA |
| | REPLICATED |
| | RESET |
| | RESOURCE |
| | RESTART |
| | RESTRICT |
| | RETRIEVE |
| | RETURN |
| | RETURNS |
| | REVOKE |
| | ROLE |
| | ROLLBACK |
| | ROLLUP |
| | ROOTPARTITION |
| | ROUTINE |
| | ROUTINES |
| | ROWS |
| | RULE |
| | SAVEPOINT |
| | SCALAR |
| | SCHEDULE |
| | SCHEMA |
| | SCHEMAS |
| | SCROLL |
| | SEARCH |
| | SECOND_P |
| | SECURITY |
| | SEGMENT |
| | SEGMENTS |
| | SEQUENCE |
| | SEQUENCES |
| | SERIALIZABLE |
| | SERVER |
| | SESSION |
| | SET |
| | SETS |
| | SHARE |
| | SHOW |
| | SHRINK |
| | SIMPLE |
| | SKIP |
| | SNAPSHOT |
| | SPLIT |
| | SQL_P |
| | STABLE |
| | STANDALONE_P |
| | START |
| | STATEMENT |
| | STATISTICS |
| | STDIN |
| | STDOUT |
| | STORAGE |
| | STORED |
| | STRICT_P |
| | STRIP_P |
| | SUBPARTITION |
| | SUBSCRIPTION |
| | SUPPORT |
| | SYSID |
| | SYSTEM_P |
| | TABLES |
| | TABLESPACE |
| | TAG |
| | TASK |
| | TEMP |
| | TEMPLATE |
| | TEMPORARY |
| | TEXT_P |
| | THRESHOLD |
| | TIES |
| | TRANSACTION |
| | TRANSFORM |
| | TRIGGER |
| | TRUNCATE |
| | TRUSTED |
| | TYPE_P |
| | TYPES_P |
| | UESCAPE |
| | UNBOUNDED |
| | UNCOMMITTED |
| | UNENCRYPTED |
| | UNKNOWN |
| | UNLISTEN |
| | UNLOCK_P |
| | UNLOGGED |
| | UNSET_P |
| | UNTIL |
| | UPDATE |
| | VACUUM |
| | VALID |
| | VALIDATE |
| | VALIDATION /* gp */ |
| | VALIDATOR |
| | VALUE_P |
| | VARYING |
| | VERSION_P |
| | VIEW |
| | VIEWS |
| | VOLATILE |
| | WAREHOUSE |
| | WAREHOUSE_SIZE |
| | WEB /* gp */ |
| | WHITESPACE_P |
| | WITHIN |
| | WITHOUT |
| | WORK |
| | WRAPPER |
| | WRITABLE |
| | WRITE |
| | XML_P |
| | YEAR_P |
| | YES_P |
| | ZONE |
| ; |
| |
| PartitionColId: PartitionIdentKeyword { $$ = pstrdup($1); } |
| | IDENT { $$ = pstrdup($1); } |
| ; |
| |
| /* Bare column label --- names that can be column labels without writing "AS". |
| * This classification is orthogonal to the other keyword categories. |
| */ |
| BareColLabel: IDENT { $$ = $1; } |
| | bare_label_keyword { $$ = pstrdup($1); } |
| ; |
| |
| |
| PartitionIdentKeyword: ABORT_P |
| | ABSOLUTE_P |
| | ACCESS |
| | ACTION |
| | ACTIVE |
| | ADMIN |
| | AFTER |
| | AGGREGATE |
| | ALSO |
| | AO_AUX_ONLY |
| | ALWAYS |
| | ASENSITIVE |
| | ASSERTION |
| | ASSIGNMENT |
| | AT |
| | ATOMIC |
| | ATTACH |
| | ATTRIBUTE |
| | BACKWARD |
| | BEFORE |
| | BEGIN_P |
| | BREADTH |
| | BY |
| | CACHE |
| | CALL |
| | CALLED |
| | CASCADE |
| | CASCADED |
| | CHAIN |
| | CHARACTERISTICS |
| | CHECKPOINT |
| | CLASS |
| | CLOSE |
| | CLUSTER |
| | COLUMNS |
| | COMMENT |
| | COMMIT |
| | COMMITTED |
| | CONCURRENCY |
| | COMPRESSION |
| | CONFIGURATION |
| | CONFLICT |
| | CONNECTION |
| | CONSTRAINTS |
| | CONTAINS |
| | CONTENT_P |
| | CONVERSION_P |
| | COORDINATOR |
| | COPY |
| | COST |
| | CPUSET |
| | CPU_MAX_PERCENT |
| | CPU_WEIGHT |
| | CREATEEXTTABLE |
| | CSV |
| | CUBE |
| | CURSOR |
| | CYCLE |
| | DATABASE |
| | DEALLOCATE |
| | DECLARE |
| | DEFAULTS |
| | DEFERRED |
| | DEFINER |
| | DELETE_P |
| | DELIMITER |
| | DELIMITERS |
| | DEPENDS |
| | DEPTH |
| | DETACH |
| | DICTIONARY |
| | DIRECTORY |
| | DISABLE_P |
| | DOMAIN_P |
| | DOUBLE_P |
| | DROP |
| | EACH |
| | ENABLE_P |
| | ENCODING |
| | ENCRYPTED |
| | ENDPOINT |
| | ERRORS |
| | ENUM_P |
| | ESCAPE |
| | EVERY |
| | EXCHANGE |
| | EXCLUDING |
| | EXCLUSIVE |
| | EXECUTE |
| | EXPLAIN |
| | EXTERNAL |
| | FAMILY |
| | FIELDS |
| | FILL |
| | FILTER |
| | FINALIZE |
| | FIRST_P |
| | FORCE |
| | FORMAT |
| | FORWARD |
| | FUNCTION |
| | GENERATED |
| | GLOBAL |
| | GRANTED |
| | GROUPING |
| | GROUPS |
| | HANDLER |
| | HASH |
| | HEADER_P |
| | HOLD |
| | HOST |
| | IF_P |
| | IMMEDIATE |
| | IMMUTABLE |
| | IMPLICIT_P |
| | IMPORT_P |
| | INCLUDE |
| | INCLUDING |
| | INCLUSIVE |
| | INCREMENT |
| | INDEX |
| | INDEXES |
| | INHERIT |
| | INHERITS |
| | INPUT_P |
| | INSENSITIVE |
| | INSERT |
| | INSTEAD |
| | INVOKER |
| | ISOLATION |
| | KEY |
| | LANGUAGE |
| | LARGE_P |
| | LAST_P |
| | LEVEL |
| | LIST |
| | LISTEN |
| | LOAD |
| | LOCAL |
| | LOCATION |
| | LOCKED |
| | LOCK_P |
| | LOGGED |
| | MASTER |
| | MATCH |
| | MAXVALUE |
| | MEMORY_QUOTA |
| | METHOD |
| | MINVALUE |
| | MISSING |
| | MODE |
| | MODIFIES |
| | MOVE |
| | NAME_P |
| | NAMES |
| | NEW |
| | NEWLINE |
| | NEXT |
| | NO |
| | NOOVERCOMMIT |
| | NOTHING |
| | NOTIFY |
| | NOWAIT |
| | NULLS_P |
| | OBJECT_P |
| | OF |
| | OIDS |
| | OLD |
| | OPERATOR |
| | OPTION |
| | OPTIONS |
| | OTHERS |
| | OVERCOMMIT |
| | OVERRIDING |
| | OWNED |
| | OWNER |
| | PARALLEL |
| | PARTIAL |
| | PARTITIONS |
| | PASSWORD |
| | PERCENT |
| | PERSISTENTLY |
| | POLICY |
| | PREPARE |
| | PREPARED |
| | PRESERVE |
| | PRIOR |
| | PRIVILEGES |
| | PROCEDURAL |
| | PROCEDURE |
| | PROCEDURES |
| | PROTOCOL |
| | PUBLICATION |
| | QUEUE |
| | QUOTE |
| | RANGE |
| | READ |
| | REASSIGN |
| | RECHECK |
| | REFERENCING |
| | REINDEX |
| | RELATIVE_P |
| | RELEASE |
| | RENAME |
| | REPEATABLE |
| | REPLACE |
| | RESET |
| | RESOURCE |
| | RESTART |
| | RESTRICT |
| | RETURN |
| | RETRIEVE |
| | RETURNS |
| | REVOKE |
| | ROLE |
| | ROLLBACK |
| | ROLLUP |
| | ROUTINE |
| | ROUTINES |
| | ROWS |
| | RULE |
| | SAVEPOINT |
| | SCALAR |
| | SCHEMA |
| | SCHEMAS |
| | SCROLL |
| | SEARCH |
| | SECURITY |
| | SEGMENT |
| | SEGMENTS |
| | SEQUENCE |
| | SERIALIZABLE |
| | SESSION |
| | SET |
| | SHARE |
| | SHOW |
| | SIMPLE |
| | SPLIT |
| | SQL_P |
| | STABLE |
| | START |
| | STATEMENT |
| | STATISTICS |
| | STDIN |
| | STDOUT |
| | STORAGE |
| | STORED |
| | STRICT_P |
| | SUBPARTITION |
| | SUPPORT |
| | SYSID |
| | SYSTEM_P |
| | TABLESAMPLE |
| | TEMP |
| | TEMPLATE |
| | TEMPORARY |
| | THRESHOLD |
| | TIES |
| | TRANSACTION |
| | TRANSFORM |
| | TRIGGER |
| | TRUNCATE |
| | TRUSTED |
| | TYPE_P |
| | UNCOMMITTED |
| | UNENCRYPTED |
| | UNKNOWN |
| | UNLISTEN |
| | UNTIL |
| | UPDATE |
| | VACUUM |
| | VALID |
| | VALIDATOR |
| | VERSION_P |
| | VIEW |
| | VALUE_P |
| | VOLATILE |
| | WORK |
| | WRITE |
| | ZONE |
| | BIGINT |
| | BIT |
| | BOOLEAN_P |
| | COALESCE |
| | DEC |
| | DECIMAL_P |
| | EXISTS |
| | EXTRACT |
| | FLOAT_P |
| | GREATEST |
| | INOUT |
| | INT_P |
| | INTEGER |
| | INTERVAL |
| | LEAST |
| | NATIONAL |
| | NCHAR |
| | NONE |
| | NULLIF |
| | NUMERIC |
| | OUT_P |
| | OVERLAY |
| | POSITION |
| | PRECISION |
| | REAL |
| | ROW |
| | SETOF |
| | SETS |
| | SMALLINT |
| | SUBSTRING |
| | TIME |
| | TIMESTAMP |
| | TREAT |
| | TRIM |
| | VALUES |
| | VARCHAR |
| | AUTHORIZATION |
| | BINARY |
| | FREEZE |
| | LOG_P |
| | OUTER_P |
| | VERBOSE |
| | MIN_COST |
| ; |
| |
| /* Column identifier --- keywords that can be column, table, etc names. |
| * |
| * Many of these keywords will in fact be recognized as type or function |
| * names too; but they have special productions for the purpose, and so |
| * can't be treated as "generic" type or function names. |
| * |
| * The type names appearing here are not usable as function names |
| * because they can be followed by '(' in typename productions, which |
| * looks too much like a function call for an LR(1) parser. |
| */ |
| col_name_keyword: |
| BETWEEN |
| | BIGINT |
| | BIT |
| | BOOLEAN_P |
| | CHAR_P |
| | CHARACTER |
| | COALESCE |
| | DEC |
| | DECIMAL_P |
| | EXISTS |
| | EXTRACT |
| | FLOAT_P |
| | GREATEST |
| | GROUPING |
| | GROUP_ID |
| | INOUT |
| | INT_P |
| | INTEGER |
| | INTERVAL |
| | JSON_ARRAY |
| | JSON_ARRAYAGG |
| | JSON_OBJECT |
| | JSON_OBJECTAGG |
| | LEAST |
| | MEDIAN |
| | NATIONAL |
| | NCHAR |
| | NONE |
| | NORMALIZE |
| | NULLIF |
| | NUMERIC |
| | OUT_P |
| | OVERLAY |
| | POSITION |
| | PRECISION |
| | REAL |
| | ROW |
| | SETOF |
| | SMALLINT |
| | SUBSTRING |
| | TIME |
| | TIMESTAMP |
| | TREAT |
| | TRIM |
| | VALUES |
| | VARCHAR |
| | XMLATTRIBUTES |
| | XMLCONCAT |
| | XMLELEMENT |
| | XMLEXISTS |
| | XMLFOREST |
| | XMLNAMESPACES |
| | XMLPARSE |
| | XMLPI |
| | XMLROOT |
| | XMLSERIALIZE |
| | XMLTABLE |
| ; |
| |
| /* Type/function identifier --- keywords that can be type or function names. |
| * |
| * Most of these are keywords that are used as operators in expressions; |
| * in general such keywords can't be column names because they would be |
| * ambiguous with variables, but they are unambiguous as function identifiers. |
| * |
| * Do not include POSITION, SUBSTRING, etc here since they have explicit |
| * productions in a_expr to support the goofy SQL9x argument syntax. |
| * - thomas 2000-11-28 |
| */ |
| type_func_name_keyword: |
| AO_AUX_ONLY |
| | AUTHORIZATION |
| | BINARY |
| | COLLATION |
| | CONCURRENTLY |
| | CROSS |
| | CURRENT_SCHEMA |
| | FREEZE |
| | FULL |
| | ILIKE |
| | INNER_P |
| | IS |
| | ISNULL |
| | JOIN |
| | LEFT |
| | LIKE |
| | NATURAL |
| | NOTNULL |
| | OUTER_P |
| | OVERLAPS |
| | RIGHT |
| | SIMILAR |
| | TABLESAMPLE |
| | VERBOSE |
| ; |
| |
| /* Reserved keyword --- these keywords are usable only as a ColLabel. |
| * |
| * Keywords appear here if they could not be distinguished from variable, |
| * type, or function names in some contexts. Don't put things here unless |
| * forced to. |
| */ |
| reserved_keyword: |
| ALL |
| | ANALYSE |
| | ANALYZE |
| | AND |
| | ANY |
| | ARRAY |
| | AS |
| | ASC |
| | ASYMMETRIC |
| | BOTH |
| | CASE |
| | CAST |
| | CHECK |
| | COLLATE |
| | COLUMN |
| | CONSTRAINT |
| | CREATE |
| | CURRENT_CATALOG |
| | CURRENT_DATE |
| | CURRENT_ROLE |
| | CURRENT_TIME |
| | CURRENT_TIMESTAMP |
| | CURRENT_USER |
| | DECODE |
| | DEFAULT |
| | DEFERRABLE |
| | DESC |
| | DIRECTORY |
| | DISTINCT |
| | DISTRIBUTED /* gp */ |
| | DO |
| | ELSE |
| | END_P |
| | EXCEPT |
| | EXCLUDE |
| | FALSE_P |
| | FETCH |
| | FOR |
| | FOREIGN |
| | FROM |
| | GRANT |
| | GROUP_P |
| | HAVING |
| | IN_P |
| | INITIALLY |
| | INTERSECT |
| | INTO |
| | LATERAL_P |
| | LEADING |
| | LIMIT |
| | LOCALTIME |
| | LOCALTIMESTAMP |
| | NOT |
| | NULL_P |
| | OFFSET |
| | ON |
| | ONLY |
| | OR |
| | ORDER |
| | PARTITION |
| | PLACING |
| | PRIMARY |
| | REFERENCES |
| | RETURNING |
| | SCATTER /* gp */ |
| | SELECT |
| | SESSION_USER |
| | SOME |
| | SYMMETRIC |
| | SYSTEM_USER |
| | TABLE |
| | THEN |
| | TO |
| | TRAILING |
| | TRUE_P |
| | UNION |
| | UNIQUE |
| | USER |
| | USING |
| | VARIADIC |
| | WHEN |
| | WHERE |
| | WINDOW |
| | WITH |
| ; |
| |
| /* |
| * While all keywords can be used as column labels when preceded by AS, |
| * not all of them can be used as a "bare" column label without AS. |
| * Those that can be used as a bare label must be listed here, |
| * in addition to appearing in one of the category lists above. |
| * |
| * Always add a new keyword to this list if possible. Mark it BARE_LABEL |
| * in kwlist.h if it is included here, or AS_LABEL if it is not. |
| */ |
| bare_label_keyword: |
| ABORT_P |
| | ABSENT |
| | ABSOLUTE_P |
| | ACCESS |
| | ACCOUNT |
| | ACTION |
| | ACTIVE |
| | ADD_P |
| | ADMIN |
| | AFTER |
| | AGGREGATE |
| | ALL |
| | ALLOWED_VALUES |
| | ALSO |
| | ALTER |
| | ALWAYS |
| | ANALYSE |
| | ANALYZE |
| | AND |
| | ANY |
| | AO_AUX_ONLY |
| | ASC |
| | ASENSITIVE |
| | ASSERTION |
| | ASSIGNMENT |
| | ASYMMETRIC |
| | AT |
| | ATOMIC |
| | ATTACH |
| | ATTRIBUTE |
| | AUTHORIZATION |
| | BACKWARD |
| | BEFORE |
| | BEGIN_P |
| | BETWEEN |
| | BIGINT |
| | BINARY |
| | BIT |
| | BOOLEAN_P |
| | BOTH |
| | BREADTH |
| | BY |
| | CACHE |
| | CALL |
| | CALLED |
| | CASCADE |
| | CASCADED |
| | CASE |
| | CAST |
| | CATALOG_P |
| | CHAIN |
| | CHARACTERISTICS |
| | CHECK |
| | CHECKPOINT |
| | CLASS |
| | CLOSE |
| | CLUSTER |
| | COALESCE |
| | COLLATE |
| | COLLATION |
| | COLUMN |
| | COLUMNS |
| | COMMENT |
| | COMMENTS |
| | COMMIT |
| | COMMITTED |
| | COMPRESSION |
| | CONCURRENCY |
| | CONCURRENTLY |
| | CONFIGURATION |
| | CONFLICT |
| | CONNECTION |
| | CONSTRAINT |
| | CONSTRAINTS |
| | CONTAINS |
| | CONTENT_P |
| | CONTINUE_P |
| | CONVERSION_P |
| | COORDINATOR |
| | COPY |
| | COST |
| | CPUSET |
| | CPU_MAX_PERCENT |
| | CPU_WEIGHT |
| | CREATEEXTTABLE |
| | CROSS |
| | CSV |
| | CUBE |
| | CURRENT_P |
| | CURRENT_CATALOG |
| | CURRENT_DATE |
| | CURRENT_ROLE |
| | CURRENT_SCHEMA |
| | CURRENT_TIME |
| | CURRENT_TIMESTAMP |
| | CURRENT_USER |
| | CURSOR |
| | CYCLE |
| | DATA_P |
| | DATABASE |
| | DEALLOCATE |
| | DEC |
| | DECIMAL_P |
| | DECLARE |
| | DECODE |
| | DEFAULT |
| | DEFAULTS |
| | DEFERRABLE |
| | DEFERRED |
| | DEFINER |
| | DELETE_P |
| | DELIMITER |
| | DELIMITERS |
| | DENY |
| | DEPENDS |
| | DEPTH |
| | DESC |
| | DETACH |
| | DICTIONARY |
| | DIRECTORY |
| | DISABLE_P |
| | DISCARD |
| | DISTINCT |
| | DO |
| | DOCUMENT_P |
| | DOMAIN_P |
| | DOUBLE_P |
| | DROP |
| | DXL |
| | DYNAMIC |
| | EACH |
| | ELSE |
| | ENABLE_P |
| | ENCODING |
| | ENCRYPTED |
| | END_P |
| | ENDPOINT |
| | ENUM_P |
| | ERRORS |
| | ESCAPE |
| | EVENT |
| | EVERY |
| | EXCHANGE |
| | EXCLUDE |
| | EXCLUDING |
| | EXCLUSIVE |
| | EXECUTE |
| | EXISTS |
| | EXPAND |
| | EXPLAIN |
| | EXPRESSION |
| | EXTENSION |
| | EXTERNAL |
| | EXTRACT |
| | FAILED_LOGIN_ATTEMPTS |
| | FALSE_P |
| | FAMILY |
| | FIELDS |
| | FILL |
| | FINALIZE |
| | FIRST_P |
| | FLOAT_P |
| | FOLLOWING |
| | FORCE |
| | FOREIGN |
| | FORMAT |
| | FORWARD |
| | FREEZE |
| | FULL |
| | FULLSCAN |
| | FUNCTION |
| | FUNCTIONS |
| | GENERATED |
| | GLOBAL |
| | GRANTED |
| | GREATEST |
| | GROUPING |
| | GROUPS |
| | GROUP_ID |
| | HANDLER |
| | HASH |
| | HEADER_P |
| | HOLD |
| | HOST |
| | IDENTITY_P |
| | IF_P |
| | IGNORE_P |
| | ILIKE |
| | IMMEDIATE |
| | IMMUTABLE |
| | IMPLICIT_P |
| | IMPORT_P |
| | IN_P |
| | INCLUDE |
| | INCLUDING |
| | INCLUSIVE |
| | INCREMENT |
| | INCREMENTAL |
| | INDENT |
| | INDEX |
| | INDEXES |
| | INHERIT |
| | INHERITS |
| | INITIALLY |
| | INITPLAN |
| | INLINE_P |
| | INNER_P |
| | INOUT |
| | INPUT_P |
| | INSENSITIVE |
| | INSERT |
| | INSTEAD |
| | INT_P |
| | INTEGER |
| | INTERVAL |
| | INVOKER |
| | IO_LIMIT |
| | IS |
| | ISOLATION |
| | JOIN |
| | JSON |
| | JSON_ARRAY |
| | JSON_ARRAYAGG |
| | JSON_OBJECT |
| | JSON_OBJECTAGG |
| | KEY |
| | KEYS |
| | LABEL |
| | LANGUAGE |
| | LARGE_P |
| | LAST_P |
| | LATERAL_P |
| | LEADING |
| | LEAKPROOF |
| | LEAST |
| | LEFT |
| | LEVEL |
| | LIKE |
| | LIST |
| | LISTEN |
| | LOAD |
| | LOCAL |
| | LOCALTIME |
| | LOCALTIMESTAMP |
| | LOCATION |
| | LOCK_P |
| | LOCKED |
| | LOCUS |
| | LOG_P |
| | LOGGED |
| | MAPPING |
| | MASTER |
| | MATCH |
| | MATCHED |
| | MATERIALIZED |
| | MAXVALUE |
| | MEDIAN |
| | MEMORY_QUOTA |
| | MERGE |
| | METHOD |
| | MINVALUE |
| | MIN_COST |
| | MISSING |
| | MODE |
| | MODIFIES |
| | MOVE |
| | NAME_P |
| | NAMES |
| | NATIONAL |
| | NATURAL |
| | NCHAR |
| | NEW |
| | NEWLINE |
| | NEXT |
| | NFC |
| | NFD |
| | NFKC |
| | NFKD |
| | NO |
| | NOCREATEEXTTABLE |
| | NONE |
| | NOOVERCOMMIT |
| | NORMALIZE |
| | NORMALIZED |
| | NOT |
| | NOTHING |
| | NOTIFY |
| | NOWAIT |
| | NULL_P |
| | NULLIF |
| | NULLS_P |
| | NUMERIC |
| | OBJECT_P |
| | OF |
| | OFF |
| | OIDS |
| | OLD |
| | ONLY |
| | OPERATOR |
| | OPTION |
| | OPTIONS |
| | OR |
| | ORDERED |
| | ORDINALITY |
| | OTHERS |
| | OUT_P |
| | OUTER_P |
| | OVERCOMMIT |
| | OVERLAY |
| | OVERRIDING |
| | OWNED |
| | OWNER |
| | PARALLEL |
| | PARAMETER |
| | PARSER |
| | PARTIAL |
| | PARTITIONS |
| | PASSING |
| | PASSWORD |
| | PASSWORD_LOCK_TIME |
| | PASSWORD_REUSE_MAX |
| | PERCENT |
| | PERSISTENTLY |
| | PLACING |
| | PLANS |
| | POLICY |
| | POSITION |
| | PRECEDING |
| | PREPARE |
| | PREPARED |
| | PRESERVE |
| | PRIMARY |
| | PRIOR |
| | PRIVILEGES |
| | PROCEDURAL |
| | PROCEDURE |
| | PROCEDURES |
| | PROFILE |
| | PROGRAM |
| | PROTOCOL |
| | PUBLICATION |
| | QUEUE |
| | QUOTE |
| | RANDOMLY |
| | RANGE |
| | READ |
| | READABLE |
| | READS |
| | REAL |
| | REASSIGN |
| | RECHECK |
| | RECURSIVE |
| | REF_P |
| | REFERENCES |
| | REFERENCING |
| | REFRESH |
| | REINDEX |
| | REJECT_P |
| | RELATIVE_P |
| | RELEASE |
| | RENAME |
| | REPEATABLE |
| | REPLACE |
| | REPLICA |
| | REPLICATED |
| | RESET |
| | RESOURCE |
| | RESTART |
| | RESTRICT |
| | RETRIEVE |
| | RETURN |
| | RETURNS |
| | REVOKE |
| | RIGHT |
| | ROLE |
| | ROLLBACK |
| | ROLLUP |
| | ROOTPARTITION |
| | ROUTINE |
| | ROUTINES |
| | ROW |
| | ROWS |
| | RULE |
| | SAVEPOINT |
| | SCALAR |
| | SCHEDULE |
| | SCHEMA |
| | SCHEMAS |
| | SCROLL |
| | SEARCH |
| | SECURITY |
| | SEGMENT |
| | SEGMENTS |
| | SELECT |
| | SEQUENCE |
| | SEQUENCES |
| | SERIALIZABLE |
| | SERVER |
| | SESSION |
| | SESSION_USER |
| | SET |
| | SETOF |
| | SETS |
| | SHARE |
| | SHOW |
| | SHRINK |
| | SIMILAR |
| | SIMPLE |
| | SKIP |
| | SMALLINT |
| | SNAPSHOT |
| | SOME |
| | SPLIT |
| | SQL_P |
| | STABLE |
| | STANDALONE_P |
| | START |
| | STATEMENT |
| | STATISTICS |
| | STDIN |
| | STDOUT |
| | STORAGE |
| | STORED |
| | STRICT_P |
| | STRIP_P |
| | SUBPARTITION |
| | SUBSCRIPTION |
| | SUBSTRING |
| | SUPPORT |
| | SYMMETRIC |
| | SYSID |
| | SYSTEM_P |
| | SYSTEM_USER |
| | TABLE |
| | TABLES |
| | TABLESAMPLE |
| | TABLESPACE |
| | TAG |
| | TASK |
| | TEMP |
| | TEMPLATE |
| | TEMPORARY |
| | TEXT_P |
| | THEN |
| | THRESHOLD |
| | TIES |
| | TIME |
| | TIMESTAMP |
| | TRAILING |
| | TRANSACTION |
| | TRANSFORM |
| | TREAT |
| | TRIGGER |
| | TRIM |
| | TRUE_P |
| | TRUNCATE |
| | TRUSTED |
| | TYPE_P |
| | TYPES_P |
| | UESCAPE |
| | UNBOUNDED |
| | UNCOMMITTED |
| | UNENCRYPTED |
| | UNIQUE |
| | UNKNOWN |
| | UNLISTEN |
| | UNLOCK_P |
| | UNLOGGED |
| | UNSET_P |
| | UNTIL |
| | UPDATE |
| | USER |
| | USING |
| | VACUUM |
| | VALID |
| | VALIDATE |
| | VALIDATION |
| | VALIDATOR |
| | VALUE_P |
| | VALUES |
| | VARCHAR |
| | VARIADIC |
| | VERBOSE |
| | VERSION_P |
| | VIEW |
| | VIEWS |
| | VOLATILE |
| | WAREHOUSE |
| | WAREHOUSE_SIZE |
| | WEB |
| | WHEN |
| | WHITESPACE_P |
| | WORK |
| | WRAPPER |
| | WRITABLE |
| | WRITE |
| | XML_P |
| | XMLATTRIBUTES |
| | XMLCONCAT |
| | XMLELEMENT |
| | XMLEXISTS |
| | XMLFOREST |
| | XMLNAMESPACES |
| | XMLPARSE |
| | XMLPI |
| | XMLROOT |
| | XMLSERIALIZE |
| | XMLTABLE |
| | YES_P |
| | ZONE |
| ; |
| |
| %% |
| |
| /* |
| * The signature of this function is required by bison. However, we |
| * ignore the passed yylloc and instead use the last token position |
| * available from the scanner. |
| */ |
| static void |
| base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg) |
| { |
| parser_yyerror(msg); |
| } |
| |
| static RawStmt * |
| makeRawStmt(Node *stmt, int stmt_location) |
| { |
| RawStmt *rs = makeNode(RawStmt); |
| |
| rs->stmt = stmt; |
| rs->stmt_location = stmt_location; |
| rs->stmt_len = 0; /* might get changed later */ |
| return rs; |
| } |
| |
| /* Adjust a RawStmt to reflect that it doesn't run to the end of the string */ |
| static void |
| updateRawStmtEnd(RawStmt *rs, int end_location) |
| { |
| /* |
| * If we already set the length, don't change it. This is for situations |
| * like "select foo ;; select bar" where the same statement will be last |
| * in the string for more than one semicolon. |
| */ |
| if (rs->stmt_len > 0) |
| return; |
| |
| /* OK, update length of RawStmt */ |
| rs->stmt_len = end_location - rs->stmt_location; |
| } |
| |
| static Node * |
| makeColumnRef(char *colname, List *indirection, |
| int location, core_yyscan_t yyscanner) |
| { |
| /* |
| * Generate a ColumnRef node, with an A_Indirection node added if there |
| * is any subscripting in the specified indirection list. However, |
| * any field selection at the start of the indirection list must be |
| * transposed into the "fields" part of the ColumnRef node. |
| */ |
| ColumnRef *c = makeNode(ColumnRef); |
| int nfields = 0; |
| ListCell *l; |
| |
| c->location = location; |
| foreach(l, indirection) |
| { |
| if (IsA(lfirst(l), A_Indices)) |
| { |
| A_Indirection *i = makeNode(A_Indirection); |
| |
| if (nfields == 0) |
| { |
| /* easy case - all indirection goes to A_Indirection */ |
| c->fields = list_make1(makeString(colname)); |
| i->indirection = check_indirection(indirection, yyscanner); |
| } |
| else |
| { |
| /* got to split the list in two */ |
| i->indirection = check_indirection(list_copy_tail(indirection, |
| nfields), |
| yyscanner); |
| indirection = list_truncate(indirection, nfields); |
| c->fields = lcons(makeString(colname), indirection); |
| } |
| i->arg = (Node *) c; |
| return (Node *) i; |
| } |
| else if (IsA(lfirst(l), A_Star)) |
| { |
| /* We only allow '*' at the end of a ColumnRef */ |
| if (lnext(indirection, l) != NULL) |
| parser_yyerror("improper use of \"*\""); |
| } |
| nfields++; |
| } |
| /* No subscripting, so all indirection gets added to field list */ |
| c->fields = lcons(makeString(colname), indirection); |
| return (Node *) c; |
| } |
| |
| static Node * |
| makeTypeCast(Node *arg, TypeName *typename, int location) |
| { |
| TypeCast *n = makeNode(TypeCast); |
| |
| n->arg = arg; |
| n->typeName = typename; |
| n->location = location; |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeStringConst(char *str, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.sval.type = T_String; |
| n->val.sval.sval = str; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeStringConstCast(char *str, int location, TypeName *typename) |
| { |
| Node *s = makeStringConst(str, location); |
| |
| return makeTypeCast(s, typename, -1); |
| } |
| |
| static Node * |
| makeIntConst(int val, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.ival.type = T_Integer; |
| n->val.ival.ival = val; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeFloatConst(char *str, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.fval.type = T_Float; |
| n->val.fval.fval = str; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeBoolAConst(bool state, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.boolval.type = T_Boolean; |
| n->val.boolval.boolval = state; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeBitStringConst(char *str, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.bsval.type = T_BitString; |
| n->val.bsval.bsval = str; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeNullAConst(int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->isnull = true; |
| n->location = location; |
| |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeAConst(Node *v, int location) |
| { |
| Node *n; |
| |
| switch (v->type) |
| { |
| case T_Float: |
| n = makeFloatConst(castNode(Float, v)->fval, location); |
| break; |
| |
| case T_Integer: |
| n = makeIntConst(castNode(Integer, v)->ival, location); |
| break; |
| |
| default: |
| /* currently not used */ |
| Assert(false); |
| n = NULL; |
| } |
| |
| return n; |
| } |
| |
| /* makeRoleSpec |
| * Create a RoleSpec with the given type |
| */ |
| static RoleSpec * |
| makeRoleSpec(RoleSpecType type, int location) |
| { |
| RoleSpec *spec = makeNode(RoleSpec); |
| |
| spec->roletype = type; |
| spec->location = location; |
| |
| return spec; |
| } |
| |
| /* check_qualified_name --- check the result of qualified_name production |
| * |
| * It's easiest to let the grammar production for qualified_name allow |
| * subscripts and '*', which we then must reject here. |
| */ |
| static void |
| check_qualified_name(List *names, core_yyscan_t yyscanner) |
| { |
| ListCell *i; |
| |
| foreach(i, names) |
| { |
| if (!IsA(lfirst(i), String)) |
| parser_yyerror("syntax error"); |
| } |
| } |
| |
| /* check_func_name --- check the result of func_name production |
| * |
| * It's easiest to let the grammar production for func_name allow subscripts |
| * and '*', which we then must reject here. |
| */ |
| static List * |
| check_func_name(List *names, core_yyscan_t yyscanner) |
| { |
| ListCell *i; |
| |
| foreach(i, names) |
| { |
| if (!IsA(lfirst(i), String)) |
| parser_yyerror("syntax error"); |
| } |
| return names; |
| } |
| |
| /* check_indirection --- check the result of indirection production |
| * |
| * We only allow '*' at the end of the list, but it's hard to enforce that |
| * in the grammar, so do it here. |
| */ |
| static List * |
| check_indirection(List *indirection, core_yyscan_t yyscanner) |
| { |
| ListCell *l; |
| |
| foreach(l, indirection) |
| { |
| if (IsA(lfirst(l), A_Star)) |
| { |
| if (lnext(indirection, l) != NULL) |
| parser_yyerror("improper use of \"*\""); |
| } |
| } |
| return indirection; |
| } |
| |
| /* extractArgTypes() |
| * Given a list of FunctionParameter nodes, extract a list of just the |
| * argument types (TypeNames) for input parameters only. This is what |
| * is needed to look up an existing function, which is what is wanted by |
| * the productions that use this call. |
| */ |
| static List * |
| extractArgTypes(List *parameters) |
| { |
| List *result = NIL; |
| ListCell *i; |
| |
| foreach(i, parameters) |
| { |
| FunctionParameter *p = (FunctionParameter *) lfirst(i); |
| |
| if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE) |
| result = lappend(result, p->argType); |
| } |
| return result; |
| } |
| |
| /* extractAggrArgTypes() |
| * As above, but work from the output of the aggr_args production. |
| */ |
| static List * |
| extractAggrArgTypes(List *aggrargs) |
| { |
| Assert(list_length(aggrargs) == 2); |
| return extractArgTypes((List *) linitial(aggrargs)); |
| } |
| |
| /* makeOrderedSetArgs() |
| * Build the result of the aggr_args production (which see the comments for). |
| * This handles only the case where both given lists are nonempty, so that |
| * we have to deal with multiple VARIADIC arguments. |
| */ |
| static List * |
| makeOrderedSetArgs(List *directargs, List *orderedargs, |
| core_yyscan_t yyscanner) |
| { |
| FunctionParameter *lastd = (FunctionParameter *) llast(directargs); |
| Integer *ndirectargs; |
| |
| /* No restriction unless last direct arg is VARIADIC */ |
| if (lastd->mode == FUNC_PARAM_VARIADIC) |
| { |
| FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs); |
| |
| /* |
| * We ignore the names, though the aggr_arg production allows them; |
| * it doesn't allow default values, so those need not be checked. |
| */ |
| if (list_length(orderedargs) != 1 || |
| firsto->mode != FUNC_PARAM_VARIADIC || |
| !equal(lastd->argType, firsto->argType)) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"), |
| parser_errposition(exprLocation((Node *) firsto)))); |
| |
| /* OK, drop the duplicate VARIADIC argument from the internal form */ |
| orderedargs = NIL; |
| } |
| |
| /* don't merge into the next line, as list_concat changes directargs */ |
| ndirectargs = makeInteger(list_length(directargs)); |
| |
| return list_make2(list_concat(directargs, orderedargs), |
| ndirectargs); |
| } |
| |
| /* insertSelectOptions() |
| * Insert ORDER BY, etc into an already-constructed SelectStmt. |
| * |
| * This routine is just to avoid duplicating code in SelectStmt productions. |
| */ |
| static void |
| insertSelectOptions(SelectStmt *stmt, |
| List *sortClause, List *lockingClause, |
| SelectLimit *limitClause, |
| WithClause *withClause, |
| core_yyscan_t yyscanner) |
| { |
| Assert(IsA(stmt, SelectStmt)); |
| |
| /* |
| * Tests here are to reject constructs like |
| * (SELECT foo ORDER BY bar) ORDER BY baz |
| */ |
| if (sortClause) |
| { |
| if (stmt->sortClause) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple ORDER BY clauses not allowed"), |
| parser_errposition(exprLocation((Node *) sortClause)))); |
| stmt->sortClause = sortClause; |
| } |
| /* We can handle multiple locking clauses, though */ |
| stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause); |
| if (limitClause && limitClause->limitOffset) |
| { |
| if (stmt->limitOffset) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple OFFSET clauses not allowed"), |
| parser_errposition(exprLocation(limitClause->limitOffset)))); |
| stmt->limitOffset = limitClause->limitOffset; |
| } |
| if (limitClause && limitClause->limitCount) |
| { |
| if (stmt->limitCount) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple LIMIT clauses not allowed"), |
| parser_errposition(exprLocation(limitClause->limitCount)))); |
| stmt->limitCount = limitClause->limitCount; |
| } |
| if (limitClause && limitClause->limitOption != LIMIT_OPTION_DEFAULT) |
| { |
| if (stmt->limitOption) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple limit options not allowed"))); |
| if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("WITH TIES cannot be specified without ORDER BY clause"))); |
| if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause) |
| { |
| ListCell *lc; |
| |
| foreach(lc, stmt->lockingClause) |
| { |
| LockingClause *lock = lfirst_node(LockingClause, lc); |
| |
| if (lock->waitPolicy == LockWaitSkip) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("%s and %s options cannot be used together", |
| "SKIP LOCKED", "WITH TIES"))); |
| } |
| } |
| stmt->limitOption = limitClause->limitOption; |
| } |
| if (withClause) |
| { |
| if (stmt->withClause) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple WITH clauses not allowed"), |
| parser_errposition(exprLocation((Node *) withClause)))); |
| stmt->withClause = withClause; |
| } |
| } |
| |
| static Node * |
| makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg) |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| |
| n->op = op; |
| n->all = all; |
| n->larg = (SelectStmt *) larg; |
| n->rarg = (SelectStmt *) rarg; |
| return (Node *) n; |
| } |
| |
| /* SystemFuncName() |
| * Build a properly-qualified reference to a built-in function. |
| */ |
| List * |
| SystemFuncName(char *name) |
| { |
| return list_make2(makeString("pg_catalog"), makeString(name)); |
| } |
| |
| /* SystemTypeName() |
| * Build a properly-qualified reference to a built-in type. |
| * |
| * typmod is defaulted, but may be changed afterwards by caller. |
| * Likewise for the location. |
| */ |
| TypeName * |
| SystemTypeName(char *name) |
| { |
| return makeTypeNameFromNameList(list_make2(makeString("pg_catalog"), |
| makeString(name))); |
| } |
| |
| /* doNegate() |
| * Handle negation of a numeric constant. |
| * |
| * Formerly, we did this here because the optimizer couldn't cope with |
| * indexquals that looked like "var = -4" --- it wants "var = const" |
| * and a unary minus operator applied to a constant didn't qualify. |
| * As of Postgres 7.0, that problem doesn't exist anymore because there |
| * is a constant-subexpression simplifier in the optimizer. However, |
| * there's still a good reason for doing this here, which is that we can |
| * postpone committing to a particular internal representation for simple |
| * negative constants. It's better to leave "-123.456" in string form |
| * until we know what the desired type is. |
| */ |
| static Node * |
| doNegate(Node *n, int location) |
| { |
| if (IsA(n, A_Const)) |
| { |
| A_Const *con = (A_Const *) n; |
| |
| /* report the constant's location as that of the '-' sign */ |
| con->location = location; |
| |
| if (IsA(&con->val, Integer)) |
| { |
| con->val.ival.ival = -con->val.ival.ival; |
| return n; |
| } |
| if (IsA(&con->val, Float)) |
| { |
| doNegateFloat(&con->val.fval); |
| return n; |
| } |
| } |
| |
| return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location); |
| } |
| |
| static void |
| doNegateFloat(Float *v) |
| { |
| char *oldval = v->fval; |
| |
| if (*oldval == '+') |
| oldval++; |
| if (*oldval == '-') |
| v->fval = oldval+1; /* just strip the '-' */ |
| else |
| v->fval = psprintf("-%s", oldval); |
| } |
| |
| static Node * |
| makeAndExpr(Node *lexpr, Node *rexpr, int location) |
| { |
| /* Flatten "a AND b AND c ..." to a single BoolExpr on sight */ |
| if (IsA(lexpr, BoolExpr)) |
| { |
| BoolExpr *blexpr = (BoolExpr *) lexpr; |
| |
| if (blexpr->boolop == AND_EXPR) |
| { |
| blexpr->args = lappend(blexpr->args, rexpr); |
| return (Node *) blexpr; |
| } |
| } |
| return (Node *) makeBoolExpr(AND_EXPR, list_make2(lexpr, rexpr), location); |
| } |
| |
| static Node * |
| makeOrExpr(Node *lexpr, Node *rexpr, int location) |
| { |
| /* Flatten "a OR b OR c ..." to a single BoolExpr on sight */ |
| if (IsA(lexpr, BoolExpr)) |
| { |
| BoolExpr *blexpr = (BoolExpr *) lexpr; |
| |
| if (blexpr->boolop == OR_EXPR) |
| { |
| blexpr->args = lappend(blexpr->args, rexpr); |
| return (Node *) blexpr; |
| } |
| } |
| return (Node *) makeBoolExpr(OR_EXPR, list_make2(lexpr, rexpr), location); |
| } |
| |
| static Node * |
| makeNotExpr(Node *expr, int location) |
| { |
| return (Node *) makeBoolExpr(NOT_EXPR, list_make1(expr), location); |
| } |
| |
| static Node * |
| makeAArrayExpr(List *elements, int location) |
| { |
| A_ArrayExpr *n = makeNode(A_ArrayExpr); |
| |
| n->elements = elements; |
| n->location = location; |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location) |
| { |
| SQLValueFunction *svf = makeNode(SQLValueFunction); |
| |
| svf->op = op; |
| /* svf->type will be filled during parse analysis */ |
| svf->typmod = typmod; |
| svf->location = location; |
| return (Node *) svf; |
| } |
| |
| static Node * |
| makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, |
| int location) |
| { |
| XmlExpr *x = makeNode(XmlExpr); |
| |
| x->op = op; |
| x->name = name; |
| /* |
| * named_args is a list of ResTarget; it'll be split apart into separate |
| * expression and name lists in transformXmlExpr(). |
| */ |
| x->named_args = named_args; |
| x->arg_names = NIL; |
| x->args = args; |
| /* xmloption, if relevant, must be filled in by caller */ |
| /* type and typmod will be filled in during parse analysis */ |
| x->type = InvalidOid; /* marks the node as not analyzed */ |
| x->location = location; |
| return (Node *) x; |
| } |
| |
| /* |
| * Merge the input and output parameters of a table function. |
| */ |
| static List * |
| mergeTableFuncParameters(List *func_args, List *columns) |
| { |
| ListCell *lc; |
| |
| /* Explicit OUT and INOUT parameters shouldn't be used in this syntax */ |
| foreach(lc, func_args) |
| { |
| FunctionParameter *p = (FunctionParameter *) lfirst(lc); |
| |
| switch (p->mode) |
| { |
| /* Input modes */ |
| case FUNC_PARAM_DEFAULT: |
| case FUNC_PARAM_IN: |
| case FUNC_PARAM_VARIADIC: |
| break; |
| |
| /* Output modes */ |
| case FUNC_PARAM_TABLE: |
| elog(ERROR, "TABLE arguments aren't allowed in TABLE functions"); /* not feasible */ |
| break; |
| case FUNC_PARAM_OUT: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("OUT arguments aren't allowed in TABLE functions"))); |
| break; |
| case FUNC_PARAM_INOUT: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("INOUT arguments aren't allowed in TABLE functions"))); |
| break; |
| } |
| } |
| |
| return list_concat(func_args, columns); |
| } |
| |
| /* |
| * Determine return type of a TABLE function. A single result column |
| * returns setof that column's type; otherwise return setof record. |
| */ |
| static TypeName * |
| TableFuncTypeName(List *columns) |
| { |
| TypeName *result; |
| |
| if (list_length(columns) == 1) |
| { |
| FunctionParameter *p = (FunctionParameter *) linitial(columns); |
| |
| result = copyObject(p->argType); |
| } |
| else |
| result = SystemTypeName("record"); |
| |
| result->setof = true; |
| |
| return result; |
| } |
| |
| /* |
| * Create the IS_NOT_DISTINCT_FROM expression node |
| * used by CASE x WHEN IS NOT DISTINCT FROM and DECODE() |
| */ |
| static Node* |
| makeIsNotDistinctFromNode(Node *expr, int position) |
| { |
| Node *n = makeNotExpr((Node *) makeSimpleA_Expr(AEXPR_DISTINCT, |
| "=", NULL, expr, position), |
| position); |
| return n; |
| } |
| |
| /* |
| * Convert a list of (dotted) names to a RangeVar (like |
| * makeRangeVarFromNameList, but with position support). The |
| * "AnyName" refers to the any_name production in the grammar. |
| */ |
| static RangeVar * |
| makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner) |
| { |
| RangeVar *r = makeNode(RangeVar); |
| |
| switch (list_length(names)) |
| { |
| case 1: |
| r->catalogname = NULL; |
| r->schemaname = NULL; |
| r->relname = strVal(linitial(names)); |
| break; |
| case 2: |
| r->catalogname = NULL; |
| r->schemaname = strVal(linitial(names)); |
| r->relname = strVal(lsecond(names)); |
| break; |
| case 3: |
| r->catalogname = strVal(linitial(names)); |
| r->schemaname = strVal(lsecond(names)); |
| r->relname = strVal(lthird(names)); |
| break; |
| default: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("improper qualified name (too many dotted names): %s", |
| NameListToString(names)), |
| parser_errposition(position))); |
| break; |
| } |
| |
| r->relpersistence = RELPERSISTENCE_PERMANENT; |
| r->location = position; |
| |
| return r; |
| } |
| |
| /* |
| * Convert a relation_name with name and namelist to a RangeVar using |
| * makeRangeVar. |
| */ |
| static RangeVar * |
| makeRangeVarFromQualifiedName(char *name, List *namelist, int location, |
| core_yyscan_t yyscanner) |
| { |
| RangeVar *r; |
| |
| check_qualified_name(namelist, yyscanner); |
| r = makeRangeVar(NULL, NULL, location); |
| |
| switch (list_length(namelist)) |
| { |
| case 1: |
| r->catalogname = NULL; |
| r->schemaname = name; |
| r->relname = strVal(linitial(namelist)); |
| break; |
| case 2: |
| r->catalogname = name; |
| r->schemaname = strVal(linitial(namelist)); |
| r->relname = strVal(lsecond(namelist)); |
| break; |
| default: |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("improper qualified name (too many dotted names): %s", |
| NameListToString(lcons(makeString(name), namelist))), |
| parser_errposition(location)); |
| break; |
| } |
| |
| return r; |
| } |
| |
| /* Separate Constraint nodes from COLLATE clauses in a ColQualList */ |
| static void |
| SplitColQualList(List *qualList, |
| List **constraintList, CollateClause **collClause, |
| core_yyscan_t yyscanner) |
| { |
| ListCell *cell; |
| |
| *collClause = NULL; |
| foreach(cell, qualList) |
| { |
| Node *n = (Node *) lfirst(cell); |
| |
| if (IsA(n, Constraint)) |
| { |
| /* keep it in list */ |
| continue; |
| } |
| if (IsA(n, CollateClause)) |
| { |
| CollateClause *c = (CollateClause *) n; |
| |
| if (*collClause) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("multiple COLLATE clauses not allowed"), |
| parser_errposition(c->location))); |
| *collClause = c; |
| } |
| else |
| elog(ERROR, "unexpected node type %d", (int) n->type); |
| /* remove non-Constraint nodes from qualList */ |
| qualList = foreach_delete_current(qualList, cell); |
| } |
| *constraintList = qualList; |
| } |
| |
| /* |
| * Process result of ConstraintAttributeSpec, and set appropriate bool flags |
| * in the output command node. Pass NULL for any flags the particular |
| * command doesn't support. |
| */ |
| 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) |
| { |
| /* defaults */ |
| if (deferrable) |
| *deferrable = false; |
| if (initdeferred) |
| *initdeferred = false; |
| if (not_valid) |
| *not_valid = false; |
| |
| if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED)) |
| { |
| if (deferrable) |
| *deferrable = true; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| /* translator: %s is CHECK, UNIQUE, or similar */ |
| errmsg("%s constraints cannot be marked DEFERRABLE", |
| constrType), |
| parser_errposition(location))); |
| } |
| |
| if (cas_bits & CAS_INITIALLY_DEFERRED) |
| { |
| if (initdeferred) |
| *initdeferred = true; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| /* translator: %s is CHECK, UNIQUE, or similar */ |
| errmsg("%s constraints cannot be marked DEFERRABLE", |
| constrType), |
| parser_errposition(location))); |
| } |
| |
| if (cas_bits & CAS_NOT_VALID) |
| { |
| if (not_valid) |
| *not_valid = true; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| /* translator: %s is CHECK, UNIQUE, or similar */ |
| errmsg("%s constraints cannot be marked NOT VALID", |
| constrType), |
| parser_errposition(location))); |
| } |
| |
| if (cas_bits & CAS_NO_INHERIT) |
| { |
| if (no_inherit) |
| *no_inherit = true; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| /* translator: %s is CHECK, UNIQUE, or similar */ |
| errmsg("%s constraints cannot be marked NO INHERIT", |
| constrType), |
| parser_errposition(location))); |
| } |
| } |
| |
| /* |
| * Parse a user-supplied partition strategy string into parse node |
| * PartitionStrategy representation, or die trying. |
| */ |
| static PartitionStrategy |
| parsePartitionStrategy(char *strategy) |
| { |
| if (pg_strcasecmp(strategy, "list") == 0) |
| return PARTITION_STRATEGY_LIST; |
| else if (pg_strcasecmp(strategy, "range") == 0) |
| return PARTITION_STRATEGY_RANGE; |
| else if (pg_strcasecmp(strategy, "hash") == 0) |
| return PARTITION_STRATEGY_HASH; |
| |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("unrecognized partitioning strategy \"%s\"", |
| strategy))); |
| return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ |
| |
| } |
| |
| /* |
| * Process pubobjspec_list to check for errors in any of the objects and |
| * convert PUBLICATIONOBJ_CONTINUATION into appropriate PublicationObjSpecType. |
| */ |
| static void |
| preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner) |
| { |
| ListCell *cell; |
| PublicationObjSpec *pubobj; |
| PublicationObjSpecType prevobjtype = PUBLICATIONOBJ_CONTINUATION; |
| |
| if (!pubobjspec_list) |
| return; |
| |
| pubobj = (PublicationObjSpec *) linitial(pubobjspec_list); |
| if (pubobj->pubobjtype == PUBLICATIONOBJ_CONTINUATION) |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid publication object list"), |
| errdetail("One of TABLE or TABLES IN SCHEMA must be specified before a standalone table or schema name."), |
| parser_errposition(pubobj->location)); |
| |
| foreach(cell, pubobjspec_list) |
| { |
| pubobj = (PublicationObjSpec *) lfirst(cell); |
| |
| if (pubobj->pubobjtype == PUBLICATIONOBJ_CONTINUATION) |
| pubobj->pubobjtype = prevobjtype; |
| |
| if (pubobj->pubobjtype == PUBLICATIONOBJ_TABLE) |
| { |
| /* relation name or pubtable must be set for this type of object */ |
| if (!pubobj->name && !pubobj->pubtable) |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid table name"), |
| parser_errposition(pubobj->location)); |
| |
| if (pubobj->name) |
| { |
| /* convert it to PublicationTable */ |
| PublicationTable *pubtable = makeNode(PublicationTable); |
| |
| pubtable->relation = |
| makeRangeVar(NULL, pubobj->name, pubobj->location); |
| pubobj->pubtable = pubtable; |
| pubobj->name = NULL; |
| } |
| } |
| else if (pubobj->pubobjtype == PUBLICATIONOBJ_TABLES_IN_SCHEMA || |
| pubobj->pubobjtype == PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA) |
| { |
| /* WHERE clause is not allowed on a schema object */ |
| if (pubobj->pubtable && pubobj->pubtable->whereClause) |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("WHERE clause not allowed for schema"), |
| parser_errposition(pubobj->location)); |
| |
| /* Column list is not allowed on a schema object */ |
| if (pubobj->pubtable && pubobj->pubtable->columns) |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("column specification not allowed for schema"), |
| parser_errposition(pubobj->location)); |
| |
| /* |
| * We can distinguish between the different type of schema |
| * objects based on whether name and pubtable is set. |
| */ |
| if (pubobj->name) |
| pubobj->pubobjtype = PUBLICATIONOBJ_TABLES_IN_SCHEMA; |
| else if (!pubobj->name && !pubobj->pubtable) |
| pubobj->pubobjtype = PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA; |
| else |
| ereport(ERROR, |
| errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid schema name"), |
| parser_errposition(pubobj->location)); |
| } |
| |
| prevobjtype = pubobj->pubobjtype; |
| } |
| } |
| |
| /*---------- |
| * Recursive view transformation |
| * |
| * Convert |
| * |
| * CREATE RECURSIVE VIEW relname (aliases) AS query |
| * |
| * to |
| * |
| * CREATE VIEW relname (aliases) AS |
| * WITH RECURSIVE relname (aliases) AS (query) |
| * SELECT aliases FROM relname |
| * |
| * Actually, just the WITH ... part, which is then inserted into the original |
| * view definition as the query. |
| * ---------- |
| */ |
| static Node * |
| makeRecursiveViewSelect(char *relname, List *aliases, Node *query) |
| { |
| SelectStmt *s = makeNode(SelectStmt); |
| WithClause *w = makeNode(WithClause); |
| CommonTableExpr *cte = makeNode(CommonTableExpr); |
| List *tl = NIL; |
| ListCell *lc; |
| |
| /* create common table expression */ |
| cte->ctename = relname; |
| cte->aliascolnames = aliases; |
| cte->ctematerialized = CTEMaterializeDefault; |
| cte->ctequery = query; |
| cte->location = -1; |
| |
| /* create WITH clause and attach CTE */ |
| w->recursive = true; |
| w->ctes = list_make1(cte); |
| w->location = -1; |
| |
| /* create target list for the new SELECT from the alias list of the |
| * recursive view specification */ |
| foreach (lc, aliases) |
| { |
| ResTarget *rt = makeNode(ResTarget); |
| |
| rt->name = NULL; |
| rt->indirection = NIL; |
| rt->val = makeColumnRef(strVal(lfirst(lc)), NIL, -1, 0); |
| rt->location = -1; |
| |
| tl = lappend(tl, rt); |
| } |
| |
| /* create new SELECT combining WITH clause, target list, and fake FROM |
| * clause */ |
| s->withClause = w; |
| s->targetList = tl; |
| s->fromClause = list_make1(makeRangeVar(NULL, relname, -1)); |
| |
| return (Node *) s; |
| } |
| |
| static bool |
| isSetWithReorganize(List **options) |
| { |
| ListCell *lc; |
| foreach (lc, *options) |
| { |
| DefElem *elem = lfirst(lc); |
| |
| if (strcmp(elem->defname, "reorganize") == 0) |
| { |
| if (list_length(*options) == 1) |
| return true; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("reorganize isn't supported with other options in SET WITH"))); |
| } |
| } |
| return false; |
| } |
| |
| |
| /* |
| * Cloudberry: a thin wax off layer to keep compatibility with the legacy syntax |
| * for appendoptimized options. Before the introduction of the tableam in |
| * postgres, appendoptimized and column orientated tables were expressed in the |
| * options list which corresponded to StdRelOptions. |
| * |
| * These specific options now are removed from the options list in favour for |
| * the corresponding accessMethod. The accessMethod takes precedence. |
| */ |
| static char * |
| greenplumLegacyAOoptions(const char *accessMethod, List **options) |
| { |
| List *amendedOptions = NIL; |
| ListCell *lc; |
| bool appendoptimized = false; |
| bool is_column_oriented = false; |
| bool appendoptimized_found = false; |
| bool is_column_oriented_found = false; |
| |
| foreach (lc, *options) |
| { |
| DefElem *elem = lfirst(lc); |
| |
| if (strcmp(elem->defname, "appendoptimized") == 0 || |
| strcmp(elem->defname, "appendonly") == 0) |
| { |
| if (appendoptimized_found) |
| ereport(ERROR, |
| (errcode(ERRCODE_DUPLICATE_OBJECT), |
| errmsg("parameter \"appendonly\" specified more than once"))); |
| appendoptimized = defGetBoolean(elem); |
| appendoptimized_found = true; |
| } |
| else if (strcmp(elem->defname, "orientation") == 0) |
| { |
| const char *value = defGetString(elem); |
| |
| if (is_column_oriented_found) |
| ereport(ERROR, |
| (errcode(ERRCODE_DUPLICATE_OBJECT), |
| errmsg("parameter \"orientation\" specified more than once"))); |
| |
| if (strcmp(value, "column") && strcmp(value, "row")) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid parameter value for \"orientation\": \"%s\"", value))); |
| |
| is_column_oriented = strcmp(value, "column") == 0; |
| is_column_oriented_found = true; |
| } |
| else |
| amendedOptions = lappend(amendedOptions, elem); |
| } |
| *options = amendedOptions; |
| |
| if (!appendoptimized && is_column_oriented_found) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("invalid option \"orientation\" for base relation"), |
| errhint("Table orientation only valid for Append Optimized relations, create an AO relation to use table orientation."))); |
| |
| /* access_method takes precedence */ |
| if (accessMethod) |
| return (char *)accessMethod; |
| |
| if (appendoptimized && is_column_oriented) |
| return pstrdup("ao_column"); |
| |
| if (appendoptimized) |
| return pstrdup("ao_row"); |
| |
| /* |
| * appendonly=false is different from appendonly option not existing in |
| * WITH clause. Hence, explicitly if this exists means heap is |
| * intended. Returning NULL will let the table creation use the default |
| * options or parents options which is not the intent. |
| */ |
| if (appendoptimized_found) |
| return pstrdup("heap"); |
| |
| return NULL; |
| } |
| |
| static void |
| check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_t yyscanner) |
| { |
| ListCell *lc; |
| foreach(lc, spec->partParams) |
| { |
| PartitionElem *e = lfirst(lc); |
| |
| if (e->expr) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("expressions in partition key not supported in legacy GPDB partition syntax"), |
| parser_errposition(e->location))); |
| } |
| } |
| |
| /* parser_init() |
| * Initialize to parse one query string |
| */ |
| void |
| parser_init(base_yy_extra_type *yyext) |
| { |
| yyext->parsetree = NIL; /* in case grammar forgets to set it */ |
| } |