From 6eb9c5a5657d1fe77b55cc261450f3538d35a94d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:19:15 +0200 Subject: Adding upstream version 13.4. Signed-off-by: Daniel Baumann --- src/backend/parser/gram.y | 16624 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 16624 insertions(+) create mode 100644 src/backend/parser/gram.y (limited to 'src/backend/parser/gram.y') diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y new file mode 100644 index 0000000..3adc087 --- /dev/null +++ b/src/backend/parser/gram.y @@ -0,0 +1,16624 @@ +%{ + +/*#define YYDEBUG 1*/ +/*------------------------------------------------------------------------- + * + * gram.y + * POSTGRESQL BISON rules/actions + * + * Portions Copyright (c) 1996-2020, 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 +#include + +#include "access/tableam.h" +#include "catalog/index.h" +#include "catalog/namespace.h" +#include "catalog/pg_am.h" +#include "catalog/pg_trigger.h" +#include "commands/defrem.h" +#include "commands/trigger.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "parser/gramparse.h" +#include "parser/parser.h" +#include "parser/parse_expr.h" +#include "storage/lmgr.h" +#include "utils/date.h" +#include "utils/datetime.h" +#include "utils/numeric.h" +#include "utils/xml.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. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYMALLOC palloc +#define YYFREE pfree + +/* 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; + +/* 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 *makeBitStringConst(char *str, int location); +static Node *makeNullAConst(int location); +static Node *makeAConst(Value *v, int location); +static Node *makeBoolAConst(bool state, 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(Value *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 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 Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); + +%} + +%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; + Value *value; + ObjectType objtype; + TypeName *typnam; + FunctionParameter *fun_param; + FunctionParameterMode fun_param_mode; + ObjectWithArgs *objwithargs; + DefElem *defelt; + SortBy *sortby; + WindowDef *windef; + JoinExpr *jexpr; + IndexElem *ielem; + 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; + struct SelectLimit *selectlimit; +} + +%type stmt schema_stmt + AlterEventTrigStmt AlterCollationStmt + AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt + AlterFdwStmt AlterForeignServerStmt AlterGroupStmt + AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt + AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterSystemStmt AlterTableStmt + AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt + AlterCompositeTypeStmt AlterUserMappingStmt + 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 CreateTableSpaceStmt + CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt + CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt + CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt + CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt + DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt + DropCastStmt DropRoleStmt + DropdbStmt DropTableSpaceStmt + DropTransformStmt + DropUserMappingStmt ExplainStmt FetchStmt + GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt + ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt + CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt + RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt + RuleActionStmt RuleActionStmtOrEmpty RuleStmt + SecLabelStmt SelectStmt TransactionStmt 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 + +%type select_no_parens select_with_parens select_clause + simple_select values_clause + +%type alter_column_default opclass_item opclass_drop alter_using +%type add_drop opt_asc_desc opt_nulls_order + +%type alter_table_cmd alter_type_cmd opt_collate_clause + replica_identity partition_cmd index_partition_cmd +%type alter_table_cmds alter_type_cmds +%type alter_identity_column_option_list +%type alter_identity_column_option + +%type opt_drop_behavior + +%type createdb_opt_list createdb_opt_items copy_opt_list + transaction_mode_list + create_extension_opt_list alter_extension_opt_list +%type createdb_opt_item copy_opt_item + transaction_mode_item + create_extension_opt_item alter_extension_opt_item + +%type opt_lock lock_type cast_context +%type vac_analyze_option_name +%type vac_analyze_option_elem +%type vac_analyze_option_list +%type vac_analyze_option_arg +%type drop_option +%type opt_or_replace opt_no + opt_grant_grant_option opt_grant_admin_option + opt_nowait opt_if_exists opt_with_data + opt_transaction_chain +%type opt_nowait_or_skip + +%type OptRoleList AlterOptRoleList +%type CreateOptRoleElem AlterOptRoleElem + +%type opt_type +%type foreign_server_version opt_foreign_server_version +%type opt_in_database + +%type OptSchemaName +%type OptSchemaEltList + +%type am_type + +%type TriggerForSpec TriggerForType +%type TriggerActionTime +%type TriggerEvents TriggerOneEvent +%type TriggerFuncArg +%type TriggerWhen +%type TransitionRelName +%type TransitionRowOrTable TransitionOldOrNew +%type TriggerTransition + +%type event_trigger_when_list event_trigger_value_list +%type event_trigger_when_item +%type enable_trigger + +%type copy_file_name + database_name access_method_clause access_method attr_name + table_access_method_clause name cursor_name file_name + index_name opt_index_name cluster_index_specification + +%type func_name handler_name qual_Op qual_all_Op subquery_Op + opt_class opt_inline_handler opt_validator validator_clause + opt_collate + +%type qualified_name insert_target OptConstrFromTable + +%type all_Op MathOp + +%type row_security_cmd RowSecurityDefaultForCmd +%type RowSecurityDefaultPermissive +%type RowSecurityOptionalWithCheck RowSecurityOptionalExpr +%type RowSecurityDefaultToRole RowSecurityOptionalToRole + +%type iso_level opt_encoding +%type grantee +%type grantee_list +%type privilege +%type privileges privilege_list +%type privilege_target +%type function_with_argtypes aggregate_with_argtypes operator_with_argtypes +%type function_with_argtypes_list aggregate_with_argtypes_list operator_with_argtypes_list +%type defacl_privilege_target +%type DefACLOption +%type DefACLOptionList +%type import_qualification_type +%type import_qualification +%type vacuum_relation +%type opt_select_limit select_limit limit_clause + +%type stmtblock stmtmulti + OptTableElementList TableElementList OptInherit definition + OptTypedTableElementList TypedTableElementList + reloptions opt_reloptions + OptWith distinct_clause opt_all_clause 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 alterfunc_opt_list + old_aggr_definition old_aggr_list + oper_argtypes RuleActionList RuleActionMulti + opt_column_list columnList opt_name_list + sort_clause opt_sort_clause sortby_list index_params + opt_include opt_c_include index_including_params + name_list role_list from_clause from_list opt_array_bounds + qualified_name_list any_name any_name_list type_name_list + any_operator expr_list attrs + target_list opt_target_list insert_column_list set_target_list + set_clause_list set_clause + def_list operator_def_list indirection opt_indirection + reloption_list group_clause 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 + create_generic_options alter_generic_options + relation_expr_list dostmt_opt_list + transform_element_list transform_type_list + TriggerTransitions TriggerReferencing + publication_name_list + vacuum_relation_list opt_vacuum_relation_list + drop_option_list + +%type group_by_list +%type group_by_item empty_grouping_set rollup_clause cube_clause +%type grouping_sets_clause +%type opt_publication_for_tables publication_for_tables +%type publication_name_item + +%type opt_fdw_options fdw_options +%type fdw_option + +%type OptTempTableName +%type into_clause create_as_target create_mv_target + +%type createfunc_opt_item common_func_opt_item dostmt_opt_item +%type func_arg func_arg_with_default table_func_column aggr_arg +%type arg_class +%type func_return func_type + +%type opt_trusted opt_restart_seqs +%type OptTemp +%type OptNoLog +%type OnCommitOption + +%type for_locking_strength +%type for_locking_item +%type for_locking_clause opt_for_locking_clause for_locking_items +%type locked_rels_list +%type all_or_distinct + +%type join_outer join_qual +%type join_type + +%type extract_list overlay_list position_list +%type substr_list trim_list +%type opt_interval interval_second +%type overlay_placing substr_from substr_for +%type unicode_normal_form + +%type opt_instead +%type opt_unique opt_concurrently opt_verbose opt_full +%type opt_freeze opt_analyze opt_default opt_recheck +%type opt_binary copy_delimiter + +%type copy_from opt_program + +%type opt_column event cursor_options opt_hold opt_set_data +%type drop_type_any_name drop_type_name drop_type_name_on_any_name + comment_type_any_name comment_type_name + security_label_type_any_name security_label_type_name + +%type fetch_args select_limit_value + offset_clause select_offset_value + select_fetch_first_value I_or_F_const +%type row_or_rows first_or_next + +%type OptSeqOptList SeqOptList OptParenthesizedSeqOptList +%type SeqOptElem + +%type insert_rest +%type opt_conf_expr +%type opt_on_conflict + +%type generic_set set_rest set_rest_more generic_reset reset_rest + SetResetClause FunctionSetResetClause + +%type TableElement TypedTableElement ConstraintElem TableFuncElement +%type columnDef columnOptions +%type def_elem reloption_elem old_aggr_elem operator_def_elem +%type 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 + ExclusionWhereClause operator_def_arg +%type rowsfrom_item rowsfrom_list opt_col_def_list +%type opt_ordinality +%type ExclusionConstraintList ExclusionConstraintElem +%type func_arg_list +%type func_arg_expr +%type row explicit_row implicit_row type_list array_expr_list +%type case_expr case_arg when_clause case_default +%type when_clause_list +%type sub_type opt_materialized +%type NumericOnly +%type NumericOnly_list +%type alias_clause opt_alias_clause +%type func_alias_clause +%type sortby +%type index_elem index_elem_options +%type table_ref +%type joined_table +%type relation_expr +%type relation_expr_opt_alias +%type tablesample_clause opt_repeatable_clause +%type target_el set_target insert_column_item + +%type generic_option_name +%type generic_option_arg +%type generic_option_elem alter_generic_option_elem +%type generic_option_list alter_generic_option_list +%type explain_option_name +%type explain_option_arg +%type explain_option_elem +%type explain_option_list + +%type reindex_target_type reindex_target_multitable +%type reindex_option_list reindex_option_elem + +%type copy_generic_opt_arg copy_generic_opt_arg_list_item +%type copy_generic_opt_elem +%type copy_generic_opt_list copy_generic_opt_arg_list +%type copy_options + +%type Typename SimpleTypename ConstTypename + GenericType Numeric opt_float + Character ConstCharacter + CharacterWithLength CharacterWithoutLength + ConstDatetime ConstInterval + Bit ConstBit BitWithLength BitWithoutLength +%type character +%type extract_arg +%type opt_varying opt_timezone opt_no_inherit + +%type Iconst SignedIconst +%type Sconst comment_text notify_payload +%type RoleId opt_boolean_or_string +%type var_list +%type ColId ColLabel var_name type_function_name param_name +%type NonReservedWord NonReservedWord_or_Sconst +%type createdb_opt_name +%type var_value zone_value +%type auth_ident RoleSpec opt_granted_by + +%type unreserved_keyword type_func_name_keyword +%type col_name_keyword reserved_keyword + +%type TableConstraint TableLikeClause +%type TableLikeOptionList TableLikeOption +%type ColQualList +%type ColConstraint ColConstraintElem ConstraintAttr +%type key_actions key_delete key_match key_update key_action +%type ConstraintAttributeSpec ConstraintAttributeElem +%type ExistingIndex + +%type constraints_set_list +%type constraints_set_mode +%type OptTableSpace OptConsTableSpace +%type OptTableSpaceOwner +%type opt_check_option + +%type opt_provider security_label + +%type xml_attribute_el +%type xml_attribute_list xml_attributes +%type xml_root_version opt_xml_root_standalone +%type xmlexists_argument +%type document_or_content +%type xml_whitespace_option +%type xmltable_column_list xmltable_column_option_list +%type xmltable_column_el +%type xmltable_column_option_el +%type xml_namespace_list +%type xml_namespace_el + +%type func_application func_expr_common_subexpr +%type func_expr func_expr_windowless +%type common_table_expr +%type with_clause opt_with_clause +%type cte_list + +%type within_group_clause +%type filter_clause +%type window_clause window_definition_list opt_partition_clause +%type window_definition over_clause window_specification + opt_frame_clause frame_extent frame_bound +%type opt_window_exclusion_clause +%type opt_existing_window_name +%type opt_if_not_exists +%type generated_when override_kind +%type PartitionSpec OptPartitionSpec +%type part_elem +%type part_params +%type PartitionBoundSpec +%type hash_partbound +%type hash_partbound_elem + +/* + * 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 IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op +%token 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 ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER + AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC + ASSERTION ASSIGNMENT ASYMMETRIC AT ATTACH ATTRIBUTE AUTHORIZATION + + BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT + BOOLEAN_P BOTH 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 CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT + 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 DESC + DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P + DOUBLE_P DROP + + EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT + EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION + EXTENSION EXTERNAL EXTRACT + + FALSE_P FAMILY FETCH FILTER FIRST_P FLOAT_P FOLLOWING FOR + FORCE FOREIGN 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 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 + + KEY + + LABEL LANGUAGE LARGE_P LAST_P LATERAL_P + LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL + LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED + + MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE 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 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 REFERENCES REFERENCING + REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA + RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP + ROUTINE ROUTINES ROW ROWS RULE + + SAVEPOINT 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 + + 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 + +/* + * 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. + * NULLS_LA and WITH_LA are needed to make the grammar LALR(1). + */ +%token NOT_LA NULLS_LA WITH_LA + + +/* 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 */ +%left POSTFIXOP /* dummy for postfix Op rules */ +/* + * To support target_el without AS, we must give IDENT an explicit priority + * between POSTFIXOP and Op. We can safely assign the same priority to + * various unreserved keywords as needed to resolve ambiguities (this can't + * have any bad effects since obviously the keywords will still behave the + * same as if they weren't keywords). We need to do this: + * for PARTITION, RANGE, ROWS, GROUPS to support opt_existing_window_name; + * for RANGE, ROWS, GROUPS so that they can follow a_expr without creating + * postfix-operator problems; + * for GENERATED so that it can follow b_expr; + * and for NULL so that it can follow b_expr in ColQualList without creating + * postfix-operator problems. + * + * 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. + * + * 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. + */ +%nonassoc UNBOUNDED /* ideally should have same precedence as IDENT */ +%nonassoc IDENT GENERATED NULL_P PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP +%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 +/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */ +%right PRESERVE STRIP_P + +%% + +/* + * The target production for the whole parse. + */ +stmtblock: stmtmulti + { + pg_yyget_extra(yyscanner)->parsetree = $1; + } + ; + +/* + * 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 ';' 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; + } + | stmt + { + if ($1 != NULL) + $$ = list_make1(makeRawStmt($1, 0)); + else + $$ = NIL; + } + ; + +stmt : + AlterEventTrigStmt + | AlterCollationStmt + | AlterDatabaseStmt + | AlterDatabaseSetStmt + | AlterDefaultPrivilegesStmt + | AlterDomainStmt + | AlterEnumStmt + | AlterExtensionStmt + | AlterExtensionContentsStmt + | AlterFdwStmt + | AlterForeignServerStmt + | AlterForeignTableStmt + | AlterFunctionStmt + | AlterGroupStmt + | AlterObjectDependsStmt + | AlterObjectSchemaStmt + | AlterOwnerStmt + | AlterOperatorStmt + | AlterTypeStmt + | AlterPolicyStmt + | AlterSeqStmt + | AlterSystemStmt + | AlterTableStmt + | AlterTblSpcStmt + | AlterCompositeTypeStmt + | AlterPublicationStmt + | AlterRoleSetStmt + | AlterRoleStmt + | AlterSubscriptionStmt + | AlterStatsStmt + | AlterTSConfigurationStmt + | AlterTSDictionaryStmt + | AlterUserMappingStmt + | AnalyzeStmt + | CallStmt + | CheckPointStmt + | ClosePortalStmt + | ClusterStmt + | CommentStmt + | ConstraintsSetStmt + | CopyStmt + | CreateAmStmt + | CreateAsStmt + | CreateAssertionStmt + | CreateCastStmt + | CreateConversionStmt + | CreateDomainStmt + | CreateExtensionStmt + | CreateFdwStmt + | CreateForeignServerStmt + | CreateForeignTableStmt + | CreateFunctionStmt + | CreateGroupStmt + | CreateMatViewStmt + | CreateOpClassStmt + | CreateOpFamilyStmt + | CreatePublicationStmt + | AlterOpFamilyStmt + | CreatePolicyStmt + | CreatePLangStmt + | CreateSchemaStmt + | CreateSeqStmt + | CreateStmt + | CreateSubscriptionStmt + | CreateStatsStmt + | CreateTableSpaceStmt + | CreateTransformStmt + | CreateTrigStmt + | CreateEventTrigStmt + | CreateRoleStmt + | CreateUserStmt + | CreateUserMappingStmt + | CreatedbStmt + | DeallocateStmt + | DeclareCursorStmt + | DefineStmt + | DeleteStmt + | DiscardStmt + | DoStmt + | DropCastStmt + | DropOpClassStmt + | DropOpFamilyStmt + | DropOwnedStmt + | DropPLangStmt + | DropStmt + | DropSubscriptionStmt + | DropTableSpaceStmt + | DropTransformStmt + | DropRoleStmt + | DropUserMappingStmt + | DropdbStmt + | ExecuteStmt + | ExplainStmt + | FetchStmt + | GrantStmt + | GrantRoleStmt + | ImportForeignSchemaStmt + | IndexStmt + | InsertStmt + | ListenStmt + | RefreshMatViewStmt + | LoadStmt + | LockStmt + | NotifyStmt + | PrepareStmt + | ReassignOwnedStmt + | ReindexStmt + | RemoveAggrStmt + | RemoveFuncStmt + | RemoveOperStmt + | RenameStmt + | RevokeStmt + | RevokeRoleStmt + | RuleStmt + | SecLabelStmt + | SelectStmt + | TransactionStmt + | TruncateStmt + | UnlistenStmt + | UpdateStmt + | VacuumStmt + | VariableResetStmt + | VariableSetStmt + | VariableShowStmt + | ViewStmt + | /*EMPTY*/ + { $$ = NULL; } + ; + +/***************************************************************************** + * + * 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 AlterOptRoleElem { $$ = lappend($1, $2); } + | /* EMPTY */ { $$ = NIL; } + ; + +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 *)makeInteger(true), @1); + } + | CONNECTION LIMIT SignedIconst + { + $$ = makeDefElem("connectionlimit", (Node *)makeInteger($3), @1); + } + | VALID UNTIL Sconst + { + $$ = makeDefElem("validUntil", (Node *)makeString($3), @1); + } + /* Supported but not documented for roles, for use by ALTER GROUP. */ + | USER role_list + { + $$ = makeDefElem("rolemembers", (Node *)$2, @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 *)makeInteger(true), @1); + else if (strcmp($1, "nosuperuser") == 0) + $$ = makeDefElem("superuser", (Node *)makeInteger(false), @1); + else if (strcmp($1, "createrole") == 0) + $$ = makeDefElem("createrole", (Node *)makeInteger(true), @1); + else if (strcmp($1, "nocreaterole") == 0) + $$ = makeDefElem("createrole", (Node *)makeInteger(false), @1); + else if (strcmp($1, "replication") == 0) + $$ = makeDefElem("isreplication", (Node *)makeInteger(true), @1); + else if (strcmp($1, "noreplication") == 0) + $$ = makeDefElem("isreplication", (Node *)makeInteger(false), @1); + else if (strcmp($1, "createdb") == 0) + $$ = makeDefElem("createdb", (Node *)makeInteger(true), @1); + else if (strcmp($1, "nocreatedb") == 0) + $$ = makeDefElem("createdb", (Node *)makeInteger(false), @1); + else if (strcmp($1, "login") == 0) + $$ = makeDefElem("canlogin", (Node *)makeInteger(true), @1); + else if (strcmp($1, "nologin") == 0) + $$ = makeDefElem("canlogin", (Node *)makeInteger(false), @1); + else if (strcmp($1, "bypassrls") == 0) + $$ = makeDefElem("bypassrls", (Node *)makeInteger(true), @1); + else if (strcmp($1, "nobypassrls") == 0) + $$ = makeDefElem("bypassrls", (Node *)makeInteger(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 *)makeInteger(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); + } + ; + + +/***************************************************************************** + * + * Create a new Postgres DBMS user (role with implied login ability) + * + *****************************************************************************/ + +CreateUserStmt: + CREATE USER RoleId opt_with OptRoleList + { + CreateRoleStmt *n = makeNode(CreateRoleStmt); + n->stmt_type = ROLESTMT_USER; + n->role = $3; + n->options = $5; + $$ = (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; + } + ; + +opt_in_database: + /* EMPTY */ { $$ = NULL; } + | IN_P DATABASE 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 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 OptSchemaName 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 OptSchemaName 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; + } + ; + +OptSchemaName: + ColId { $$ = $1; } + | /* EMPTY */ { $$ = NULL; } + ; + +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 + ; + + +/***************************************************************************** + * + * 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 (meaning we reject anything that is a key 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.val.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 ] variations + * + * Note: we accept all subcommands for each of the five 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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 INDEX qualified_name alter_table_cmds + { + AlterTableStmt *n = makeNode(AlterTableStmt); + n->relation = $3; + n->cmds = $4; + n->relkind = 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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->relkind = 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_table_cmds: + alter_table_cmd { $$ = list_make1($1); } + | alter_table_cmds ',' alter_table_cmd { $$ = lappend($1, $3); } + ; + +partition_cmd: + /* ALTER TABLE ATTACH PARTITION 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; + n->def = (Node *) cmd; + + $$ = (Node *) n; + } + /* ALTER TABLE DETACH PARTITION */ + | DETACH PARTITION qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + PartitionCmd *cmd = makeNode(PartitionCmd); + + n->subtype = AT_DetachPartition; + cmd->name = $3; + cmd->bound = NULL; + n->def = (Node *) cmd; + + $$ = (Node *) n; + } + ; + +index_partition_cmd: + /* ALTER INDEX ATTACH PARTITION */ + ATTACH PARTITION qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + PartitionCmd *cmd = makeNode(PartitionCmd); + + n->subtype = AT_AttachPartition; + cmd->name = $3; + cmd->bound = NULL; + n->def = (Node *) cmd; + + $$ = (Node *) n; + } + ; + +alter_table_cmd: + /* ALTER TABLE ADD */ + ADD_P columnDef + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_AddColumn; + n->def = $2; + n->missing_ok = false; + $$ = (Node *)n; + } + /* ALTER TABLE ADD IF NOT EXISTS */ + | 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 ADD COLUMN */ + | ADD_P COLUMN columnDef + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_AddColumn; + n->def = $3; + n->missing_ok = false; + $$ = (Node *)n; + } + /* ALTER TABLE ADD COLUMN IF NOT EXISTS */ + | 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 ALTER [COLUMN] {SET DEFAULT |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 ALTER [COLUMN] 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 ALTER [COLUMN] 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 ALTER [COLUMN] DROP EXPRESSION */ + | ALTER opt_column ColId DROP EXPRESSION + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropExpression; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE ALTER [COLUMN] 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 ALTER [COLUMN] SET STATISTICS */ + | 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 ALTER [COLUMN] SET STATISTICS */ + | 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 ALTER [COLUMN] 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 ALTER [COLUMN] RESET ( column_parameter = value [, ... ] ) */ + | 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 ALTER [COLUMN] SET STORAGE */ + | ALTER opt_column ColId SET STORAGE ColId + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetStorage; + n->name = $3; + n->def = (Node *) makeString($6); + $$ = (Node *)n; + } + /* ALTER TABLE ALTER [COLUMN] 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 ALTER [COLUMN] SET /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 ALTER [COLUMN] 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 ALTER [COLUMN] 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 DROP [COLUMN] IF EXISTS [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 DROP [COLUMN] [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 ALTER [COLUMN] [SET DATA] TYPE + * [ USING ] + */ + | 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 ALTER [COLUMN] 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 ADD CONSTRAINT ... */ + | ADD_P TableConstraint + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_AddConstraint; + n->def = $2; + $$ = (Node *)n; + } + /* ALTER TABLE 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, "ALTER CONSTRAINT statement", + &c->deferrable, + &c->initdeferred, + NULL, NULL, yyscanner); + $$ = (Node *)n; + } + /* ALTER TABLE VALIDATE CONSTRAINT ... */ + | VALIDATE CONSTRAINT name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ValidateConstraint; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE DROP CONSTRAINT IF EXISTS [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 DROP CONSTRAINT [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 SET WITHOUT OIDS, for backward compat */ + | SET WITHOUT OIDS + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropOids; + $$ = (Node *)n; + } + /* ALTER TABLE CLUSTER ON */ + | CLUSTER ON name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ClusterOn; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE SET WITHOUT CLUSTER */ + | SET WITHOUT CLUSTER + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropCluster; + n->name = NULL; + $$ = (Node *)n; + } + /* ALTER TABLE SET LOGGED */ + | SET LOGGED + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetLogged; + $$ = (Node *)n; + } + /* ALTER TABLE SET UNLOGGED */ + | SET UNLOGGED + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetUnLogged; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE TRIGGER */ + | ENABLE_P TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableTrig; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE ALWAYS TRIGGER */ + | ENABLE_P ALWAYS TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableAlwaysTrig; + n->name = $4; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE REPLICA TRIGGER */ + | ENABLE_P REPLICA TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableReplicaTrig; + n->name = $4; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE TRIGGER ALL */ + | ENABLE_P TRIGGER ALL + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableTrigAll; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE TRIGGER USER */ + | ENABLE_P TRIGGER USER + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableTrigUser; + $$ = (Node *)n; + } + /* ALTER TABLE DISABLE TRIGGER */ + | DISABLE_P TRIGGER name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DisableTrig; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE DISABLE TRIGGER ALL */ + | DISABLE_P TRIGGER ALL + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DisableTrigAll; + $$ = (Node *)n; + } + /* ALTER TABLE DISABLE TRIGGER USER */ + | DISABLE_P TRIGGER USER + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DisableTrigUser; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE RULE */ + | ENABLE_P RULE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableRule; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE ALWAYS RULE */ + | ENABLE_P ALWAYS RULE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableAlwaysRule; + n->name = $4; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE REPLICA RULE */ + | ENABLE_P REPLICA RULE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableReplicaRule; + n->name = $4; + $$ = (Node *)n; + } + /* ALTER TABLE DISABLE RULE */ + | DISABLE_P RULE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DisableRule; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE INHERIT */ + | INHERIT qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_AddInherit; + n->def = (Node *) $2; + $$ = (Node *)n; + } + /* ALTER TABLE NO INHERIT */ + | NO INHERIT qualified_name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropInherit; + n->def = (Node *) $3; + $$ = (Node *)n; + } + /* ALTER TABLE OF */ + | 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 NOT OF */ + | NOT OF + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropOf; + $$ = (Node *)n; + } + /* ALTER TABLE OWNER TO RoleSpec */ + | OWNER TO RoleSpec + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ChangeOwner; + n->newowner = $3; + $$ = (Node *)n; + } + /* ALTER TABLE SET TABLESPACE */ + | SET TABLESPACE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetTableSpace; + n->name = $3; + $$ = (Node *)n; + } + /* ALTER TABLE SET (...) */ + | SET reloptions + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetRelOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } + /* ALTER TABLE RESET (...) */ + | RESET reloptions + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ResetRelOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } + /* ALTER TABLE REPLICA IDENTITY */ + | REPLICA IDENTITY_P replica_identity + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ReplicaIdentity; + n->def = $3; + $$ = (Node *)n; + } + /* ALTER TABLE ENABLE ROW LEVEL SECURITY */ + | ENABLE_P ROW LEVEL SECURITY + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_EnableRowSecurity; + $$ = (Node *)n; + } + /* ALTER TABLE DISABLE ROW LEVEL SECURITY */ + | DISABLE_P ROW LEVEL SECURITY + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DisableRowSecurity; + $$ = (Node *)n; + } + /* ALTER TABLE FORCE ROW LEVEL SECURITY */ + | FORCE ROW LEVEL SECURITY + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_ForceRowSecurity; + $$ = (Node *)n; + } + /* ALTER TABLE 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; + } + ; + +alter_column_default: + SET DEFAULT a_expr { $$ = $3; } + | DROP DEFAULT { $$ = NULL; } + ; + +opt_drop_behavior: + CASCADE { $$ = DROP_CASCADE; } + | RESTRICT { $$ = DROP_RESTRICT; } + | /* EMPTY */ { $$ = DROP_RESTRICT; /* default */ } + ; + +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 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->relkind = 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 ADD ATTRIBUTE [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 DROP ATTRIBUTE IF EXISTS [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 DROP ATTRIBUTE [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 ALTER ATTRIBUTE [SET DATA] TYPE [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 + * + *****************************************************************************/ + +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 copy_delimiter opt_with + copy_options where_clause + { + 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->whereClause = $11; + + if (n->is_program && n->filename == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("STDIN/STDOUT not allowed with PROGRAM"), + parser_errposition(@8))); + + if (!n->is_from && n->whereClause != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("WHERE clause not allowed with COPY TO"), + parser_errposition(@11))); + + n->options = NIL; + /* Concatenate user-supplied flags */ + if ($2) + n->options = lappend(n->options, $2); + if ($8) + n->options = lappend(n->options, $8); + if ($10) + n->options = list_concat(n->options, $10); + $$ = (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; + } + ; + +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; } + ; + +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 *)makeInteger(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 *)makeInteger(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); + } + ; + +/* 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 OptPartitionSpec table_access_method_clause OptWith + OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $4->relpersistence = $2; + n->relation = $4; + n->tableElts = $6; + n->inhRelations = $8; + n->partspec = $9; + n->ofTypename = NULL; + n->constraints = NIL; + n->accessMethod = $10; + n->options = $11; + n->oncommit = $12; + n->tablespacename = $13; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' + OptTableElementList ')' OptInherit OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $7->relpersistence = $2; + n->relation = $7; + n->tableElts = $9; + n->inhRelations = $11; + n->partspec = $12; + n->ofTypename = NULL; + n->constraints = NIL; + n->accessMethod = $13; + n->options = $14; + n->oncommit = $15; + n->tablespacename = $16; + n->if_not_exists = true; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE qualified_name OF any_name + OptTypedTableElementList OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $4->relpersistence = $2; + n->relation = $4; + n->tableElts = $7; + n->inhRelations = NIL; + n->partspec = $8; + 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; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name + OptTypedTableElementList OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $7->relpersistence = $2; + n->relation = $7; + n->tableElts = $10; + n->inhRelations = NIL; + n->partspec = $11; + 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; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name + OptTypedTableElementList PartitionBoundSpec OptPartitionSpec + table_access_method_clause OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $4->relpersistence = $2; + n->relation = $4; + n->tableElts = $8; + n->inhRelations = list_make1($7); + n->partbound = $9; + n->partspec = $10; + n->ofTypename = NULL; + n->constraints = NIL; + n->accessMethod = $11; + n->options = $12; + n->oncommit = $13; + n->tablespacename = $14; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF + qualified_name OptTypedTableElementList PartitionBoundSpec OptPartitionSpec + table_access_method_clause OptWith OnCommitOption OptTableSpace + { + CreateStmt *n = makeNode(CreateStmt); + $7->relpersistence = $2; + n->relation = $7; + n->tableElts = $11; + n->inhRelations = list_make1($10); + n->partbound = $12; + n->partspec = $13; + n->ofTypename = NULL; + n->constraints = NIL; + n->accessMethod = $14; + n->options = $15; + n->oncommit = $16; + n->tablespacename = $17; + n->if_not_exists = true; + $$ = (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; } + ; + +TypedTableElement: + columnOptions { $$ = $1; } + | TableConstraint { $$ = $1; } + ; + +columnDef: ColId Typename create_generic_options ColQualList + { + 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->collOid = InvalidOid; + n->fdwoptions = $3; + SplitColQualList($4, &n->constraints, &n->collClause, + yyscanner); + 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; + } + ; + +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; + } + ; + +/* 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_definition OptConsTableSpace + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = NULL; + n->options = $2; + n->indexname = NULL; + n->indexspace = $3; + $$ = (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 = (char) ($5 >> 8); + n->fk_del_action = (char) ($5 & 0xFF); + n->skip_validation = false; + n->initially_valid = true; + $$ = (Node *)n; + } + ; + +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; } + | 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 '(' columnList ')' opt_c_include opt_definition OptConsTableSpace + ConstraintAttributeSpec + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_UNIQUE; + n->location = @1; + n->keys = $3; + n->including = $5; + n->options = $6; + n->indexname = NULL; + n->indexspace = $7; + processCASbits($8, @8, "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 ExclusionWhereClause + 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 = (char) ($10 >> 8); + n->fk_del_action = (char) ($10 & 0xFF); + 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); + } + ; + +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); + } + ; + +ExclusionWhereClause: + WHERE '(' a_expr ')' { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + +/* + * We combine the update and delete actions into one value temporarily + * for simplicity of parsing, and then break them down again in the + * calling production. update is in the left 8 bits, delete in the right. + * Note that NOACTION is the default. + */ +key_actions: + key_update + { $$ = ($1 << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); } + | key_delete + { $$ = (FKCONSTR_ACTION_NOACTION << 8) | ($1 & 0xFF); } + | key_update key_delete + { $$ = ($1 << 8) | ($2 & 0xFF); } + | key_delete key_update + { $$ = ($2 << 8) | ($1 & 0xFF); } + | /*EMPTY*/ + { $$ = (FKCONSTR_ACTION_NOACTION << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); } + ; + +key_update: ON UPDATE key_action { $$ = $3; } + ; + +key_delete: ON DELETE_P key_action { $$ = $3; } + ; + +key_action: + NO ACTION { $$ = FKCONSTR_ACTION_NOACTION; } + | RESTRICT { $$ = FKCONSTR_ACTION_RESTRICT; } + | CASCADE { $$ = FKCONSTR_ACTION_CASCADE; } + | SET NULL_P { $$ = FKCONSTR_ACTION_SETNULL; } + | SET DEFAULT { $$ = FKCONSTR_ACTION_SETDEFAULT; } + ; + +OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } + | /*EMPTY*/ { $$ = NIL; } + ; + +/* Optional partition key specification */ +OptPartitionSpec: PartitionSpec { $$ = $1; } + | /*EMPTY*/ { $$ = NULL; } + ; + +PartitionSpec: PARTITION BY ColId '(' part_params ')' + { + PartitionSpec *n = makeNode(PartitionSpec); + + n->strategy = $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_class + { + 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_class + { + 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_class + { + 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 access_method { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; } + ; + +/* WITHOUT OIDS is legacy only */ +OptWith: + WITH reloptions { $$ = $2; } + | WITHOUT OIDS { $$ = NIL; } + | /*EMPTY*/ { $$ = NIL; } + ; + +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 index_name { $$ = $3; } + ; + +/***************************************************************************** + * + * 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. + * + *****************************************************************************/ + +CreateStatsStmt: + CREATE STATISTICS any_name + opt_name_list ON expr_list 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 expr_list 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; + } + ; + + +/***************************************************************************** + * + * QUERY : + * ALTER STATISTICS [IF EXISTS] stats_name + * SET STATISTICS + * + *****************************************************************************/ + +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 + { + CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); + ctas->query = $6; + ctas->into = $4; + ctas->relkind = OBJECT_TABLE; + ctas->is_select_into = false; + ctas->if_not_exists = false; + /* cram additional flags into the IntoClause */ + $4->rel->relpersistence = $2; + $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->relkind = 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 */ + } + ; + +opt_with_data: + WITH DATA_P { $$ = true; } + | WITH NO DATA_P { $$ = false; } + | /*EMPTY*/ { $$ = true; } + ; + + +/***************************************************************************** + * + * QUERY : + * CREATE MATERIALIZED VIEW relname AS SelectStmt + * + *****************************************************************************/ + +CreateMatViewStmt: + CREATE OptNoLog MATERIALIZED VIEW create_mv_target AS SelectStmt opt_with_data + { + CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); + ctas->query = $7; + ctas->into = $5; + ctas->relkind = 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); + $$ = (Node *) ctas; + } + | CREATE OptNoLog MATERIALIZED VIEW IF_P NOT EXISTS create_mv_target AS SelectStmt opt_with_data + { + CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); + ctas->query = $10; + ctas->into = $8; + ctas->relkind = OBJECT_MATVIEW; + ctas->is_select_into = false; + ctas->if_not_exists = true; + /* cram additional flags into the IntoClause */ + $8->rel->relpersistence = $2; + $8->skipData = !($11); + $$ = (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 */ + } + ; + +OptNoLog: UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; } + | /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; } + ; + + +/***************************************************************************** + * + * QUERY : + * REFRESH MATERIALIZED VIEW 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); + $$ = (Node *) n; + } + ; + + +/***************************************************************************** + * + * QUERY : + * CREATE SEQUENCE seqname + * ALTER SEQUENCE seqname + * + *****************************************************************************/ + +CreateSeqStmt: + CREATE OptTemp SEQUENCE qualified_name OptSeqOptList + { + CreateSeqStmt *n = makeNode(CreateSeqStmt); + $4->relpersistence = $2; + n->sequence = $4; + n->options = $5; + n->ownerId = InvalidOid; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList + { + CreateSeqStmt *n = makeNode(CreateSeqStmt); + $7->relpersistence = $2; + n->sequence = $7; + n->options = $8; + n->ownerId = InvalidOid; + n->if_not_exists = true; + $$ = (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 *)makeInteger(true), @1); + } + | NO CYCLE + { + $$ = makeDefElem("cycle", (Node *)makeInteger(false), @1); + } + | INCREMENT opt_by NumericOnly + { + $$ = makeDefElem("increment", (Node *)$3, @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 + { + /* not documented, only used by pg_dump */ + $$ = 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); + } + ; + +opt_by: BY {} + | /* empty */ {} + ; + +NumericOnly: + FCONST { $$ = makeFloat($1); } + | '+' FCONST { $$ = makeFloat($2); } + | '-' FCONST + { + $$ = makeFloat($2); + doNegateFloat($$); + } + | SignedIconst { $$ = 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 NonReservedWord_or_Sconst + { + /* + * 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 NonReservedWord_or_Sconst + 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; } + ; + +DropPLangStmt: + DROP opt_procedural LANGUAGE NonReservedWord_or_Sconst opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_LANGUAGE; + n->objects = list_make1(makeString($4)); + n->behavior = $5; + n->missing_ok = false; + n->concurrent = false; + $$ = (Node *)n; + } + | DROP opt_procedural LANGUAGE IF_P EXISTS NonReservedWord_or_Sconst opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_LANGUAGE; + n->objects = list_make1(makeString($6)); + n->behavior = $7; + n->missing_ok = true; + n->concurrent = false; + $$ = (Node *)n; + } + ; + +opt_procedural: + PROCEDURAL {} + | /*EMPTY*/ {} + ; + +/***************************************************************************** + * + * QUERY: + * CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/' + * + *****************************************************************************/ + +CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions + { + CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); + n->tablespacename = $3; + n->owner = $4; + n->location = $6; + n->options = $7; + $$ = (Node *) n; + } + ; + +OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; } + | /*EMPTY */ { $$ = NULL; } + ; + +/***************************************************************************** + * + * QUERY : + * DROP 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 *)makeInteger(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 ACCESS METHOD name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_ACCESS_METHOD; + n->object = (Node *) makeString($7); + $$ = (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 COLLATION any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_COLLATION; + n->object = (Node *) $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop CONVERSION_P any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_CONVERSION; + n->object = (Node *) $6; + $$ = (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 opt_procedural LANGUAGE name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_LANGUAGE; + n->object = (Node *) makeString($7); + $$ = (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 access_method + { + 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 access_method + { + 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 SCHEMA name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_SCHEMA; + n->object = (Node *) makeString($6); + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop EVENT TRIGGER name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_EVENT_TRIGGER; + n->object = (Node *) makeString($7); + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop TABLE any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_TABLE; + n->object = (Node *) $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop TEXT_P SEARCH PARSER any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_TSPARSER; + n->object = (Node *) $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop TEXT_P SEARCH DICTIONARY any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_TSDICTIONARY; + n->object = (Node *) $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop TEXT_P SEARCH TEMPLATE any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_TSTEMPLATE; + n->object = (Node *) $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop TEXT_P SEARCH CONFIGURATION any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_TSCONFIGURATION; + n->object = (Node *) $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop SEQUENCE any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_SEQUENCE; + n->object = (Node *) $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop VIEW any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_VIEW; + n->object = (Node *) $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop MATERIALIZED VIEW any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_MATVIEW; + n->object = (Node *) $7; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop FOREIGN TABLE any_name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_FOREIGN_TABLE; + n->object = (Node *) $7; + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop FOREIGN DATA_P WRAPPER name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_FDW; + n->object = (Node *) makeString($8); + $$ = (Node *)n; + } + | ALTER EXTENSION name add_drop SERVER name + { + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); + n->extname = $3; + n->action = $4; + n->objtype = OBJECT_FOREIGN_SERVER; + n->object = (Node *) makeString($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 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 FOREIGN TABLE relname (...) SERVER name (...) + * + *****************************************************************************/ + +CreateForeignTableStmt: + CREATE FOREIGN TABLE qualified_name + '(' OptTableElementList ')' + OptInherit SERVER name create_generic_options + { + 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; + $$ = (Node *) n; + } + | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name + '(' OptTableElementList ')' + OptInherit SERVER name create_generic_options + { + 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; + $$ = (Node *) n; + } + | CREATE FOREIGN TABLE qualified_name + PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec + SERVER name create_generic_options + { + 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; + $$ = (Node *) n; + } + | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name + PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec + SERVER name create_generic_options + { + 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; + $$ = (Node *) n; + } + ; + +/***************************************************************************** + * + * QUERY: + * ALTER FOREIGN TABLE relname [...] + * + *****************************************************************************/ + +AlterForeignTableStmt: + ALTER FOREIGN TABLE relation_expr alter_table_cmds + { + AlterTableStmt *n = makeNode(AlterTableStmt); + n->relation = $4; + n->cmds = $5; + n->relkind = 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->relkind = OBJECT_FOREIGN_TABLE; + n->missing_ok = true; + $$ = (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: + * 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; + } + ; + +/***************************************************************************** + * + * 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 TRIGGER name TriggerActionTime TriggerEvents ON + qualified_name TriggerReferencing TriggerForSpec TriggerWhen + EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')' + { + CreateTrigStmt *n = makeNode(CreateTrigStmt); + n->trigname = $3; + n->relation = $7; + n->funcname = $13; + n->args = $15; + n->row = $9; + n->timing = $4; + n->events = intVal(linitial($5)); + n->columns = (List *) lsecond($5); + n->whenClause = $10; + n->transitionRels = $8; + n->isconstraint = false; + n->deferrable = false; + n->initdeferred = false; + n->constrrel = NULL; + $$ = (Node *)n; + } + | CREATE 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->trigname = $4; + n->relation = $8; + n->funcname = $17; + n->args = $19; + n->row = true; + n->timing = TRIGGER_TYPE_AFTER; + n->events = intVal(linitial($6)); + n->columns = (List *) lsecond($6); + n->whenClause = $14; + n->transitionRels = NIL; + n->isconstraint = true; + processCASbits($10, @10, "TRIGGER", + &n->deferrable, &n->initdeferred, NULL, + NULL, yyscanner); + n->constrrel = $9; + $$ = (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 */ + { + /* + * If ROW/STATEMENT not specified, default to + * STATEMENT, per SQL + */ + $$ = false; + } + ; + +TriggerForOptEach: + EACH {} + | /*EMPTY*/ {} + ; + +TriggerForType: + ROW { $$ = true; } + | STATEMENT { $$ = 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 + { + $$ = makeString(psprintf("%d", $1)); + } + | FCONST { $$ = makeString($1); } + | Sconst { $$ = makeString($1); } + | ColLabel { $$ = 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 AGGREGATE func_name aggr_args definition + { + DefineStmt *n = makeNode(DefineStmt); + n->kind = OBJECT_AGGREGATE; + n->oldstyle = false; + n->replace = $2; + n->defnames = $4; + n->args = $5; + n->definition = $6; + $$ = (Node *)n; + } + | CREATE opt_or_replace 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 = $4; + n->args = NIL; + n->definition = $5; + $$ = (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 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; + } + ; + +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; } + | 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 access_method 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 access_method + { + CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt); + n->opfamilyname = $4; + n->amname = $6; + $$ = (Node *) n; + } + ; + +AlterOpFamilyStmt: + ALTER OPERATOR FAMILY any_name USING access_method 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 access_method 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 access_method 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; + $$ = (Node *) n; + } + | DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method 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; + $$ = (Node *) n; + } + ; + +DropOpFamilyStmt: + DROP OPERATOR FAMILY any_name USING access_method 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; + $$ = (Node *) n; + } + | DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method 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; + $$ = (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 drop_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; + $$ = (Node *)n; + } + | DROP drop_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; + $$ = (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; + $$ = (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; + $$ = (Node *)n; + } + | DROP drop_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; + $$ = (Node *) n; + } + | DROP drop_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; + $$ = (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; + $$ = (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; + $$ = (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; + $$ = (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; + $$ = (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; + $$ = (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; + $$ = (Node *)n; + } + ; + +/* object types taking any_name_list */ +drop_type_any_name: + TABLE { $$ = OBJECT_TABLE; } + | SEQUENCE { $$ = OBJECT_SEQUENCE; } + | VIEW { $$ = OBJECT_VIEW; } + | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } + | INDEX { $$ = OBJECT_INDEX; } + | FOREIGN 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_list */ +drop_type_name: + ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; } + | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } + | EXTENSION { $$ = OBJECT_EXTENSION; } + | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; } + | PUBLICATION { $$ = OBJECT_PUBLICATION; } + | SCHEMA { $$ = OBJECT_SCHEMA; } + | SERVER { $$ = OBJECT_FOREIGN_SERVER; } + ; + +/* object types attached to a table */ +drop_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; } + ; + +/***************************************************************************** + * + * The COMMENT ON statement can take different forms based upon the type of + * the object associated with the comment. The form of the statement is: + * + * COMMENT ON [ [ ACCESS METHOD | CONVERSION | COLLATION | + * DATABASE | DOMAIN | + * EXTENSION | EVENT TRIGGER | FOREIGN DATA WRAPPER | + * FOREIGN TABLE | INDEX | [PROCEDURAL] LANGUAGE | + * MATERIALIZED VIEW | POLICY | ROLE | SCHEMA | SEQUENCE | + * SERVER | STATISTICS | TABLE | TABLESPACE | + * TEXT SEARCH CONFIGURATION | TEXT SEARCH DICTIONARY | + * TEXT SEARCH PARSER | TEXT SEARCH TEMPLATE | TYPE | + * VIEW] | + * AGGREGATE (arg1, ...) | + * CAST ( AS ) | + * COLUMN . | + * CONSTRAINT ON | + * CONSTRAINT ON DOMAIN | + * FUNCTION (arg1, arg2, ...) | + * LARGE OBJECT | + * OPERATOR (leftoperand_typ, rightoperand_typ) | + * OPERATOR CLASS USING | + * OPERATOR FAMILY USING | + * RULE ON | + * TRIGGER ON ] + * IS { 'text' | NULL } + * + *****************************************************************************/ + +CommentStmt: + COMMENT ON comment_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 comment_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 POLICY name ON any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_POLICY; + 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 RULE name ON any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_RULE; + n->object = (Node *) lappend($6, makeString($4)); + n->comment = $8; + $$ = (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 TRIGGER name ON any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_TRIGGER; + n->object = (Node *) lappend($6, makeString($4)); + n->comment = $8; + $$ = (Node *) n; + } + | COMMENT ON OPERATOR CLASS any_name USING access_method 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 access_method 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; + } + ; + +/* object types taking any_name */ +comment_type_any_name: + COLUMN { $$ = OBJECT_COLUMN; } + | INDEX { $$ = OBJECT_INDEX; } + | SEQUENCE { $$ = OBJECT_SEQUENCE; } + | STATISTICS { $$ = OBJECT_STATISTIC_EXT; } + | TABLE { $$ = OBJECT_TABLE; } + | VIEW { $$ = OBJECT_VIEW; } + | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; } + | COLLATION { $$ = OBJECT_COLLATION; } + | CONVERSION_P { $$ = OBJECT_CONVERSION; } + | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } + | TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; } + | TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; } + | TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; } + | TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; } + ; + +/* object types taking name */ +comment_type_name: + ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; } + | DATABASE { $$ = OBJECT_DATABASE; } + | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } + | EXTENSION { $$ = OBJECT_EXTENSION; } + | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; } + | opt_procedural LANGUAGE { $$ = OBJECT_LANGUAGE; } + | PUBLICATION { $$ = OBJECT_PUBLICATION; } + | ROLE { $$ = OBJECT_ROLE; } + | SCHEMA { $$ = OBJECT_SCHEMA; } + | SERVER { $$ = OBJECT_FOREIGN_SERVER; } + | SUBSCRIPTION { $$ = OBJECT_SUBSCRIPTION; } + | TABLESPACE { $$ = OBJECT_TABLESPACE; } + ; + +comment_text: + Sconst { $$ = $1; } + | NULL_P { $$ = NULL; } + ; + + +/***************************************************************************** + * + * SECURITY LABEL [FOR ] ON IS