summaryrefslogtreecommitdiffstats
path: root/src/backend/parser/gram.y
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/backend/parser/gram.y17264
1 files changed, 17264 insertions, 0 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 0000000..fe2af56
--- /dev/null
+++ b/src/backend/parser/gram.y
@@ -0,0 +1,17264 @@
+%{
+
+/*#define YYDEBUG 1*/
+/*-------------------------------------------------------------------------
+ *
+ * gram.y
+ * POSTGRESQL BISON rules/actions
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/parser/gram.y
+ *
+ * HISTORY
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Sept, 1994 POSTQUEL to SQL conversion
+ * Andrew Yu Oct, 1994 lispy code conversion
+ *
+ * NOTES
+ * CAPITALS are used to represent terminal symbols.
+ * non-capitals are used to represent non-terminals.
+ *
+ * In general, nothing in this file should initiate database accesses
+ * nor depend on changeable state (such as SET variables). If you do
+ * database accesses, your code will fail when we have aborted the
+ * current transaction and are just parsing commands to find the next
+ * ROLLBACK or COMMIT. If you make use of SET variables, then you
+ * will do the wrong thing in multi-query strings like this:
+ * SET constraint_exclusion TO off; SELECT * FROM foo;
+ * because the entire string is parsed by gram.y before the SET gets
+ * executed. Anything that depends on the database or changeable state
+ * should be handled during parse analysis so that it happens at the
+ * right time not the wrong time.
+ *
+ * WARNINGS
+ * If you use a list, make sure the datum is a node so that the printing
+ * routines work.
+ *
+ * Sometimes we assign constants to makeStrings. Make sure we don't free
+ * those.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "access/tableam.h"
+#include "catalog/index.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_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 "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;
+
+/* Private struct for the result of group_clause production */
+typedef struct GroupClause
+{
+ bool distinct;
+ List *list;
+} GroupClause;
+
+/* 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;
+ StatsElem *selem;
+ Alias *alias;
+ RangeVar *range;
+ IntoClause *into;
+ WithClause *with;
+ InferClause *infer;
+ OnConflictClause *onconflict;
+ A_Indices *aind;
+ ResTarget *target;
+ struct PrivTarget *privtarget;
+ AccessPriv *accesspriv;
+ struct ImportQual *importqual;
+ InsertStmt *istmt;
+ VariableSetStmt *vsetstmt;
+ PartitionElem *partelem;
+ PartitionSpec *partspec;
+ PartitionBoundSpec *partboundspec;
+ RoleSpec *rolespec;
+ struct SelectLimit *selectlimit;
+ SetQuantifier setquantifier;
+ struct GroupClause *groupclause;
+}
+
+%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
+ AlterEventTrigStmt AlterCollationStmt
+ AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
+ AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
+ AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
+ AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
+ AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt
+ 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 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 ReturnStmt RevokeStmt RevokeRoleStmt
+ RuleActionStmt RuleActionStmtOrEmpty RuleStmt
+ SecLabelStmt SelectStmt TransactionStmt TransactionStmtLegacy TruncateStmt
+ UnlistenStmt UpdateStmt VacuumStmt
+ VariableResetStmt VariableSetStmt VariableShowStmt
+ ViewStmt CheckPointStmt CreateConversionStmt
+ DeallocateStmt PrepareStmt ExecuteStmt
+ DropOwnedStmt ReassignOwnedStmt
+ AlterTSConfigurationStmt AlterTSDictionaryStmt
+ CreateMatViewStmt RefreshMatViewStmt CreateAmStmt
+ CreatePublicationStmt AlterPublicationStmt
+ CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt
+
+%type <node> select_no_parens select_with_parens select_clause
+ simple_select values_clause
+ PLpgSQL_Expr PLAssignStmt
+
+%type <node> alter_column_default opclass_item opclass_drop alter_using
+%type <ival> add_drop opt_asc_desc opt_nulls_order
+
+%type <node> alter_table_cmd alter_type_cmd opt_collate_clause
+ replica_identity partition_cmd index_partition_cmd
+%type <list> alter_table_cmds alter_type_cmds
+%type <list> alter_identity_column_option_list
+%type <defelt> alter_identity_column_option
+
+%type <dbehavior> opt_drop_behavior
+
+%type <list> createdb_opt_list createdb_opt_items copy_opt_list
+ transaction_mode_list
+ create_extension_opt_list alter_extension_opt_list
+%type <defelt> createdb_opt_item copy_opt_item
+ transaction_mode_item
+ create_extension_opt_item alter_extension_opt_item
+
+%type <ival> opt_lock lock_type cast_context
+%type <str> utility_option_name
+%type <defelt> utility_option_elem
+%type <list> utility_option_list
+%type <node> utility_option_arg
+%type <defelt> drop_option
+%type <boolean> opt_or_replace opt_no
+ opt_grant_grant_option opt_grant_admin_option
+ opt_nowait opt_if_exists opt_with_data
+ opt_transaction_chain
+%type <ival> opt_nowait_or_skip
+
+%type <list> OptRoleList AlterOptRoleList
+%type <defelt> CreateOptRoleElem AlterOptRoleElem
+
+%type <str> opt_type
+%type <str> foreign_server_version opt_foreign_server_version
+%type <str> opt_in_database
+
+%type <str> OptSchemaName
+%type <list> OptSchemaEltList
+
+%type <chr> am_type
+
+%type <boolean> TriggerForSpec TriggerForType
+%type <ival> TriggerActionTime
+%type <list> TriggerEvents TriggerOneEvent
+%type <value> TriggerFuncArg
+%type <node> TriggerWhen
+%type <str> TransitionRelName
+%type <boolean> TransitionRowOrTable TransitionOldOrNew
+%type <node> TriggerTransition
+
+%type <list> event_trigger_when_list event_trigger_value_list
+%type <defelt> event_trigger_when_item
+%type <chr> enable_trigger
+
+%type <str> copy_file_name
+ access_method_clause attr_name
+ table_access_method_clause name cursor_name file_name
+ opt_index_name cluster_index_specification
+
+%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
+ opt_class opt_inline_handler opt_validator validator_clause
+ opt_collate
+
+%type <range> qualified_name insert_target OptConstrFromTable
+
+%type <str> all_Op MathOp
+
+%type <str> row_security_cmd RowSecurityDefaultForCmd
+%type <boolean> RowSecurityDefaultPermissive
+%type <node> RowSecurityOptionalWithCheck RowSecurityOptionalExpr
+%type <list> RowSecurityDefaultToRole RowSecurityOptionalToRole
+
+%type <str> iso_level opt_encoding
+%type <rolespec> grantee
+%type <list> grantee_list
+%type <accesspriv> privilege
+%type <list> privileges privilege_list
+%type <privtarget> privilege_target
+%type <objwithargs> function_with_argtypes aggregate_with_argtypes operator_with_argtypes
+%type <list> function_with_argtypes_list aggregate_with_argtypes_list operator_with_argtypes_list
+%type <ival> defacl_privilege_target
+%type <defelt> DefACLOption
+%type <list> DefACLOptionList
+%type <ival> import_qualification_type
+%type <importqual> import_qualification
+%type <node> vacuum_relation
+%type <selectlimit> opt_select_limit select_limit limit_clause
+
+%type <list> parse_toplevel stmtmulti routine_body_stmt_list
+ OptTableElementList TableElementList OptInherit definition
+ OptTypedTableElementList TypedTableElementList
+ reloptions opt_reloptions
+ OptWith opt_definition func_args func_args_list
+ func_args_with_defaults func_args_with_defaults_list
+ aggr_args aggr_args_list
+ func_as createfunc_opt_list opt_createfunc_opt_list alterfunc_opt_list
+ old_aggr_definition old_aggr_list
+ oper_argtypes RuleActionList RuleActionMulti
+ opt_column_list columnList opt_name_list
+ sort_clause opt_sort_clause sortby_list index_params stats_params
+ opt_include opt_c_include index_including_params
+ name_list role_list from_clause from_list opt_array_bounds
+ qualified_name_list any_name any_name_list type_name_list
+ any_operator expr_list attrs
+ distinct_clause opt_distinct_clause
+ target_list opt_target_list insert_column_list set_target_list
+ set_clause_list set_clause
+ def_list operator_def_list indirection opt_indirection
+ reloption_list TriggerFuncArgs opclass_item_list opclass_drop_list
+ opclass_purpose opt_opfamily transaction_mode_list_or_empty
+ OptTableFuncElementList TableFuncElementList opt_type_modifiers
+ prep_type_clause
+ execute_param_clause using_clause returning_clause
+ opt_enum_val_list enum_val_list table_func_column_list
+ create_generic_options alter_generic_options
+ relation_expr_list dostmt_opt_list
+ transform_element_list transform_type_list
+ TriggerTransitions TriggerReferencing
+ vacuum_relation_list opt_vacuum_relation_list
+ drop_option_list
+
+%type <node> opt_routine_body
+%type <groupclause> group_clause
+%type <list> group_by_list
+%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
+%type <node> grouping_sets_clause
+%type <node> opt_publication_for_tables publication_for_tables
+
+%type <list> opt_fdw_options fdw_options
+%type <defelt> fdw_option
+
+%type <range> OptTempTableName
+%type <into> into_clause create_as_target create_mv_target
+
+%type <defelt> createfunc_opt_item common_func_opt_item dostmt_opt_item
+%type <fun_param> func_arg func_arg_with_default table_func_column aggr_arg
+%type <fun_param_mode> arg_class
+%type <typnam> func_return func_type
+
+%type <boolean> opt_trusted opt_restart_seqs
+%type <ival> OptTemp
+%type <ival> OptNoLog
+%type <oncommit> OnCommitOption
+
+%type <ival> for_locking_strength
+%type <node> for_locking_item
+%type <list> for_locking_clause opt_for_locking_clause for_locking_items
+%type <list> locked_rels_list
+%type <setquantifier> set_quantifier
+
+%type <node> join_qual
+%type <jtype> join_type
+
+%type <list> extract_list overlay_list position_list
+%type <list> substr_list trim_list
+%type <list> opt_interval interval_second
+%type <str> unicode_normal_form
+
+%type <boolean> opt_instead
+%type <boolean> opt_unique opt_concurrently opt_verbose opt_full
+%type <boolean> opt_freeze opt_analyze opt_default opt_recheck
+%type <defelt> opt_binary copy_delimiter
+
+%type <boolean> copy_from opt_program
+
+%type <ival> event cursor_options opt_hold opt_set_data
+%type <objtype> object_type_any_name object_type_name object_type_name_on_any_name
+ drop_type_name
+
+%type <node> fetch_args select_limit_value
+ offset_clause select_offset_value
+ select_fetch_first_value I_or_F_const
+%type <ival> row_or_rows first_or_next
+
+%type <list> OptSeqOptList SeqOptList OptParenthesizedSeqOptList
+%type <defelt> SeqOptElem
+
+%type <istmt> insert_rest
+%type <infer> opt_conf_expr
+%type <onconflict> opt_on_conflict
+
+%type <vsetstmt> generic_set set_rest set_rest_more generic_reset reset_rest
+ SetResetClause FunctionSetResetClause
+
+%type <node> TableElement TypedTableElement ConstraintElem TableFuncElement
+%type <node> columnDef columnOptions
+%type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem
+%type <node> def_arg columnElem where_clause where_or_current_clause
+ a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound
+ columnref in_expr having_clause func_table xmltable array_expr
+ OptWhereClause operator_def_arg
+%type <list> rowsfrom_item rowsfrom_list opt_col_def_list
+%type <boolean> opt_ordinality
+%type <list> ExclusionConstraintList ExclusionConstraintElem
+%type <list> func_arg_list func_arg_list_opt
+%type <node> func_arg_expr
+%type <list> row explicit_row implicit_row type_list array_expr_list
+%type <node> case_expr case_arg when_clause case_default
+%type <list> when_clause_list
+%type <node> opt_search_clause opt_cycle_clause
+%type <ival> sub_type opt_materialized
+%type <value> NumericOnly
+%type <list> NumericOnly_list
+%type <alias> alias_clause opt_alias_clause opt_alias_clause_for_join_using
+%type <list> func_alias_clause
+%type <sortby> sortby
+%type <ielem> index_elem index_elem_options
+%type <selem> stats_param
+%type <node> table_ref
+%type <jexpr> joined_table
+%type <range> relation_expr
+%type <range> relation_expr_opt_alias
+%type <node> tablesample_clause opt_repeatable_clause
+%type <target> target_el set_target insert_column_item
+
+%type <str> generic_option_name
+%type <node> generic_option_arg
+%type <defelt> generic_option_elem alter_generic_option_elem
+%type <list> generic_option_list alter_generic_option_list
+
+%type <ival> reindex_target_type reindex_target_multitable
+
+%type <node> copy_generic_opt_arg copy_generic_opt_arg_list_item
+%type <defelt> copy_generic_opt_elem
+%type <list> copy_generic_opt_list copy_generic_opt_arg_list
+%type <list> copy_options
+
+%type <typnam> Typename SimpleTypename ConstTypename
+ GenericType Numeric opt_float
+ Character ConstCharacter
+ CharacterWithLength CharacterWithoutLength
+ ConstDatetime ConstInterval
+ Bit ConstBit BitWithLength BitWithoutLength
+%type <str> character
+%type <str> extract_arg
+%type <boolean> opt_varying opt_timezone opt_no_inherit
+
+%type <ival> Iconst SignedIconst
+%type <str> Sconst comment_text notify_payload
+%type <str> RoleId opt_boolean_or_string
+%type <list> var_list
+%type <str> ColId ColLabel BareColLabel
+%type <str> NonReservedWord NonReservedWord_or_Sconst
+%type <str> var_name type_function_name param_name
+%type <str> createdb_opt_name plassign_target
+%type <node> var_value zone_value
+%type <rolespec> auth_ident RoleSpec opt_granted_by
+
+%type <keyword> unreserved_keyword type_func_name_keyword
+%type <keyword> col_name_keyword reserved_keyword
+%type <keyword> bare_label_keyword
+
+%type <node> TableConstraint TableLikeClause
+%type <ival> TableLikeOptionList TableLikeOption
+%type <str> column_compression opt_column_compression
+%type <list> ColQualList
+%type <node> ColConstraint ColConstraintElem ConstraintAttr
+%type <ival> key_actions key_delete key_match key_update key_action
+%type <ival> ConstraintAttributeSpec ConstraintAttributeElem
+%type <str> ExistingIndex
+
+%type <list> constraints_set_list
+%type <boolean> constraints_set_mode
+%type <str> OptTableSpace OptConsTableSpace
+%type <rolespec> OptTableSpaceOwner
+%type <ival> opt_check_option
+
+%type <str> opt_provider security_label
+
+%type <target> xml_attribute_el
+%type <list> xml_attribute_list xml_attributes
+%type <node> xml_root_version opt_xml_root_standalone
+%type <node> xmlexists_argument
+%type <ival> document_or_content
+%type <boolean> xml_whitespace_option
+%type <list> xmltable_column_list xmltable_column_option_list
+%type <node> xmltable_column_el
+%type <defelt> xmltable_column_option_el
+%type <list> xml_namespace_list
+%type <target> xml_namespace_el
+
+%type <node> func_application func_expr_common_subexpr
+%type <node> func_expr func_expr_windowless
+%type <node> common_table_expr
+%type <with> with_clause opt_with_clause
+%type <list> cte_list
+
+%type <list> within_group_clause
+%type <node> filter_clause
+%type <list> window_clause window_definition_list opt_partition_clause
+%type <windef> window_definition over_clause window_specification
+ opt_frame_clause frame_extent frame_bound
+%type <ival> opt_window_exclusion_clause
+%type <str> opt_existing_window_name
+%type <boolean> opt_if_not_exists
+%type <ival> generated_when override_kind
+%type <partspec> PartitionSpec OptPartitionSpec
+%type <partelem> part_elem
+%type <list> part_params
+%type <partboundspec> PartitionBoundSpec
+%type <list> hash_partbound
+%type <defelt> 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 <str> IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op
+%token <ival> ICONST PARAM
+%token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER
+%token LESS_EQUALS GREATER_EQUALS NOT_EQUALS
+
+/*
+ * If you want to make any keyword changes, update the keyword table in
+ * src/include/parser/kwlist.h and add new keywords to the appropriate one
+ * of the reserved-or-not-so-reserved keyword lists, below; search
+ * this file for "Keyword category lists".
+ */
+
+/* ordinary key words in alphabetical order */
+%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
+ AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
+ ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION
+
+ BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
+ BOOLEAN_P BOTH BREADTH BY
+
+ CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
+ CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
+ CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT
+ COMMITTED COMPRESSION CONCURRENTLY CONFIGURATION CONFLICT
+ CONNECTION CONSTRAINT CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY
+ COST CREATE CROSS CSV CUBE CURRENT_P
+ CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA
+ CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
+
+ DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
+ DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC
+ DETACH DICTIONARY 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 FINALIZE 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 RETURN 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
+
+/*
+ * The grammar likewise thinks these tokens are keywords, but they are never
+ * generated by the scanner. Rather, they can be injected by parser.c as
+ * the initial token of the string (using the lookahead-token mechanism
+ * implemented there). This provides a way to tell the grammar to parse
+ * something other than the usual list of SQL commands.
+ */
+%token MODE_TYPE_NAME
+%token MODE_PLPGSQL_EXPR
+%token MODE_PLPGSQL_ASSIGN1
+%token MODE_PLPGSQL_ASSIGN2
+%token MODE_PLPGSQL_ASSIGN3
+
+
+/* Precedence: lowest to highest */
+%nonassoc SET /* see relation_expr_opt_alias */
+%left UNION EXCEPT
+%left INTERSECT
+%left OR
+%left AND
+%right NOT
+%nonassoc IS ISNULL NOTNULL /* IS sets precedence for IS NULL, etc */
+%nonassoc '<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
+%nonassoc BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
+%nonassoc ESCAPE /* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
+/*
+ * To support target_el without AS, it used to be necessary to assign IDENT an
+ * explicit precedence just less than Op. While that's not really necessary
+ * since we removed postfix operators, it's still helpful to do so because
+ * there are some other unreserved keywords that need precedence assignments.
+ * If those keywords have the same precedence as IDENT then they clearly act
+ * the same as non-keywords, reducing the risk of unwanted precedence effects.
+ *
+ * We need to do this for PARTITION, RANGE, ROWS, and GROUPS to support
+ * opt_existing_window_name (see comment there).
+ *
+ * The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
+ * are even messier: since UNBOUNDED is an unreserved keyword (per spec!),
+ * there is no principled way to distinguish these from the productions
+ * a_expr PRECEDING/FOLLOWING. We hack this up by giving UNBOUNDED slightly
+ * lower precedence than PRECEDING and FOLLOWING. At present this doesn't
+ * appear to cause UNBOUNDED to be treated differently from other unreserved
+ * keywords anywhere else in the grammar, but it's definitely risky. We can
+ * blame any funny behavior of UNBOUNDED on the SQL standard, though.
+ *
+ * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
+ * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
+ * rather than reducing a conflicting rule that takes CUBE as a function name.
+ * Using the same precedence as IDENT seems right for the reasons given above.
+ */
+%nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */
+%nonassoc IDENT 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
+
+%%
+
+/*
+ * The target production for the whole parse.
+ *
+ * Ordinarily we parse a list of statements, but if we see one of the
+ * special MODE_XXX symbols as first token, we parse something else.
+ * The options here correspond to enum RawParseMode, which see for details.
+ */
+parse_toplevel:
+ stmtmulti
+ {
+ pg_yyget_extra(yyscanner)->parsetree = $1;
+ }
+ | MODE_TYPE_NAME Typename
+ {
+ pg_yyget_extra(yyscanner)->parsetree = list_make1($2);
+ }
+ | MODE_PLPGSQL_EXPR PLpgSQL_Expr
+ {
+ pg_yyget_extra(yyscanner)->parsetree =
+ list_make1(makeRawStmt($2, 0));
+ }
+ | MODE_PLPGSQL_ASSIGN1 PLAssignStmt
+ {
+ PLAssignStmt *n = (PLAssignStmt *) $2;
+ n->nnames = 1;
+ pg_yyget_extra(yyscanner)->parsetree =
+ list_make1(makeRawStmt((Node *) n, 0));
+ }
+ | MODE_PLPGSQL_ASSIGN2 PLAssignStmt
+ {
+ PLAssignStmt *n = (PLAssignStmt *) $2;
+ n->nnames = 2;
+ pg_yyget_extra(yyscanner)->parsetree =
+ list_make1(makeRawStmt((Node *) n, 0));
+ }
+ | MODE_PLPGSQL_ASSIGN3 PLAssignStmt
+ {
+ PLAssignStmt *n = (PLAssignStmt *) $2;
+ n->nnames = 3;
+ pg_yyget_extra(yyscanner)->parsetree =
+ list_make1(makeRawStmt((Node *) n, 0));
+ }
+ ;
+
+/*
+ * At top level, we wrap each stmt with a RawStmt node carrying start location
+ * and length of the stmt's text. Notice that the start loc/len are driven
+ * entirely from semicolon locations (@2). It would seem natural to use
+ * @1 or @3 to get the true start location of a stmt, but that doesn't work
+ * for statements that can start with empty nonterminals (opt_with_clause is
+ * the main offender here); as noted in the comments for YYLLOC_DEFAULT,
+ * we'd get -1 for the location in such cases.
+ * We also take care to discard empty statements entirely.
+ */
+stmtmulti: stmtmulti ';' toplevel_stmt
+ {
+ if ($1 != NIL)
+ {
+ /* update length of previous stmt */
+ updateRawStmtEnd(llast_node(RawStmt, $1), @2);
+ }
+ if ($3 != NULL)
+ $$ = lappend($1, makeRawStmt($3, @2 + 1));
+ else
+ $$ = $1;
+ }
+ | toplevel_stmt
+ {
+ if ($1 != NULL)
+ $$ = list_make1(makeRawStmt($1, 0));
+ else
+ $$ = NIL;
+ }
+ ;
+
+/*
+ * toplevel_stmt includes BEGIN and END. stmt does not include them, because
+ * those words have different meanings in function bodys.
+ */
+toplevel_stmt:
+ stmt
+ | TransactionStmtLegacy
+ ;
+
+stmt:
+ AlterEventTrigStmt
+ | AlterCollationStmt
+ | AlterDatabaseStmt
+ | AlterDatabaseSetStmt
+ | AlterDefaultPrivilegesStmt
+ | AlterDomainStmt
+ | AlterEnumStmt
+ | AlterExtensionStmt
+ | AlterExtensionContentsStmt
+ | AlterFdwStmt
+ | AlterForeignServerStmt
+ | 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
+ | 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 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 | FOREIGN TABLE ] variations
+ *
+ * Note: we accept all subcommands for each of the variants, and sort
+ * out what's really legal at execution time.
+ *****************************************************************************/
+
+AlterTableStmt:
+ ALTER TABLE relation_expr alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = $4;
+ n->objtype = OBJECT_TABLE;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $5;
+ n->cmds = $6;
+ n->objtype = OBJECT_TABLE;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr partition_cmd
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = list_make1($4);
+ n->objtype = OBJECT_TABLE;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr partition_cmd
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $5;
+ n->cmds = list_make1($6);
+ n->objtype = OBJECT_TABLE;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $6;
+ n->objtype = OBJECT_TABLE;
+ n->roles = NIL;
+ n->new_tablespacename = $9;
+ n->nowait = $10;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $6;
+ n->objtype = OBJECT_TABLE;
+ n->roles = $9;
+ n->new_tablespacename = $12;
+ n->nowait = $13;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = $4;
+ n->objtype = OBJECT_INDEX;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX IF_P EXISTS qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $5;
+ n->cmds = $6;
+ n->objtype = OBJECT_INDEX;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX qualified_name index_partition_cmd
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = list_make1($4);
+ n->objtype = OBJECT_INDEX;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $6;
+ n->objtype = OBJECT_INDEX;
+ n->roles = NIL;
+ n->new_tablespacename = $9;
+ n->nowait = $10;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $6;
+ n->objtype = OBJECT_INDEX;
+ n->roles = $9;
+ n->new_tablespacename = $12;
+ n->nowait = $13;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = $4;
+ n->objtype = OBJECT_SEQUENCE;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE IF_P EXISTS qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $5;
+ n->cmds = $6;
+ n->objtype = OBJECT_SEQUENCE;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $3;
+ n->cmds = $4;
+ n->objtype = OBJECT_VIEW;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW IF_P EXISTS qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $5;
+ n->cmds = $6;
+ n->objtype = OBJECT_VIEW;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $4;
+ n->cmds = $5;
+ n->objtype = OBJECT_MATVIEW;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $6;
+ n->cmds = $7;
+ n->objtype = OBJECT_MATVIEW;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $7;
+ n->objtype = OBJECT_MATVIEW;
+ n->roles = NIL;
+ n->new_tablespacename = $10;
+ n->nowait = $11;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait
+ {
+ AlterTableMoveAllStmt *n =
+ makeNode(AlterTableMoveAllStmt);
+ n->orig_tablespacename = $7;
+ n->objtype = OBJECT_MATVIEW;
+ n->roles = $10;
+ n->new_tablespacename = $13;
+ n->nowait = $14;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE relation_expr alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $4;
+ n->cmds = $5;
+ n->objtype = OBJECT_FOREIGN_TABLE;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr alter_table_cmds
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->relation = $6;
+ n->cmds = $7;
+ n->objtype = OBJECT_FOREIGN_TABLE;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+alter_table_cmds:
+ alter_table_cmd { $$ = list_make1($1); }
+ | alter_table_cmds ',' alter_table_cmd { $$ = lappend($1, $3); }
+ ;
+
+partition_cmd:
+ /* ALTER TABLE <name> ATTACH PARTITION <table_name> FOR VALUES */
+ ATTACH PARTITION qualified_name PartitionBoundSpec
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ PartitionCmd *cmd = makeNode(PartitionCmd);
+
+ n->subtype = AT_AttachPartition;
+ cmd->name = $3;
+ cmd->bound = $4;
+ cmd->concurrent = false;
+ n->def = (Node *) cmd;
+
+ $$ = (Node *) n;
+ }
+ /* ALTER TABLE <name> DETACH PARTITION <partition_name> [CONCURRENTLY] */
+ | DETACH PARTITION qualified_name opt_concurrently
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ PartitionCmd *cmd = makeNode(PartitionCmd);
+
+ n->subtype = AT_DetachPartition;
+ cmd->name = $3;
+ cmd->bound = NULL;
+ cmd->concurrent = $4;
+ n->def = (Node *) cmd;
+
+ $$ = (Node *) n;
+ }
+ | DETACH PARTITION qualified_name FINALIZE
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ PartitionCmd *cmd = makeNode(PartitionCmd);
+
+ n->subtype = AT_DetachPartitionFinalize;
+ cmd->name = $3;
+ cmd->bound = NULL;
+ cmd->concurrent = false;
+ n->def = (Node *) cmd;
+ $$ = (Node *) n;
+ }
+ ;
+
+index_partition_cmd:
+ /* ALTER INDEX <name> ATTACH PARTITION <index_name> */
+ ATTACH PARTITION qualified_name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ PartitionCmd *cmd = makeNode(PartitionCmd);
+
+ n->subtype = AT_AttachPartition;
+ cmd->name = $3;
+ cmd->bound = NULL;
+ cmd->concurrent = false;
+ n->def = (Node *) cmd;
+
+ $$ = (Node *) n;
+ }
+ ;
+
+alter_table_cmd:
+ /* ALTER TABLE <name> ADD <coldef> */
+ ADD_P columnDef
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddColumn;
+ n->def = $2;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ADD IF NOT EXISTS <coldef> */
+ | ADD_P IF_P NOT EXISTS columnDef
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddColumn;
+ n->def = $5;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ADD COLUMN <coldef> */
+ | ADD_P COLUMN columnDef
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddColumn;
+ n->def = $3;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ADD COLUMN IF NOT EXISTS <coldef> */
+ | ADD_P COLUMN IF_P NOT EXISTS columnDef
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddColumn;
+ n->def = $6;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */
+ | ALTER opt_column ColId alter_column_default
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ColumnDefault;
+ n->name = $3;
+ n->def = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP NOT NULL */
+ | ALTER opt_column ColId DROP NOT NULL_P
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropNotNull;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET NOT NULL */
+ | ALTER opt_column ColId SET NOT NULL_P
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetNotNull;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP EXPRESSION */
+ | ALTER opt_column ColId DROP EXPRESSION
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropExpression;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP EXPRESSION IF EXISTS */
+ | ALTER opt_column ColId DROP EXPRESSION IF_P EXISTS
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropExpression;
+ n->name = $3;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS <SignedIconst> */
+ | ALTER opt_column ColId SET STATISTICS SignedIconst
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetStatistics;
+ n->name = $3;
+ n->def = (Node *) makeInteger($6);
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colnum> SET STATISTICS <SignedIconst> */
+ | ALTER opt_column Iconst SET STATISTICS SignedIconst
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+
+ if ($3 <= 0 || $3 > PG_INT16_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("column number must be in range from 1 to %d", PG_INT16_MAX),
+ parser_errposition(@3)));
+
+ n->subtype = AT_SetStatistics;
+ n->num = (int16) $3;
+ n->def = (Node *) makeInteger($6);
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
+ | ALTER opt_column ColId SET reloptions
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetOptions;
+ n->name = $3;
+ n->def = (Node *) $5;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> RESET ( column_parameter = 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 <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
+ | 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 <name> ALTER [COLUMN] <colname> SET COMPRESSION <cm> */
+ | ALTER opt_column ColId SET column_compression
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetCompression;
+ n->name = $3;
+ n->def = (Node *) makeString($5);
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> ADD GENERATED ... AS IDENTITY ... */
+ | ALTER opt_column ColId ADD_P GENERATED generated_when AS IDENTITY_P OptParenthesizedSeqOptList
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ Constraint *c = makeNode(Constraint);
+
+ c->contype = CONSTR_IDENTITY;
+ c->generated_when = $6;
+ c->options = $9;
+ c->location = @5;
+
+ n->subtype = AT_AddIdentity;
+ n->name = $3;
+ n->def = (Node *) c;
+
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> SET <sequence options>/RESET */
+ | ALTER opt_column ColId alter_identity_column_option_list
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetIdentity;
+ n->name = $3;
+ n->def = (Node *) $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP IDENTITY */
+ | ALTER opt_column ColId DROP IDENTITY_P
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropIdentity;
+ n->name = $3;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP IDENTITY IF EXISTS */
+ | ALTER opt_column ColId DROP IDENTITY_P IF_P EXISTS
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropIdentity;
+ n->name = $3;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DROP [COLUMN] IF EXISTS <colname> [RESTRICT|CASCADE] */
+ | DROP opt_column IF_P EXISTS ColId opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropColumn;
+ n->name = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DROP [COLUMN] <colname> [RESTRICT|CASCADE] */
+ | DROP opt_column ColId opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropColumn;
+ n->name = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /*
+ * ALTER TABLE <name> ALTER [COLUMN] <colname> [SET DATA] TYPE <typename>
+ * [ USING <expression> ]
+ */
+ | ALTER opt_column ColId opt_set_data TYPE_P Typename opt_collate_clause alter_using
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ ColumnDef *def = makeNode(ColumnDef);
+ n->subtype = AT_AlterColumnType;
+ n->name = $3;
+ n->def = (Node *) def;
+ /* We only use these fields of the ColumnDef node */
+ def->typeName = $6;
+ def->collClause = (CollateClause *) $7;
+ def->raw_default = $8;
+ def->location = @3;
+ $$ = (Node *)n;
+ }
+ /* ALTER FOREIGN TABLE <name> ALTER [COLUMN] <colname> OPTIONS */
+ | ALTER opt_column ColId alter_generic_options
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AlterColumnGenericOptions;
+ n->name = $3;
+ n->def = (Node *) $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ADD CONSTRAINT ... */
+ | ADD_P TableConstraint
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddConstraint;
+ n->def = $2;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ALTER CONSTRAINT ... */
+ | ALTER CONSTRAINT name ConstraintAttributeSpec
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ Constraint *c = makeNode(Constraint);
+ n->subtype = AT_AlterConstraint;
+ n->def = (Node *) c;
+ c->contype = CONSTR_FOREIGN; /* others not supported, yet */
+ c->conname = $3;
+ processCASbits($4, @4, "ALTER CONSTRAINT statement",
+ &c->deferrable,
+ &c->initdeferred,
+ NULL, NULL, yyscanner);
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> VALIDATE CONSTRAINT ... */
+ | VALIDATE CONSTRAINT name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ValidateConstraint;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */
+ | DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropConstraint;
+ n->name = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */
+ | DROP CONSTRAINT name opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropConstraint;
+ n->name = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET WITHOUT OIDS, for backward compat */
+ | SET WITHOUT OIDS
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropOids;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> CLUSTER ON <indexname> */
+ | CLUSTER ON name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ClusterOn;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET WITHOUT CLUSTER */
+ | SET WITHOUT CLUSTER
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropCluster;
+ n->name = NULL;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET LOGGED */
+ | SET LOGGED
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetLogged;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET UNLOGGED */
+ | SET UNLOGGED
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetUnLogged;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE TRIGGER <trig> */
+ | ENABLE_P TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableTrig;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE ALWAYS TRIGGER <trig> */
+ | ENABLE_P ALWAYS TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */
+ | ENABLE_P REPLICA TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaTrig;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE TRIGGER ALL */
+ | ENABLE_P TRIGGER ALL
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableTrigAll;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE TRIGGER USER */
+ | ENABLE_P TRIGGER USER
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableTrigUser;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE TRIGGER <trig> */
+ | DISABLE_P TRIGGER name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableTrig;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE TRIGGER ALL */
+ | DISABLE_P TRIGGER ALL
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableTrigAll;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE TRIGGER USER */
+ | DISABLE_P TRIGGER USER
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableTrigUser;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE RULE <rule> */
+ | ENABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */
+ | ENABLE_P ALWAYS RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableAlwaysRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */
+ | ENABLE_P REPLICA RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableReplicaRule;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE RULE <rule> */
+ | DISABLE_P RULE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableRule;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> INHERIT <parent> */
+ | INHERIT qualified_name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddInherit;
+ n->def = (Node *) $2;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> NO INHERIT <parent> */
+ | NO INHERIT qualified_name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropInherit;
+ n->def = (Node *) $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> OF <type_name> */
+ | OF any_name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ TypeName *def = makeTypeNameFromNameList($2);
+ def->location = @2;
+ n->subtype = AT_AddOf;
+ n->def = (Node *) def;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> NOT OF */
+ | NOT OF
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropOf;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ChangeOwner;
+ n->newowner = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
+ | SET TABLESPACE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetTableSpace;
+ n->name = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET (...) */
+ | SET reloptions
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetRelOptions;
+ n->def = (Node *)$2;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> RESET (...) */
+ | RESET reloptions
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ResetRelOptions;
+ n->def = (Node *)$2;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> REPLICA IDENTITY */
+ | REPLICA IDENTITY_P replica_identity
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ReplicaIdentity;
+ n->def = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> ENABLE ROW LEVEL SECURITY */
+ | ENABLE_P ROW LEVEL SECURITY
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_EnableRowSecurity;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> DISABLE ROW LEVEL SECURITY */
+ | DISABLE_P ROW LEVEL SECURITY
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DisableRowSecurity;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> FORCE ROW LEVEL SECURITY */
+ | FORCE ROW LEVEL SECURITY
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_ForceRowSecurity;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> NO FORCE ROW LEVEL SECURITY */
+ | NO FORCE ROW LEVEL SECURITY
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_NoForceRowSecurity;
+ $$ = (Node *)n;
+ }
+ | alter_generic_options
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_GenericOptions;
+ n->def = (Node *)$1;
+ $$ = (Node *) n;
+ }
+ ;
+
+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->objtype = OBJECT_TYPE;
+ $$ = (Node *)n;
+ }
+ ;
+
+alter_type_cmds:
+ alter_type_cmd { $$ = list_make1($1); }
+ | alter_type_cmds ',' alter_type_cmd { $$ = lappend($1, $3); }
+ ;
+
+alter_type_cmd:
+ /* ALTER TYPE <name> ADD ATTRIBUTE <coldef> [RESTRICT|CASCADE] */
+ ADD_P ATTRIBUTE TableFuncElement opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AddColumn;
+ n->def = $3;
+ n->behavior = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> [RESTRICT|CASCADE] */
+ | DROP ATTRIBUTE IF_P EXISTS ColId opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropColumn;
+ n->name = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER TYPE <name> DROP ATTRIBUTE <attname> [RESTRICT|CASCADE] */
+ | DROP ATTRIBUTE ColId opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DropColumn;
+ n->name = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */
+ | ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_collate_clause opt_drop_behavior
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ ColumnDef *def = makeNode(ColumnDef);
+ n->subtype = AT_AlterColumnType;
+ n->name = $3;
+ n->def = (Node *) def;
+ n->behavior = $8;
+ /* We only use these fields of the ColumnDef node */
+ def->typeName = $6;
+ def->collClause = (CollateClause *) $7;
+ def->raw_default = NULL;
+ def->location = @3;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * close <portalname>
+ *
+ *****************************************************************************/
+
+ClosePortalStmt:
+ CLOSE cursor_name
+ {
+ ClosePortalStmt *n = makeNode(ClosePortalStmt);
+ n->portalname = $2;
+ $$ = (Node *)n;
+ }
+ | CLOSE ALL
+ {
+ ClosePortalStmt *n = makeNode(ClosePortalStmt);
+ n->portalname = NULL;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * COPY relname [(columnList)] FROM/TO file [WITH] [(options)]
+ * COPY ( query ) TO file [WITH] [(options)]
+ *
+ * where 'query' can be one of:
+ * { SELECT | UPDATE | INSERT | DELETE }
+ *
+ * and 'file' can be one of:
+ * { PROGRAM 'command' | STDIN | STDOUT | 'filename' }
+ *
+ * In the preferred syntax the options are comma-separated
+ * and use generic identifiers instead of keywords. The pre-9.0
+ * syntax had a hard-wired, space-separated set of options.
+ *
+ * Really old syntax, from versions 7.2 and prior:
+ * COPY [ BINARY ] table FROM/TO file
+ * [ [ USING ] DELIMITERS 'delimiter' ] ]
+ * [ WITH NULL AS 'null string' ]
+ * This option placement is not supported with COPY (query...).
+ *
+ *****************************************************************************/
+
+CopyStmt: COPY opt_binary qualified_name opt_column_list
+ copy_from opt_program copy_file_name 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 opt_column_compression create_generic_options ColQualList
+ {
+ ColumnDef *n = makeNode(ColumnDef);
+ n->colname = $1;
+ n->typeName = $2;
+ n->compression = $3;
+ 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 = $4;
+ SplitColQualList($5, &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;
+ }
+ ;
+
+column_compression:
+ COMPRESSION ColId { $$ = $2; }
+ | COMPRESSION DEFAULT { $$ = pstrdup("default"); }
+ ;
+
+opt_column_compression:
+ column_compression { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+ColQualList:
+ ColQualList ColConstraint { $$ = lappend($1, $2); }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+ColConstraint:
+ CONSTRAINT name ColConstraintElem
+ {
+ Constraint *n = castNode(Constraint, $3);
+ n->conname = $2;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | ColConstraintElem { $$ = $1; }
+ | ConstraintAttr { $$ = $1; }
+ | COLLATE any_name
+ {
+ /*
+ * Note: the CollateClause is momentarily included in
+ * the list built by ColQualList, but we split it out
+ * again in SplitColQualList.
+ */
+ CollateClause *n = makeNode(CollateClause);
+ n->arg = NULL;
+ n->collname = $2;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ ;
+
+/* 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; }
+ | COMPRESSION { $$ = CREATE_TABLE_LIKE_COMPRESSION; }
+ | CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
+ | DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; }
+ | IDENTITY_P { $$ = CREATE_TABLE_LIKE_IDENTITY; }
+ | GENERATED { $$ = CREATE_TABLE_LIKE_GENERATED; }
+ | INDEXES { $$ = CREATE_TABLE_LIKE_INDEXES; }
+ | STATISTICS { $$ = CREATE_TABLE_LIKE_STATISTICS; }
+ | STORAGE { $$ = CREATE_TABLE_LIKE_STORAGE; }
+ | ALL { $$ = CREATE_TABLE_LIKE_ALL; }
+ ;
+
+
+/* ConstraintElem specifies constraint syntax which is not embedded into
+ * a column definition. ColConstraintElem specifies the embedded form.
+ * - thomas 1997-12-03
+ */
+TableConstraint:
+ CONSTRAINT name ConstraintElem
+ {
+ Constraint *n = castNode(Constraint, $3);
+ n->conname = $2;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | ConstraintElem { $$ = $1; }
+ ;
+
+ConstraintElem:
+ CHECK '(' a_expr ')' ConstraintAttributeSpec
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_CHECK;
+ n->location = @1;
+ n->raw_expr = $3;
+ n->cooked_expr = NULL;
+ processCASbits($5, @5, "CHECK",
+ NULL, NULL, &n->skip_validation,
+ &n->is_no_inherit, yyscanner);
+ n->initially_valid = !n->skip_validation;
+ $$ = (Node *)n;
+ }
+ | UNIQUE '(' 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 OptWhereClause
+ ConstraintAttributeSpec
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_EXCLUSION;
+ n->location = @1;
+ n->access_method = $2;
+ n->exclusions = $4;
+ n->including = $6;
+ n->options = $7;
+ n->indexname = NULL;
+ n->indexspace = $8;
+ n->where_clause = $9;
+ processCASbits($10, @10, "EXCLUDE",
+ &n->deferrable, &n->initdeferred, NULL,
+ NULL, yyscanner);
+ $$ = (Node *)n;
+ }
+ | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
+ opt_column_list key_match key_actions ConstraintAttributeSpec
+ {
+ Constraint *n = makeNode(Constraint);
+ n->contype = CONSTR_FOREIGN;
+ n->location = @1;
+ n->pktable = $7;
+ n->fk_attrs = $4;
+ n->pk_attrs = $8;
+ n->fk_matchtype = $9;
+ n->fk_upd_action = (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);
+ }
+ ;
+
+OptWhereClause:
+ 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 name { $$ = $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 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 stats_params FROM from_list
+ {
+ CreateStatsStmt *n = makeNode(CreateStatsStmt);
+ n->defnames = $3;
+ n->stat_types = $4;
+ n->exprs = $6;
+ n->relations = $8;
+ n->stxcomment = NULL;
+ n->if_not_exists = false;
+ $$ = (Node *)n;
+ }
+ | CREATE STATISTICS IF_P NOT EXISTS any_name
+ opt_name_list ON stats_params FROM from_list
+ {
+ CreateStatsStmt *n = makeNode(CreateStatsStmt);
+ n->defnames = $6;
+ n->stat_types = $7;
+ n->exprs = $9;
+ n->relations = $11;
+ n->stxcomment = NULL;
+ n->if_not_exists = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*
+ * Statistics attributes can be either simple column references, or arbitrary
+ * expressions in parens. For compatibility with index attributes permitted
+ * in CREATE INDEX, we allow an expression that's just a function call to be
+ * written without parens.
+ */
+
+stats_params: stats_param { $$ = list_make1($1); }
+ | stats_params ',' stats_param { $$ = lappend($1, $3); }
+ ;
+
+stats_param: ColId
+ {
+ $$ = makeNode(StatsElem);
+ $$->name = $1;
+ $$->expr = NULL;
+ }
+ | func_expr_windowless
+ {
+ $$ = makeNode(StatsElem);
+ $$->name = NULL;
+ $$->expr = $1;
+ }
+ | '(' a_expr ')'
+ {
+ $$ = makeNode(StatsElem);
+ $$->name = NULL;
+ $$->expr = $2;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * ALTER STATISTICS [IF EXISTS] stats_name
+ * SET STATISTICS <SignedIconst>
+ *
+ *****************************************************************************/
+
+AlterStatsStmt:
+ ALTER STATISTICS any_name SET STATISTICS SignedIconst
+ {
+ AlterStatsStmt *n = makeNode(AlterStatsStmt);
+ n->defnames = $3;
+ n->missing_ok = false;
+ n->stxstattarget = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER STATISTICS IF_P EXISTS any_name SET STATISTICS SignedIconst
+ {
+ AlterStatsStmt *n = makeNode(AlterStatsStmt);
+ n->defnames = $5;
+ n->missing_ok = true;
+ n->stxstattarget = $8;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * CREATE TABLE relname AS SelectStmt [ WITH [NO] DATA ]
+ *
+ *
+ * Note: SELECT ... INTO is a now-deprecated alternative for this.
+ *
+ *****************************************************************************/
+
+CreateAsStmt:
+ CREATE OptTemp TABLE create_as_target AS SelectStmt opt_with_data
+ {
+ CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+ ctas->query = $6;
+ ctas->into = $4;
+ ctas->objtype = OBJECT_TABLE;
+ ctas->is_select_into = false;
+ ctas->if_not_exists = false;
+ /* cram additional flags into the IntoClause */
+ $4->rel->relpersistence = $2;
+ $4->skipData = !($7);
+ $$ = (Node *) ctas;
+ }
+ | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS SelectStmt opt_with_data
+ {
+ CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+ ctas->query = $9;
+ ctas->into = $7;
+ ctas->objtype = OBJECT_TABLE;
+ ctas->is_select_into = false;
+ ctas->if_not_exists = true;
+ /* cram additional flags into the IntoClause */
+ $7->rel->relpersistence = $2;
+ $7->skipData = !($10);
+ $$ = (Node *) ctas;
+ }
+ ;
+
+create_as_target:
+ qualified_name opt_column_list table_access_method_clause
+ OptWith OnCommitOption OptTableSpace
+ {
+ $$ = makeNode(IntoClause);
+ $$->rel = $1;
+ $$->colNames = $2;
+ $$->accessMethod = $3;
+ $$->options = $4;
+ $$->onCommit = $5;
+ $$->tableSpaceName = $6;
+ $$->viewQuery = NULL;
+ $$->skipData = false; /* might get changed later */
+ }
+ ;
+
+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->objtype = OBJECT_MATVIEW;
+ ctas->is_select_into = false;
+ ctas->if_not_exists = false;
+ /* cram additional flags into the IntoClause */
+ $5->rel->relpersistence = $2;
+ $5->skipData = !($8);
+ $$ = (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->objtype = 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 name
+ {
+ /*
+ * We now interpret parameterless CREATE LANGUAGE as
+ * CREATE EXTENSION. "OR REPLACE" is silently translated
+ * to "IF NOT EXISTS", which isn't quite the same, but
+ * seems more useful than throwing an error. We just
+ * ignore TRUSTED, as the previous code would have too.
+ */
+ CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
+ n->if_not_exists = $2;
+ n->extname = $6;
+ n->options = NIL;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE name
+ HANDLER handler_name opt_inline_handler opt_validator
+ {
+ CreatePLangStmt *n = makeNode(CreatePLangStmt);
+ n->replace = $2;
+ n->plname = $6;
+ n->plhandler = $8;
+ n->plinline = $9;
+ n->plvalidator = $10;
+ n->pltrusted = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_trusted:
+ TRUSTED { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+/* This ought to be just func_name, but that causes reduce/reduce conflicts
+ * (CREATE LANGUAGE is the only place where func_name isn't followed by '(').
+ * Work around by using simple names, instead.
+ */
+handler_name:
+ name { $$ = list_make1(makeString($1)); }
+ | name attrs { $$ = lcons(makeString($1), $2); }
+ ;
+
+opt_inline_handler:
+ INLINE_P handler_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+validator_clause:
+ VALIDATOR handler_name { $$ = $2; }
+ | NO VALIDATOR { $$ = NIL; }
+ ;
+
+opt_validator:
+ validator_clause { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_procedural:
+ PROCEDURAL
+ | /*EMPTY*/
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
+ *
+ *****************************************************************************/
+
+CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions
+ {
+ 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 <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 object_type_name name
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = $5;
+ n->object = (Node *) makeString($6);
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop object_type_any_name any_name
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = $5;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop AGGREGATE aggregate_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_AGGREGATE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')'
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_CAST;
+ n->object = (Node *) list_make2($7, $9);
+ $$ = (Node *) n;
+ }
+ | ALTER EXTENSION name add_drop DOMAIN_P Typename
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_DOMAIN;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop FUNCTION function_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_FUNCTION;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop OPERATOR operator_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_OPERATOR;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING name
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_OPCLASS;
+ n->object = (Node *) lcons(makeString($9), $7);
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING name
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_OPFAMILY;
+ n->object = (Node *) lcons(makeString($9), $7);
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop PROCEDURE function_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop ROUTINE function_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop TRANSFORM FOR Typename LANGUAGE name
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_TRANSFORM;
+ n->object = (Node *) list_make2($7, makeString($9));
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop TYPE_P Typename
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_TYPE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE FOREIGN DATA WRAPPER name options
+ *
+ *****************************************************************************/
+
+CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options
+ {
+ CreateFdwStmt *n = makeNode(CreateFdwStmt);
+ n->fdwname = $5;
+ n->func_options = $6;
+ n->options = $7;
+ $$ = (Node *) n;
+ }
+ ;
+
+fdw_option:
+ HANDLER handler_name { $$ = makeDefElem("handler", (Node *)$2, @1); }
+ | NO HANDLER { $$ = makeDefElem("handler", NULL, @1); }
+ | VALIDATOR handler_name { $$ = makeDefElem("validator", (Node *)$2, @1); }
+ | NO VALIDATOR { $$ = makeDefElem("validator", NULL, @1); }
+ ;
+
+fdw_options:
+ fdw_option { $$ = list_make1($1); }
+ | fdw_options fdw_option { $$ = lappend($1, $2); }
+ ;
+
+opt_fdw_options:
+ fdw_options { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * ALTER FOREIGN DATA WRAPPER name options
+ *
+ ****************************************************************************/
+
+AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options
+ {
+ AlterFdwStmt *n = makeNode(AlterFdwStmt);
+ n->fdwname = $5;
+ n->func_options = $6;
+ n->options = $7;
+ $$ = (Node *) n;
+ }
+ | ALTER FOREIGN DATA_P WRAPPER name fdw_options
+ {
+ AlterFdwStmt *n = makeNode(AlterFdwStmt);
+ n->fdwname = $5;
+ n->func_options = $6;
+ n->options = NIL;
+ $$ = (Node *) n;
+ }
+ ;
+
+/* Options definition for CREATE FDW, SERVER 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:
+ * 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 opt_or_replace TRIGGER name TriggerActionTime TriggerEvents ON
+ qualified_name TriggerReferencing TriggerForSpec TriggerWhen
+ EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')'
+ {
+ CreateTrigStmt *n = makeNode(CreateTrigStmt);
+ n->replace = $2;
+ n->isconstraint = false;
+ n->trigname = $4;
+ n->relation = $8;
+ n->funcname = $14;
+ n->args = $16;
+ n->row = $10;
+ n->timing = $5;
+ n->events = intVal(linitial($6));
+ n->columns = (List *) lsecond($6);
+ n->whenClause = $11;
+ n->transitionRels = $9;
+ n->deferrable = false;
+ n->initdeferred = false;
+ n->constrrel = NULL;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace CONSTRAINT TRIGGER name AFTER TriggerEvents ON
+ qualified_name OptConstrFromTable ConstraintAttributeSpec
+ FOR EACH ROW TriggerWhen
+ EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')'
+ {
+ CreateTrigStmt *n = makeNode(CreateTrigStmt);
+ n->replace = $2;
+ if (n->replace) /* not supported, see CreateTrigger */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported")));
+ n->isconstraint = true;
+ n->trigname = $5;
+ n->relation = $9;
+ n->funcname = $18;
+ n->args = $20;
+ n->row = true;
+ n->timing = TRIGGER_TYPE_AFTER;
+ n->events = intVal(linitial($7));
+ n->columns = (List *) lsecond($7);
+ n->whenClause = $15;
+ n->transitionRels = NIL;
+ processCASbits($11, @11, "TRIGGER",
+ &n->deferrable, &n->initdeferred, NULL,
+ NULL, yyscanner);
+ n->constrrel = $10;
+ $$ = (Node *)n;
+ }
+ ;
+
+TriggerActionTime:
+ BEFORE { $$ = TRIGGER_TYPE_BEFORE; }
+ | AFTER { $$ = TRIGGER_TYPE_AFTER; }
+ | INSTEAD OF { $$ = TRIGGER_TYPE_INSTEAD; }
+ ;
+
+TriggerEvents:
+ TriggerOneEvent
+ { $$ = $1; }
+ | TriggerEvents OR TriggerOneEvent
+ {
+ int events1 = intVal(linitial($1));
+ int events2 = intVal(linitial($3));
+ List *columns1 = (List *) lsecond($1);
+ List *columns2 = (List *) lsecond($3);
+
+ if (events1 & events2)
+ parser_yyerror("duplicate trigger events specified");
+ /*
+ * concat'ing the columns lists loses information about
+ * which columns went with which event, but so long as
+ * only UPDATE carries columns and we disallow multiple
+ * UPDATE items, it doesn't matter. Command execution
+ * should just ignore the columns for non-UPDATE events.
+ */
+ $$ = list_make2(makeInteger(events1 | events2),
+ list_concat(columns1, columns2));
+ }
+ ;
+
+TriggerOneEvent:
+ INSERT
+ { $$ = list_make2(makeInteger(TRIGGER_TYPE_INSERT), NIL); }
+ | DELETE_P
+ { $$ = list_make2(makeInteger(TRIGGER_TYPE_DELETE), NIL); }
+ | UPDATE
+ { $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), NIL); }
+ | UPDATE OF columnList
+ { $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), $3); }
+ | TRUNCATE
+ { $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); }
+ ;
+
+TriggerReferencing:
+ REFERENCING TriggerTransitions { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+TriggerTransitions:
+ TriggerTransition { $$ = list_make1($1); }
+ | TriggerTransitions TriggerTransition { $$ = lappend($1, $2); }
+ ;
+
+TriggerTransition:
+ TransitionOldOrNew TransitionRowOrTable opt_as TransitionRelName
+ {
+ TriggerTransition *n = makeNode(TriggerTransition);
+ n->name = $4;
+ n->isNew = $1;
+ n->isTable = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+TransitionOldOrNew:
+ NEW { $$ = true; }
+ | OLD { $$ = false; }
+ ;
+
+TransitionRowOrTable:
+ TABLE { $$ = true; }
+ /*
+ * According to the standard, lack of a keyword here implies ROW.
+ * Support for that would require prohibiting ROW entirely here,
+ * reserving the keyword ROW, and/or requiring AS (instead of
+ * allowing it to be optional, as the standard specifies) as the
+ * next token. Requiring ROW seems cleanest and easiest to
+ * explain.
+ */
+ | ROW { $$ = false; }
+ ;
+
+TransitionRelName:
+ ColId { $$ = $1; }
+ ;
+
+TriggerForSpec:
+ FOR TriggerForOptEach TriggerForType
+ {
+ $$ = $3;
+ }
+ | /* EMPTY */
+ {
+ /*
+ * 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 name opt_opfamily AS opclass_item_list
+ {
+ CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
+ n->opclassname = $4;
+ n->isDefault = $5;
+ n->datatype = $8;
+ n->amname = $10;
+ n->opfamilyname = $11;
+ n->items = $13;
+ $$ = (Node *) n;
+ }
+ ;
+
+opclass_item_list:
+ opclass_item { $$ = list_make1($1); }
+ | opclass_item_list ',' opclass_item { $$ = lappend($1, $3); }
+ ;
+
+opclass_item:
+ OPERATOR Iconst any_operator opclass_purpose opt_recheck
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ ObjectWithArgs *owa = makeNode(ObjectWithArgs);
+ owa->objname = $3;
+ owa->objargs = NIL;
+ n->itemtype = OPCLASS_ITEM_OPERATOR;
+ n->name = owa;
+ n->number = $2;
+ n->order_family = $4;
+ $$ = (Node *) n;
+ }
+ | OPERATOR Iconst operator_with_argtypes opclass_purpose
+ opt_recheck
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_OPERATOR;
+ n->name = $3;
+ n->number = $2;
+ n->order_family = $4;
+ $$ = (Node *) n;
+ }
+ | FUNCTION Iconst function_with_argtypes
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_FUNCTION;
+ n->name = $3;
+ n->number = $2;
+ $$ = (Node *) n;
+ }
+ | FUNCTION Iconst '(' type_list ')' function_with_argtypes
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_FUNCTION;
+ n->name = $6;
+ n->number = $2;
+ n->class_args = $4;
+ $$ = (Node *) n;
+ }
+ | STORAGE Typename
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_STORAGETYPE;
+ n->storedtype = $2;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_default: DEFAULT { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_opfamily: FAMILY any_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opclass_purpose: FOR SEARCH { $$ = NIL; }
+ | FOR ORDER BY any_name { $$ = $4; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_recheck: RECHECK
+ {
+ /*
+ * RECHECK no longer does anything in opclass definitions,
+ * but we still accept it to ease porting of old database
+ * dumps.
+ */
+ ereport(NOTICE,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("RECHECK is no longer required"),
+ errhint("Update your data type."),
+ parser_errposition(@1)));
+ $$ = true;
+ }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+
+CreateOpFamilyStmt:
+ CREATE OPERATOR FAMILY any_name USING name
+ {
+ CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
+AlterOpFamilyStmt:
+ ALTER OPERATOR FAMILY any_name USING name ADD_P opclass_item_list
+ {
+ AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ n->isDrop = false;
+ n->items = $8;
+ $$ = (Node *) n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING name DROP opclass_drop_list
+ {
+ AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ n->isDrop = true;
+ n->items = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
+opclass_drop_list:
+ opclass_drop { $$ = list_make1($1); }
+ | opclass_drop_list ',' opclass_drop { $$ = lappend($1, $3); }
+ ;
+
+opclass_drop:
+ OPERATOR Iconst '(' type_list ')'
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_OPERATOR;
+ n->number = $2;
+ n->class_args = $4;
+ $$ = (Node *) n;
+ }
+ | FUNCTION Iconst '(' type_list ')'
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_FUNCTION;
+ n->number = $2;
+ n->class_args = $4;
+ $$ = (Node *) n;
+ }
+ ;
+
+
+DropOpClassStmt:
+ DROP OPERATOR CLASS any_name USING name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->objects = list_make1(lcons(makeString($6), $4));
+ n->removeType = OBJECT_OPCLASS;
+ n->behavior = $7;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *) n;
+ }
+ | DROP OPERATOR CLASS IF_P EXISTS any_name USING name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->objects = list_make1(lcons(makeString($8), $6));
+ n->removeType = OBJECT_OPCLASS;
+ n->behavior = $9;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *) n;
+ }
+ ;
+
+DropOpFamilyStmt:
+ DROP OPERATOR FAMILY any_name USING name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->objects = list_make1(lcons(makeString($6), $4));
+ n->removeType = OBJECT_OPFAMILY;
+ n->behavior = $7;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *) n;
+ }
+ | DROP OPERATOR FAMILY IF_P EXISTS any_name USING name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->objects = list_make1(lcons(makeString($8), $6));
+ n->removeType = OBJECT_OPFAMILY;
+ n->behavior = $9;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *) n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ *
+ * DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ]
+ * REASSIGN OWNED BY username [, username ...] TO username
+ *
+ *****************************************************************************/
+DropOwnedStmt:
+ DROP OWNED BY role_list opt_drop_behavior
+ {
+ DropOwnedStmt *n = makeNode(DropOwnedStmt);
+ n->roles = $4;
+ n->behavior = $5;
+ $$ = (Node *)n;
+ }
+ ;
+
+ReassignOwnedStmt:
+ REASSIGN OWNED BY role_list TO RoleSpec
+ {
+ ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
+ n->roles = $4;
+ n->newrole = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ *
+ * DROP itemtype [ IF EXISTS ] itemname [, itemname ...]
+ * [ RESTRICT | CASCADE ]
+ *
+ *****************************************************************************/
+
+DropStmt: DROP object_type_any_name IF_P EXISTS any_name_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = $2;
+ n->missing_ok = true;
+ n->objects = $5;
+ n->behavior = $6;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP object_type_any_name any_name_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = $2;
+ n->missing_ok = false;
+ n->objects = $3;
+ n->behavior = $4;
+ n->concurrent = false;
+ $$ = (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 object_type_name_on_any_name name ON any_name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = $2;
+ n->objects = list_make1(lappend($5, makeString($3)));
+ n->behavior = $6;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *) n;
+ }
+ | DROP object_type_name_on_any_name IF_P EXISTS name ON any_name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = $2;
+ n->objects = list_make1(lappend($7, makeString($5)));
+ n->behavior = $8;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (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/any_name_list */
+object_type_any_name:
+ TABLE { $$ = OBJECT_TABLE; }
+ | SEQUENCE { $$ = OBJECT_SEQUENCE; }
+ | VIEW { $$ = OBJECT_VIEW; }
+ | MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
+ | INDEX { $$ = OBJECT_INDEX; }
+ | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
+ | COLLATION { $$ = OBJECT_COLLATION; }
+ | CONVERSION_P { $$ = OBJECT_CONVERSION; }
+ | STATISTICS { $$ = OBJECT_STATISTIC_EXT; }
+ | TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; }
+ | TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; }
+ | TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; }
+ | TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; }
+ ;
+
+/*
+ * object types taking name/name_list
+ *
+ * DROP handles some of them separately
+ */
+
+object_type_name:
+ drop_type_name { $$ = $1; }
+ | DATABASE { $$ = OBJECT_DATABASE; }
+ | ROLE { $$ = OBJECT_ROLE; }
+ | SUBSCRIPTION { $$ = OBJECT_SUBSCRIPTION; }
+ | TABLESPACE { $$ = OBJECT_TABLESPACE; }
+ ;
+
+drop_type_name:
+ ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; }
+ | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
+ | EXTENSION { $$ = OBJECT_EXTENSION; }
+ | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; }
+ | opt_procedural LANGUAGE { $$ = OBJECT_LANGUAGE; }
+ | PUBLICATION { $$ = OBJECT_PUBLICATION; }
+ | SCHEMA { $$ = OBJECT_SCHEMA; }
+ | SERVER { $$ = OBJECT_FOREIGN_SERVER; }
+ ;
+
+/* object types attached to a table */
+object_type_name_on_any_name:
+ POLICY { $$ = OBJECT_POLICY; }
+ | RULE { $$ = OBJECT_RULE; }
+ | TRIGGER { $$ = OBJECT_TRIGGER; }
+ ;
+
+any_name_list:
+ any_name { $$ = list_make1($1); }
+ | any_name_list ',' any_name { $$ = lappend($1, $3); }
+ ;
+
+any_name: ColId { $$ = list_make1(makeString($1)); }
+ | ColId attrs { $$ = lcons(makeString($1), $2); }
+ ;
+
+attrs: '.' attr_name
+ { $$ = list_make1(makeString($2)); }
+ | attrs '.' attr_name
+ { $$ = lappend($1, makeString($3)); }
+ ;
+
+type_name_list:
+ Typename { $$ = list_make1($1); }
+ | type_name_list ',' Typename { $$ = lappend($1, $3); }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * truncate table relname1, relname2, ...
+ *
+ *****************************************************************************/
+
+TruncateStmt:
+ TRUNCATE opt_table relation_expr_list opt_restart_seqs opt_drop_behavior
+ {
+ TruncateStmt *n = makeNode(TruncateStmt);
+ n->relations = $3;
+ n->restart_seqs = $4;
+ n->behavior = $5;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_restart_seqs:
+ CONTINUE_P IDENTITY_P { $$ = false; }
+ | RESTART IDENTITY_P { $$ = true; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
+/*****************************************************************************
+ *
+ * COMMENT ON <object> IS <text>
+ *
+ *****************************************************************************/
+
+CommentStmt:
+ COMMENT ON object_type_any_name any_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = $3;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON COLUMN any_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_COLUMN;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON object_type_name name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = $3;
+ n->object = (Node *) makeString($4);
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON TYPE_P Typename IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_TYPE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON DOMAIN_P Typename IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_DOMAIN;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON AGGREGATE aggregate_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_AGGREGATE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON FUNCTION function_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_FUNCTION;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON OPERATOR operator_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_OPERATOR;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON CONSTRAINT name ON any_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_TABCONSTRAINT;
+ n->object = (Node *) lappend($6, makeString($4));
+ n->comment = $8;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_DOMCONSTRAINT;
+ /*
+ * should use Typename not any_name in the production, but
+ * there's a shift/reduce conflict if we do that, so fix it
+ * up here.
+ */
+ n->object = (Node *) list_make2(makeTypeNameFromNameList($7), makeString($4));
+ n->comment = $9;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON object_type_name_on_any_name name ON any_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = $3;
+ n->object = (Node *) lappend($6, makeString($4));
+ n->comment = $8;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON PROCEDURE function_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON ROUTINE function_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON TRANSFORM FOR Typename LANGUAGE name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_TRANSFORM;
+ n->object = (Node *) list_make2($5, makeString($7));
+ n->comment = $9;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON OPERATOR CLASS any_name USING name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_OPCLASS;
+ n->object = (Node *) lcons(makeString($7), $5);
+ n->comment = $9;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON OPERATOR FAMILY any_name USING name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_OPFAMILY;
+ n->object = (Node *) lcons(makeString($7), $5);
+ n->comment = $9;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_LARGEOBJECT;
+ n->object = (Node *) $5;
+ n->comment = $7;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_CAST;
+ n->object = (Node *) list_make2($5, $7);
+ n->comment = $10;
+ $$ = (Node *) n;
+ }
+ ;
+
+comment_text:
+ Sconst { $$ = $1; }
+ | NULL_P { $$ = NULL; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * SECURITY LABEL [FOR <provider>] ON <object> IS <label>
+ *
+ * As with COMMENT ON, <object> can refer to various types of database
+ * objects (e.g. TABLE, COLUMN, etc.).
+ *
+ *****************************************************************************/
+
+SecLabelStmt:
+ SECURITY LABEL opt_provider ON object_type_any_name any_name
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = $5;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON COLUMN any_name
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_COLUMN;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON object_type_name name
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = $5;
+ n->object = (Node *) makeString($6);
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON TYPE_P Typename
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_TYPE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON DOMAIN_P Typename
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_DOMAIN;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON AGGREGATE aggregate_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_AGGREGATE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON FUNCTION function_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_FUNCTION;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON LARGE_P OBJECT_P NumericOnly
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_LARGEOBJECT;
+ n->object = (Node *) $7;
+ n->label = $9;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON PROCEDURE function_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON ROUTINE function_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_provider: FOR NonReservedWord_or_Sconst { $$ = $2; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+security_label: Sconst { $$ = $1; }
+ | NULL_P { $$ = NULL; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * fetch/move
+ *
+ *****************************************************************************/
+
+FetchStmt: FETCH fetch_args
+ {
+ FetchStmt *n = (FetchStmt *) $2;
+ n->ismove = false;
+ $$ = (Node *)n;
+ }
+ | MOVE fetch_args
+ {
+ FetchStmt *n = (FetchStmt *) $2;
+ n->ismove = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+fetch_args: cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $1;
+ n->direction = FETCH_FORWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $2;
+ n->direction = FETCH_FORWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | NEXT opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_FORWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | PRIOR opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_BACKWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | FIRST_P opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_ABSOLUTE;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | LAST_P opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_ABSOLUTE;
+ n->howMany = -1;
+ $$ = (Node *)n;
+ }
+ | ABSOLUTE_P SignedIconst opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_ABSOLUTE;
+ n->howMany = $2;
+ $$ = (Node *)n;
+ }
+ | RELATIVE_P SignedIconst opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_RELATIVE;
+ n->howMany = $2;
+ $$ = (Node *)n;
+ }
+ | SignedIconst opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_FORWARD;
+ n->howMany = $1;
+ $$ = (Node *)n;
+ }
+ | ALL opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_FORWARD;
+ n->howMany = FETCH_ALL;
+ $$ = (Node *)n;
+ }
+ | FORWARD opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_FORWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | FORWARD SignedIconst opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_FORWARD;
+ n->howMany = $2;
+ $$ = (Node *)n;
+ }
+ | FORWARD ALL opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_FORWARD;
+ n->howMany = FETCH_ALL;
+ $$ = (Node *)n;
+ }
+ | BACKWARD opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $3;
+ n->direction = FETCH_BACKWARD;
+ n->howMany = 1;
+ $$ = (Node *)n;
+ }
+ | BACKWARD SignedIconst opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_BACKWARD;
+ n->howMany = $2;
+ $$ = (Node *)n;
+ }
+ | BACKWARD ALL opt_from_in cursor_name
+ {
+ FetchStmt *n = makeNode(FetchStmt);
+ n->portalname = $4;
+ n->direction = FETCH_BACKWARD;
+ n->howMany = FETCH_ALL;
+ $$ = (Node *)n;
+ }
+ ;
+
+from_in: FROM
+ | IN_P
+ ;
+
+opt_from_in: from_in
+ | /* EMPTY */
+ ;
+
+
+/*****************************************************************************
+ *
+ * GRANT and REVOKE statements
+ *
+ *****************************************************************************/
+
+GrantStmt: GRANT privileges ON privilege_target TO grantee_list
+ opt_grant_grant_option opt_granted_by
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = true;
+ n->privileges = $2;
+ n->targtype = ($4)->targtype;
+ n->objtype = ($4)->objtype;
+ n->objects = ($4)->objs;
+ n->grantees = $6;
+ n->grant_option = $7;
+ n->grantor = $8;
+ $$ = (Node*)n;
+ }
+ ;
+
+RevokeStmt:
+ REVOKE privileges ON privilege_target
+ FROM grantee_list opt_granted_by opt_drop_behavior
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = false;
+ n->grant_option = false;
+ n->privileges = $2;
+ n->targtype = ($4)->targtype;
+ n->objtype = ($4)->objtype;
+ n->objects = ($4)->objs;
+ n->grantees = $6;
+ n->grantor = $7;
+ n->behavior = $8;
+ $$ = (Node *)n;
+ }
+ | REVOKE GRANT OPTION FOR privileges ON privilege_target
+ FROM grantee_list opt_granted_by opt_drop_behavior
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = false;
+ n->grant_option = true;
+ n->privileges = $5;
+ n->targtype = ($7)->targtype;
+ n->objtype = ($7)->objtype;
+ n->objects = ($7)->objs;
+ n->grantees = $9;
+ n->grantor = $10;
+ n->behavior = $11;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*
+ * Privilege names are represented as strings; the validity of the privilege
+ * names gets checked at execution. This is a bit annoying but we have little
+ * choice because of the syntactic conflict with lists of role names in
+ * GRANT/REVOKE. What's more, we have to call out in the "privilege"
+ * production any reserved keywords that need to be usable as privilege names.
+ */
+
+/* either ALL [PRIVILEGES] or a list of individual privileges */
+privileges: privilege_list
+ { $$ = $1; }
+ | ALL
+ { $$ = NIL; }
+ | ALL PRIVILEGES
+ { $$ = NIL; }
+ | ALL '(' columnList ')'
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = NULL;
+ n->cols = $3;
+ $$ = list_make1(n);
+ }
+ | ALL PRIVILEGES '(' columnList ')'
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = NULL;
+ n->cols = $4;
+ $$ = list_make1(n);
+ }
+ ;
+
+privilege_list: privilege { $$ = list_make1($1); }
+ | privilege_list ',' privilege { $$ = lappend($1, $3); }
+ ;
+
+privilege: SELECT opt_column_list
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = pstrdup($1);
+ n->cols = $2;
+ $$ = n;
+ }
+ | REFERENCES opt_column_list
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = pstrdup($1);
+ n->cols = $2;
+ $$ = n;
+ }
+ | CREATE opt_column_list
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = pstrdup($1);
+ n->cols = $2;
+ $$ = n;
+ }
+ | ColId opt_column_list
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = $1;
+ n->cols = $2;
+ $$ = n;
+ }
+ ;
+
+
+/* Don't bother trying to fold the first two rules into one using
+ * opt_table. You're going to get conflicts.
+ */
+privilege_target:
+ qualified_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_TABLE;
+ n->objs = $1;
+ $$ = n;
+ }
+ | TABLE qualified_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_TABLE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | SEQUENCE qualified_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_SEQUENCE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | FOREIGN DATA_P WRAPPER name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_FDW;
+ n->objs = $4;
+ $$ = n;
+ }
+ | FOREIGN SERVER name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_FOREIGN_SERVER;
+ n->objs = $3;
+ $$ = n;
+ }
+ | FUNCTION function_with_argtypes_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_FUNCTION;
+ n->objs = $2;
+ $$ = n;
+ }
+ | PROCEDURE function_with_argtypes_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_PROCEDURE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | ROUTINE function_with_argtypes_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_ROUTINE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | DATABASE name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_DATABASE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | DOMAIN_P any_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_DOMAIN;
+ n->objs = $2;
+ $$ = n;
+ }
+ | LANGUAGE name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_LANGUAGE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | LARGE_P OBJECT_P NumericOnly_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_LARGEOBJECT;
+ n->objs = $3;
+ $$ = n;
+ }
+ | SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_SCHEMA;
+ n->objs = $2;
+ $$ = n;
+ }
+ | TABLESPACE name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_TABLESPACE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | TYPE_P any_name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = OBJECT_TYPE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | ALL TABLES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = OBJECT_TABLE;
+ n->objs = $5;
+ $$ = n;
+ }
+ | ALL SEQUENCES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = OBJECT_SEQUENCE;
+ n->objs = $5;
+ $$ = n;
+ }
+ | ALL FUNCTIONS IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = OBJECT_FUNCTION;
+ n->objs = $5;
+ $$ = n;
+ }
+ | ALL PROCEDURES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = OBJECT_PROCEDURE;
+ n->objs = $5;
+ $$ = n;
+ }
+ | ALL ROUTINES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = OBJECT_ROUTINE;
+ n->objs = $5;
+ $$ = n;
+ }
+ ;
+
+
+grantee_list:
+ grantee { $$ = list_make1($1); }
+ | grantee_list ',' grantee { $$ = lappend($1, $3); }
+ ;
+
+grantee:
+ RoleSpec { $$ = $1; }
+ | GROUP_P RoleSpec { $$ = $2; }
+ ;
+
+
+opt_grant_grant_option:
+ WITH GRANT OPTION { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+/*****************************************************************************
+ *
+ * GRANT and REVOKE ROLE statements
+ *
+ *****************************************************************************/
+
+GrantRoleStmt:
+ GRANT privilege_list TO role_list opt_grant_admin_option opt_granted_by
+ {
+ GrantRoleStmt *n = makeNode(GrantRoleStmt);
+ n->is_grant = true;
+ n->granted_roles = $2;
+ n->grantee_roles = $4;
+ n->admin_opt = $5;
+ n->grantor = $6;
+ $$ = (Node*)n;
+ }
+ ;
+
+RevokeRoleStmt:
+ REVOKE privilege_list FROM role_list opt_granted_by opt_drop_behavior
+ {
+ GrantRoleStmt *n = makeNode(GrantRoleStmt);
+ n->is_grant = false;
+ n->admin_opt = false;
+ n->granted_roles = $2;
+ n->grantee_roles = $4;
+ n->behavior = $6;
+ $$ = (Node*)n;
+ }
+ | REVOKE ADMIN OPTION FOR privilege_list FROM role_list opt_granted_by opt_drop_behavior
+ {
+ GrantRoleStmt *n = makeNode(GrantRoleStmt);
+ n->is_grant = false;
+ n->admin_opt = true;
+ n->granted_roles = $5;
+ n->grantee_roles = $7;
+ n->behavior = $9;
+ $$ = (Node*)n;
+ }
+ ;
+
+opt_grant_admin_option: WITH ADMIN OPTION { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER DEFAULT PRIVILEGES statement
+ *
+ *****************************************************************************/
+
+AlterDefaultPrivilegesStmt:
+ ALTER DEFAULT PRIVILEGES DefACLOptionList DefACLAction
+ {
+ AlterDefaultPrivilegesStmt *n = makeNode(AlterDefaultPrivilegesStmt);
+ n->options = $4;
+ n->action = (GrantStmt *) $5;
+ $$ = (Node*)n;
+ }
+ ;
+
+DefACLOptionList:
+ DefACLOptionList DefACLOption { $$ = lappend($1, $2); }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+DefACLOption:
+ IN_P SCHEMA name_list
+ {
+ $$ = makeDefElem("schemas", (Node *)$3, @1);
+ }
+ | FOR ROLE role_list
+ {
+ $$ = makeDefElem("roles", (Node *)$3, @1);
+ }
+ | FOR USER role_list
+ {
+ $$ = makeDefElem("roles", (Node *)$3, @1);
+ }
+ ;
+
+/*
+ * This should match GRANT/REVOKE, except that individual target objects
+ * are not mentioned and we only allow a subset of object types.
+ */
+DefACLAction:
+ GRANT privileges ON defacl_privilege_target TO grantee_list
+ opt_grant_grant_option
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = true;
+ n->privileges = $2;
+ n->targtype = ACL_TARGET_DEFAULTS;
+ n->objtype = $4;
+ n->objects = NIL;
+ n->grantees = $6;
+ n->grant_option = $7;
+ $$ = (Node*)n;
+ }
+ | REVOKE privileges ON defacl_privilege_target
+ FROM grantee_list opt_drop_behavior
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = false;
+ n->grant_option = false;
+ n->privileges = $2;
+ n->targtype = ACL_TARGET_DEFAULTS;
+ n->objtype = $4;
+ n->objects = NIL;
+ n->grantees = $6;
+ n->behavior = $7;
+ $$ = (Node *)n;
+ }
+ | REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target
+ FROM grantee_list opt_drop_behavior
+ {
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = false;
+ n->grant_option = true;
+ n->privileges = $5;
+ n->targtype = ACL_TARGET_DEFAULTS;
+ n->objtype = $7;
+ n->objects = NIL;
+ n->grantees = $9;
+ n->behavior = $10;
+ $$ = (Node *)n;
+ }
+ ;
+
+defacl_privilege_target:
+ TABLES { $$ = OBJECT_TABLE; }
+ | FUNCTIONS { $$ = OBJECT_FUNCTION; }
+ | ROUTINES { $$ = OBJECT_FUNCTION; }
+ | SEQUENCES { $$ = OBJECT_SEQUENCE; }
+ | TYPES_P { $$ = OBJECT_TYPE; }
+ | SCHEMAS { $$ = OBJECT_SCHEMA; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY: CREATE INDEX
+ *
+ * Note: we cannot put TABLESPACE clause after WHERE clause unless we are
+ * willing to make TABLESPACE a fully reserved word.
+ *****************************************************************************/
+
+IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name
+ ON relation_expr access_method_clause '(' index_params ')'
+ opt_include opt_reloptions OptTableSpace where_clause
+ {
+ IndexStmt *n = makeNode(IndexStmt);
+ n->unique = $2;
+ n->concurrent = $4;
+ n->idxname = $5;
+ n->relation = $7;
+ n->accessMethod = $8;
+ n->indexParams = $10;
+ n->indexIncludingParams = $12;
+ n->options = $13;
+ n->tableSpace = $14;
+ n->whereClause = $15;
+ n->excludeOpNames = NIL;
+ n->idxcomment = NULL;
+ n->indexOid = InvalidOid;
+ n->oldNode = InvalidOid;
+ n->oldCreateSubid = InvalidSubTransactionId;
+ n->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
+ n->primary = false;
+ n->isconstraint = false;
+ n->deferrable = false;
+ n->initdeferred = false;
+ n->transformed = false;
+ n->if_not_exists = false;
+ n->reset_default_tblspc = false;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS name
+ ON relation_expr access_method_clause '(' index_params ')'
+ opt_include opt_reloptions OptTableSpace where_clause
+ {
+ IndexStmt *n = makeNode(IndexStmt);
+ n->unique = $2;
+ n->concurrent = $4;
+ n->idxname = $8;
+ n->relation = $10;
+ n->accessMethod = $11;
+ n->indexParams = $13;
+ n->indexIncludingParams = $15;
+ n->options = $16;
+ n->tableSpace = $17;
+ n->whereClause = $18;
+ n->excludeOpNames = NIL;
+ n->idxcomment = NULL;
+ n->indexOid = InvalidOid;
+ n->oldNode = InvalidOid;
+ n->oldCreateSubid = InvalidSubTransactionId;
+ n->oldFirstRelfilenodeSubid = InvalidSubTransactionId;
+ n->primary = false;
+ n->isconstraint = false;
+ n->deferrable = false;
+ n->initdeferred = false;
+ n->transformed = false;
+ n->if_not_exists = true;
+ n->reset_default_tblspc = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_unique:
+ UNIQUE { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_concurrently:
+ CONCURRENTLY { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_index_name:
+ name { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+access_method_clause:
+ USING name { $$ = $2; }
+ | /*EMPTY*/ { $$ = DEFAULT_INDEX_TYPE; }
+ ;
+
+index_params: index_elem { $$ = list_make1($1); }
+ | index_params ',' index_elem { $$ = lappend($1, $3); }
+ ;
+
+
+index_elem_options:
+ opt_collate opt_class opt_asc_desc opt_nulls_order
+ {
+ $$ = makeNode(IndexElem);
+ $$->name = NULL;
+ $$->expr = NULL;
+ $$->indexcolname = NULL;
+ $$->collation = $1;
+ $$->opclass = $2;
+ $$->opclassopts = NIL;
+ $$->ordering = $3;
+ $$->nulls_ordering = $4;
+ }
+ | opt_collate any_name reloptions opt_asc_desc opt_nulls_order
+ {
+ $$ = makeNode(IndexElem);
+ $$->name = NULL;
+ $$->expr = NULL;
+ $$->indexcolname = NULL;
+ $$->collation = $1;
+ $$->opclass = $2;
+ $$->opclassopts = $3;
+ $$->ordering = $4;
+ $$->nulls_ordering = $5;
+ }
+ ;
+
+/*
+ * Index attributes can be either simple column references, or arbitrary
+ * expressions in parens. For backwards-compatibility reasons, we allow
+ * an expression that's just a function call to be written without parens.
+ */
+index_elem: ColId index_elem_options
+ {
+ $$ = $2;
+ $$->name = $1;
+ }
+ | func_expr_windowless index_elem_options
+ {
+ $$ = $2;
+ $$->expr = $1;
+ }
+ | '(' a_expr ')' index_elem_options
+ {
+ $$ = $4;
+ $$->expr = $2;
+ }
+ ;
+
+opt_include: INCLUDE '(' index_including_params ')' { $$ = $3; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+index_including_params: index_elem { $$ = list_make1($1); }
+ | index_including_params ',' index_elem { $$ = lappend($1, $3); }
+ ;
+
+opt_collate: COLLATE any_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_class: any_name { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_asc_desc: ASC { $$ = SORTBY_ASC; }
+ | DESC { $$ = SORTBY_DESC; }
+ | /*EMPTY*/ { $$ = SORTBY_DEFAULT; }
+ ;
+
+opt_nulls_order: NULLS_LA FIRST_P { $$ = SORTBY_NULLS_FIRST; }
+ | NULLS_LA LAST_P { $$ = SORTBY_NULLS_LAST; }
+ | /*EMPTY*/ { $$ = SORTBY_NULLS_DEFAULT; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * create [or replace] function <fname>
+ * [(<type-1> { , <type-n>})]
+ * returns <type-r>
+ * as <filename or code in language as appropriate>
+ * language <lang> [with parameters]
+ *
+ *****************************************************************************/
+
+CreateFunctionStmt:
+ CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
+ RETURNS func_return opt_createfunc_opt_list opt_routine_body
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->is_procedure = false;
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = $5;
+ n->returnType = $7;
+ n->options = $8;
+ n->sql_body = $9;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
+ RETURNS TABLE '(' table_func_column_list ')' opt_createfunc_opt_list opt_routine_body
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->is_procedure = false;
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = mergeTableFuncParameters($5, $9);
+ n->returnType = TableFuncTypeName($9);
+ n->returnType->location = @7;
+ n->options = $11;
+ n->sql_body = $12;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
+ opt_createfunc_opt_list opt_routine_body
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->is_procedure = false;
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = $5;
+ n->returnType = NULL;
+ n->options = $6;
+ n->sql_body = $7;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace PROCEDURE func_name func_args_with_defaults
+ opt_createfunc_opt_list opt_routine_body
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->is_procedure = true;
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = $5;
+ n->returnType = NULL;
+ n->options = $6;
+ n->sql_body = $7;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_or_replace:
+ OR REPLACE { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+func_args: '(' func_args_list ')' { $$ = $2; }
+ | '(' ')' { $$ = NIL; }
+ ;
+
+func_args_list:
+ func_arg { $$ = list_make1($1); }
+ | func_args_list ',' func_arg { $$ = lappend($1, $3); }
+ ;
+
+function_with_argtypes_list:
+ function_with_argtypes { $$ = list_make1($1); }
+ | function_with_argtypes_list ',' function_with_argtypes
+ { $$ = lappend($1, $3); }
+ ;
+
+function_with_argtypes:
+ func_name func_args
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = $1;
+ n->objargs = extractArgTypes($2);
+ n->objfuncargs = $2;
+ $$ = n;
+ }
+ /*
+ * Because of reduce/reduce conflicts, we can't use func_name
+ * below, but we can write it out the long way, which actually
+ * allows more cases.
+ */
+ | type_func_name_keyword
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = list_make1(makeString(pstrdup($1)));
+ n->args_unspecified = true;
+ $$ = n;
+ }
+ | ColId
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = list_make1(makeString($1));
+ n->args_unspecified = true;
+ $$ = n;
+ }
+ | ColId indirection
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = check_func_name(lcons(makeString($1), $2),
+ yyscanner);
+ n->args_unspecified = true;
+ $$ = n;
+ }
+ ;
+
+/*
+ * func_args_with_defaults is separate because we only want to accept
+ * defaults in CREATE FUNCTION, not in ALTER etc.
+ */
+func_args_with_defaults:
+ '(' func_args_with_defaults_list ')' { $$ = $2; }
+ | '(' ')' { $$ = NIL; }
+ ;
+
+func_args_with_defaults_list:
+ func_arg_with_default { $$ = list_make1($1); }
+ | func_args_with_defaults_list ',' func_arg_with_default
+ { $$ = lappend($1, $3); }
+ ;
+
+/*
+ * The style with arg_class first is SQL99 standard, but Oracle puts
+ * param_name first; accept both since it's likely people will try both
+ * anyway. Don't bother trying to save productions by letting arg_class
+ * have an empty alternative ... you'll get shift/reduce conflicts.
+ *
+ * We can catch over-specified arguments here if we want to,
+ * but for now better to silently swallow typmod, etc.
+ * - thomas 2000-03-22
+ */
+func_arg:
+ arg_class param_name func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = $2;
+ n->argType = $3;
+ n->mode = $1;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ | param_name arg_class func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = $1;
+ n->argType = $3;
+ n->mode = $2;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ | param_name func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = $1;
+ n->argType = $2;
+ n->mode = FUNC_PARAM_DEFAULT;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ | arg_class func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = NULL;
+ n->argType = $2;
+ n->mode = $1;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ | func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = NULL;
+ n->argType = $1;
+ n->mode = FUNC_PARAM_DEFAULT;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ ;
+
+/* INOUT is SQL99 standard, IN OUT is for Oracle compatibility */
+arg_class: IN_P { $$ = FUNC_PARAM_IN; }
+ | OUT_P { $$ = FUNC_PARAM_OUT; }
+ | INOUT { $$ = FUNC_PARAM_INOUT; }
+ | IN_P OUT_P { $$ = FUNC_PARAM_INOUT; }
+ | VARIADIC { $$ = FUNC_PARAM_VARIADIC; }
+ ;
+
+/*
+ * Ideally param_name should be ColId, but that causes too many conflicts.
+ */
+param_name: type_function_name
+ ;
+
+func_return:
+ func_type
+ {
+ /* We can catch over-specified results here if we want to,
+ * but for now better to silently swallow typmod, etc.
+ * - thomas 2000-03-22
+ */
+ $$ = $1;
+ }
+ ;
+
+/*
+ * We would like to make the %TYPE productions here be ColId attrs etc,
+ * but that causes reduce/reduce conflicts. type_function_name
+ * is next best choice.
+ */
+func_type: Typename { $$ = $1; }
+ | type_function_name attrs '%' TYPE_P
+ {
+ $$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
+ $$->pct_type = true;
+ $$->location = @1;
+ }
+ | SETOF type_function_name attrs '%' TYPE_P
+ {
+ $$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
+ $$->pct_type = true;
+ $$->setof = true;
+ $$->location = @2;
+ }
+ ;
+
+func_arg_with_default:
+ func_arg
+ {
+ $$ = $1;
+ }
+ | func_arg DEFAULT a_expr
+ {
+ $$ = $1;
+ $$->defexpr = $3;
+ }
+ | func_arg '=' a_expr
+ {
+ $$ = $1;
+ $$->defexpr = $3;
+ }
+ ;
+
+/* Aggregate args can be most things that function args can be */
+aggr_arg: func_arg
+ {
+ if (!($1->mode == FUNC_PARAM_DEFAULT ||
+ $1->mode == FUNC_PARAM_IN ||
+ $1->mode == FUNC_PARAM_VARIADIC))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("aggregates cannot have output arguments"),
+ parser_errposition(@1)));
+ $$ = $1;
+ }
+ ;
+
+/*
+ * The SQL standard offers no guidance on how to declare aggregate argument
+ * lists, since it doesn't have CREATE AGGREGATE etc. We accept these cases:
+ *
+ * (*) - normal agg with no args
+ * (aggr_arg,...) - normal agg with args
+ * (ORDER BY aggr_arg,...) - ordered-set agg with no direct args
+ * (aggr_arg,... ORDER BY aggr_arg,...) - ordered-set agg with direct args
+ *
+ * The zero-argument case is spelled with '*' for consistency with COUNT(*).
+ *
+ * An additional restriction is that if the direct-args list ends in a
+ * VARIADIC item, the ordered-args list must contain exactly one item that
+ * is also VARIADIC with the same type. This allows us to collapse the two
+ * VARIADIC items into one, which is necessary to represent the aggregate in
+ * pg_proc. We check this at the grammar stage so that we can return a list
+ * in which the second VARIADIC item is already discarded, avoiding extra work
+ * in cases such as DROP AGGREGATE.
+ *
+ * The return value of this production is a two-element list, in which the
+ * first item is a sublist of FunctionParameter nodes (with any duplicate
+ * VARIADIC item already dropped, as per above) and the second is an integer
+ * Value node, containing -1 if there was no ORDER BY and otherwise the number
+ * of argument declarations before the ORDER BY. (If this number is equal
+ * to the first sublist's length, then we dropped a duplicate VARIADIC item.)
+ * This representation is passed as-is to CREATE AGGREGATE; for operations
+ * on existing aggregates, we can just apply extractArgTypes to the first
+ * sublist.
+ */
+aggr_args: '(' '*' ')'
+ {
+ $$ = list_make2(NIL, makeInteger(-1));
+ }
+ | '(' aggr_args_list ')'
+ {
+ $$ = list_make2($2, makeInteger(-1));
+ }
+ | '(' ORDER BY aggr_args_list ')'
+ {
+ $$ = list_make2($4, makeInteger(0));
+ }
+ | '(' aggr_args_list ORDER BY aggr_args_list ')'
+ {
+ /* this is the only case requiring consistency checking */
+ $$ = makeOrderedSetArgs($2, $5, yyscanner);
+ }
+ ;
+
+aggr_args_list:
+ aggr_arg { $$ = list_make1($1); }
+ | aggr_args_list ',' aggr_arg { $$ = lappend($1, $3); }
+ ;
+
+aggregate_with_argtypes:
+ func_name aggr_args
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = $1;
+ n->objargs = extractAggrArgTypes($2);
+ n->objfuncargs = (List *) linitial($2);
+ $$ = n;
+ }
+ ;
+
+aggregate_with_argtypes_list:
+ aggregate_with_argtypes { $$ = list_make1($1); }
+ | aggregate_with_argtypes_list ',' aggregate_with_argtypes
+ { $$ = lappend($1, $3); }
+ ;
+
+opt_createfunc_opt_list:
+ createfunc_opt_list
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+createfunc_opt_list:
+ /* Must be at least one to prevent conflict */
+ createfunc_opt_item { $$ = list_make1($1); }
+ | createfunc_opt_list createfunc_opt_item { $$ = lappend($1, $2); }
+ ;
+
+/*
+ * Options common to both CREATE FUNCTION and ALTER FUNCTION
+ */
+common_func_opt_item:
+ CALLED ON NULL_P INPUT_P
+ {
+ $$ = makeDefElem("strict", (Node *)makeInteger(false), @1);
+ }
+ | RETURNS NULL_P ON NULL_P INPUT_P
+ {
+ $$ = makeDefElem("strict", (Node *)makeInteger(true), @1);
+ }
+ | STRICT_P
+ {
+ $$ = makeDefElem("strict", (Node *)makeInteger(true), @1);
+ }
+ | IMMUTABLE
+ {
+ $$ = makeDefElem("volatility", (Node *)makeString("immutable"), @1);
+ }
+ | STABLE
+ {
+ $$ = makeDefElem("volatility", (Node *)makeString("stable"), @1);
+ }
+ | VOLATILE
+ {
+ $$ = makeDefElem("volatility", (Node *)makeString("volatile"), @1);
+ }
+ | EXTERNAL SECURITY DEFINER
+ {
+ $$ = makeDefElem("security", (Node *)makeInteger(true), @1);
+ }
+ | EXTERNAL SECURITY INVOKER
+ {
+ $$ = makeDefElem("security", (Node *)makeInteger(false), @1);
+ }
+ | SECURITY DEFINER
+ {
+ $$ = makeDefElem("security", (Node *)makeInteger(true), @1);
+ }
+ | SECURITY INVOKER
+ {
+ $$ = makeDefElem("security", (Node *)makeInteger(false), @1);
+ }
+ | LEAKPROOF
+ {
+ $$ = makeDefElem("leakproof", (Node *)makeInteger(true), @1);
+ }
+ | NOT LEAKPROOF
+ {
+ $$ = makeDefElem("leakproof", (Node *)makeInteger(false), @1);
+ }
+ | COST NumericOnly
+ {
+ $$ = makeDefElem("cost", (Node *)$2, @1);
+ }
+ | ROWS NumericOnly
+ {
+ $$ = makeDefElem("rows", (Node *)$2, @1);
+ }
+ | SUPPORT any_name
+ {
+ $$ = makeDefElem("support", (Node *)$2, @1);
+ }
+ | FunctionSetResetClause
+ {
+ /* we abuse the normal content of a DefElem here */
+ $$ = makeDefElem("set", (Node *)$1, @1);
+ }
+ | PARALLEL ColId
+ {
+ $$ = makeDefElem("parallel", (Node *)makeString($2), @1);
+ }
+ ;
+
+createfunc_opt_item:
+ AS func_as
+ {
+ $$ = makeDefElem("as", (Node *)$2, @1);
+ }
+ | LANGUAGE NonReservedWord_or_Sconst
+ {
+ $$ = makeDefElem("language", (Node *)makeString($2), @1);
+ }
+ | TRANSFORM transform_type_list
+ {
+ $$ = makeDefElem("transform", (Node *)$2, @1);
+ }
+ | WINDOW
+ {
+ $$ = makeDefElem("window", (Node *)makeInteger(true), @1);
+ }
+ | common_func_opt_item
+ {
+ $$ = $1;
+ }
+ ;
+
+func_as: Sconst { $$ = list_make1(makeString($1)); }
+ | Sconst ',' Sconst
+ {
+ $$ = list_make2(makeString($1), makeString($3));
+ }
+ ;
+
+ReturnStmt: RETURN a_expr
+ {
+ ReturnStmt *r = makeNode(ReturnStmt);
+ r->returnval = (Node *) $2;
+ $$ = (Node *) r;
+ }
+ ;
+
+opt_routine_body:
+ ReturnStmt
+ {
+ $$ = $1;
+ }
+ | BEGIN_P ATOMIC routine_body_stmt_list END_P
+ {
+ /*
+ * A compound statement is stored as a single-item list
+ * containing the list of statements as its member. That
+ * way, the parse analysis code can tell apart an empty
+ * body from no body at all.
+ */
+ $$ = (Node *) list_make1($3);
+ }
+ | /*EMPTY*/
+ {
+ $$ = NULL;
+ }
+ ;
+
+routine_body_stmt_list:
+ routine_body_stmt_list routine_body_stmt ';'
+ {
+ /* As in stmtmulti, discard empty statements */
+ if ($2 != NULL)
+ $$ = lappend($1, $2);
+ else
+ $$ = $1;
+ }
+ | /*EMPTY*/
+ {
+ $$ = NIL;
+ }
+ ;
+
+routine_body_stmt:
+ stmt
+ | ReturnStmt
+ ;
+
+transform_type_list:
+ FOR TYPE_P Typename { $$ = list_make1($3); }
+ | transform_type_list ',' FOR TYPE_P Typename { $$ = lappend($1, $5); }
+ ;
+
+opt_definition:
+ WITH definition { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+table_func_column: param_name func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = $1;
+ n->argType = $2;
+ n->mode = FUNC_PARAM_TABLE;
+ n->defexpr = NULL;
+ $$ = n;
+ }
+ ;
+
+table_func_column_list:
+ table_func_column
+ {
+ $$ = list_make1($1);
+ }
+ | table_func_column_list ',' table_func_column
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+/*****************************************************************************
+ * ALTER FUNCTION / ALTER PROCEDURE / ALTER ROUTINE
+ *
+ * RENAME and OWNER subcommands are already provided by the generic
+ * ALTER infrastructure, here we just specify alterations that can
+ * only be applied to functions.
+ *
+ *****************************************************************************/
+AlterFunctionStmt:
+ ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict
+ {
+ AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_FUNCTION;
+ n->func = $3;
+ n->actions = $4;
+ $$ = (Node *) n;
+ }
+ | ALTER PROCEDURE function_with_argtypes alterfunc_opt_list opt_restrict
+ {
+ AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_PROCEDURE;
+ n->func = $3;
+ n->actions = $4;
+ $$ = (Node *) n;
+ }
+ | ALTER ROUTINE function_with_argtypes alterfunc_opt_list opt_restrict
+ {
+ AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_ROUTINE;
+ n->func = $3;
+ n->actions = $4;
+ $$ = (Node *) n;
+ }
+ ;
+
+alterfunc_opt_list:
+ /* At least one option must be specified */
+ common_func_opt_item { $$ = list_make1($1); }
+ | alterfunc_opt_list common_func_opt_item { $$ = lappend($1, $2); }
+ ;
+
+/* Ignored, merely for SQL compliance */
+opt_restrict:
+ RESTRICT
+ | /* EMPTY */
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ *
+ * DROP FUNCTION funcname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
+ * DROP PROCEDURE procname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
+ * DROP ROUTINE routname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
+ * DROP AGGREGATE aggname (arg1, ...) [ RESTRICT | CASCADE ]
+ * DROP OPERATOR opname (leftoperand_typ, rightoperand_typ) [ RESTRICT | CASCADE ]
+ *
+ *****************************************************************************/
+
+RemoveFuncStmt:
+ DROP FUNCTION function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_FUNCTION;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP FUNCTION IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_FUNCTION;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP PROCEDURE function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_PROCEDURE;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP PROCEDURE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_PROCEDURE;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP ROUTINE function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_ROUTINE;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP ROUTINE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_ROUTINE;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+RemoveAggrStmt:
+ DROP AGGREGATE aggregate_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_AGGREGATE;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_AGGREGATE;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+RemoveOperStmt:
+ DROP OPERATOR operator_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_OPERATOR;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP OPERATOR IF_P EXISTS operator_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_OPERATOR;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+oper_argtypes:
+ '(' Typename ')'
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("missing argument"),
+ errhint("Use NONE to denote the missing argument of a unary operator."),
+ parser_errposition(@3)));
+ }
+ | '(' Typename ',' Typename ')'
+ { $$ = list_make2($2, $4); }
+ | '(' NONE ',' Typename ')' /* left unary */
+ { $$ = list_make2(NULL, $4); }
+ | '(' Typename ',' NONE ')' /* right unary */
+ { $$ = list_make2($2, NULL); }
+ ;
+
+any_operator:
+ all_Op
+ { $$ = list_make1(makeString($1)); }
+ | ColId '.' any_operator
+ { $$ = lcons(makeString($1), $3); }
+ ;
+
+operator_with_argtypes_list:
+ operator_with_argtypes { $$ = list_make1($1); }
+ | operator_with_argtypes_list ',' operator_with_argtypes
+ { $$ = lappend($1, $3); }
+ ;
+
+operator_with_argtypes:
+ any_operator oper_argtypes
+ {
+ ObjectWithArgs *n = makeNode(ObjectWithArgs);
+ n->objname = $1;
+ n->objargs = $2;
+ $$ = n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * DO <anonymous code block> [ LANGUAGE language ]
+ *
+ * We use a DefElem list for future extensibility, and to allow flexibility
+ * in the clause order.
+ *
+ *****************************************************************************/
+
+DoStmt: DO dostmt_opt_list
+ {
+ DoStmt *n = makeNode(DoStmt);
+ n->args = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+dostmt_opt_list:
+ dostmt_opt_item { $$ = list_make1($1); }
+ | dostmt_opt_list dostmt_opt_item { $$ = lappend($1, $2); }
+ ;
+
+dostmt_opt_item:
+ Sconst
+ {
+ $$ = makeDefElem("as", (Node *)makeString($1), @1);
+ }
+ | LANGUAGE NonReservedWord_or_Sconst
+ {
+ $$ = makeDefElem("language", (Node *)makeString($2), @1);
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * CREATE CAST / DROP CAST
+ *
+ *****************************************************************************/
+
+CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
+ WITH FUNCTION function_with_argtypes cast_context
+ {
+ CreateCastStmt *n = makeNode(CreateCastStmt);
+ n->sourcetype = $4;
+ n->targettype = $6;
+ n->func = $10;
+ n->context = (CoercionContext) $11;
+ n->inout = false;
+ $$ = (Node *)n;
+ }
+ | CREATE CAST '(' Typename AS Typename ')'
+ WITHOUT FUNCTION cast_context
+ {
+ CreateCastStmt *n = makeNode(CreateCastStmt);
+ n->sourcetype = $4;
+ n->targettype = $6;
+ n->func = NULL;
+ n->context = (CoercionContext) $10;
+ n->inout = false;
+ $$ = (Node *)n;
+ }
+ | CREATE CAST '(' Typename AS Typename ')'
+ WITH INOUT cast_context
+ {
+ CreateCastStmt *n = makeNode(CreateCastStmt);
+ n->sourcetype = $4;
+ n->targettype = $6;
+ n->func = NULL;
+ n->context = (CoercionContext) $10;
+ n->inout = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+cast_context: AS IMPLICIT_P { $$ = COERCION_IMPLICIT; }
+ | AS ASSIGNMENT { $$ = COERCION_ASSIGNMENT; }
+ | /*EMPTY*/ { $$ = COERCION_EXPLICIT; }
+ ;
+
+
+DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_CAST;
+ n->objects = list_make1(list_make2($5, $7));
+ n->behavior = $9;
+ n->missing_ok = $3;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_if_exists: IF_P EXISTS { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * CREATE TRANSFORM / DROP TRANSFORM
+ *
+ *****************************************************************************/
+
+CreateTransformStmt: CREATE opt_or_replace TRANSFORM FOR Typename LANGUAGE name '(' transform_element_list ')'
+ {
+ CreateTransformStmt *n = makeNode(CreateTransformStmt);
+ n->replace = $2;
+ n->type_name = $5;
+ n->lang = $7;
+ n->fromsql = linitial($9);
+ n->tosql = lsecond($9);
+ $$ = (Node *)n;
+ }
+ ;
+
+transform_element_list: FROM SQL_P WITH FUNCTION function_with_argtypes ',' TO SQL_P WITH FUNCTION function_with_argtypes
+ {
+ $$ = list_make2($5, $11);
+ }
+ | TO SQL_P WITH FUNCTION function_with_argtypes ',' FROM SQL_P WITH FUNCTION function_with_argtypes
+ {
+ $$ = list_make2($11, $5);
+ }
+ | FROM SQL_P WITH FUNCTION function_with_argtypes
+ {
+ $$ = list_make2($5, NULL);
+ }
+ | TO SQL_P WITH FUNCTION function_with_argtypes
+ {
+ $$ = list_make2(NULL, $5);
+ }
+ ;
+
+
+DropTransformStmt: DROP TRANSFORM opt_if_exists FOR Typename LANGUAGE name opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_TRANSFORM;
+ n->objects = list_make1(list_make2($5, makeString($7)));
+ n->behavior = $8;
+ n->missing_ok = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ *
+ * REINDEX [ (options) ] type [CONCURRENTLY] <name>
+ *****************************************************************************/
+
+ReindexStmt:
+ REINDEX reindex_target_type opt_concurrently qualified_name
+ {
+ ReindexStmt *n = makeNode(ReindexStmt);
+ n->kind = $2;
+ n->relation = $4;
+ n->name = NULL;
+ n->params = NIL;
+ if ($3)
+ n->params = lappend(n->params,
+ makeDefElem("concurrently", NULL, @3));
+ $$ = (Node *)n;
+ }
+ | REINDEX reindex_target_multitable opt_concurrently name
+ {
+ ReindexStmt *n = makeNode(ReindexStmt);
+ n->kind = $2;
+ n->name = $4;
+ n->relation = NULL;
+ n->params = NIL;
+ if ($3)
+ n->params = lappend(n->params,
+ makeDefElem("concurrently", NULL, @3));
+ $$ = (Node *)n;
+ }
+ | REINDEX '(' utility_option_list ')' reindex_target_type opt_concurrently qualified_name
+ {
+ ReindexStmt *n = makeNode(ReindexStmt);
+ n->kind = $5;
+ n->relation = $7;
+ n->name = NULL;
+ n->params = $3;
+ if ($6)
+ n->params = lappend(n->params,
+ makeDefElem("concurrently", NULL, @6));
+ $$ = (Node *)n;
+ }
+ | REINDEX '(' utility_option_list ')' reindex_target_multitable opt_concurrently name
+ {
+ ReindexStmt *n = makeNode(ReindexStmt);
+ n->kind = $5;
+ n->name = $7;
+ n->relation = NULL;
+ n->params = $3;
+ if ($6)
+ n->params = lappend(n->params,
+ makeDefElem("concurrently", NULL, @6));
+ $$ = (Node *)n;
+ }
+ ;
+reindex_target_type:
+ INDEX { $$ = REINDEX_OBJECT_INDEX; }
+ | TABLE { $$ = REINDEX_OBJECT_TABLE; }
+ ;
+reindex_target_multitable:
+ SCHEMA { $$ = REINDEX_OBJECT_SCHEMA; }
+ | SYSTEM_P { $$ = REINDEX_OBJECT_SYSTEM; }
+ | DATABASE { $$ = REINDEX_OBJECT_DATABASE; }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER TABLESPACE
+ *
+ *****************************************************************************/
+
+AlterTblSpcStmt:
+ ALTER TABLESPACE name SET reloptions
+ {
+ AlterTableSpaceOptionsStmt *n =
+ makeNode(AlterTableSpaceOptionsStmt);
+ n->tablespacename = $3;
+ n->options = $5;
+ n->isReset = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLESPACE name RESET reloptions
+ {
+ AlterTableSpaceOptionsStmt *n =
+ makeNode(AlterTableSpaceOptionsStmt);
+ n->tablespacename = $3;
+ n->options = $5;
+ n->isReset = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER THING name RENAME TO newname
+ *
+ *****************************************************************************/
+
+RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_AGGREGATE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER COLLATION any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLLATION;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER CONVERSION_P any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_CONVERSION;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER DATABASE name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_DATABASE;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER DOMAIN_P any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_DOMAIN;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_DOMCONSTRAINT;
+ n->object = (Node *) $3;
+ n->subname = $6;
+ n->newname = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FDW;
+ n->object = (Node *) makeString($5);
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FUNCTION function_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FUNCTION;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER GROUP_P RoleId RENAME TO RoleId
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ROLE;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER opt_procedural LANGUAGE name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_LANGUAGE;
+ n->object = (Node *) makeString($4);
+ n->newname = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR CLASS any_name USING name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_OPCLASS;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newname = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_OPFAMILY;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newname = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER POLICY name ON qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_POLICY;
+ n->relation = $5;
+ n->subname = $3;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER POLICY IF_P EXISTS name ON qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_POLICY;
+ n->relation = $7;
+ n->subname = $5;
+ n->newname = $10;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER PROCEDURE function_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER PUBLICATION name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_PUBLICATION;
+ n->object = (Node *) makeString($3);
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SCHEMA name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_SCHEMA;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SERVER name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FOREIGN_SERVER;
+ n->object = (Node *) makeString($3);
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_SUBSCRIPTION;
+ n->object = (Node *) makeString($3);
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TABLE;
+ n->relation = $3;
+ n->subname = NULL;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TABLE;
+ n->relation = $5;
+ n->subname = NULL;
+ n->newname = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_SEQUENCE;
+ n->relation = $3;
+ n->subname = NULL;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE IF_P EXISTS qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_SEQUENCE;
+ n->relation = $5;
+ n->subname = NULL;
+ n->newname = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_VIEW;
+ n->relation = $3;
+ n->subname = NULL;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW IF_P EXISTS qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_VIEW;
+ n->relation = $5;
+ n->subname = NULL;
+ n->newname = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->subname = NULL;
+ n->newname = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_MATVIEW;
+ n->relation = $6;
+ n->subname = NULL;
+ n->newname = $9;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_INDEX;
+ n->relation = $3;
+ n->subname = NULL;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX IF_P EXISTS qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_INDEX;
+ n->relation = $5;
+ n->subname = NULL;
+ n->newname = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE relation_expr RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FOREIGN_TABLE;
+ n->relation = $4;
+ n->subname = NULL;
+ n->newname = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_FOREIGN_TABLE;
+ n->relation = $6;
+ n->subname = NULL;
+ n->newname = $9;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_TABLE;
+ n->relation = $3;
+ n->subname = $6;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_TABLE;
+ n->relation = $5;
+ n->subname = $8;
+ n->newname = $10;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW qualified_name RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_VIEW;
+ n->relation = $3;
+ n->subname = $6;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_VIEW;
+ n->relation = $5;
+ n->subname = $8;
+ n->newname = $10;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW qualified_name RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->subname = $7;
+ n->newname = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_MATVIEW;
+ n->relation = $6;
+ n->subname = $9;
+ n->newname = $11;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TABCONSTRAINT;
+ n->relation = $3;
+ n->subname = $6;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TABCONSTRAINT;
+ n->relation = $5;
+ n->subname = $8;
+ n->newname = $10;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE relation_expr RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_FOREIGN_TABLE;
+ n->relation = $4;
+ n->subname = $7;
+ n->newname = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_COLUMN;
+ n->relationType = OBJECT_FOREIGN_TABLE;
+ n->relation = $6;
+ n->subname = $9;
+ n->newname = $11;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER RULE name ON qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_RULE;
+ n->relation = $5;
+ n->subname = $3;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TRIGGER name ON qualified_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TRIGGER;
+ n->relation = $5;
+ n->subname = $3;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER EVENT TRIGGER name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_EVENT_TRIGGER;
+ n->object = (Node *) makeString($4);
+ n->newname = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER ROLE RoleId RENAME TO RoleId
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ROLE;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER USER RoleId RENAME TO RoleId
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ROLE;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLESPACE name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TABLESPACE;
+ n->subname = $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER STATISTICS any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_STATISTIC_EXT;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TSPARSER;
+ n->object = (Node *) $5;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TSDICTIONARY;
+ n->object = (Node *) $5;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TSTEMPLATE;
+ n->object = (Node *) $5;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TSCONFIGURATION;
+ n->object = (Node *) $5;
+ n->newname = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TYPE_P any_name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_TYPE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ATTRIBUTE;
+ n->relationType = OBJECT_TYPE;
+ n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
+ n->subname = $6;
+ n->newname = $8;
+ n->behavior = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_column: COLUMN
+ | /*EMPTY*/
+ ;
+
+opt_set_data: SET DATA_P { $$ = 1; }
+ | /*EMPTY*/ { $$ = 0; }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER THING name DEPENDS ON EXTENSION name
+ *
+ *****************************************************************************/
+
+AlterObjectDependsStmt:
+ ALTER FUNCTION function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_FUNCTION;
+ n->object = (Node *) $3;
+ n->extname = makeString($8);
+ n->remove = $4;
+ $$ = (Node *)n;
+ }
+ | ALTER PROCEDURE function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->extname = makeString($8);
+ n->remove = $4;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->extname = makeString($8);
+ n->remove = $4;
+ $$ = (Node *)n;
+ }
+ | ALTER TRIGGER name ON qualified_name opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_TRIGGER;
+ n->relation = $5;
+ n->object = (Node *) list_make1(makeString($3));
+ n->extname = makeString($10);
+ n->remove = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW qualified_name opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->extname = makeString($9);
+ n->remove = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER INDEX qualified_name opt_no DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_INDEX;
+ n->relation = $3;
+ n->extname = makeString($8);
+ n->remove = $4;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_no: NO { $$ = true; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER THING name SET SCHEMA name
+ *
+ *****************************************************************************/
+
+AlterObjectSchemaStmt:
+ ALTER AGGREGATE aggregate_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_AGGREGATE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER COLLATION any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_COLLATION;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER CONVERSION_P any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_CONVERSION;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER DOMAIN_P any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_DOMAIN;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_EXTENSION;
+ n->object = (Node *) makeString($3);
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FUNCTION function_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_FUNCTION;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR operator_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_OPERATOR;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR CLASS any_name USING name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_OPCLASS;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newschema = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_OPFAMILY;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newschema = $9;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER PROCEDURE function_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE relation_expr SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TABLE;
+ n->relation = $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLE IF_P EXISTS relation_expr SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TABLE;
+ n->relation = $5;
+ n->newschema = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER STATISTICS any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_STATISTIC_EXT;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TSPARSER;
+ n->object = (Node *) $5;
+ n->newschema = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TSDICTIONARY;
+ n->object = (Node *) $5;
+ n->newschema = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TSTEMPLATE;
+ n->object = (Node *) $5;
+ n->newschema = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TSCONFIGURATION;
+ n->object = (Node *) $5;
+ n->newschema = $8;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_SEQUENCE;
+ n->relation = $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_SEQUENCE;
+ n->relation = $5;
+ n->newschema = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_VIEW;
+ n->relation = $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER VIEW IF_P EXISTS qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_VIEW;
+ n->relation = $5;
+ n->newschema = $8;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_MATVIEW;
+ n->relation = $4;
+ n->newschema = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_MATVIEW;
+ n->relation = $6;
+ n->newschema = $9;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE relation_expr SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_FOREIGN_TABLE;
+ n->relation = $4;
+ n->newschema = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN TABLE IF_P EXISTS relation_expr SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_FOREIGN_TABLE;
+ n->relation = $6;
+ n->newschema = $9;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ | ALTER TYPE_P any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_TYPE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER OPERATOR name SET define
+ *
+ *****************************************************************************/
+
+AlterOperatorStmt:
+ ALTER OPERATOR operator_with_argtypes SET '(' operator_def_list ')'
+ {
+ AlterOperatorStmt *n = makeNode(AlterOperatorStmt);
+ n->opername = $3;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+operator_def_list: operator_def_elem { $$ = list_make1($1); }
+ | operator_def_list ',' operator_def_elem { $$ = lappend($1, $3); }
+ ;
+
+operator_def_elem: ColLabel '=' NONE
+ { $$ = makeDefElem($1, NULL, @1); }
+ | ColLabel '=' operator_def_arg
+ { $$ = makeDefElem($1, (Node *) $3, @1); }
+ ;
+
+/* must be similar enough to def_arg to avoid reduce/reduce conflicts */
+operator_def_arg:
+ func_type { $$ = (Node *)$1; }
+ | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); }
+ | qual_all_Op { $$ = (Node *)$1; }
+ | NumericOnly { $$ = (Node *)$1; }
+ | Sconst { $$ = (Node *)makeString($1); }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER TYPE name SET define
+ *
+ * We repurpose ALTER OPERATOR's version of "definition" here
+ *
+ *****************************************************************************/
+
+AlterTypeStmt:
+ ALTER TYPE_P any_name SET '(' operator_def_list ')'
+ {
+ AlterTypeStmt *n = makeNode(AlterTypeStmt);
+ n->typeName = $3;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER THING name OWNER TO newname
+ *
+ *****************************************************************************/
+
+AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_AGGREGATE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER COLLATION any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_COLLATION;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_CONVERSION;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER DATABASE name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_DATABASE;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_DOMAIN;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_FUNCTION;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_LANGUAGE;
+ n->object = (Node *) makeString($4);
+ n->newowner = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_LARGEOBJECT;
+ n->object = (Node *) $4;
+ n->newowner = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR operator_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_OPERATOR;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR CLASS any_name USING name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_OPCLASS;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newowner = $9;
+ $$ = (Node *)n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_OPFAMILY;
+ n->object = (Node *) lcons(makeString($6), $4);
+ n->newowner = $9;
+ $$ = (Node *)n;
+ }
+ | ALTER PROCEDURE function_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER SCHEMA name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_SCHEMA;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_TYPE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER TABLESPACE name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_TABLESPACE;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER STATISTICS any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_STATISTIC_EXT;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_TSDICTIONARY;
+ n->object = (Node *) $5;
+ n->newowner = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_TSCONFIGURATION;
+ n->object = (Node *) $5;
+ n->newowner = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_FDW;
+ n->object = (Node *) makeString($5);
+ n->newowner = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER SERVER name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_FOREIGN_SERVER;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_EVENT_TRIGGER;
+ n->object = (Node *) makeString($4);
+ n->newowner = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER PUBLICATION name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_PUBLICATION;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_SUBSCRIPTION;
+ n->object = (Node *) makeString($3);
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * CREATE PUBLICATION name [ FOR TABLE ] [ WITH options ]
+ *
+ *****************************************************************************/
+
+CreatePublicationStmt:
+ CREATE PUBLICATION name opt_publication_for_tables opt_definition
+ {
+ CreatePublicationStmt *n = makeNode(CreatePublicationStmt);
+ n->pubname = $3;
+ n->options = $5;
+ if ($4 != NULL)
+ {
+ /* FOR TABLE */
+ if (IsA($4, List))
+ n->tables = (List *)$4;
+ /* FOR ALL TABLES */
+ else
+ n->for_all_tables = true;
+ }
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_publication_for_tables:
+ publication_for_tables { $$ = $1; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+publication_for_tables:
+ FOR TABLE relation_expr_list
+ {
+ $$ = (Node *) $3;
+ }
+ | FOR ALL TABLES
+ {
+ $$ = (Node *) makeInteger(true);
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * ALTER PUBLICATION name SET ( options )
+ *
+ * ALTER PUBLICATION name ADD TABLE table [, table2]
+ *
+ * ALTER PUBLICATION name DROP TABLE table [, table2]
+ *
+ * ALTER PUBLICATION name SET TABLE table [, table2]
+ *
+ *****************************************************************************/
+
+AlterPublicationStmt:
+ ALTER PUBLICATION name SET definition
+ {
+ AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
+ n->pubname = $3;
+ n->options = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER PUBLICATION name ADD_P TABLE relation_expr_list
+ {
+ AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
+ n->pubname = $3;
+ n->tables = $6;
+ n->tableAction = DEFELEM_ADD;
+ $$ = (Node *)n;
+ }
+ | ALTER PUBLICATION name SET TABLE relation_expr_list
+ {
+ AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
+ n->pubname = $3;
+ n->tables = $6;
+ n->tableAction = DEFELEM_SET;
+ $$ = (Node *)n;
+ }
+ | ALTER PUBLICATION name DROP TABLE relation_expr_list
+ {
+ AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
+ n->pubname = $3;
+ n->tables = $6;
+ n->tableAction = DEFELEM_DROP;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * CREATE SUBSCRIPTION name ...
+ *
+ *****************************************************************************/
+
+CreateSubscriptionStmt:
+ CREATE SUBSCRIPTION name CONNECTION Sconst PUBLICATION name_list opt_definition
+ {
+ CreateSubscriptionStmt *n =
+ makeNode(CreateSubscriptionStmt);
+ n->subname = $3;
+ n->conninfo = $5;
+ n->publication = $7;
+ n->options = $8;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER SUBSCRIPTION name ...
+ *
+ *****************************************************************************/
+
+AlterSubscriptionStmt:
+ ALTER SUBSCRIPTION name SET definition
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_OPTIONS;
+ n->subname = $3;
+ n->options = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name CONNECTION Sconst
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_CONNECTION;
+ n->subname = $3;
+ n->conninfo = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name REFRESH PUBLICATION opt_definition
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_REFRESH;
+ n->subname = $3;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name ADD_P PUBLICATION name_list opt_definition
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_ADD_PUBLICATION;
+ n->subname = $3;
+ n->publication = $6;
+ n->options = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name DROP PUBLICATION name_list opt_definition
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_DROP_PUBLICATION;
+ n->subname = $3;
+ n->publication = $6;
+ n->options = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name SET PUBLICATION name_list opt_definition
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_SET_PUBLICATION;
+ n->subname = $3;
+ n->publication = $6;
+ n->options = $7;
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name ENABLE_P
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_ENABLED;
+ n->subname = $3;
+ n->options = list_make1(makeDefElem("enabled",
+ (Node *)makeInteger(true), @1));
+ $$ = (Node *)n;
+ }
+ | ALTER SUBSCRIPTION name DISABLE_P
+ {
+ AlterSubscriptionStmt *n =
+ makeNode(AlterSubscriptionStmt);
+ n->kind = ALTER_SUBSCRIPTION_ENABLED;
+ n->subname = $3;
+ n->options = list_make1(makeDefElem("enabled",
+ (Node *)makeInteger(false), @1));
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * DROP SUBSCRIPTION [ IF EXISTS ] name
+ *
+ *****************************************************************************/
+
+DropSubscriptionStmt: DROP SUBSCRIPTION name opt_drop_behavior
+ {
+ DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt);
+ n->subname = $3;
+ n->missing_ok = false;
+ n->behavior = $4;
+ $$ = (Node *) n;
+ }
+ | DROP SUBSCRIPTION IF_P EXISTS name opt_drop_behavior
+ {
+ DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt);
+ n->subname = $5;
+ n->missing_ok = true;
+ n->behavior = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY: Define Rewrite Rule
+ *
+ *****************************************************************************/
+
+RuleStmt: CREATE opt_or_replace RULE name AS
+ ON event TO qualified_name where_clause
+ DO opt_instead RuleActionList
+ {
+ RuleStmt *n = makeNode(RuleStmt);
+ n->replace = $2;
+ n->relation = $9;
+ n->rulename = $4;
+ n->whereClause = $10;
+ n->event = $7;
+ n->instead = $12;
+ n->actions = $13;
+ $$ = (Node *)n;
+ }
+ ;
+
+RuleActionList:
+ NOTHING { $$ = NIL; }
+ | RuleActionStmt { $$ = list_make1($1); }
+ | '(' RuleActionMulti ')' { $$ = $2; }
+ ;
+
+/* the thrashing around here is to discard "empty" statements... */
+RuleActionMulti:
+ RuleActionMulti ';' RuleActionStmtOrEmpty
+ { if ($3 != NULL)
+ $$ = lappend($1, $3);
+ else
+ $$ = $1;
+ }
+ | RuleActionStmtOrEmpty
+ { if ($1 != NULL)
+ $$ = list_make1($1);
+ else
+ $$ = NIL;
+ }
+ ;
+
+RuleActionStmt:
+ SelectStmt
+ | InsertStmt
+ | UpdateStmt
+ | DeleteStmt
+ | NotifyStmt
+ ;
+
+RuleActionStmtOrEmpty:
+ RuleActionStmt { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+event: SELECT { $$ = CMD_SELECT; }
+ | UPDATE { $$ = CMD_UPDATE; }
+ | DELETE_P { $$ = CMD_DELETE; }
+ | INSERT { $$ = CMD_INSERT; }
+ ;
+
+opt_instead:
+ INSTEAD { $$ = true; }
+ | ALSO { $$ = false; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * NOTIFY <identifier> can appear both in rule bodies and
+ * as a query-level command
+ *
+ *****************************************************************************/
+
+NotifyStmt: NOTIFY ColId notify_payload
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->conditionname = $2;
+ n->payload = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+notify_payload:
+ ',' Sconst { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+ListenStmt: LISTEN ColId
+ {
+ ListenStmt *n = makeNode(ListenStmt);
+ n->conditionname = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+UnlistenStmt:
+ UNLISTEN ColId
+ {
+ UnlistenStmt *n = makeNode(UnlistenStmt);
+ n->conditionname = $2;
+ $$ = (Node *)n;
+ }
+ | UNLISTEN '*'
+ {
+ UnlistenStmt *n = makeNode(UnlistenStmt);
+ n->conditionname = NULL;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * Transactions:
+ *
+ * BEGIN / COMMIT / ROLLBACK
+ * (also older versions END / ABORT)
+ *
+ *****************************************************************************/
+
+TransactionStmt:
+ ABORT_P opt_transaction opt_transaction_chain
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_ROLLBACK;
+ n->options = NIL;
+ n->chain = $3;
+ $$ = (Node *)n;
+ }
+ | START TRANSACTION transaction_mode_list_or_empty
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_START;
+ n->options = $3;
+ $$ = (Node *)n;
+ }
+ | COMMIT opt_transaction opt_transaction_chain
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_COMMIT;
+ n->options = NIL;
+ n->chain = $3;
+ $$ = (Node *)n;
+ }
+ | ROLLBACK opt_transaction opt_transaction_chain
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_ROLLBACK;
+ n->options = NIL;
+ n->chain = $3;
+ $$ = (Node *)n;
+ }
+ | SAVEPOINT ColId
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_SAVEPOINT;
+ n->savepoint_name = $2;
+ $$ = (Node *)n;
+ }
+ | RELEASE SAVEPOINT ColId
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_RELEASE;
+ n->savepoint_name = $3;
+ $$ = (Node *)n;
+ }
+ | RELEASE ColId
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_RELEASE;
+ n->savepoint_name = $2;
+ $$ = (Node *)n;
+ }
+ | ROLLBACK opt_transaction TO SAVEPOINT ColId
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_ROLLBACK_TO;
+ n->savepoint_name = $5;
+ $$ = (Node *)n;
+ }
+ | ROLLBACK opt_transaction TO ColId
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_ROLLBACK_TO;
+ n->savepoint_name = $4;
+ $$ = (Node *)n;
+ }
+ | PREPARE TRANSACTION Sconst
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_PREPARE;
+ n->gid = $3;
+ $$ = (Node *)n;
+ }
+ | COMMIT PREPARED Sconst
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_COMMIT_PREPARED;
+ n->gid = $3;
+ $$ = (Node *)n;
+ }
+ | ROLLBACK PREPARED Sconst
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_ROLLBACK_PREPARED;
+ n->gid = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+TransactionStmtLegacy:
+ BEGIN_P opt_transaction transaction_mode_list_or_empty
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_BEGIN;
+ n->options = $3;
+ $$ = (Node *)n;
+ }
+ | END_P opt_transaction opt_transaction_chain
+ {
+ TransactionStmt *n = makeNode(TransactionStmt);
+ n->kind = TRANS_STMT_COMMIT;
+ n->options = NIL;
+ n->chain = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_transaction: WORK
+ | TRANSACTION
+ | /*EMPTY*/
+ ;
+
+transaction_mode_item:
+ ISOLATION LEVEL iso_level
+ { $$ = makeDefElem("transaction_isolation",
+ makeStringConst($3, @3), @1); }
+ | READ ONLY
+ { $$ = makeDefElem("transaction_read_only",
+ makeIntConst(true, @1), @1); }
+ | READ WRITE
+ { $$ = makeDefElem("transaction_read_only",
+ makeIntConst(false, @1), @1); }
+ | DEFERRABLE
+ { $$ = makeDefElem("transaction_deferrable",
+ makeIntConst(true, @1), @1); }
+ | NOT DEFERRABLE
+ { $$ = makeDefElem("transaction_deferrable",
+ makeIntConst(false, @1), @1); }
+ ;
+
+/* Syntax with commas is SQL-spec, without commas is Postgres historical */
+transaction_mode_list:
+ transaction_mode_item
+ { $$ = list_make1($1); }
+ | transaction_mode_list ',' transaction_mode_item
+ { $$ = lappend($1, $3); }
+ | transaction_mode_list transaction_mode_item
+ { $$ = lappend($1, $2); }
+ ;
+
+transaction_mode_list_or_empty:
+ transaction_mode_list
+ | /* EMPTY */
+ { $$ = NIL; }
+ ;
+
+opt_transaction_chain:
+ AND CHAIN { $$ = true; }
+ | AND NO CHAIN { $$ = false; }
+ | /* EMPTY */ { $$ = false; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
+ * AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
+ *
+ *****************************************************************************/
+
+ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions
+ AS SelectStmt opt_check_option
+ {
+ ViewStmt *n = makeNode(ViewStmt);
+ n->view = $4;
+ n->view->relpersistence = $2;
+ n->aliases = $5;
+ n->query = $8;
+ n->replace = false;
+ n->options = $6;
+ n->withCheckOption = $9;
+ $$ = (Node *) n;
+ }
+ | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list opt_reloptions
+ AS SelectStmt opt_check_option
+ {
+ ViewStmt *n = makeNode(ViewStmt);
+ n->view = $6;
+ n->view->relpersistence = $4;
+ n->aliases = $7;
+ n->query = $10;
+ n->replace = true;
+ n->options = $8;
+ n->withCheckOption = $11;
+ $$ = (Node *) n;
+ }
+ | CREATE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions
+ AS SelectStmt opt_check_option
+ {
+ ViewStmt *n = makeNode(ViewStmt);
+ n->view = $5;
+ n->view->relpersistence = $2;
+ n->aliases = $7;
+ n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $11);
+ n->replace = false;
+ n->options = $9;
+ n->withCheckOption = $12;
+ if (n->withCheckOption != NO_CHECK_OPTION)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("WITH CHECK OPTION not supported on recursive views"),
+ parser_errposition(@12)));
+ $$ = (Node *) n;
+ }
+ | CREATE OR REPLACE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions
+ AS SelectStmt opt_check_option
+ {
+ ViewStmt *n = makeNode(ViewStmt);
+ n->view = $7;
+ n->view->relpersistence = $4;
+ n->aliases = $9;
+ n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $13);
+ n->replace = true;
+ n->options = $11;
+ n->withCheckOption = $14;
+ if (n->withCheckOption != NO_CHECK_OPTION)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("WITH CHECK OPTION not supported on recursive views"),
+ parser_errposition(@14)));
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_check_option:
+ WITH CHECK OPTION { $$ = CASCADED_CHECK_OPTION; }
+ | WITH CASCADED CHECK OPTION { $$ = CASCADED_CHECK_OPTION; }
+ | WITH LOCAL CHECK OPTION { $$ = LOCAL_CHECK_OPTION; }
+ | /* EMPTY */ { $$ = NO_CHECK_OPTION; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * LOAD "filename"
+ *
+ *****************************************************************************/
+
+LoadStmt: LOAD file_name
+ {
+ LoadStmt *n = makeNode(LoadStmt);
+ n->filename = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * CREATE DATABASE
+ *
+ *****************************************************************************/
+
+CreatedbStmt:
+ CREATE DATABASE name opt_with createdb_opt_list
+ {
+ CreatedbStmt *n = makeNode(CreatedbStmt);
+ n->dbname = $3;
+ n->options = $5;
+ $$ = (Node *)n;
+ }
+ ;
+
+createdb_opt_list:
+ createdb_opt_items { $$ = $1; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+createdb_opt_items:
+ createdb_opt_item { $$ = list_make1($1); }
+ | createdb_opt_items createdb_opt_item { $$ = lappend($1, $2); }
+ ;
+
+createdb_opt_item:
+ createdb_opt_name opt_equal SignedIconst
+ {
+ $$ = makeDefElem($1, (Node *)makeInteger($3), @1);
+ }
+ | createdb_opt_name opt_equal opt_boolean_or_string
+ {
+ $$ = makeDefElem($1, (Node *)makeString($3), @1);
+ }
+ | createdb_opt_name opt_equal DEFAULT
+ {
+ $$ = makeDefElem($1, NULL, @1);
+ }
+ ;
+
+/*
+ * Ideally we'd use ColId here, but that causes shift/reduce conflicts against
+ * the ALTER DATABASE SET/RESET syntaxes. Instead call out specific keywords
+ * we need, and allow IDENT so that database option names don't have to be
+ * parser keywords unless they are already keywords for other reasons.
+ *
+ * XXX this coding technique is fragile since if someone makes a formerly
+ * non-keyword option name into a keyword and forgets to add it here, the
+ * option will silently break. Best defense is to provide a regression test
+ * exercising every such option, at least at the syntax level.
+ */
+createdb_opt_name:
+ IDENT { $$ = $1; }
+ | CONNECTION LIMIT { $$ = pstrdup("connection_limit"); }
+ | ENCODING { $$ = pstrdup($1); }
+ | LOCATION { $$ = pstrdup($1); }
+ | OWNER { $$ = pstrdup($1); }
+ | TABLESPACE { $$ = pstrdup($1); }
+ | TEMPLATE { $$ = pstrdup($1); }
+ ;
+
+/*
+ * Though the equals sign doesn't match other WITH options, pg_dump uses
+ * equals for backward compatibility, and it doesn't seem worth removing it.
+ */
+opt_equal: '='
+ | /*EMPTY*/
+ ;
+
+
+/*****************************************************************************
+ *
+ * ALTER DATABASE
+ *
+ *****************************************************************************/
+
+AlterDatabaseStmt:
+ ALTER DATABASE name WITH createdb_opt_list
+ {
+ AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
+ n->dbname = $3;
+ n->options = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER DATABASE name createdb_opt_list
+ {
+ AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
+ n->dbname = $3;
+ n->options = $4;
+ $$ = (Node *)n;
+ }
+ | ALTER DATABASE name SET TABLESPACE name
+ {
+ AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
+ n->dbname = $3;
+ n->options = list_make1(makeDefElem("tablespace",
+ (Node *)makeString($6), @6));
+ $$ = (Node *)n;
+ }
+ ;
+
+AlterDatabaseSetStmt:
+ ALTER DATABASE name SetResetClause
+ {
+ AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
+ n->dbname = $3;
+ n->setstmt = $4;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * DROP DATABASE [ IF EXISTS ] dbname [ [ WITH ] ( options ) ]
+ *
+ * This is implicitly CASCADE, no need for drop behavior
+ *****************************************************************************/
+
+DropdbStmt: DROP DATABASE name
+ {
+ DropdbStmt *n = makeNode(DropdbStmt);
+ n->dbname = $3;
+ n->missing_ok = false;
+ n->options = NULL;
+ $$ = (Node *)n;
+ }
+ | DROP DATABASE IF_P EXISTS name
+ {
+ DropdbStmt *n = makeNode(DropdbStmt);
+ n->dbname = $5;
+ n->missing_ok = true;
+ n->options = NULL;
+ $$ = (Node *)n;
+ }
+ | DROP DATABASE name opt_with '(' drop_option_list ')'
+ {
+ DropdbStmt *n = makeNode(DropdbStmt);
+ n->dbname = $3;
+ n->missing_ok = false;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
+ | DROP DATABASE IF_P EXISTS name opt_with '(' drop_option_list ')'
+ {
+ DropdbStmt *n = makeNode(DropdbStmt);
+ n->dbname = $5;
+ n->missing_ok = true;
+ n->options = $8;
+ $$ = (Node *)n;
+ }
+ ;
+
+drop_option_list:
+ drop_option
+ {
+ $$ = list_make1((Node *) $1);
+ }
+ | drop_option_list ',' drop_option
+ {
+ $$ = lappend($1, (Node *) $3);
+ }
+ ;
+
+/*
+ * Currently only the FORCE option is supported, but the syntax is designed
+ * to be extensible so that we can add more options in the future if required.
+ */
+drop_option:
+ FORCE
+ {
+ $$ = makeDefElem("force", NULL, @1);
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * ALTER COLLATION
+ *
+ *****************************************************************************/
+
+AlterCollationStmt: ALTER COLLATION any_name REFRESH VERSION_P
+ {
+ AlterCollationStmt *n = makeNode(AlterCollationStmt);
+ n->collname = $3;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * ALTER SYSTEM
+ *
+ * This is used to change configuration parameters persistently.
+ *****************************************************************************/
+
+AlterSystemStmt:
+ ALTER SYSTEM_P SET generic_set
+ {
+ AlterSystemStmt *n = makeNode(AlterSystemStmt);
+ n->setstmt = $4;
+ $$ = (Node *)n;
+ }
+ | ALTER SYSTEM_P RESET generic_reset
+ {
+ AlterSystemStmt *n = makeNode(AlterSystemStmt);
+ n->setstmt = $4;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * Manipulate a domain
+ *
+ *****************************************************************************/
+
+CreateDomainStmt:
+ CREATE DOMAIN_P any_name opt_as Typename ColQualList
+ {
+ CreateDomainStmt *n = makeNode(CreateDomainStmt);
+ n->domainname = $3;
+ n->typeName = $5;
+ SplitColQualList($6, &n->constraints, &n->collClause,
+ yyscanner);
+ $$ = (Node *)n;
+ }
+ ;
+
+AlterDomainStmt:
+ /* ALTER DOMAIN <domain> {SET DEFAULT <expr>|DROP DEFAULT} */
+ ALTER DOMAIN_P any_name alter_column_default
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'T';
+ n->typeName = $3;
+ n->def = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> DROP NOT NULL */
+ | ALTER DOMAIN_P any_name DROP NOT NULL_P
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'N';
+ n->typeName = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> SET NOT NULL */
+ | ALTER DOMAIN_P any_name SET NOT NULL_P
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'O';
+ n->typeName = $3;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> ADD CONSTRAINT ... */
+ | ALTER DOMAIN_P any_name ADD_P TableConstraint
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'C';
+ n->typeName = $3;
+ n->def = $5;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */
+ | ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'X';
+ n->typeName = $3;
+ n->name = $6;
+ n->behavior = $7;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */
+ | ALTER DOMAIN_P any_name DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'X';
+ n->typeName = $3;
+ n->name = $8;
+ n->behavior = $9;
+ n->missing_ok = true;
+ $$ = (Node *)n;
+ }
+ /* ALTER DOMAIN <domain> VALIDATE CONSTRAINT <name> */
+ | ALTER DOMAIN_P any_name VALIDATE CONSTRAINT name
+ {
+ AlterDomainStmt *n = makeNode(AlterDomainStmt);
+ n->subtype = 'V';
+ n->typeName = $3;
+ n->name = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_as: AS
+ | /* EMPTY */
+ ;
+
+
+/*****************************************************************************
+ *
+ * Manipulate a text search dictionary or configuration
+ *
+ *****************************************************************************/
+
+AlterTSDictionaryStmt:
+ ALTER TEXT_P SEARCH DICTIONARY any_name definition
+ {
+ AlterTSDictionaryStmt *n = makeNode(AlterTSDictionaryStmt);
+ n->dictname = $5;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
+ ;
+
+AlterTSConfigurationStmt:
+ ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list any_with any_name_list
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_ADD_MAPPING;
+ n->cfgname = $5;
+ n->tokentype = $9;
+ n->dicts = $11;
+ n->override = false;
+ n->replace = false;
+ $$ = (Node*)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list any_with any_name_list
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN;
+ n->cfgname = $5;
+ n->tokentype = $9;
+ n->dicts = $11;
+ n->override = true;
+ n->replace = false;
+ $$ = (Node*)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name any_with any_name
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_REPLACE_DICT;
+ n->cfgname = $5;
+ n->tokentype = NIL;
+ n->dicts = list_make2($9,$11);
+ n->override = false;
+ n->replace = true;
+ $$ = (Node*)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name any_with any_name
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
+ n->cfgname = $5;
+ n->tokentype = $9;
+ n->dicts = list_make2($11,$13);
+ n->override = false;
+ n->replace = true;
+ $$ = (Node*)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_DROP_MAPPING;
+ n->cfgname = $5;
+ n->tokentype = $9;
+ n->missing_ok = false;
+ $$ = (Node*)n;
+ }
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list
+ {
+ AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
+ n->kind = ALTER_TSCONFIG_DROP_MAPPING;
+ n->cfgname = $5;
+ n->tokentype = $11;
+ n->missing_ok = true;
+ $$ = (Node*)n;
+ }
+ ;
+
+/* Use this if TIME or ORDINALITY after WITH should be taken as an identifier */
+any_with: WITH
+ | WITH_LA
+ ;
+
+
+/*****************************************************************************
+ *
+ * Manipulate a conversion
+ *
+ * CREATE [DEFAULT] CONVERSION <conversion_name>
+ * FOR <encoding_name> TO <encoding_name> FROM <func_name>
+ *
+ *****************************************************************************/
+
+CreateConversionStmt:
+ CREATE opt_default CONVERSION_P any_name FOR Sconst
+ TO Sconst FROM any_name
+ {
+ CreateConversionStmt *n = makeNode(CreateConversionStmt);
+ n->conversion_name = $4;
+ n->for_encoding_name = $6;
+ n->to_encoding_name = $8;
+ n->func_name = $10;
+ n->def = $2;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CLUSTER [VERBOSE] <qualified_name> [ USING <index_name> ]
+ * CLUSTER [ (options) ] <qualified_name> [ USING <index_name> ]
+ * CLUSTER [VERBOSE]
+ * CLUSTER [VERBOSE] <index_name> ON <qualified_name> (for pre-8.3)
+ *
+ *****************************************************************************/
+
+ClusterStmt:
+ CLUSTER opt_verbose qualified_name cluster_index_specification
+ {
+ ClusterStmt *n = makeNode(ClusterStmt);
+ n->relation = $3;
+ n->indexname = $4;
+ n->params = NIL;
+ if ($2)
+ n->params = lappend(n->params, makeDefElem("verbose", NULL, @2));
+ $$ = (Node*)n;
+ }
+
+ | CLUSTER '(' utility_option_list ')' qualified_name cluster_index_specification
+ {
+ ClusterStmt *n = makeNode(ClusterStmt);
+ n->relation = $5;
+ n->indexname = $6;
+ n->params = $3;
+ $$ = (Node*)n;
+ }
+ | CLUSTER opt_verbose
+ {
+ ClusterStmt *n = makeNode(ClusterStmt);
+ n->relation = NULL;
+ n->indexname = NULL;
+ n->params = NIL;
+ if ($2)
+ n->params = lappend(n->params, makeDefElem("verbose", NULL, @2));
+ $$ = (Node*)n;
+ }
+ /* kept for pre-8.3 compatibility */
+ | CLUSTER opt_verbose name ON qualified_name
+ {
+ ClusterStmt *n = makeNode(ClusterStmt);
+ n->relation = $5;
+ n->indexname = $3;
+ n->params = NIL;
+ if ($2)
+ n->params = lappend(n->params, makeDefElem("verbose", NULL, @2));
+ $$ = (Node*)n;
+ }
+ ;
+
+cluster_index_specification:
+ USING name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * VACUUM
+ * ANALYZE
+ *
+ *****************************************************************************/
+
+VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list
+ {
+ VacuumStmt *n = makeNode(VacuumStmt);
+ n->options = NIL;
+ if ($2)
+ n->options = lappend(n->options,
+ makeDefElem("full", NULL, @2));
+ if ($3)
+ n->options = lappend(n->options,
+ makeDefElem("freeze", NULL, @3));
+ if ($4)
+ n->options = lappend(n->options,
+ makeDefElem("verbose", NULL, @4));
+ if ($5)
+ n->options = lappend(n->options,
+ makeDefElem("analyze", NULL, @5));
+ n->rels = $6;
+ n->is_vacuumcmd = true;
+ $$ = (Node *)n;
+ }
+ | VACUUM '(' utility_option_list ')' opt_vacuum_relation_list
+ {
+ VacuumStmt *n = makeNode(VacuumStmt);
+ n->options = $3;
+ n->rels = $5;
+ n->is_vacuumcmd = true;
+ $$ = (Node *) n;
+ }
+ ;
+
+AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
+ {
+ VacuumStmt *n = makeNode(VacuumStmt);
+ n->options = NIL;
+ if ($2)
+ n->options = lappend(n->options,
+ makeDefElem("verbose", NULL, @2));
+ n->rels = $3;
+ n->is_vacuumcmd = false;
+ $$ = (Node *)n;
+ }
+ | analyze_keyword '(' utility_option_list ')' opt_vacuum_relation_list
+ {
+ VacuumStmt *n = makeNode(VacuumStmt);
+ n->options = $3;
+ n->rels = $5;
+ n->is_vacuumcmd = false;
+ $$ = (Node *) n;
+ }
+ ;
+
+utility_option_list:
+ utility_option_elem
+ {
+ $$ = list_make1($1);
+ }
+ | utility_option_list ',' utility_option_elem
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+analyze_keyword:
+ ANALYZE
+ | ANALYSE /* British */
+ ;
+
+utility_option_elem:
+ utility_option_name utility_option_arg
+ {
+ $$ = makeDefElem($1, $2, @1);
+ }
+ ;
+
+utility_option_name:
+ NonReservedWord { $$ = $1; }
+ | analyze_keyword { $$ = "analyze"; }
+ ;
+
+utility_option_arg:
+ opt_boolean_or_string { $$ = (Node *) makeString($1); }
+ | NumericOnly { $$ = (Node *) $1; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+opt_analyze:
+ analyze_keyword { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_verbose:
+ VERBOSE { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_full: FULL { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_freeze: FREEZE { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_name_list:
+ '(' name_list ')' { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+vacuum_relation:
+ qualified_name opt_name_list
+ {
+ $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2);
+ }
+ ;
+
+vacuum_relation_list:
+ vacuum_relation
+ { $$ = list_make1($1); }
+ | vacuum_relation_list ',' vacuum_relation
+ { $$ = lappend($1, $3); }
+ ;
+
+opt_vacuum_relation_list:
+ vacuum_relation_list { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * EXPLAIN [ANALYZE] [VERBOSE] query
+ * EXPLAIN ( options ) query
+ *
+ *****************************************************************************/
+
+ExplainStmt:
+ EXPLAIN ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $2;
+ n->options = NIL;
+ $$ = (Node *) n;
+ }
+ | EXPLAIN analyze_keyword opt_verbose ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $4;
+ n->options = list_make1(makeDefElem("analyze", NULL, @2));
+ if ($3)
+ n->options = lappend(n->options,
+ makeDefElem("verbose", NULL, @3));
+ $$ = (Node *) n;
+ }
+ | EXPLAIN VERBOSE ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $3;
+ n->options = list_make1(makeDefElem("verbose", NULL, @2));
+ $$ = (Node *) n;
+ }
+ | EXPLAIN '(' utility_option_list ')' ExplainableStmt
+ {
+ ExplainStmt *n = makeNode(ExplainStmt);
+ n->query = $5;
+ n->options = $3;
+ $$ = (Node *) n;
+ }
+ ;
+
+ExplainableStmt:
+ SelectStmt
+ | InsertStmt
+ | UpdateStmt
+ | DeleteStmt
+ | DeclareCursorStmt
+ | CreateAsStmt
+ | CreateMatViewStmt
+ | RefreshMatViewStmt
+ | ExecuteStmt /* by default all are $$=$1 */
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * PREPARE <plan_name> [(args, ...)] AS <query>
+ *
+ *****************************************************************************/
+
+PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
+ {
+ PrepareStmt *n = makeNode(PrepareStmt);
+ n->name = $2;
+ n->argtypes = $3;
+ n->query = $5;
+ $$ = (Node *) n;
+ }
+ ;
+
+prep_type_clause: '(' type_list ')' { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+PreparableStmt:
+ SelectStmt
+ | InsertStmt
+ | UpdateStmt
+ | DeleteStmt /* by default all are $$=$1 */
+ ;
+
+/*****************************************************************************
+ *
+ * EXECUTE <plan_name> [(params, ...)]
+ * CREATE TABLE <name> AS EXECUTE <plan_name> [(params, ...)]
+ *
+ *****************************************************************************/
+
+ExecuteStmt: EXECUTE name execute_param_clause
+ {
+ ExecuteStmt *n = makeNode(ExecuteStmt);
+ n->name = $2;
+ n->params = $3;
+ $$ = (Node *) n;
+ }
+ | CREATE OptTemp TABLE create_as_target AS
+ EXECUTE name execute_param_clause opt_with_data
+ {
+ CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+ ExecuteStmt *n = makeNode(ExecuteStmt);
+ n->name = $7;
+ n->params = $8;
+ ctas->query = (Node *) n;
+ ctas->into = $4;
+ ctas->objtype = OBJECT_TABLE;
+ ctas->is_select_into = false;
+ ctas->if_not_exists = false;
+ /* cram additional flags into the IntoClause */
+ $4->rel->relpersistence = $2;
+ $4->skipData = !($9);
+ $$ = (Node *) ctas;
+ }
+ | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS
+ EXECUTE name execute_param_clause opt_with_data
+ {
+ CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+ ExecuteStmt *n = makeNode(ExecuteStmt);
+ n->name = $10;
+ n->params = $11;
+ ctas->query = (Node *) n;
+ ctas->into = $7;
+ ctas->objtype = OBJECT_TABLE;
+ ctas->is_select_into = false;
+ ctas->if_not_exists = true;
+ /* cram additional flags into the IntoClause */
+ $7->rel->relpersistence = $2;
+ $7->skipData = !($12);
+ $$ = (Node *) ctas;
+ }
+ ;
+
+execute_param_clause: '(' expr_list ')' { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * DEALLOCATE [PREPARE] <plan_name>
+ *
+ *****************************************************************************/
+
+DeallocateStmt: DEALLOCATE name
+ {
+ DeallocateStmt *n = makeNode(DeallocateStmt);
+ n->name = $2;
+ $$ = (Node *) n;
+ }
+ | DEALLOCATE PREPARE name
+ {
+ DeallocateStmt *n = makeNode(DeallocateStmt);
+ n->name = $3;
+ $$ = (Node *) n;
+ }
+ | DEALLOCATE ALL
+ {
+ DeallocateStmt *n = makeNode(DeallocateStmt);
+ n->name = NULL;
+ $$ = (Node *) n;
+ }
+ | DEALLOCATE PREPARE ALL
+ {
+ DeallocateStmt *n = makeNode(DeallocateStmt);
+ n->name = NULL;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * INSERT STATEMENTS
+ *
+ *****************************************************************************/
+
+InsertStmt:
+ opt_with_clause INSERT INTO insert_target insert_rest
+ opt_on_conflict returning_clause
+ {
+ $5->relation = $4;
+ $5->onConflictClause = $6;
+ $5->returningList = $7;
+ $5->withClause = $1;
+ $$ = (Node *) $5;
+ }
+ ;
+
+/*
+ * Can't easily make AS optional here, because VALUES in insert_rest would
+ * have a shift/reduce conflict with VALUES as an optional alias. We could
+ * easily allow unreserved_keywords as optional aliases, but that'd be an odd
+ * divergence from other places. So just require AS for now.
+ */
+insert_target:
+ qualified_name
+ {
+ $$ = $1;
+ }
+ | qualified_name AS ColId
+ {
+ $1->alias = makeAlias($3, NIL);
+ $$ = $1;
+ }
+ ;
+
+insert_rest:
+ SelectStmt
+ {
+ $$ = makeNode(InsertStmt);
+ $$->cols = NIL;
+ $$->selectStmt = $1;
+ }
+ | OVERRIDING override_kind VALUE_P SelectStmt
+ {
+ $$ = makeNode(InsertStmt);
+ $$->cols = NIL;
+ $$->override = $2;
+ $$->selectStmt = $4;
+ }
+ | '(' insert_column_list ')' SelectStmt
+ {
+ $$ = makeNode(InsertStmt);
+ $$->cols = $2;
+ $$->selectStmt = $4;
+ }
+ | '(' insert_column_list ')' OVERRIDING override_kind VALUE_P SelectStmt
+ {
+ $$ = makeNode(InsertStmt);
+ $$->cols = $2;
+ $$->override = $5;
+ $$->selectStmt = $7;
+ }
+ | DEFAULT VALUES
+ {
+ $$ = makeNode(InsertStmt);
+ $$->cols = NIL;
+ $$->selectStmt = NULL;
+ }
+ ;
+
+override_kind:
+ USER { $$ = OVERRIDING_USER_VALUE; }
+ | SYSTEM_P { $$ = OVERRIDING_SYSTEM_VALUE; }
+ ;
+
+insert_column_list:
+ insert_column_item
+ { $$ = list_make1($1); }
+ | insert_column_list ',' insert_column_item
+ { $$ = lappend($1, $3); }
+ ;
+
+insert_column_item:
+ ColId opt_indirection
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $1;
+ $$->indirection = check_indirection($2, yyscanner);
+ $$->val = NULL;
+ $$->location = @1;
+ }
+ ;
+
+opt_on_conflict:
+ ON CONFLICT opt_conf_expr DO UPDATE SET set_clause_list where_clause
+ {
+ $$ = makeNode(OnConflictClause);
+ $$->action = ONCONFLICT_UPDATE;
+ $$->infer = $3;
+ $$->targetList = $7;
+ $$->whereClause = $8;
+ $$->location = @1;
+ }
+ |
+ ON CONFLICT opt_conf_expr DO NOTHING
+ {
+ $$ = makeNode(OnConflictClause);
+ $$->action = ONCONFLICT_NOTHING;
+ $$->infer = $3;
+ $$->targetList = NIL;
+ $$->whereClause = NULL;
+ $$->location = @1;
+ }
+ | /*EMPTY*/
+ {
+ $$ = NULL;
+ }
+ ;
+
+opt_conf_expr:
+ '(' index_params ')' where_clause
+ {
+ $$ = makeNode(InferClause);
+ $$->indexElems = $2;
+ $$->whereClause = $4;
+ $$->conname = NULL;
+ $$->location = @1;
+ }
+ |
+ ON CONSTRAINT name
+ {
+ $$ = makeNode(InferClause);
+ $$->indexElems = NIL;
+ $$->whereClause = NULL;
+ $$->conname = $3;
+ $$->location = @1;
+ }
+ | /*EMPTY*/
+ {
+ $$ = NULL;
+ }
+ ;
+
+returning_clause:
+ RETURNING target_list { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * DELETE STATEMENTS
+ *
+ *****************************************************************************/
+
+DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias
+ using_clause where_or_current_clause returning_clause
+ {
+ DeleteStmt *n = makeNode(DeleteStmt);
+ n->relation = $4;
+ n->usingClause = $5;
+ n->whereClause = $6;
+ n->returningList = $7;
+ n->withClause = $1;
+ $$ = (Node *)n;
+ }
+ ;
+
+using_clause:
+ USING from_list { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * LOCK TABLE
+ *
+ *****************************************************************************/
+
+LockStmt: LOCK_P opt_table relation_expr_list opt_lock opt_nowait
+ {
+ LockStmt *n = makeNode(LockStmt);
+
+ n->relations = $3;
+ n->mode = $4;
+ n->nowait = $5;
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_lock: IN_P lock_type MODE { $$ = $2; }
+ | /*EMPTY*/ { $$ = AccessExclusiveLock; }
+ ;
+
+lock_type: ACCESS SHARE { $$ = AccessShareLock; }
+ | ROW SHARE { $$ = RowShareLock; }
+ | ROW EXCLUSIVE { $$ = RowExclusiveLock; }
+ | SHARE UPDATE EXCLUSIVE { $$ = ShareUpdateExclusiveLock; }
+ | SHARE { $$ = ShareLock; }
+ | SHARE ROW EXCLUSIVE { $$ = ShareRowExclusiveLock; }
+ | EXCLUSIVE { $$ = ExclusiveLock; }
+ | ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; }
+ ;
+
+opt_nowait: NOWAIT { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_nowait_or_skip:
+ NOWAIT { $$ = LockWaitError; }
+ | SKIP LOCKED { $$ = LockWaitSkip; }
+ | /*EMPTY*/ { $$ = LockWaitBlock; }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * UpdateStmt (UPDATE)
+ *
+ *****************************************************************************/
+
+UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias
+ SET set_clause_list
+ from_clause
+ where_or_current_clause
+ returning_clause
+ {
+ UpdateStmt *n = makeNode(UpdateStmt);
+ n->relation = $3;
+ n->targetList = $5;
+ n->fromClause = $6;
+ n->whereClause = $7;
+ n->returningList = $8;
+ n->withClause = $1;
+ $$ = (Node *)n;
+ }
+ ;
+
+set_clause_list:
+ set_clause { $$ = $1; }
+ | set_clause_list ',' set_clause { $$ = list_concat($1,$3); }
+ ;
+
+set_clause:
+ set_target '=' a_expr
+ {
+ $1->val = (Node *) $3;
+ $$ = list_make1($1);
+ }
+ | '(' set_target_list ')' '=' a_expr
+ {
+ int ncolumns = list_length($2);
+ int i = 1;
+ ListCell *col_cell;
+
+ /* Create a MultiAssignRef source for each target */
+ foreach(col_cell, $2)
+ {
+ ResTarget *res_col = (ResTarget *) lfirst(col_cell);
+ MultiAssignRef *r = makeNode(MultiAssignRef);
+
+ r->source = (Node *) $5;
+ r->colno = i;
+ r->ncolumns = ncolumns;
+ res_col->val = (Node *) r;
+ i++;
+ }
+
+ $$ = $2;
+ }
+ ;
+
+set_target:
+ ColId opt_indirection
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $1;
+ $$->indirection = check_indirection($2, yyscanner);
+ $$->val = NULL; /* upper production sets this */
+ $$->location = @1;
+ }
+ ;
+
+set_target_list:
+ set_target { $$ = list_make1($1); }
+ | set_target_list ',' set_target { $$ = lappend($1,$3); }
+ ;
+
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CURSOR STATEMENTS
+ *
+ *****************************************************************************/
+DeclareCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR SelectStmt
+ {
+ DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
+ n->portalname = $2;
+ /* currently we always set FAST_PLAN option */
+ n->options = $3 | $5 | CURSOR_OPT_FAST_PLAN;
+ n->query = $7;
+ $$ = (Node *)n;
+ }
+ ;
+
+cursor_name: name { $$ = $1; }
+ ;
+
+cursor_options: /*EMPTY*/ { $$ = 0; }
+ | cursor_options NO SCROLL { $$ = $1 | CURSOR_OPT_NO_SCROLL; }
+ | cursor_options SCROLL { $$ = $1 | CURSOR_OPT_SCROLL; }
+ | cursor_options BINARY { $$ = $1 | CURSOR_OPT_BINARY; }
+ | cursor_options ASENSITIVE { $$ = $1 | CURSOR_OPT_ASENSITIVE; }
+ | cursor_options INSENSITIVE { $$ = $1 | CURSOR_OPT_INSENSITIVE; }
+ ;
+
+opt_hold: /* EMPTY */ { $$ = 0; }
+ | WITH HOLD { $$ = CURSOR_OPT_HOLD; }
+ | WITHOUT HOLD { $$ = 0; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * SELECT STATEMENTS
+ *
+ *****************************************************************************/
+
+/* A complete SELECT statement looks like this.
+ *
+ * The rule returns either a single SelectStmt node or a tree of them,
+ * representing a set-operation tree.
+ *
+ * There is an ambiguity when a sub-SELECT is within an a_expr and there
+ * are excess parentheses: do the parentheses belong to the sub-SELECT or
+ * to the surrounding a_expr? We don't really care, but bison wants to know.
+ * To resolve the ambiguity, we are careful to define the grammar so that
+ * the decision is staved off as long as possible: as long as we can keep
+ * absorbing parentheses into the sub-SELECT, we will do so, and only when
+ * it's no longer possible to do that will we decide that parens belong to
+ * the expression. For example, in "SELECT (((SELECT 2)) + 3)" the extra
+ * parentheses are treated as part of the sub-select. The necessity of doing
+ * it that way is shown by "SELECT (((SELECT 2)) UNION SELECT 2)". Had we
+ * parsed "((SELECT 2))" as an a_expr, it'd be too late to go back to the
+ * SELECT viewpoint when we see the UNION.
+ *
+ * This approach is implemented by defining a nonterminal select_with_parens,
+ * which represents a SELECT with at least one outer layer of parentheses,
+ * and being careful to use select_with_parens, never '(' SelectStmt ')',
+ * in the expression grammar. We will then have shift-reduce conflicts
+ * which we can resolve in favor of always treating '(' <select> ')' as
+ * a select_with_parens. To resolve the conflicts, the productions that
+ * conflict with the select_with_parens productions are manually given
+ * precedences lower than the precedence of ')', thereby ensuring that we
+ * shift ')' (and then reduce to select_with_parens) rather than trying to
+ * reduce the inner <select> nonterminal to something else. We use UMINUS
+ * precedence for this, which is a fairly arbitrary choice.
+ *
+ * To be able to define select_with_parens itself without ambiguity, we need
+ * a nonterminal select_no_parens that represents a SELECT structure with no
+ * outermost parentheses. This is a little bit tedious, but it works.
+ *
+ * In non-expression contexts, we use SelectStmt which can represent a SELECT
+ * with or without outer parentheses.
+ */
+
+SelectStmt: select_no_parens %prec UMINUS
+ | select_with_parens %prec UMINUS
+ ;
+
+select_with_parens:
+ '(' select_no_parens ')' { $$ = $2; }
+ | '(' select_with_parens ')' { $$ = $2; }
+ ;
+
+/*
+ * This rule parses the equivalent of the standard's <query expression>.
+ * The duplicative productions are annoying, but hard to get rid of without
+ * creating shift/reduce conflicts.
+ *
+ * The locking clause (FOR UPDATE etc) may be before or after LIMIT/OFFSET.
+ * In <=7.2.X, LIMIT/OFFSET had to be after FOR UPDATE
+ * We now support both orderings, but prefer LIMIT/OFFSET before the locking
+ * clause.
+ * 2002-08-28 bjm
+ */
+select_no_parens:
+ simple_select { $$ = $1; }
+ | select_clause sort_clause
+ {
+ insertSelectOptions((SelectStmt *) $1, $2, NIL,
+ NULL, NULL,
+ yyscanner);
+ $$ = $1;
+ }
+ | select_clause opt_sort_clause for_locking_clause opt_select_limit
+ {
+ insertSelectOptions((SelectStmt *) $1, $2, $3,
+ $4,
+ NULL,
+ yyscanner);
+ $$ = $1;
+ }
+ | select_clause opt_sort_clause select_limit opt_for_locking_clause
+ {
+ insertSelectOptions((SelectStmt *) $1, $2, $4,
+ $3,
+ NULL,
+ yyscanner);
+ $$ = $1;
+ }
+ | with_clause select_clause
+ {
+ insertSelectOptions((SelectStmt *) $2, NULL, NIL,
+ NULL,
+ $1,
+ yyscanner);
+ $$ = $2;
+ }
+ | with_clause select_clause sort_clause
+ {
+ insertSelectOptions((SelectStmt *) $2, $3, NIL,
+ NULL,
+ $1,
+ yyscanner);
+ $$ = $2;
+ }
+ | with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit
+ {
+ insertSelectOptions((SelectStmt *) $2, $3, $4,
+ $5,
+ $1,
+ yyscanner);
+ $$ = $2;
+ }
+ | with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
+ {
+ insertSelectOptions((SelectStmt *) $2, $3, $5,
+ $4,
+ $1,
+ yyscanner);
+ $$ = $2;
+ }
+ ;
+
+select_clause:
+ simple_select { $$ = $1; }
+ | select_with_parens { $$ = $1; }
+ ;
+
+/*
+ * This rule parses SELECT statements that can appear within set operations,
+ * including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify
+ * the ordering of the set operations. Without '(' and ')' we want the
+ * operations to be ordered per the precedence specs at the head of this file.
+ *
+ * As with select_no_parens, simple_select cannot have outer parentheses,
+ * but can have parenthesized subclauses.
+ *
+ * It might appear that we could fold the first two alternatives into one
+ * by using opt_distinct_clause. However, that causes a shift/reduce conflict
+ * against INSERT ... SELECT ... ON CONFLICT. We avoid the ambiguity by
+ * requiring SELECT DISTINCT [ON] to be followed by a non-empty target_list.
+ *
+ * Note that sort clauses cannot be included at this level --- SQL requires
+ * SELECT foo UNION SELECT bar ORDER BY baz
+ * to be parsed as
+ * (SELECT foo UNION SELECT bar) ORDER BY baz
+ * not
+ * SELECT foo UNION (SELECT bar ORDER BY baz)
+ * Likewise for WITH, FOR UPDATE and LIMIT. Therefore, those clauses are
+ * described as part of the select_no_parens production, not simple_select.
+ * This does not limit functionality, because you can reintroduce these
+ * clauses inside parentheses.
+ *
+ * NOTE: only the leftmost component SelectStmt should have INTO.
+ * However, this is not checked by the grammar; parse analysis must check it.
+ */
+simple_select:
+ SELECT opt_all_clause opt_target_list
+ into_clause from_clause where_clause
+ group_clause having_clause window_clause
+ {
+ SelectStmt *n = makeNode(SelectStmt);
+ n->targetList = $3;
+ n->intoClause = $4;
+ n->fromClause = $5;
+ n->whereClause = $6;
+ n->groupClause = ($7)->list;
+ n->groupDistinct = ($7)->distinct;
+ n->havingClause = $8;
+ n->windowClause = $9;
+ $$ = (Node *)n;
+ }
+ | SELECT distinct_clause target_list
+ into_clause from_clause where_clause
+ group_clause having_clause window_clause
+ {
+ SelectStmt *n = makeNode(SelectStmt);
+ n->distinctClause = $2;
+ n->targetList = $3;
+ n->intoClause = $4;
+ n->fromClause = $5;
+ n->whereClause = $6;
+ n->groupClause = ($7)->list;
+ n->groupDistinct = ($7)->distinct;
+ n->havingClause = $8;
+ n->windowClause = $9;
+ $$ = (Node *)n;
+ }
+ | values_clause { $$ = $1; }
+ | TABLE relation_expr
+ {
+ /* same as SELECT * FROM relation_expr */
+ ColumnRef *cr = makeNode(ColumnRef);
+ ResTarget *rt = makeNode(ResTarget);
+ SelectStmt *n = makeNode(SelectStmt);
+
+ cr->fields = list_make1(makeNode(A_Star));
+ cr->location = -1;
+
+ rt->name = NULL;
+ rt->indirection = NIL;
+ rt->val = (Node *)cr;
+ rt->location = -1;
+
+ n->targetList = list_make1(rt);
+ n->fromClause = list_make1($2);
+ $$ = (Node *)n;
+ }
+ | select_clause UNION set_quantifier select_clause
+ {
+ $$ = makeSetOp(SETOP_UNION, $3 == SET_QUANTIFIER_ALL, $1, $4);
+ }
+ | select_clause INTERSECT set_quantifier select_clause
+ {
+ $$ = makeSetOp(SETOP_INTERSECT, $3 == SET_QUANTIFIER_ALL, $1, $4);
+ }
+ | select_clause EXCEPT set_quantifier select_clause
+ {
+ $$ = makeSetOp(SETOP_EXCEPT, $3 == SET_QUANTIFIER_ALL, $1, $4);
+ }
+ ;
+
+/*
+ * SQL standard WITH clause looks like:
+ *
+ * WITH [ RECURSIVE ] <query name> [ (<column>,...) ]
+ * AS (query) [ SEARCH or CYCLE clause ]
+ *
+ * Recognizing WITH_LA here allows a CTE to be named TIME or ORDINALITY.
+ */
+with_clause:
+ WITH cte_list
+ {
+ $$ = makeNode(WithClause);
+ $$->ctes = $2;
+ $$->recursive = false;
+ $$->location = @1;
+ }
+ | WITH_LA cte_list
+ {
+ $$ = makeNode(WithClause);
+ $$->ctes = $2;
+ $$->recursive = false;
+ $$->location = @1;
+ }
+ | WITH RECURSIVE cte_list
+ {
+ $$ = makeNode(WithClause);
+ $$->ctes = $3;
+ $$->recursive = true;
+ $$->location = @1;
+ }
+ ;
+
+cte_list:
+ common_table_expr { $$ = list_make1($1); }
+ | cte_list ',' common_table_expr { $$ = lappend($1, $3); }
+ ;
+
+common_table_expr: name opt_name_list AS opt_materialized '(' PreparableStmt ')' opt_search_clause opt_cycle_clause
+ {
+ CommonTableExpr *n = makeNode(CommonTableExpr);
+ n->ctename = $1;
+ n->aliascolnames = $2;
+ n->ctematerialized = $4;
+ n->ctequery = $6;
+ n->search_clause = castNode(CTESearchClause, $8);
+ n->cycle_clause = castNode(CTECycleClause, $9);
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_materialized:
+ MATERIALIZED { $$ = CTEMaterializeAlways; }
+ | NOT MATERIALIZED { $$ = CTEMaterializeNever; }
+ | /*EMPTY*/ { $$ = CTEMaterializeDefault; }
+ ;
+
+opt_search_clause:
+ SEARCH DEPTH FIRST_P BY columnList SET ColId
+ {
+ CTESearchClause *n = makeNode(CTESearchClause);
+ n->search_col_list = $5;
+ n->search_breadth_first = false;
+ n->search_seq_column = $7;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | SEARCH BREADTH FIRST_P BY columnList SET ColId
+ {
+ CTESearchClause *n = makeNode(CTESearchClause);
+ n->search_col_list = $5;
+ n->search_breadth_first = true;
+ n->search_seq_column = $7;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | /*EMPTY*/
+ {
+ $$ = NULL;
+ }
+ ;
+
+opt_cycle_clause:
+ CYCLE columnList SET ColId TO AexprConst DEFAULT AexprConst USING ColId
+ {
+ CTECycleClause *n = makeNode(CTECycleClause);
+ n->cycle_col_list = $2;
+ n->cycle_mark_column = $4;
+ n->cycle_mark_value = $6;
+ n->cycle_mark_default = $8;
+ n->cycle_path_column = $10;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | CYCLE columnList SET ColId USING ColId
+ {
+ CTECycleClause *n = makeNode(CTECycleClause);
+ n->cycle_col_list = $2;
+ n->cycle_mark_column = $4;
+ n->cycle_mark_value = makeBoolAConst(true, -1);
+ n->cycle_mark_default = makeBoolAConst(false, -1);
+ n->cycle_path_column = $6;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ | /*EMPTY*/
+ {
+ $$ = NULL;
+ }
+ ;
+
+opt_with_clause:
+ with_clause { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+into_clause:
+ INTO OptTempTableName
+ {
+ $$ = makeNode(IntoClause);
+ $$->rel = $2;
+ $$->colNames = NIL;
+ $$->options = NIL;
+ $$->onCommit = ONCOMMIT_NOOP;
+ $$->tableSpaceName = NULL;
+ $$->viewQuery = NULL;
+ $$->skipData = false;
+ }
+ | /*EMPTY*/
+ { $$ = NULL; }
+ ;
+
+/*
+ * Redundancy here is needed to avoid shift/reduce conflicts,
+ * since TEMP is not a reserved word. See also OptTemp.
+ */
+OptTempTableName:
+ TEMPORARY opt_table qualified_name
+ {
+ $$ = $3;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | TEMP opt_table qualified_name
+ {
+ $$ = $3;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | LOCAL TEMPORARY opt_table qualified_name
+ {
+ $$ = $4;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | LOCAL TEMP opt_table qualified_name
+ {
+ $$ = $4;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | GLOBAL TEMPORARY opt_table qualified_name
+ {
+ ereport(WARNING,
+ (errmsg("GLOBAL is deprecated in temporary table creation"),
+ parser_errposition(@1)));
+ $$ = $4;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | GLOBAL TEMP opt_table qualified_name
+ {
+ ereport(WARNING,
+ (errmsg("GLOBAL is deprecated in temporary table creation"),
+ parser_errposition(@1)));
+ $$ = $4;
+ $$->relpersistence = RELPERSISTENCE_TEMP;
+ }
+ | UNLOGGED opt_table qualified_name
+ {
+ $$ = $3;
+ $$->relpersistence = RELPERSISTENCE_UNLOGGED;
+ }
+ | TABLE qualified_name
+ {
+ $$ = $2;
+ $$->relpersistence = RELPERSISTENCE_PERMANENT;
+ }
+ | qualified_name
+ {
+ $$ = $1;
+ $$->relpersistence = RELPERSISTENCE_PERMANENT;
+ }
+ ;
+
+opt_table: TABLE
+ | /*EMPTY*/
+ ;
+
+set_quantifier:
+ ALL { $$ = SET_QUANTIFIER_ALL; }
+ | DISTINCT { $$ = SET_QUANTIFIER_DISTINCT; }
+ | /*EMPTY*/ { $$ = SET_QUANTIFIER_DEFAULT; }
+ ;
+
+/* We use (NIL) as a placeholder to indicate that all target expressions
+ * should be placed in the DISTINCT list during parsetree analysis.
+ */
+distinct_clause:
+ DISTINCT { $$ = list_make1(NIL); }
+ | DISTINCT ON '(' expr_list ')' { $$ = $4; }
+ ;
+
+opt_all_clause:
+ ALL
+ | /*EMPTY*/
+ ;
+
+opt_distinct_clause:
+ distinct_clause { $$ = $1; }
+ | opt_all_clause { $$ = NIL; }
+ ;
+
+opt_sort_clause:
+ sort_clause { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+sort_clause:
+ ORDER BY sortby_list { $$ = $3; }
+ ;
+
+sortby_list:
+ sortby { $$ = list_make1($1); }
+ | sortby_list ',' sortby { $$ = lappend($1, $3); }
+ ;
+
+sortby: a_expr USING qual_all_Op opt_nulls_order
+ {
+ $$ = makeNode(SortBy);
+ $$->node = $1;
+ $$->sortby_dir = SORTBY_USING;
+ $$->sortby_nulls = $4;
+ $$->useOp = $3;
+ $$->location = @3;
+ }
+ | a_expr opt_asc_desc opt_nulls_order
+ {
+ $$ = makeNode(SortBy);
+ $$->node = $1;
+ $$->sortby_dir = $2;
+ $$->sortby_nulls = $3;
+ $$->useOp = NIL;
+ $$->location = -1; /* no operator */
+ }
+ ;
+
+
+select_limit:
+ limit_clause offset_clause
+ {
+ $$ = $1;
+ ($$)->limitOffset = $2;
+ }
+ | offset_clause limit_clause
+ {
+ $$ = $2;
+ ($$)->limitOffset = $1;
+ }
+ | limit_clause
+ {
+ $$ = $1;
+ }
+ | offset_clause
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = $1;
+ n->limitCount = NULL;
+ n->limitOption = LIMIT_OPTION_COUNT;
+ $$ = n;
+ }
+ ;
+
+opt_select_limit:
+ select_limit { $$ = $1; }
+ | /* EMPTY */ { $$ = NULL; }
+ ;
+
+limit_clause:
+ LIMIT select_limit_value
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = NULL;
+ n->limitCount = $2;
+ n->limitOption = LIMIT_OPTION_COUNT;
+ $$ = n;
+ }
+ | LIMIT select_limit_value ',' select_offset_value
+ {
+ /* Disabled because it was too confusing, bjm 2002-02-18 */
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("LIMIT #,# syntax is not supported"),
+ errhint("Use separate LIMIT and OFFSET clauses."),
+ parser_errposition(@1)));
+ }
+ /* SQL:2008 syntax */
+ /* to avoid shift/reduce conflicts, handle the optional value with
+ * a separate production rather than an opt_ expression. The fact
+ * that ONLY is fully reserved means that this way, we defer any
+ * decision about what rule reduces ROW or ROWS to the point where
+ * we can see the ONLY token in the lookahead slot.
+ */
+ | FETCH first_or_next select_fetch_first_value row_or_rows ONLY
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = NULL;
+ n->limitCount = $3;
+ n->limitOption = LIMIT_OPTION_COUNT;
+ $$ = n;
+ }
+ | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = NULL;
+ n->limitCount = $3;
+ n->limitOption = LIMIT_OPTION_WITH_TIES;
+ $$ = n;
+ }
+ | FETCH first_or_next row_or_rows ONLY
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = NULL;
+ n->limitCount = makeIntConst(1, -1);
+ n->limitOption = LIMIT_OPTION_COUNT;
+ $$ = n;
+ }
+ | FETCH first_or_next row_or_rows WITH TIES
+ {
+ SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
+ n->limitOffset = NULL;
+ n->limitCount = makeIntConst(1, -1);
+ n->limitOption = LIMIT_OPTION_WITH_TIES;
+ $$ = n;
+ }
+ ;
+
+offset_clause:
+ OFFSET select_offset_value
+ { $$ = $2; }
+ /* SQL:2008 syntax */
+ | OFFSET select_fetch_first_value row_or_rows
+ { $$ = $2; }
+ ;
+
+select_limit_value:
+ a_expr { $$ = $1; }
+ | ALL
+ {
+ /* LIMIT ALL is represented as a NULL constant */
+ $$ = makeNullAConst(@1);
+ }
+ ;
+
+select_offset_value:
+ a_expr { $$ = $1; }
+ ;
+
+/*
+ * Allowing full expressions without parentheses causes various parsing
+ * problems with the trailing ROW/ROWS key words. SQL spec only calls for
+ * <simple value specification>, which is either a literal or a parameter (but
+ * an <SQL parameter reference> could be an identifier, bringing up conflicts
+ * with ROW/ROWS). We solve this by leveraging the presence of ONLY (see above)
+ * to determine whether the expression is missing rather than trying to make it
+ * optional in this rule.
+ *
+ * c_expr covers almost all the spec-required cases (and more), but it doesn't
+ * cover signed numeric literals, which are allowed by the spec. So we include
+ * those here explicitly. We need FCONST as well as ICONST because values that
+ * don't fit in the platform's "long", but do fit in bigint, should still be
+ * accepted here. (This is possible in 64-bit Windows as well as all 32-bit
+ * builds.)
+ */
+select_fetch_first_value:
+ c_expr { $$ = $1; }
+ | '+' I_or_F_const
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
+ | '-' I_or_F_const
+ { $$ = doNegate($2, @1); }
+ ;
+
+I_or_F_const:
+ Iconst { $$ = makeIntConst($1,@1); }
+ | FCONST { $$ = makeFloatConst($1,@1); }
+ ;
+
+/* noise words */
+row_or_rows: ROW { $$ = 0; }
+ | ROWS { $$ = 0; }
+ ;
+
+first_or_next: FIRST_P { $$ = 0; }
+ | NEXT { $$ = 0; }
+ ;
+
+
+/*
+ * This syntax for group_clause tries to follow the spec quite closely.
+ * However, the spec allows only column references, not expressions,
+ * which introduces an ambiguity between implicit row constructors
+ * (a,b) and lists of column references.
+ *
+ * We handle this by using the a_expr production for what the spec calls
+ * <ordinary grouping set>, which in the spec represents either one column
+ * reference or a parenthesized list of column references. Then, we check the
+ * top node of the a_expr to see if it's an implicit RowExpr, and if so, just
+ * grab and use the list, discarding the node. (this is done in parse analysis,
+ * not here)
+ *
+ * (we abuse the row_format field of RowExpr to distinguish implicit and
+ * explicit row constructors; it's debatable if anyone sanely wants to use them
+ * in a group clause, but if they have a reason to, we make it possible.)
+ *
+ * Each item in the group_clause list is either an expression tree or a
+ * GroupingSet node of some type.
+ */
+group_clause:
+ GROUP_P BY set_quantifier group_by_list
+ {
+ GroupClause *n = (GroupClause *) palloc(sizeof(GroupClause));
+ n->distinct = $3 == SET_QUANTIFIER_DISTINCT;
+ n->list = $4;
+ $$ = n;
+ }
+ | /*EMPTY*/
+ {
+ GroupClause *n = (GroupClause *) palloc(sizeof(GroupClause));
+ n->distinct = false;
+ n->list = NIL;
+ $$ = n;
+ }
+ ;
+
+group_by_list:
+ group_by_item { $$ = list_make1($1); }
+ | group_by_list ',' group_by_item { $$ = lappend($1,$3); }
+ ;
+
+group_by_item:
+ a_expr { $$ = $1; }
+ | empty_grouping_set { $$ = $1; }
+ | cube_clause { $$ = $1; }
+ | rollup_clause { $$ = $1; }
+ | grouping_sets_clause { $$ = $1; }
+ ;
+
+empty_grouping_set:
+ '(' ')'
+ {
+ $$ = (Node *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, @1);
+ }
+ ;
+
+/*
+ * These hacks rely on setting precedence of CUBE and ROLLUP below that of '(',
+ * so that they shift in these rules rather than reducing the conflicting
+ * unreserved_keyword rule.
+ */
+
+rollup_clause:
+ ROLLUP '(' expr_list ')'
+ {
+ $$ = (Node *) makeGroupingSet(GROUPING_SET_ROLLUP, $3, @1);
+ }
+ ;
+
+cube_clause:
+ CUBE '(' expr_list ')'
+ {
+ $$ = (Node *) makeGroupingSet(GROUPING_SET_CUBE, $3, @1);
+ }
+ ;
+
+grouping_sets_clause:
+ GROUPING SETS '(' group_by_list ')'
+ {
+ $$ = (Node *) makeGroupingSet(GROUPING_SET_SETS, $4, @1);
+ }
+ ;
+
+having_clause:
+ HAVING a_expr { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+for_locking_clause:
+ for_locking_items { $$ = $1; }
+ | FOR READ ONLY { $$ = NIL; }
+ ;
+
+opt_for_locking_clause:
+ for_locking_clause { $$ = $1; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+for_locking_items:
+ for_locking_item { $$ = list_make1($1); }
+ | for_locking_items for_locking_item { $$ = lappend($1, $2); }
+ ;
+
+for_locking_item:
+ for_locking_strength locked_rels_list opt_nowait_or_skip
+ {
+ LockingClause *n = makeNode(LockingClause);
+ n->lockedRels = $2;
+ n->strength = $1;
+ n->waitPolicy = $3;
+ $$ = (Node *) n;
+ }
+ ;
+
+for_locking_strength:
+ FOR UPDATE { $$ = LCS_FORUPDATE; }
+ | FOR NO KEY UPDATE { $$ = LCS_FORNOKEYUPDATE; }
+ | FOR SHARE { $$ = LCS_FORSHARE; }
+ | FOR KEY SHARE { $$ = LCS_FORKEYSHARE; }
+ ;
+
+locked_rels_list:
+ OF qualified_name_list { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+
+/*
+ * We should allow ROW '(' expr_list ')' too, but that seems to require
+ * making VALUES a fully reserved word, which will probably break more apps
+ * than allowing the noise-word is worth.
+ */
+values_clause:
+ VALUES '(' expr_list ')'
+ {
+ SelectStmt *n = makeNode(SelectStmt);
+ n->valuesLists = list_make1($3);
+ $$ = (Node *) n;
+ }
+ | values_clause ',' '(' expr_list ')'
+ {
+ SelectStmt *n = (SelectStmt *) $1;
+ n->valuesLists = lappend(n->valuesLists, $4);
+ $$ = (Node *) n;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * clauses common to all Optimizable Stmts:
+ * from_clause - allow list of both JOIN expressions and table names
+ * where_clause - qualifications for joins or restrictions
+ *
+ *****************************************************************************/
+
+from_clause:
+ FROM from_list { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+from_list:
+ table_ref { $$ = list_make1($1); }
+ | from_list ',' table_ref { $$ = lappend($1, $3); }
+ ;
+
+/*
+ * table_ref is where an alias clause can be attached.
+ */
+table_ref: relation_expr opt_alias_clause
+ {
+ $1->alias = $2;
+ $$ = (Node *) $1;
+ }
+ | relation_expr opt_alias_clause tablesample_clause
+ {
+ RangeTableSample *n = (RangeTableSample *) $3;
+ $1->alias = $2;
+ /* relation_expr goes inside the RangeTableSample node */
+ n->relation = (Node *) $1;
+ $$ = (Node *) n;
+ }
+ | func_table func_alias_clause
+ {
+ RangeFunction *n = (RangeFunction *) $1;
+ n->alias = linitial($2);
+ n->coldeflist = lsecond($2);
+ $$ = (Node *) n;
+ }
+ | LATERAL_P func_table func_alias_clause
+ {
+ RangeFunction *n = (RangeFunction *) $2;
+ n->lateral = true;
+ n->alias = linitial($3);
+ n->coldeflist = lsecond($3);
+ $$ = (Node *) n;
+ }
+ | xmltable opt_alias_clause
+ {
+ RangeTableFunc *n = (RangeTableFunc *) $1;
+ n->alias = $2;
+ $$ = (Node *) n;
+ }
+ | LATERAL_P xmltable opt_alias_clause
+ {
+ RangeTableFunc *n = (RangeTableFunc *) $2;
+ n->lateral = true;
+ n->alias = $3;
+ $$ = (Node *) n;
+ }
+ | select_with_parens opt_alias_clause
+ {
+ RangeSubselect *n = makeNode(RangeSubselect);
+ n->lateral = false;
+ n->subquery = $1;
+ n->alias = $2;
+ /*
+ * The SQL spec does not permit a subselect
+ * (<derived_table>) without an alias clause,
+ * so we don't either. This avoids the problem
+ * of needing to invent a unique refname for it.
+ * That could be surmounted if there's sufficient
+ * popular demand, but for now let's just implement
+ * the spec and see if anyone complains.
+ * However, it does seem like a good idea to emit
+ * an error message that's better than "syntax error".
+ */
+ if ($2 == NULL)
+ {
+ if (IsA($1, SelectStmt) &&
+ ((SelectStmt *) $1)->valuesLists)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("VALUES in FROM must have an alias"),
+ errhint("For example, FROM (VALUES ...) [AS] foo."),
+ parser_errposition(@1)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery in FROM must have an alias"),
+ errhint("For example, FROM (SELECT ...) [AS] foo."),
+ parser_errposition(@1)));
+ }
+ $$ = (Node *) n;
+ }
+ | LATERAL_P select_with_parens opt_alias_clause
+ {
+ RangeSubselect *n = makeNode(RangeSubselect);
+ n->lateral = true;
+ n->subquery = $2;
+ n->alias = $3;
+ /* same comment as above */
+ if ($3 == NULL)
+ {
+ if (IsA($2, SelectStmt) &&
+ ((SelectStmt *) $2)->valuesLists)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("VALUES in FROM must have an alias"),
+ errhint("For example, FROM (VALUES ...) [AS] foo."),
+ parser_errposition(@2)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery in FROM must have an alias"),
+ errhint("For example, FROM (SELECT ...) [AS] foo."),
+ parser_errposition(@2)));
+ }
+ $$ = (Node *) n;
+ }
+ | joined_table
+ {
+ $$ = (Node *) $1;
+ }
+ | '(' joined_table ')' alias_clause
+ {
+ $2->alias = $4;
+ $$ = (Node *) $2;
+ }
+ ;
+
+
+/*
+ * It may seem silly to separate joined_table from table_ref, but there is
+ * method in SQL's madness: if you don't do it this way you get reduce-
+ * reduce conflicts, because it's not clear to the parser generator whether
+ * to expect alias_clause after ')' or not. For the same reason we must
+ * treat 'JOIN' and 'join_type JOIN' separately, rather than allowing
+ * join_type to expand to empty; if we try it, the parser generator can't
+ * figure out when to reduce an empty join_type right after table_ref.
+ *
+ * Note that a CROSS JOIN is the same as an unqualified
+ * INNER JOIN, and an INNER JOIN/ON has the same shape
+ * but a qualification expression to limit membership.
+ * A NATURAL JOIN implicitly matches column names between
+ * tables and the shape is determined by which columns are
+ * in common. We'll collect columns during the later transformations.
+ */
+
+joined_table:
+ '(' joined_table ')'
+ {
+ $$ = $2;
+ }
+ | table_ref CROSS JOIN table_ref
+ {
+ /* CROSS JOIN is same as unqualified inner join */
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = JOIN_INNER;
+ n->isNatural = false;
+ n->larg = $1;
+ n->rarg = $4;
+ n->usingClause = NIL;
+ n->join_using_alias = NULL;
+ n->quals = NULL;
+ $$ = n;
+ }
+ | table_ref join_type JOIN table_ref join_qual
+ {
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = $2;
+ n->isNatural = false;
+ n->larg = $1;
+ n->rarg = $4;
+ if ($5 != NULL && IsA($5, List))
+ {
+ /* USING clause */
+ n->usingClause = linitial_node(List, castNode(List, $5));
+ n->join_using_alias = lsecond_node(Alias, castNode(List, $5));
+ }
+ else
+ {
+ /* ON clause */
+ n->quals = $5;
+ }
+ $$ = n;
+ }
+ | table_ref JOIN table_ref join_qual
+ {
+ /* letting join_type reduce to empty doesn't work */
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = JOIN_INNER;
+ n->isNatural = false;
+ n->larg = $1;
+ n->rarg = $3;
+ if ($4 != NULL && IsA($4, List))
+ {
+ /* USING clause */
+ n->usingClause = linitial_node(List, castNode(List, $4));
+ n->join_using_alias = lsecond_node(Alias, castNode(List, $4));
+ }
+ else
+ {
+ /* ON clause */
+ n->quals = $4;
+ }
+ $$ = n;
+ }
+ | table_ref NATURAL join_type JOIN table_ref
+ {
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = $3;
+ n->isNatural = true;
+ n->larg = $1;
+ n->rarg = $5;
+ n->usingClause = NIL; /* figure out which columns later... */
+ n->join_using_alias = NULL;
+ n->quals = NULL; /* fill later */
+ $$ = n;
+ }
+ | table_ref NATURAL JOIN table_ref
+ {
+ /* letting join_type reduce to empty doesn't work */
+ JoinExpr *n = makeNode(JoinExpr);
+ n->jointype = JOIN_INNER;
+ n->isNatural = true;
+ n->larg = $1;
+ n->rarg = $4;
+ n->usingClause = NIL; /* figure out which columns later... */
+ n->join_using_alias = NULL;
+ n->quals = NULL; /* fill later */
+ $$ = n;
+ }
+ ;
+
+alias_clause:
+ AS ColId '(' name_list ')'
+ {
+ $$ = makeNode(Alias);
+ $$->aliasname = $2;
+ $$->colnames = $4;
+ }
+ | AS ColId
+ {
+ $$ = makeNode(Alias);
+ $$->aliasname = $2;
+ }
+ | ColId '(' name_list ')'
+ {
+ $$ = makeNode(Alias);
+ $$->aliasname = $1;
+ $$->colnames = $3;
+ }
+ | ColId
+ {
+ $$ = makeNode(Alias);
+ $$->aliasname = $1;
+ }
+ ;
+
+opt_alias_clause: alias_clause { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/*
+ * The alias clause after JOIN ... USING only accepts the AS ColId spelling,
+ * per SQL standard. (The grammar could parse the other variants, but they
+ * don't seem to be useful, and it might lead to parser problems in the
+ * future.)
+ */
+opt_alias_clause_for_join_using:
+ AS ColId
+ {
+ $$ = makeNode(Alias);
+ $$->aliasname = $2;
+ /* the column name list will be inserted later */
+ }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/*
+ * func_alias_clause can include both an Alias and a coldeflist, so we make it
+ * return a 2-element list that gets disassembled by calling production.
+ */
+func_alias_clause:
+ alias_clause
+ {
+ $$ = list_make2($1, NIL);
+ }
+ | AS '(' TableFuncElementList ')'
+ {
+ $$ = list_make2(NULL, $3);
+ }
+ | AS ColId '(' TableFuncElementList ')'
+ {
+ Alias *a = makeNode(Alias);
+ a->aliasname = $2;
+ $$ = list_make2(a, $4);
+ }
+ | ColId '(' TableFuncElementList ')'
+ {
+ Alias *a = makeNode(Alias);
+ a->aliasname = $1;
+ $$ = list_make2(a, $3);
+ }
+ | /*EMPTY*/
+ {
+ $$ = list_make2(NULL, NIL);
+ }
+ ;
+
+join_type: FULL opt_outer { $$ = JOIN_FULL; }
+ | LEFT opt_outer { $$ = JOIN_LEFT; }
+ | RIGHT opt_outer { $$ = JOIN_RIGHT; }
+ | INNER_P { $$ = JOIN_INNER; }
+ ;
+
+/* OUTER is just noise... */
+opt_outer: OUTER_P
+ | /*EMPTY*/
+ ;
+
+/* JOIN qualification clauses
+ * Possibilities are:
+ * USING ( column list ) [ AS alias ]
+ * allows only unqualified column names,
+ * which must match between tables.
+ * ON expr allows more general qualifications.
+ *
+ * We return USING as a two-element List (the first item being a sub-List
+ * of the common column names, and the second either an Alias item or NULL).
+ * An ON-expr will not be a List, so it can be told apart that way.
+ */
+
+join_qual: USING '(' name_list ')' opt_alias_clause_for_join_using
+ {
+ $$ = (Node *) list_make2($3, $5);
+ }
+ | ON a_expr
+ {
+ $$ = $2;
+ }
+ ;
+
+
+relation_expr:
+ qualified_name
+ {
+ /* inheritance query, implicitly */
+ $$ = $1;
+ $$->inh = true;
+ $$->alias = NULL;
+ }
+ | qualified_name '*'
+ {
+ /* inheritance query, explicitly */
+ $$ = $1;
+ $$->inh = true;
+ $$->alias = NULL;
+ }
+ | ONLY qualified_name
+ {
+ /* no inheritance */
+ $$ = $2;
+ $$->inh = false;
+ $$->alias = NULL;
+ }
+ | ONLY '(' qualified_name ')'
+ {
+ /* no inheritance, SQL99-style syntax */
+ $$ = $3;
+ $$->inh = false;
+ $$->alias = NULL;
+ }
+ ;
+
+
+relation_expr_list:
+ relation_expr { $$ = list_make1($1); }
+ | relation_expr_list ',' relation_expr { $$ = lappend($1, $3); }
+ ;
+
+
+/*
+ * Given "UPDATE foo set set ...", we have to decide without looking any
+ * further ahead whether the first "set" is an alias or the UPDATE's SET
+ * keyword. Since "set" is allowed as a column name both interpretations
+ * are feasible. We resolve the shift/reduce conflict by giving the first
+ * relation_expr_opt_alias production a higher precedence than the SET token
+ * has, causing the parser to prefer to reduce, in effect assuming that the
+ * SET is not an alias.
+ */
+relation_expr_opt_alias: relation_expr %prec UMINUS
+ {
+ $$ = $1;
+ }
+ | relation_expr ColId
+ {
+ Alias *alias = makeNode(Alias);
+ alias->aliasname = $2;
+ $1->alias = alias;
+ $$ = $1;
+ }
+ | relation_expr AS ColId
+ {
+ Alias *alias = makeNode(Alias);
+ alias->aliasname = $3;
+ $1->alias = alias;
+ $$ = $1;
+ }
+ ;
+
+/*
+ * TABLESAMPLE decoration in a FROM item
+ */
+tablesample_clause:
+ TABLESAMPLE func_name '(' expr_list ')' opt_repeatable_clause
+ {
+ RangeTableSample *n = makeNode(RangeTableSample);
+ /* n->relation will be filled in later */
+ n->method = $2;
+ n->args = $4;
+ n->repeatable = $6;
+ n->location = @2;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_repeatable_clause:
+ REPEATABLE '(' a_expr ')' { $$ = (Node *) $3; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/*
+ * func_table represents a function invocation in a FROM list. It can be
+ * a plain function call, like "foo(...)", or a ROWS FROM expression with
+ * one or more function calls, "ROWS FROM (foo(...), bar(...))",
+ * optionally with WITH ORDINALITY attached.
+ * In the ROWS FROM syntax, a column definition list can be given for each
+ * function, for example:
+ * ROWS FROM (foo() AS (foo_res_a text, foo_res_b text),
+ * bar() AS (bar_res_a text, bar_res_b text))
+ * It's also possible to attach a column definition list to the RangeFunction
+ * as a whole, but that's handled by the table_ref production.
+ */
+func_table: func_expr_windowless opt_ordinality
+ {
+ RangeFunction *n = makeNode(RangeFunction);
+ n->lateral = false;
+ n->ordinality = $2;
+ n->is_rowsfrom = false;
+ n->functions = list_make1(list_make2($1, NIL));
+ /* alias and coldeflist are set by table_ref production */
+ $$ = (Node *) n;
+ }
+ | ROWS FROM '(' rowsfrom_list ')' opt_ordinality
+ {
+ RangeFunction *n = makeNode(RangeFunction);
+ n->lateral = false;
+ n->ordinality = $6;
+ n->is_rowsfrom = true;
+ n->functions = $4;
+ /* alias and coldeflist are set by table_ref production */
+ $$ = (Node *) n;
+ }
+ ;
+
+rowsfrom_item: func_expr_windowless opt_col_def_list
+ { $$ = list_make2($1, $2); }
+ ;
+
+rowsfrom_list:
+ rowsfrom_item { $$ = list_make1($1); }
+ | rowsfrom_list ',' rowsfrom_item { $$ = lappend($1, $3); }
+ ;
+
+opt_col_def_list: AS '(' TableFuncElementList ')' { $$ = $3; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_ordinality: WITH_LA ORDINALITY { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+
+where_clause:
+ WHERE a_expr { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/* variant for UPDATE and DELETE */
+where_or_current_clause:
+ WHERE a_expr { $$ = $2; }
+ | WHERE CURRENT_P OF cursor_name
+ {
+ CurrentOfExpr *n = makeNode(CurrentOfExpr);
+ /* cvarno is filled in by parse analysis */
+ n->cursor_name = $4;
+ n->cursor_param = 0;
+ $$ = (Node *) n;
+ }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+
+OptTableFuncElementList:
+ TableFuncElementList { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+TableFuncElementList:
+ TableFuncElement
+ {
+ $$ = list_make1($1);
+ }
+ | TableFuncElementList ',' TableFuncElement
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+TableFuncElement: ColId Typename opt_collate_clause
+ {
+ ColumnDef *n = makeNode(ColumnDef);
+ n->colname = $1;
+ n->typeName = $2;
+ n->inhcount = 0;
+ n->is_local = true;
+ n->is_not_null = false;
+ n->is_from_type = false;
+ n->storage = 0;
+ n->raw_default = NULL;
+ n->cooked_default = NULL;
+ n->collClause = (CollateClause *) $3;
+ n->collOid = InvalidOid;
+ n->constraints = NIL;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*
+ * XMLTABLE
+ */
+xmltable:
+ XMLTABLE '(' c_expr xmlexists_argument COLUMNS xmltable_column_list ')'
+ {
+ RangeTableFunc *n = makeNode(RangeTableFunc);
+ n->rowexpr = $3;
+ n->docexpr = $4;
+ n->columns = $6;
+ n->namespaces = NIL;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | XMLTABLE '(' XMLNAMESPACES '(' xml_namespace_list ')' ','
+ c_expr xmlexists_argument COLUMNS xmltable_column_list ')'
+ {
+ RangeTableFunc *n = makeNode(RangeTableFunc);
+ n->rowexpr = $8;
+ n->docexpr = $9;
+ n->columns = $11;
+ n->namespaces = $5;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ ;
+
+xmltable_column_list: xmltable_column_el { $$ = list_make1($1); }
+ | xmltable_column_list ',' xmltable_column_el { $$ = lappend($1, $3); }
+ ;
+
+xmltable_column_el:
+ ColId Typename
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+
+ fc->colname = $1;
+ fc->for_ordinality = false;
+ fc->typeName = $2;
+ fc->is_not_null = false;
+ fc->colexpr = NULL;
+ fc->coldefexpr = NULL;
+ fc->location = @1;
+
+ $$ = (Node *) fc;
+ }
+ | ColId Typename xmltable_column_option_list
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+ ListCell *option;
+ bool nullability_seen = false;
+
+ fc->colname = $1;
+ fc->typeName = $2;
+ fc->for_ordinality = false;
+ fc->is_not_null = false;
+ fc->colexpr = NULL;
+ fc->coldefexpr = NULL;
+ fc->location = @1;
+
+ foreach(option, $3)
+ {
+ DefElem *defel = (DefElem *) lfirst(option);
+
+ if (strcmp(defel->defname, "default") == 0)
+ {
+ if (fc->coldefexpr != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one DEFAULT value is allowed"),
+ parser_errposition(defel->location)));
+ fc->coldefexpr = defel->arg;
+ }
+ else if (strcmp(defel->defname, "path") == 0)
+ {
+ if (fc->colexpr != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one PATH value per column is allowed"),
+ parser_errposition(defel->location)));
+ fc->colexpr = defel->arg;
+ }
+ else if (strcmp(defel->defname, "is_not_null") == 0)
+ {
+ if (nullability_seen)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant NULL / NOT NULL declarations for column \"%s\"", fc->colname),
+ parser_errposition(defel->location)));
+ fc->is_not_null = intVal(defel->arg);
+ nullability_seen = true;
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized column option \"%s\"",
+ defel->defname),
+ parser_errposition(defel->location)));
+ }
+ }
+ $$ = (Node *) fc;
+ }
+ | ColId FOR ORDINALITY
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+
+ fc->colname = $1;
+ fc->for_ordinality = true;
+ /* other fields are ignored, initialized by makeNode */
+ fc->location = @1;
+
+ $$ = (Node *) fc;
+ }
+ ;
+
+xmltable_column_option_list:
+ xmltable_column_option_el
+ { $$ = list_make1($1); }
+ | xmltable_column_option_list xmltable_column_option_el
+ { $$ = lappend($1, $2); }
+ ;
+
+xmltable_column_option_el:
+ IDENT b_expr
+ { $$ = makeDefElem($1, $2, @1); }
+ | DEFAULT b_expr
+ { $$ = makeDefElem("default", $2, @1); }
+ | NOT NULL_P
+ { $$ = makeDefElem("is_not_null", (Node *) makeInteger(true), @1); }
+ | NULL_P
+ { $$ = makeDefElem("is_not_null", (Node *) makeInteger(false), @1); }
+ ;
+
+xml_namespace_list:
+ xml_namespace_el
+ { $$ = list_make1($1); }
+ | xml_namespace_list ',' xml_namespace_el
+ { $$ = lappend($1, $3); }
+ ;
+
+xml_namespace_el:
+ b_expr AS ColLabel
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $3;
+ $$->indirection = NIL;
+ $$->val = $1;
+ $$->location = @1;
+ }
+ | DEFAULT b_expr
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = $2;
+ $$->location = @1;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * Type syntax
+ * SQL introduces a large amount of type-specific syntax.
+ * Define individual clauses to handle these cases, and use
+ * the generic case to handle regular type-extensible Postgres syntax.
+ * - thomas 1997-10-10
+ *
+ *****************************************************************************/
+
+Typename: SimpleTypename opt_array_bounds
+ {
+ $$ = $1;
+ $$->arrayBounds = $2;
+ }
+ | SETOF SimpleTypename opt_array_bounds
+ {
+ $$ = $2;
+ $$->arrayBounds = $3;
+ $$->setof = true;
+ }
+ /* SQL standard syntax, currently only one-dimensional */
+ | SimpleTypename ARRAY '[' Iconst ']'
+ {
+ $$ = $1;
+ $$->arrayBounds = list_make1(makeInteger($4));
+ }
+ | SETOF SimpleTypename ARRAY '[' Iconst ']'
+ {
+ $$ = $2;
+ $$->arrayBounds = list_make1(makeInteger($5));
+ $$->setof = true;
+ }
+ | SimpleTypename ARRAY
+ {
+ $$ = $1;
+ $$->arrayBounds = list_make1(makeInteger(-1));
+ }
+ | SETOF SimpleTypename ARRAY
+ {
+ $$ = $2;
+ $$->arrayBounds = list_make1(makeInteger(-1));
+ $$->setof = true;
+ }
+ ;
+
+opt_array_bounds:
+ opt_array_bounds '[' ']'
+ { $$ = lappend($1, makeInteger(-1)); }
+ | opt_array_bounds '[' Iconst ']'
+ { $$ = lappend($1, makeInteger($3)); }
+ | /*EMPTY*/
+ { $$ = NIL; }
+ ;
+
+SimpleTypename:
+ GenericType { $$ = $1; }
+ | Numeric { $$ = $1; }
+ | Bit { $$ = $1; }
+ | Character { $$ = $1; }
+ | ConstDatetime { $$ = $1; }
+ | ConstInterval opt_interval
+ {
+ $$ = $1;
+ $$->typmods = $2;
+ }
+ | ConstInterval '(' Iconst ')'
+ {
+ $$ = $1;
+ $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
+ makeIntConst($3, @3));
+ }
+ ;
+
+/* We have a separate ConstTypename to allow defaulting fixed-length
+ * types such as CHAR() and BIT() to an unspecified length.
+ * SQL9x requires that these default to a length of one, but this
+ * makes no sense for constructs like CHAR 'hi' and BIT '0101',
+ * where there is an obvious better choice to make.
+ * Note that ConstInterval is not included here since it must
+ * be pushed up higher in the rules to accommodate the postfix
+ * options (e.g. INTERVAL '1' YEAR). Likewise, we have to handle
+ * the generic-type-name case in AexprConst to avoid premature
+ * reduce/reduce conflicts against function names.
+ */
+ConstTypename:
+ Numeric { $$ = $1; }
+ | ConstBit { $$ = $1; }
+ | ConstCharacter { $$ = $1; }
+ | ConstDatetime { $$ = $1; }
+ ;
+
+/*
+ * GenericType covers all type names that don't have special syntax mandated
+ * by the standard, including qualified names. We also allow type modifiers.
+ * To avoid parsing conflicts against function invocations, the modifiers
+ * have to be shown as expr_list here, but parse analysis will only accept
+ * constants for them.
+ */
+GenericType:
+ type_function_name opt_type_modifiers
+ {
+ $$ = makeTypeName($1);
+ $$->typmods = $2;
+ $$->location = @1;
+ }
+ | type_function_name attrs opt_type_modifiers
+ {
+ $$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
+ $$->typmods = $3;
+ $$->location = @1;
+ }
+ ;
+
+opt_type_modifiers: '(' expr_list ')' { $$ = $2; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+/*
+ * SQL numeric data types
+ */
+Numeric: INT_P
+ {
+ $$ = SystemTypeName("int4");
+ $$->location = @1;
+ }
+ | INTEGER
+ {
+ $$ = SystemTypeName("int4");
+ $$->location = @1;
+ }
+ | SMALLINT
+ {
+ $$ = SystemTypeName("int2");
+ $$->location = @1;
+ }
+ | BIGINT
+ {
+ $$ = SystemTypeName("int8");
+ $$->location = @1;
+ }
+ | REAL
+ {
+ $$ = SystemTypeName("float4");
+ $$->location = @1;
+ }
+ | FLOAT_P opt_float
+ {
+ $$ = $2;
+ $$->location = @1;
+ }
+ | DOUBLE_P PRECISION
+ {
+ $$ = SystemTypeName("float8");
+ $$->location = @1;
+ }
+ | DECIMAL_P opt_type_modifiers
+ {
+ $$ = SystemTypeName("numeric");
+ $$->typmods = $2;
+ $$->location = @1;
+ }
+ | DEC opt_type_modifiers
+ {
+ $$ = SystemTypeName("numeric");
+ $$->typmods = $2;
+ $$->location = @1;
+ }
+ | NUMERIC opt_type_modifiers
+ {
+ $$ = SystemTypeName("numeric");
+ $$->typmods = $2;
+ $$->location = @1;
+ }
+ | BOOLEAN_P
+ {
+ $$ = SystemTypeName("bool");
+ $$->location = @1;
+ }
+ ;
+
+opt_float: '(' Iconst ')'
+ {
+ /*
+ * Check FLOAT() precision limits assuming IEEE floating
+ * types - thomas 1997-09-18
+ */
+ if ($2 < 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("precision for type float must be at least 1 bit"),
+ parser_errposition(@2)));
+ else if ($2 <= 24)
+ $$ = SystemTypeName("float4");
+ else if ($2 <= 53)
+ $$ = SystemTypeName("float8");
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("precision for type float must be less than 54 bits"),
+ parser_errposition(@2)));
+ }
+ | /*EMPTY*/
+ {
+ $$ = SystemTypeName("float8");
+ }
+ ;
+
+/*
+ * SQL bit-field data types
+ * The following implements BIT() and BIT VARYING().
+ */
+Bit: BitWithLength
+ {
+ $$ = $1;
+ }
+ | BitWithoutLength
+ {
+ $$ = $1;
+ }
+ ;
+
+/* ConstBit is like Bit except "BIT" defaults to unspecified length */
+/* See notes for ConstCharacter, which addresses same issue for "CHAR" */
+ConstBit: BitWithLength
+ {
+ $$ = $1;
+ }
+ | BitWithoutLength
+ {
+ $$ = $1;
+ $$->typmods = NIL;
+ }
+ ;
+
+BitWithLength:
+ BIT opt_varying '(' expr_list ')'
+ {
+ char *typname;
+
+ typname = $2 ? "varbit" : "bit";
+ $$ = SystemTypeName(typname);
+ $$->typmods = $4;
+ $$->location = @1;
+ }
+ ;
+
+BitWithoutLength:
+ BIT opt_varying
+ {
+ /* bit defaults to bit(1), varbit to no limit */
+ if ($2)
+ {
+ $$ = SystemTypeName("varbit");
+ }
+ else
+ {
+ $$ = SystemTypeName("bit");
+ $$->typmods = list_make1(makeIntConst(1, -1));
+ }
+ $$->location = @1;
+ }
+ ;
+
+
+/*
+ * SQL character data types
+ * The following implements CHAR() and VARCHAR().
+ */
+Character: CharacterWithLength
+ {
+ $$ = $1;
+ }
+ | CharacterWithoutLength
+ {
+ $$ = $1;
+ }
+ ;
+
+ConstCharacter: CharacterWithLength
+ {
+ $$ = $1;
+ }
+ | CharacterWithoutLength
+ {
+ /* Length was not specified so allow to be unrestricted.
+ * This handles problems with fixed-length (bpchar) strings
+ * which in column definitions must default to a length
+ * of one, but should not be constrained if the length
+ * was not specified.
+ */
+ $$ = $1;
+ $$->typmods = NIL;
+ }
+ ;
+
+CharacterWithLength: character '(' Iconst ')'
+ {
+ $$ = SystemTypeName($1);
+ $$->typmods = list_make1(makeIntConst($3, @3));
+ $$->location = @1;
+ }
+ ;
+
+CharacterWithoutLength: character
+ {
+ $$ = SystemTypeName($1);
+ /* char defaults to char(1), varchar to no limit */
+ if (strcmp($1, "bpchar") == 0)
+ $$->typmods = list_make1(makeIntConst(1, -1));
+ $$->location = @1;
+ }
+ ;
+
+character: CHARACTER opt_varying
+ { $$ = $2 ? "varchar": "bpchar"; }
+ | CHAR_P opt_varying
+ { $$ = $2 ? "varchar": "bpchar"; }
+ | VARCHAR
+ { $$ = "varchar"; }
+ | NATIONAL CHARACTER opt_varying
+ { $$ = $3 ? "varchar": "bpchar"; }
+ | NATIONAL CHAR_P opt_varying
+ { $$ = $3 ? "varchar": "bpchar"; }
+ | NCHAR opt_varying
+ { $$ = $2 ? "varchar": "bpchar"; }
+ ;
+
+opt_varying:
+ VARYING { $$ = true; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+/*
+ * SQL date/time types
+ */
+ConstDatetime:
+ TIMESTAMP '(' Iconst ')' opt_timezone
+ {
+ if ($5)
+ $$ = SystemTypeName("timestamptz");
+ else
+ $$ = SystemTypeName("timestamp");
+ $$->typmods = list_make1(makeIntConst($3, @3));
+ $$->location = @1;
+ }
+ | TIMESTAMP opt_timezone
+ {
+ if ($2)
+ $$ = SystemTypeName("timestamptz");
+ else
+ $$ = SystemTypeName("timestamp");
+ $$->location = @1;
+ }
+ | TIME '(' Iconst ')' opt_timezone
+ {
+ if ($5)
+ $$ = SystemTypeName("timetz");
+ else
+ $$ = SystemTypeName("time");
+ $$->typmods = list_make1(makeIntConst($3, @3));
+ $$->location = @1;
+ }
+ | TIME opt_timezone
+ {
+ if ($2)
+ $$ = SystemTypeName("timetz");
+ else
+ $$ = SystemTypeName("time");
+ $$->location = @1;
+ }
+ ;
+
+ConstInterval:
+ INTERVAL
+ {
+ $$ = SystemTypeName("interval");
+ $$->location = @1;
+ }
+ ;
+
+opt_timezone:
+ WITH_LA TIME ZONE { $$ = true; }
+ | WITHOUT TIME ZONE { $$ = false; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+opt_interval:
+ YEAR_P
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); }
+ | MONTH_P
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); }
+ | DAY_P
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1)); }
+ | HOUR_P
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); }
+ | MINUTE_P
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); }
+ | interval_second
+ { $$ = $1; }
+ | YEAR_P TO MONTH_P
+ {
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
+ INTERVAL_MASK(MONTH), @1));
+ }
+ | DAY_P TO HOUR_P
+ {
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
+ INTERVAL_MASK(HOUR), @1));
+ }
+ | DAY_P TO MINUTE_P
+ {
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
+ INTERVAL_MASK(HOUR) |
+ INTERVAL_MASK(MINUTE), @1));
+ }
+ | DAY_P TO interval_second
+ {
+ $$ = $3;
+ linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
+ INTERVAL_MASK(HOUR) |
+ INTERVAL_MASK(MINUTE) |
+ INTERVAL_MASK(SECOND), @1);
+ }
+ | HOUR_P TO MINUTE_P
+ {
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
+ INTERVAL_MASK(MINUTE), @1));
+ }
+ | HOUR_P TO interval_second
+ {
+ $$ = $3;
+ linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
+ INTERVAL_MASK(MINUTE) |
+ INTERVAL_MASK(SECOND), @1);
+ }
+ | MINUTE_P TO interval_second
+ {
+ $$ = $3;
+ linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
+ INTERVAL_MASK(SECOND), @1);
+ }
+ | /*EMPTY*/
+ { $$ = NIL; }
+ ;
+
+interval_second:
+ SECOND_P
+ {
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1));
+ }
+ | SECOND_P '(' Iconst ')'
+ {
+ $$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1),
+ makeIntConst($3, @3));
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * expression grammar
+ *
+ *****************************************************************************/
+
+/*
+ * General expressions
+ * This is the heart of the expression syntax.
+ *
+ * We have two expression types: a_expr is the unrestricted kind, and
+ * b_expr is a subset that must be used in some places to avoid shift/reduce
+ * conflicts. For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr"
+ * because that use of AND conflicts with AND as a boolean operator. So,
+ * b_expr is used in BETWEEN and we remove boolean keywords from b_expr.
+ *
+ * Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
+ * always be used by surrounding it with parens.
+ *
+ * c_expr is all the productions that are common to a_expr and b_expr;
+ * it's factored out just to eliminate redundant coding.
+ *
+ * Be careful of productions involving more than one terminal token.
+ * By default, bison will assign such productions the precedence of their
+ * last terminal, but in nearly all cases you want it to be the precedence
+ * of the first terminal instead; otherwise you will not get the behavior
+ * you expect! So we use %prec annotations freely to set precedences.
+ */
+a_expr: c_expr { $$ = $1; }
+ | a_expr TYPECAST Typename
+ { $$ = makeTypeCast($1, $3, @2); }
+ | a_expr COLLATE any_name
+ {
+ CollateClause *n = makeNode(CollateClause);
+ n->arg = $1;
+ n->collname = $3;
+ n->location = @2;
+ $$ = (Node *) n;
+ }
+ | a_expr AT TIME ZONE a_expr %prec AT
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("timezone"),
+ list_make2($5, $1),
+ COERCE_SQL_SYNTAX,
+ @2);
+ }
+ /*
+ * These operators must be called out explicitly in order to make use
+ * of bison's automatic operator-precedence handling. All other
+ * operator names are handled by the generic productions using "Op",
+ * below; and all those operators will have the same precedence.
+ *
+ * If you add more explicitly-known operators, be sure to add them
+ * also to b_expr and to the MathOp list below.
+ */
+ | '+' a_expr %prec UMINUS
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
+ | '-' a_expr %prec UMINUS
+ { $$ = doNegate($2, @1); }
+ | a_expr '+' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
+ | a_expr '-' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
+ | a_expr '*' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
+ | a_expr '/' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
+ | a_expr '%' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
+ | a_expr '^' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
+ | a_expr '<' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
+ | a_expr '>' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
+ | a_expr '=' a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
+ | a_expr LESS_EQUALS a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); }
+ | a_expr GREATER_EQUALS a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
+ | a_expr NOT_EQUALS a_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
+
+ | a_expr qual_Op a_expr %prec Op
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
+ | qual_Op a_expr %prec Op
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
+
+ | a_expr AND a_expr
+ { $$ = makeAndExpr($1, $3, @2); }
+ | a_expr OR a_expr
+ { $$ = makeOrExpr($1, $3, @2); }
+ | NOT a_expr
+ { $$ = makeNotExpr($2, @1); }
+ | NOT_LA a_expr %prec NOT
+ { $$ = makeNotExpr($2, @1); }
+
+ | a_expr LIKE a_expr
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
+ $1, $3, @2);
+ }
+ | a_expr LIKE a_expr ESCAPE a_expr %prec LIKE
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
+ list_make2($3, $5),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "~~",
+ $1, (Node *) n, @2);
+ }
+ | a_expr NOT_LA LIKE a_expr %prec NOT_LA
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
+ $1, $4, @2);
+ }
+ | a_expr NOT_LA LIKE a_expr ESCAPE a_expr %prec NOT_LA
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
+ list_make2($4, $6),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_LIKE, "!~~",
+ $1, (Node *) n, @2);
+ }
+ | a_expr ILIKE a_expr
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
+ $1, $3, @2);
+ }
+ | a_expr ILIKE a_expr ESCAPE a_expr %prec ILIKE
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
+ list_make2($3, $5),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "~~*",
+ $1, (Node *) n, @2);
+ }
+ | a_expr NOT_LA ILIKE a_expr %prec NOT_LA
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
+ $1, $4, @2);
+ }
+ | a_expr NOT_LA ILIKE a_expr ESCAPE a_expr %prec NOT_LA
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("like_escape"),
+ list_make2($4, $6),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_ILIKE, "!~~*",
+ $1, (Node *) n, @2);
+ }
+
+ | a_expr SIMILAR TO a_expr %prec SIMILAR
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
+ list_make1($4),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
+ $1, (Node *) n, @2);
+ }
+ | a_expr SIMILAR TO a_expr ESCAPE a_expr %prec SIMILAR
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
+ list_make2($4, $6),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "~",
+ $1, (Node *) n, @2);
+ }
+ | a_expr NOT_LA SIMILAR TO a_expr %prec NOT_LA
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
+ list_make1($5),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
+ $1, (Node *) n, @2);
+ }
+ | a_expr NOT_LA SIMILAR TO a_expr ESCAPE a_expr %prec NOT_LA
+ {
+ FuncCall *n = makeFuncCall(SystemFuncName("similar_to_escape"),
+ list_make2($5, $7),
+ COERCE_EXPLICIT_CALL,
+ @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_SIMILAR, "!~",
+ $1, (Node *) n, @2);
+ }
+
+ /* NullTest clause
+ * Define SQL-style Null test clause.
+ * Allow two forms described in the standard:
+ * a IS NULL
+ * a IS NOT NULL
+ * Allow two SQL extensions
+ * a ISNULL
+ * a NOTNULL
+ */
+ | a_expr IS NULL_P %prec IS
+ {
+ NullTest *n = makeNode(NullTest);
+ n->arg = (Expr *) $1;
+ n->nulltesttype = IS_NULL;
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ | a_expr ISNULL
+ {
+ NullTest *n = makeNode(NullTest);
+ n->arg = (Expr *) $1;
+ n->nulltesttype = IS_NULL;
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ | a_expr IS NOT NULL_P %prec IS
+ {
+ NullTest *n = makeNode(NullTest);
+ n->arg = (Expr *) $1;
+ n->nulltesttype = IS_NOT_NULL;
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ | a_expr NOTNULL
+ {
+ NullTest *n = makeNode(NullTest);
+ n->arg = (Expr *) $1;
+ n->nulltesttype = IS_NOT_NULL;
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ | row OVERLAPS row
+ {
+ if (list_length($1) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("wrong number of parameters on left side of OVERLAPS expression"),
+ parser_errposition(@1)));
+ if (list_length($3) != 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("wrong number of parameters on right side of OVERLAPS expression"),
+ parser_errposition(@3)));
+ $$ = (Node *) makeFuncCall(SystemFuncName("overlaps"),
+ list_concat($1, $3),
+ COERCE_SQL_SYNTAX,
+ @2);
+ }
+ | a_expr IS TRUE_P %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_TRUE;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS NOT TRUE_P %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_NOT_TRUE;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS FALSE_P %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_FALSE;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS NOT FALSE_P %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_NOT_FALSE;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS UNKNOWN %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_UNKNOWN;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS NOT UNKNOWN %prec IS
+ {
+ BooleanTest *b = makeNode(BooleanTest);
+ b->arg = (Expr *) $1;
+ b->booltesttype = IS_NOT_UNKNOWN;
+ b->location = @2;
+ $$ = (Node *)b;
+ }
+ | a_expr IS DISTINCT FROM a_expr %prec IS
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
+ }
+ | a_expr IS NOT DISTINCT FROM a_expr %prec IS
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2);
+ }
+ | a_expr BETWEEN opt_asymmetric b_expr AND a_expr %prec BETWEEN
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN,
+ "BETWEEN",
+ $1,
+ (Node *) list_make2($4, $6),
+ @2);
+ }
+ | a_expr NOT_LA BETWEEN opt_asymmetric b_expr AND a_expr %prec NOT_LA
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN,
+ "NOT BETWEEN",
+ $1,
+ (Node *) list_make2($5, $7),
+ @2);
+ }
+ | a_expr BETWEEN SYMMETRIC b_expr AND a_expr %prec BETWEEN
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN_SYM,
+ "BETWEEN SYMMETRIC",
+ $1,
+ (Node *) list_make2($4, $6),
+ @2);
+ }
+ | a_expr NOT_LA BETWEEN SYMMETRIC b_expr AND a_expr %prec NOT_LA
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN_SYM,
+ "NOT BETWEEN SYMMETRIC",
+ $1,
+ (Node *) list_make2($5, $7),
+ @2);
+ }
+ | a_expr IN_P in_expr
+ {
+ /* in_expr returns a SubLink or a list of a_exprs */
+ if (IsA($3, SubLink))
+ {
+ /* generate foo = ANY (subquery) */
+ SubLink *n = (SubLink *) $3;
+ n->subLinkType = ANY_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = $1;
+ n->operName = NIL; /* show it's IN not = ANY */
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ else
+ {
+ /* generate scalar IN expression */
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
+ }
+ }
+ | a_expr NOT_LA IN_P in_expr %prec NOT_LA
+ {
+ /* in_expr returns a SubLink or a list of a_exprs */
+ if (IsA($4, SubLink))
+ {
+ /* generate NOT (foo = ANY (subquery)) */
+ /* Make an = ANY node */
+ SubLink *n = (SubLink *) $4;
+ n->subLinkType = ANY_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = $1;
+ n->operName = NIL; /* show it's IN not = ANY */
+ n->location = @2;
+ /* Stick a NOT on top; must have same parse location */
+ $$ = makeNotExpr((Node *) n, @2);
+ }
+ else
+ {
+ /* generate scalar NOT IN expression */
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
+ }
+ }
+ | a_expr subquery_Op sub_type select_with_parens %prec Op
+ {
+ SubLink *n = makeNode(SubLink);
+ n->subLinkType = $3;
+ n->subLinkId = 0;
+ n->testexpr = $1;
+ n->operName = $2;
+ n->subselect = $4;
+ n->location = @2;
+ $$ = (Node *)n;
+ }
+ | a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
+ {
+ if ($3 == ANY_SUBLINK)
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
+ else
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
+ }
+ | UNIQUE select_with_parens
+ {
+ /* Not sure how to get rid of the parentheses
+ * but there are lots of shift/reduce errors without them.
+ *
+ * Should be able to implement this by plopping the entire
+ * select into a node, then transforming the target expressions
+ * from whatever they are into count(*), and testing the
+ * entire result equal to one.
+ * But, will probably implement a separate node in the executor.
+ */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("UNIQUE predicate is not yet implemented"),
+ parser_errposition(@1)));
+ }
+ | a_expr IS DOCUMENT_P %prec IS
+ {
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
+ }
+ | a_expr IS NOT DOCUMENT_P %prec IS
+ {
+ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
+ @2);
+ }
+ | a_expr IS NORMALIZED %prec IS
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("is_normalized"),
+ list_make1($1),
+ COERCE_SQL_SYNTAX,
+ @2);
+ }
+ | a_expr IS unicode_normal_form NORMALIZED %prec IS
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("is_normalized"),
+ list_make2($1, makeStringConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @2);
+ }
+ | a_expr IS NOT NORMALIZED %prec IS
+ {
+ $$ = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"),
+ list_make1($1),
+ COERCE_SQL_SYNTAX,
+ @2),
+ @2);
+ }
+ | a_expr IS NOT unicode_normal_form NORMALIZED %prec IS
+ {
+ $$ = makeNotExpr((Node *) makeFuncCall(SystemFuncName("is_normalized"),
+ list_make2($1, makeStringConst($4, @4)),
+ COERCE_SQL_SYNTAX,
+ @2),
+ @2);
+ }
+ | DEFAULT
+ {
+ /*
+ * The SQL spec only allows DEFAULT in "contextually typed
+ * expressions", but for us, it's easier to allow it in
+ * any a_expr and then throw error during parse analysis
+ * if it's in an inappropriate context. This way also
+ * lets us say something smarter than "syntax error".
+ */
+ SetToDefault *n = makeNode(SetToDefault);
+ /* parse analysis will fill in the rest */
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*
+ * Restricted expressions
+ *
+ * b_expr is a subset of the complete expression syntax defined by a_expr.
+ *
+ * Presently, AND, NOT, IS, and IN are the a_expr keywords that would
+ * cause trouble in the places where b_expr is used. For simplicity, we
+ * just eliminate all the boolean-keyword-operator productions from b_expr.
+ */
+b_expr: c_expr
+ { $$ = $1; }
+ | b_expr TYPECAST Typename
+ { $$ = makeTypeCast($1, $3, @2); }
+ | '+' b_expr %prec UMINUS
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
+ | '-' b_expr %prec UMINUS
+ { $$ = doNegate($2, @1); }
+ | b_expr '+' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
+ | b_expr '-' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
+ | b_expr '*' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
+ | b_expr '/' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
+ | b_expr '%' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
+ | b_expr '^' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
+ | b_expr '<' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
+ | b_expr '>' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
+ | b_expr '=' b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
+ | b_expr LESS_EQUALS b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); }
+ | b_expr GREATER_EQUALS b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
+ | b_expr NOT_EQUALS b_expr
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
+ | b_expr qual_Op b_expr %prec Op
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
+ | qual_Op b_expr %prec Op
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
+ | b_expr IS DISTINCT FROM b_expr %prec IS
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
+ }
+ | b_expr IS NOT DISTINCT FROM b_expr %prec IS
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2);
+ }
+ | b_expr IS DOCUMENT_P %prec IS
+ {
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
+ }
+ | b_expr IS NOT DOCUMENT_P %prec IS
+ {
+ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
+ @2);
+ }
+ ;
+
+/*
+ * Productions that can be used in both a_expr and b_expr.
+ *
+ * Note: productions that refer recursively to a_expr or b_expr mostly
+ * cannot appear here. However, it's OK to refer to a_exprs that occur
+ * inside parentheses, such as function arguments; that cannot introduce
+ * ambiguity to the b_expr syntax.
+ */
+c_expr: columnref { $$ = $1; }
+ | AexprConst { $$ = $1; }
+ | PARAM opt_indirection
+ {
+ ParamRef *p = makeNode(ParamRef);
+ p->number = $1;
+ p->location = @1;
+ if ($2)
+ {
+ A_Indirection *n = makeNode(A_Indirection);
+ n->arg = (Node *) p;
+ n->indirection = check_indirection($2, yyscanner);
+ $$ = (Node *) n;
+ }
+ else
+ $$ = (Node *) p;
+ }
+ | '(' a_expr ')' opt_indirection
+ {
+ if ($4)
+ {
+ A_Indirection *n = makeNode(A_Indirection);
+ n->arg = $2;
+ n->indirection = check_indirection($4, yyscanner);
+ $$ = (Node *)n;
+ }
+ else
+ $$ = $2;
+ }
+ | case_expr
+ { $$ = $1; }
+ | func_expr
+ { $$ = $1; }
+ | select_with_parens %prec UMINUS
+ {
+ SubLink *n = makeNode(SubLink);
+ n->subLinkType = EXPR_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = NULL;
+ n->operName = NIL;
+ n->subselect = $1;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | select_with_parens indirection
+ {
+ /*
+ * Because the select_with_parens nonterminal is designed
+ * to "eat" as many levels of parens as possible, the
+ * '(' a_expr ')' opt_indirection production above will
+ * fail to match a sub-SELECT with indirection decoration;
+ * the sub-SELECT won't be regarded as an a_expr as long
+ * as there are parens around it. To support applying
+ * subscripting or field selection to a sub-SELECT result,
+ * we need this redundant-looking production.
+ */
+ SubLink *n = makeNode(SubLink);
+ A_Indirection *a = makeNode(A_Indirection);
+ n->subLinkType = EXPR_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = NULL;
+ n->operName = NIL;
+ n->subselect = $1;
+ n->location = @1;
+ a->arg = (Node *)n;
+ a->indirection = check_indirection($2, yyscanner);
+ $$ = (Node *)a;
+ }
+ | EXISTS select_with_parens
+ {
+ SubLink *n = makeNode(SubLink);
+ n->subLinkType = EXISTS_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = NULL;
+ n->operName = NIL;
+ n->subselect = $2;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | ARRAY select_with_parens
+ {
+ SubLink *n = makeNode(SubLink);
+ n->subLinkType = ARRAY_SUBLINK;
+ n->subLinkId = 0;
+ n->testexpr = NULL;
+ n->operName = NIL;
+ n->subselect = $2;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | ARRAY array_expr
+ {
+ A_ArrayExpr *n = castNode(A_ArrayExpr, $2);
+ /* point outermost A_ArrayExpr to the ARRAY keyword */
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | explicit_row
+ {
+ RowExpr *r = makeNode(RowExpr);
+ r->args = $1;
+ r->row_typeid = InvalidOid; /* not analyzed yet */
+ r->colnames = NIL; /* to be filled in during analysis */
+ r->row_format = COERCE_EXPLICIT_CALL; /* abuse */
+ r->location = @1;
+ $$ = (Node *)r;
+ }
+ | implicit_row
+ {
+ RowExpr *r = makeNode(RowExpr);
+ r->args = $1;
+ r->row_typeid = InvalidOid; /* not analyzed yet */
+ r->colnames = NIL; /* to be filled in during analysis */
+ r->row_format = COERCE_IMPLICIT_CAST; /* abuse */
+ r->location = @1;
+ $$ = (Node *)r;
+ }
+ | GROUPING '(' expr_list ')'
+ {
+ GroupingFunc *g = makeNode(GroupingFunc);
+ g->args = $3;
+ g->location = @1;
+ $$ = (Node *)g;
+ }
+ ;
+
+func_application: func_name '(' ')'
+ {
+ $$ = (Node *) makeFuncCall($1, NIL,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ }
+ | func_name '(' func_arg_list opt_sort_clause ')'
+ {
+ FuncCall *n = makeFuncCall($1, $3,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->agg_order = $4;
+ $$ = (Node *)n;
+ }
+ | func_name '(' VARIADIC func_arg_expr opt_sort_clause ')'
+ {
+ FuncCall *n = makeFuncCall($1, list_make1($4),
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->func_variadic = true;
+ n->agg_order = $5;
+ $$ = (Node *)n;
+ }
+ | func_name '(' func_arg_list ',' VARIADIC func_arg_expr opt_sort_clause ')'
+ {
+ FuncCall *n = makeFuncCall($1, lappend($3, $6),
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->func_variadic = true;
+ n->agg_order = $7;
+ $$ = (Node *)n;
+ }
+ | func_name '(' ALL func_arg_list opt_sort_clause ')'
+ {
+ FuncCall *n = makeFuncCall($1, $4,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->agg_order = $5;
+ /* Ideally we'd mark the FuncCall node to indicate
+ * "must be an aggregate", but there's no provision
+ * for that in FuncCall at the moment.
+ */
+ $$ = (Node *)n;
+ }
+ | func_name '(' DISTINCT func_arg_list opt_sort_clause ')'
+ {
+ FuncCall *n = makeFuncCall($1, $4,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->agg_order = $5;
+ n->agg_distinct = true;
+ $$ = (Node *)n;
+ }
+ | func_name '(' '*' ')'
+ {
+ /*
+ * We consider AGGREGATE(*) to invoke a parameterless
+ * aggregate. This does the right thing for COUNT(*),
+ * and there are no other aggregates in SQL that accept
+ * '*' as parameter.
+ *
+ * The FuncCall node is also marked agg_star = true,
+ * so that later processing can detect what the argument
+ * really was.
+ */
+ FuncCall *n = makeFuncCall($1, NIL,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ n->agg_star = true;
+ $$ = (Node *)n;
+ }
+ ;
+
+
+/*
+ * func_expr and its cousin func_expr_windowless are split out from c_expr just
+ * so that we have classifications for "everything that is a function call or
+ * looks like one". This isn't very important, but it saves us having to
+ * document which variants are legal in places like "FROM function()" or the
+ * backwards-compatible functional-index syntax for CREATE INDEX.
+ * (Note that many of the special SQL functions wouldn't actually make any
+ * sense as functional index entries, but we ignore that consideration here.)
+ */
+func_expr: func_application within_group_clause filter_clause over_clause
+ {
+ FuncCall *n = (FuncCall *) $1;
+ /*
+ * The order clause for WITHIN GROUP and the one for
+ * plain-aggregate ORDER BY share a field, so we have to
+ * check here that at most one is present. We also check
+ * for DISTINCT and VARIADIC here to give a better error
+ * location. Other consistency checks are deferred to
+ * parse analysis.
+ */
+ if ($2 != NIL)
+ {
+ if (n->agg_order != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("cannot use multiple ORDER BY clauses with WITHIN GROUP"),
+ parser_errposition(@2)));
+ if (n->agg_distinct)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("cannot use DISTINCT with WITHIN GROUP"),
+ parser_errposition(@2)));
+ if (n->func_variadic)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("cannot use VARIADIC with WITHIN GROUP"),
+ parser_errposition(@2)));
+ n->agg_order = $2;
+ n->agg_within_group = true;
+ }
+ n->agg_filter = $3;
+ n->over = $4;
+ $$ = (Node *) n;
+ }
+ | func_expr_common_subexpr
+ { $$ = $1; }
+ ;
+
+/*
+ * As func_expr but does not accept WINDOW functions directly
+ * (but they can still be contained in arguments for functions etc).
+ * Use this when window expressions are not allowed, where needed to
+ * disambiguate the grammar (e.g. in CREATE INDEX).
+ */
+func_expr_windowless:
+ func_application { $$ = $1; }
+ | func_expr_common_subexpr { $$ = $1; }
+ ;
+
+/*
+ * Special expressions that are considered to be functions.
+ */
+func_expr_common_subexpr:
+ COLLATION FOR '(' a_expr ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("pg_collation_for"),
+ list_make1($4),
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | CURRENT_DATE
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ }
+ | CURRENT_TIME
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ }
+ | CURRENT_TIME '(' Iconst ')'
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ }
+ | CURRENT_TIMESTAMP
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ }
+ | CURRENT_TIMESTAMP '(' Iconst ')'
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ }
+ | LOCALTIME
+ {
+ $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ }
+ | LOCALTIME '(' Iconst ')'
+ {
+ $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ }
+ | LOCALTIMESTAMP
+ {
+ $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ }
+ | LOCALTIMESTAMP '(' Iconst ')'
+ {
+ $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ }
+ | CURRENT_ROLE
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
+ }
+ | CURRENT_USER
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
+ }
+ | SESSION_USER
+ {
+ $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
+ }
+ | USER
+ {
+ $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
+ }
+ | CURRENT_CATALOG
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
+ }
+ | CURRENT_SCHEMA
+ {
+ $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
+ }
+ | CAST '(' a_expr AS Typename ')'
+ { $$ = makeTypeCast($3, $5, @1); }
+ | EXTRACT '(' extract_list ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("extract"),
+ $3,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | NORMALIZE '(' a_expr ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("normalize"),
+ list_make1($3),
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | NORMALIZE '(' a_expr ',' unicode_normal_form ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("normalize"),
+ list_make2($3, makeStringConst($5, @5)),
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | OVERLAY '(' overlay_list ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("overlay"),
+ $3,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | OVERLAY '(' func_arg_list_opt ')'
+ {
+ /*
+ * allow functions named overlay() to be called without
+ * special syntax
+ */
+ $$ = (Node *) makeFuncCall(list_make1(makeString("overlay")),
+ $3,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ }
+ | POSITION '(' position_list ')'
+ {
+ /*
+ * position(A in B) is converted to position(B, A)
+ *
+ * We deliberately don't offer a "plain syntax" option
+ * for position(), because the reversal of the arguments
+ * creates too much risk of confusion.
+ */
+ $$ = (Node *) makeFuncCall(SystemFuncName("position"),
+ $3,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | SUBSTRING '(' substr_list ')'
+ {
+ /* substring(A from B for C) is converted to
+ * substring(A, B, C) - thomas 2000-11-28
+ */
+ $$ = (Node *) makeFuncCall(SystemFuncName("substring"),
+ $3,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | SUBSTRING '(' func_arg_list_opt ')'
+ {
+ /*
+ * allow functions named substring() to be called without
+ * special syntax
+ */
+ $$ = (Node *) makeFuncCall(list_make1(makeString("substring")),
+ $3,
+ COERCE_EXPLICIT_CALL,
+ @1);
+ }
+ | TREAT '(' a_expr AS Typename ')'
+ {
+ /* TREAT(expr AS target) converts expr of a particular type to target,
+ * which is defined to be a subtype of the original expression.
+ * In SQL99, this is intended for use with structured UDTs,
+ * but let's make this a generally useful form allowing stronger
+ * coercions than are handled by implicit casting.
+ *
+ * Convert SystemTypeName() to SystemFuncName() even though
+ * at the moment they result in the same thing.
+ */
+ $$ = (Node *) makeFuncCall(SystemFuncName(strVal(llast($5->names))),
+ list_make1($3),
+ COERCE_EXPLICIT_CALL,
+ @1);
+ }
+ | TRIM '(' BOTH trim_list ')'
+ {
+ /* various trim expressions are defined in SQL
+ * - thomas 1997-07-19
+ */
+ $$ = (Node *) makeFuncCall(SystemFuncName("btrim"),
+ $4,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | TRIM '(' LEADING trim_list ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("ltrim"),
+ $4,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | TRIM '(' TRAILING trim_list ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("rtrim"),
+ $4,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | TRIM '(' trim_list ')'
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("btrim"),
+ $3,
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | NULLIF '(' a_expr ',' a_expr ')'
+ {
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
+ }
+ | COALESCE '(' expr_list ')'
+ {
+ CoalesceExpr *c = makeNode(CoalesceExpr);
+ c->args = $3;
+ c->location = @1;
+ $$ = (Node *)c;
+ }
+ | GREATEST '(' expr_list ')'
+ {
+ MinMaxExpr *v = makeNode(MinMaxExpr);
+ v->args = $3;
+ v->op = IS_GREATEST;
+ v->location = @1;
+ $$ = (Node *)v;
+ }
+ | LEAST '(' expr_list ')'
+ {
+ MinMaxExpr *v = makeNode(MinMaxExpr);
+ v->args = $3;
+ v->op = IS_LEAST;
+ v->location = @1;
+ $$ = (Node *)v;
+ }
+ | XMLCONCAT '(' expr_list ')'
+ {
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
+ }
+ | XMLELEMENT '(' NAME_P ColLabel ')'
+ {
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
+ }
+ | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
+ {
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
+ }
+ | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
+ {
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
+ }
+ | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
+ {
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
+ }
+ | XMLEXISTS '(' c_expr xmlexists_argument ')'
+ {
+ /* xmlexists(A PASSING [BY REF] B [BY REF]) is
+ * converted to xmlexists(A, B)*/
+ $$ = (Node *) makeFuncCall(SystemFuncName("xmlexists"),
+ list_make2($3, $4),
+ COERCE_SQL_SYNTAX,
+ @1);
+ }
+ | XMLFOREST '(' xml_attribute_list ')'
+ {
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
+ }
+ | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
+ {
+ XmlExpr *x = (XmlExpr *)
+ makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ list_make2($4, makeBoolAConst($5, -1)),
+ @1);
+ x->xmloption = $3;
+ $$ = (Node *)x;
+ }
+ | XMLPI '(' NAME_P ColLabel ')'
+ {
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
+ }
+ | XMLPI '(' NAME_P ColLabel ',' a_expr ')'
+ {
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
+ }
+ | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
+ {
+ $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
+ list_make3($3, $5, $6), @1);
+ }
+ | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
+ {
+ XmlSerialize *n = makeNode(XmlSerialize);
+ n->xmloption = $3;
+ n->expr = $4;
+ n->typeName = $6;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ ;
+
+/*
+ * SQL/XML support
+ */
+xml_root_version: VERSION_P a_expr
+ { $$ = $2; }
+ | VERSION_P NO VALUE_P
+ { $$ = makeNullAConst(-1); }
+ ;
+
+opt_xml_root_standalone: ',' STANDALONE_P YES_P
+ { $$ = makeIntConst(XML_STANDALONE_YES, -1); }
+ | ',' STANDALONE_P NO
+ { $$ = makeIntConst(XML_STANDALONE_NO, -1); }
+ | ',' STANDALONE_P NO VALUE_P
+ { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
+ | /*EMPTY*/
+ { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
+ ;
+
+xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
+ ;
+
+xml_attribute_list: xml_attribute_el { $$ = list_make1($1); }
+ | xml_attribute_list ',' xml_attribute_el { $$ = lappend($1, $3); }
+ ;
+
+xml_attribute_el: a_expr AS ColLabel
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $3;
+ $$->indirection = NIL;
+ $$->val = (Node *) $1;
+ $$->location = @1;
+ }
+ | a_expr
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = (Node *) $1;
+ $$->location = @1;
+ }
+ ;
+
+document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; }
+ | CONTENT_P { $$ = XMLOPTION_CONTENT; }
+ ;
+
+xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
+ | STRIP_P WHITESPACE_P { $$ = false; }
+ | /*EMPTY*/ { $$ = false; }
+ ;
+
+/* We allow several variants for SQL and other compatibility. */
+xmlexists_argument:
+ PASSING c_expr
+ {
+ $$ = $2;
+ }
+ | PASSING c_expr xml_passing_mech
+ {
+ $$ = $2;
+ }
+ | PASSING xml_passing_mech c_expr
+ {
+ $$ = $3;
+ }
+ | PASSING xml_passing_mech c_expr xml_passing_mech
+ {
+ $$ = $3;
+ }
+ ;
+
+xml_passing_mech:
+ BY REF
+ | BY VALUE_P
+ ;
+
+
+/*
+ * Aggregate decoration clauses
+ */
+within_group_clause:
+ WITHIN GROUP_P '(' sort_clause ')' { $$ = $4; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+filter_clause:
+ FILTER '(' WHERE a_expr ')' { $$ = $4; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+
+/*
+ * Window Definitions
+ */
+window_clause:
+ WINDOW window_definition_list { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+window_definition_list:
+ window_definition { $$ = list_make1($1); }
+ | window_definition_list ',' window_definition
+ { $$ = lappend($1, $3); }
+ ;
+
+window_definition:
+ ColId AS window_specification
+ {
+ WindowDef *n = $3;
+ n->name = $1;
+ $$ = n;
+ }
+ ;
+
+over_clause: OVER window_specification
+ { $$ = $2; }
+ | OVER ColId
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->name = $2;
+ n->refname = NULL;
+ n->partitionClause = NIL;
+ n->orderClause = NIL;
+ n->frameOptions = FRAMEOPTION_DEFAULTS;
+ n->startOffset = NULL;
+ n->endOffset = NULL;
+ n->location = @2;
+ $$ = n;
+ }
+ | /*EMPTY*/
+ { $$ = NULL; }
+ ;
+
+window_specification: '(' opt_existing_window_name opt_partition_clause
+ opt_sort_clause opt_frame_clause ')'
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->name = NULL;
+ n->refname = $2;
+ n->partitionClause = $3;
+ n->orderClause = $4;
+ /* copy relevant fields of opt_frame_clause */
+ n->frameOptions = $5->frameOptions;
+ n->startOffset = $5->startOffset;
+ n->endOffset = $5->endOffset;
+ n->location = @1;
+ $$ = n;
+ }
+ ;
+
+/*
+ * If we see PARTITION, RANGE, ROWS or GROUPS as the first token after the '('
+ * of a window_specification, we want the assumption to be that there is
+ * no existing_window_name; but those keywords are unreserved and so could
+ * be ColIds. We fix this by making them have the same precedence as IDENT
+ * and giving the empty production here a slightly higher precedence, so
+ * that the shift/reduce conflict is resolved in favor of reducing the rule.
+ * These keywords are thus precluded from being an existing_window_name but
+ * are not reserved for any other purpose.
+ */
+opt_existing_window_name: ColId { $$ = $1; }
+ | /*EMPTY*/ %prec Op { $$ = NULL; }
+ ;
+
+opt_partition_clause: PARTITION BY expr_list { $$ = $3; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+/*
+ * For frame clauses, we return a WindowDef, but only some fields are used:
+ * frameOptions, startOffset, and endOffset.
+ */
+opt_frame_clause:
+ RANGE frame_extent opt_window_exclusion_clause
+ {
+ WindowDef *n = $2;
+ n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_RANGE;
+ n->frameOptions |= $3;
+ $$ = n;
+ }
+ | ROWS frame_extent opt_window_exclusion_clause
+ {
+ WindowDef *n = $2;
+ n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS;
+ n->frameOptions |= $3;
+ $$ = n;
+ }
+ | GROUPS frame_extent opt_window_exclusion_clause
+ {
+ WindowDef *n = $2;
+ n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_GROUPS;
+ n->frameOptions |= $3;
+ $$ = n;
+ }
+ | /*EMPTY*/
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_DEFAULTS;
+ n->startOffset = NULL;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ ;
+
+frame_extent: frame_bound
+ {
+ WindowDef *n = $1;
+ /* reject invalid cases */
+ if (n->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
+ parser_errposition(@1)));
+ if (n->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame starting from following row cannot end with current row"),
+ parser_errposition(@1)));
+ n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
+ $$ = n;
+ }
+ | BETWEEN frame_bound AND frame_bound
+ {
+ WindowDef *n1 = $2;
+ WindowDef *n2 = $4;
+ /* form merged options */
+ int frameOptions = n1->frameOptions;
+ /* shift converts START_ options to END_ options */
+ frameOptions |= n2->frameOptions << 1;
+ frameOptions |= FRAMEOPTION_BETWEEN;
+ /* reject invalid cases */
+ if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
+ parser_errposition(@2)));
+ if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING)
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame end cannot be UNBOUNDED PRECEDING"),
+ parser_errposition(@4)));
+ if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
+ (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING))
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame starting from current row cannot have preceding rows"),
+ parser_errposition(@4)));
+ if ((frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) &&
+ (frameOptions & (FRAMEOPTION_END_OFFSET_PRECEDING |
+ FRAMEOPTION_END_CURRENT_ROW)))
+ ereport(ERROR,
+ (errcode(ERRCODE_WINDOWING_ERROR),
+ errmsg("frame starting from following row cannot have preceding rows"),
+ parser_errposition(@4)));
+ n1->frameOptions = frameOptions;
+ n1->endOffset = n2->startOffset;
+ $$ = n1;
+ }
+ ;
+
+/*
+ * This is used for both frame start and frame end, with output set up on
+ * the assumption it's frame start; the frame_extent productions must reject
+ * invalid cases.
+ */
+frame_bound:
+ UNBOUNDED PRECEDING
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_START_UNBOUNDED_PRECEDING;
+ n->startOffset = NULL;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ | UNBOUNDED FOLLOWING
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_START_UNBOUNDED_FOLLOWING;
+ n->startOffset = NULL;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ | CURRENT_P ROW
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_START_CURRENT_ROW;
+ n->startOffset = NULL;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ | a_expr PRECEDING
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_START_OFFSET_PRECEDING;
+ n->startOffset = $1;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ | a_expr FOLLOWING
+ {
+ WindowDef *n = makeNode(WindowDef);
+ n->frameOptions = FRAMEOPTION_START_OFFSET_FOLLOWING;
+ n->startOffset = $1;
+ n->endOffset = NULL;
+ $$ = n;
+ }
+ ;
+
+opt_window_exclusion_clause:
+ EXCLUDE CURRENT_P ROW { $$ = FRAMEOPTION_EXCLUDE_CURRENT_ROW; }
+ | EXCLUDE GROUP_P { $$ = FRAMEOPTION_EXCLUDE_GROUP; }
+ | EXCLUDE TIES { $$ = FRAMEOPTION_EXCLUDE_TIES; }
+ | EXCLUDE NO OTHERS { $$ = 0; }
+ | /*EMPTY*/ { $$ = 0; }
+ ;
+
+
+/*
+ * Supporting nonterminals for expressions.
+ */
+
+/* Explicit row production.
+ *
+ * SQL99 allows an optional ROW keyword, so we can now do single-element rows
+ * without conflicting with the parenthesized a_expr production. Without the
+ * ROW keyword, there must be more than one a_expr inside the parens.
+ */
+row: ROW '(' expr_list ')' { $$ = $3; }
+ | ROW '(' ')' { $$ = NIL; }
+ | '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); }
+ ;
+
+explicit_row: ROW '(' expr_list ')' { $$ = $3; }
+ | ROW '(' ')' { $$ = NIL; }
+ ;
+
+implicit_row: '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); }
+ ;
+
+sub_type: ANY { $$ = ANY_SUBLINK; }
+ | SOME { $$ = ANY_SUBLINK; }
+ | ALL { $$ = ALL_SUBLINK; }
+ ;
+
+all_Op: Op { $$ = $1; }
+ | MathOp { $$ = $1; }
+ ;
+
+MathOp: '+' { $$ = "+"; }
+ | '-' { $$ = "-"; }
+ | '*' { $$ = "*"; }
+ | '/' { $$ = "/"; }
+ | '%' { $$ = "%"; }
+ | '^' { $$ = "^"; }
+ | '<' { $$ = "<"; }
+ | '>' { $$ = ">"; }
+ | '=' { $$ = "="; }
+ | LESS_EQUALS { $$ = "<="; }
+ | GREATER_EQUALS { $$ = ">="; }
+ | NOT_EQUALS { $$ = "<>"; }
+ ;
+
+qual_Op: Op
+ { $$ = list_make1(makeString($1)); }
+ | OPERATOR '(' any_operator ')'
+ { $$ = $3; }
+ ;
+
+qual_all_Op:
+ all_Op
+ { $$ = list_make1(makeString($1)); }
+ | OPERATOR '(' any_operator ')'
+ { $$ = $3; }
+ ;
+
+subquery_Op:
+ all_Op
+ { $$ = list_make1(makeString($1)); }
+ | OPERATOR '(' any_operator ')'
+ { $$ = $3; }
+ | LIKE
+ { $$ = list_make1(makeString("~~")); }
+ | NOT_LA LIKE
+ { $$ = list_make1(makeString("!~~")); }
+ | ILIKE
+ { $$ = list_make1(makeString("~~*")); }
+ | NOT_LA ILIKE
+ { $$ = list_make1(makeString("!~~*")); }
+/* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
+ * the regular expression is preprocessed by a function (similar_to_escape),
+ * and the ~ operator for posix regular expressions is used.
+ * x SIMILAR TO y -> x ~ similar_to_escape(y)
+ * this transformation is made on the fly by the parser upwards.
+ * however the SubLink structure which handles any/some/all stuff
+ * is not ready for such a thing.
+ */
+ ;
+
+expr_list: a_expr
+ {
+ $$ = list_make1($1);
+ }
+ | expr_list ',' a_expr
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+/* function arguments can have names */
+func_arg_list: func_arg_expr
+ {
+ $$ = list_make1($1);
+ }
+ | func_arg_list ',' func_arg_expr
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+func_arg_expr: a_expr
+ {
+ $$ = $1;
+ }
+ | param_name COLON_EQUALS a_expr
+ {
+ NamedArgExpr *na = makeNode(NamedArgExpr);
+ na->name = $1;
+ na->arg = (Expr *) $3;
+ na->argnumber = -1; /* until determined */
+ na->location = @1;
+ $$ = (Node *) na;
+ }
+ | param_name EQUALS_GREATER a_expr
+ {
+ NamedArgExpr *na = makeNode(NamedArgExpr);
+ na->name = $1;
+ na->arg = (Expr *) $3;
+ na->argnumber = -1; /* until determined */
+ na->location = @1;
+ $$ = (Node *) na;
+ }
+ ;
+
+func_arg_list_opt: func_arg_list { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+type_list: Typename { $$ = list_make1($1); }
+ | type_list ',' Typename { $$ = lappend($1, $3); }
+ ;
+
+array_expr: '[' expr_list ']'
+ {
+ $$ = makeAArrayExpr($2, @1);
+ }
+ | '[' array_expr_list ']'
+ {
+ $$ = makeAArrayExpr($2, @1);
+ }
+ | '[' ']'
+ {
+ $$ = makeAArrayExpr(NIL, @1);
+ }
+ ;
+
+array_expr_list: array_expr { $$ = list_make1($1); }
+ | array_expr_list ',' array_expr { $$ = lappend($1, $3); }
+ ;
+
+
+extract_list:
+ extract_arg FROM a_expr
+ {
+ $$ = list_make2(makeStringConst($1, @1), $3);
+ }
+ ;
+
+/* Allow delimited string Sconst in extract_arg as an SQL extension.
+ * - thomas 2001-04-12
+ */
+extract_arg:
+ IDENT { $$ = $1; }
+ | YEAR_P { $$ = "year"; }
+ | MONTH_P { $$ = "month"; }
+ | DAY_P { $$ = "day"; }
+ | HOUR_P { $$ = "hour"; }
+ | MINUTE_P { $$ = "minute"; }
+ | SECOND_P { $$ = "second"; }
+ | Sconst { $$ = $1; }
+ ;
+
+unicode_normal_form:
+ NFC { $$ = "NFC"; }
+ | NFD { $$ = "NFD"; }
+ | NFKC { $$ = "NFKC"; }
+ | NFKD { $$ = "NFKD"; }
+ ;
+
+/* OVERLAY() arguments */
+overlay_list:
+ a_expr PLACING a_expr FROM a_expr FOR a_expr
+ {
+ /* overlay(A PLACING B FROM C FOR D) is converted to overlay(A, B, C, D) */
+ $$ = list_make4($1, $3, $5, $7);
+ }
+ | a_expr PLACING a_expr FROM a_expr
+ {
+ /* overlay(A PLACING B FROM C) is converted to overlay(A, B, C) */
+ $$ = list_make3($1, $3, $5);
+ }
+ ;
+
+/* position_list uses b_expr not a_expr to avoid conflict with general IN */
+position_list:
+ b_expr IN_P b_expr { $$ = list_make2($3, $1); }
+ ;
+
+/*
+ * SUBSTRING() arguments
+ *
+ * Note that SQL:1999 has both
+ * text FROM int FOR int
+ * and
+ * text FROM pattern FOR escape
+ *
+ * In the parser we map them both to a call to the substring() function and
+ * rely on type resolution to pick the right one.
+ *
+ * In SQL:2003, the second variant was changed to
+ * text SIMILAR pattern ESCAPE escape
+ * We could in theory map that to a different function internally, but
+ * since we still support the SQL:1999 version, we don't. However,
+ * ruleutils.c will reverse-list the call in the newer style.
+ */
+substr_list:
+ a_expr FROM a_expr FOR a_expr
+ {
+ $$ = list_make3($1, $3, $5);
+ }
+ | a_expr FOR a_expr FROM a_expr
+ {
+ /* not legal per SQL, but might as well allow it */
+ $$ = list_make3($1, $5, $3);
+ }
+ | a_expr FROM a_expr
+ {
+ /*
+ * Because we aren't restricting data types here, this
+ * syntax can end up resolving to textregexsubstr().
+ * We've historically allowed that to happen, so continue
+ * to accept it. However, ruleutils.c will reverse-list
+ * such a call in regular function call syntax.
+ */
+ $$ = list_make2($1, $3);
+ }
+ | a_expr FOR a_expr
+ {
+ /* not legal per SQL */
+
+ /*
+ * Since there are no cases where this syntax allows
+ * a textual FOR value, we forcibly cast the argument
+ * to int4. The possible matches in pg_proc are
+ * substring(text,int4) and substring(text,text),
+ * and we don't want the parser to choose the latter,
+ * which it is likely to do if the second argument
+ * is unknown or doesn't have an implicit cast to int4.
+ */
+ $$ = list_make3($1, makeIntConst(1, -1),
+ makeTypeCast($3,
+ SystemTypeName("int4"), -1));
+ }
+ | a_expr SIMILAR a_expr ESCAPE a_expr
+ {
+ $$ = list_make3($1, $3, $5);
+ }
+ ;
+
+trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); }
+ | FROM expr_list { $$ = $2; }
+ | expr_list { $$ = $1; }
+ ;
+
+in_expr: select_with_parens
+ {
+ SubLink *n = makeNode(SubLink);
+ n->subselect = $1;
+ /* other fields will be filled later */
+ $$ = (Node *)n;
+ }
+ | '(' expr_list ')' { $$ = (Node *)$2; }
+ ;
+
+/*
+ * Define SQL-style CASE clause.
+ * - Full specification
+ * CASE WHEN a = b THEN c ... ELSE d END
+ * - Implicit argument
+ * CASE a WHEN b THEN c ... ELSE d END
+ */
+case_expr: CASE case_arg when_clause_list case_default END_P
+ {
+ CaseExpr *c = makeNode(CaseExpr);
+ c->casetype = InvalidOid; /* not analyzed yet */
+ c->arg = (Expr *) $2;
+ c->args = $3;
+ c->defresult = (Expr *) $4;
+ c->location = @1;
+ $$ = (Node *)c;
+ }
+ ;
+
+when_clause_list:
+ /* There must be at least one */
+ when_clause { $$ = list_make1($1); }
+ | when_clause_list when_clause { $$ = lappend($1, $2); }
+ ;
+
+when_clause:
+ WHEN a_expr THEN a_expr
+ {
+ CaseWhen *w = makeNode(CaseWhen);
+ w->expr = (Expr *) $2;
+ w->result = (Expr *) $4;
+ w->location = @1;
+ $$ = (Node *)w;
+ }
+ ;
+
+case_default:
+ ELSE a_expr { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+case_arg: a_expr { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+columnref: ColId
+ {
+ $$ = makeColumnRef($1, NIL, @1, yyscanner);
+ }
+ | ColId indirection
+ {
+ $$ = makeColumnRef($1, $2, @1, yyscanner);
+ }
+ ;
+
+indirection_el:
+ '.' attr_name
+ {
+ $$ = (Node *) makeString($2);
+ }
+ | '.' '*'
+ {
+ $$ = (Node *) makeNode(A_Star);
+ }
+ | '[' a_expr ']'
+ {
+ A_Indices *ai = makeNode(A_Indices);
+ ai->is_slice = false;
+ ai->lidx = NULL;
+ ai->uidx = $2;
+ $$ = (Node *) ai;
+ }
+ | '[' opt_slice_bound ':' opt_slice_bound ']'
+ {
+ A_Indices *ai = makeNode(A_Indices);
+ ai->is_slice = true;
+ ai->lidx = $2;
+ ai->uidx = $4;
+ $$ = (Node *) ai;
+ }
+ ;
+
+opt_slice_bound:
+ a_expr { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+indirection:
+ indirection_el { $$ = list_make1($1); }
+ | indirection indirection_el { $$ = lappend($1, $2); }
+ ;
+
+opt_indirection:
+ /*EMPTY*/ { $$ = NIL; }
+ | opt_indirection indirection_el { $$ = lappend($1, $2); }
+ ;
+
+opt_asymmetric: ASYMMETRIC
+ | /*EMPTY*/
+ ;
+
+
+/*****************************************************************************
+ *
+ * target list for SELECT
+ *
+ *****************************************************************************/
+
+opt_target_list: target_list { $$ = $1; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+target_list:
+ target_el { $$ = list_make1($1); }
+ | target_list ',' target_el { $$ = lappend($1, $3); }
+ ;
+
+target_el: a_expr AS ColLabel
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $3;
+ $$->indirection = NIL;
+ $$->val = (Node *)$1;
+ $$->location = @1;
+ }
+ | a_expr BareColLabel
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $2;
+ $$->indirection = NIL;
+ $$->val = (Node *)$1;
+ $$->location = @1;
+ }
+ | a_expr
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = (Node *)$1;
+ $$->location = @1;
+ }
+ | '*'
+ {
+ ColumnRef *n = makeNode(ColumnRef);
+ n->fields = list_make1(makeNode(A_Star));
+ n->location = @1;
+
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = (Node *)n;
+ $$->location = @1;
+ }
+ ;
+
+
+/*****************************************************************************
+ *
+ * Names and constants
+ *
+ *****************************************************************************/
+
+qualified_name_list:
+ qualified_name { $$ = list_make1($1); }
+ | qualified_name_list ',' qualified_name { $$ = lappend($1, $3); }
+ ;
+
+/*
+ * The production for a qualified relation name has to exactly match the
+ * production for a qualified func_name, because in a FROM clause we cannot
+ * tell which we are parsing until we see what comes after it ('(' for a
+ * func_name, something else for a relation). Therefore we allow 'indirection'
+ * which may contain subscripts, and reject that case in the C code.
+ */
+qualified_name:
+ ColId
+ {
+ $$ = makeRangeVar(NULL, $1, @1);
+ }
+ | ColId indirection
+ {
+ check_qualified_name($2, yyscanner);
+ $$ = makeRangeVar(NULL, NULL, @1);
+ switch (list_length($2))
+ {
+ case 1:
+ $$->catalogname = NULL;
+ $$->schemaname = $1;
+ $$->relname = strVal(linitial($2));
+ break;
+ case 2:
+ $$->catalogname = $1;
+ $$->schemaname = strVal(linitial($2));
+ $$->relname = strVal(lsecond($2));
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("improper qualified name (too many dotted names): %s",
+ NameListToString(lcons(makeString($1), $2))),
+ parser_errposition(@1)));
+ break;
+ }
+ }
+ ;
+
+name_list: name
+ { $$ = list_make1(makeString($1)); }
+ | name_list ',' name
+ { $$ = lappend($1, makeString($3)); }
+ ;
+
+
+name: ColId { $$ = $1; };
+
+attr_name: ColLabel { $$ = $1; };
+
+file_name: Sconst { $$ = $1; };
+
+/*
+ * The production for a qualified func_name has to exactly match the
+ * production for a qualified columnref, because we cannot tell which we
+ * are parsing until we see what comes after it ('(' or Sconst for a func_name,
+ * anything else for a columnref). Therefore we allow 'indirection' which
+ * may contain subscripts, and reject that case in the C code. (If we
+ * ever implement SQL99-like methods, such syntax may actually become legal!)
+ */
+func_name: type_function_name
+ { $$ = list_make1(makeString($1)); }
+ | ColId indirection
+ {
+ $$ = check_func_name(lcons(makeString($1), $2),
+ yyscanner);
+ }
+ ;
+
+
+/*
+ * Constants
+ */
+AexprConst: Iconst
+ {
+ $$ = makeIntConst($1, @1);
+ }
+ | FCONST
+ {
+ $$ = makeFloatConst($1, @1);
+ }
+ | Sconst
+ {
+ $$ = makeStringConst($1, @1);
+ }
+ | BCONST
+ {
+ $$ = makeBitStringConst($1, @1);
+ }
+ | XCONST
+ {
+ /* This is a bit constant per SQL99:
+ * Without Feature F511, "BIT data type",
+ * a <general literal> shall not be a
+ * <bit string literal> or a <hex string literal>.
+ */
+ $$ = makeBitStringConst($1, @1);
+ }
+ | func_name Sconst
+ {
+ /* generic type 'literal' syntax */
+ TypeName *t = makeTypeNameFromNameList($1);
+ t->location = @1;
+ $$ = makeStringConstCast($2, @2, t);
+ }
+ | func_name '(' func_arg_list opt_sort_clause ')' Sconst
+ {
+ /* generic syntax with a type modifier */
+ TypeName *t = makeTypeNameFromNameList($1);
+ ListCell *lc;
+
+ /*
+ * We must use func_arg_list and opt_sort_clause in the
+ * production to avoid reduce/reduce conflicts, but we
+ * don't actually wish to allow NamedArgExpr in this
+ * context, nor ORDER BY.
+ */
+ foreach(lc, $3)
+ {
+ NamedArgExpr *arg = (NamedArgExpr *) lfirst(lc);
+
+ if (IsA(arg, NamedArgExpr))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("type modifier cannot have parameter name"),
+ parser_errposition(arg->location)));
+ }
+ if ($4 != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("type modifier cannot have ORDER BY"),
+ parser_errposition(@4)));
+
+ t->typmods = $3;
+ t->location = @1;
+ $$ = makeStringConstCast($6, @6, t);
+ }
+ | ConstTypename Sconst
+ {
+ $$ = makeStringConstCast($2, @2, $1);
+ }
+ | ConstInterval Sconst opt_interval
+ {
+ TypeName *t = $1;
+ t->typmods = $3;
+ $$ = makeStringConstCast($2, @2, t);
+ }
+ | ConstInterval '(' Iconst ')' Sconst
+ {
+ TypeName *t = $1;
+ t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
+ makeIntConst($3, @3));
+ $$ = makeStringConstCast($5, @5, t);
+ }
+ | TRUE_P
+ {
+ $$ = makeBoolAConst(true, @1);
+ }
+ | FALSE_P
+ {
+ $$ = makeBoolAConst(false, @1);
+ }
+ | NULL_P
+ {
+ $$ = makeNullAConst(@1);
+ }
+ ;
+
+Iconst: ICONST { $$ = $1; };
+Sconst: SCONST { $$ = $1; };
+
+SignedIconst: Iconst { $$ = $1; }
+ | '+' Iconst { $$ = + $2; }
+ | '-' Iconst { $$ = - $2; }
+ ;
+
+/* Role specifications */
+RoleId: RoleSpec
+ {
+ RoleSpec *spc = (RoleSpec *) $1;
+ switch (spc->roletype)
+ {
+ case ROLESPEC_CSTRING:
+ $$ = spc->rolename;
+ break;
+ case ROLESPEC_PUBLIC:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "public"),
+ parser_errposition(@1)));
+ break;
+ case ROLESPEC_SESSION_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name here",
+ "SESSION_USER"),
+ parser_errposition(@1)));
+ break;
+ case ROLESPEC_CURRENT_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name here",
+ "CURRENT_USER"),
+ parser_errposition(@1)));
+ break;
+ case ROLESPEC_CURRENT_ROLE:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name here",
+ "CURRENT_ROLE"),
+ parser_errposition(@1)));
+ break;
+ }
+ }
+ ;
+
+RoleSpec: NonReservedWord
+ {
+ /*
+ * "public" and "none" are not keywords, but they must
+ * be treated specially here.
+ */
+ RoleSpec *n;
+ if (strcmp($1, "public") == 0)
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_PUBLIC, @1);
+ n->roletype = ROLESPEC_PUBLIC;
+ }
+ else if (strcmp($1, "none") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "none"),
+ parser_errposition(@1)));
+ }
+ else
+ {
+ n = makeRoleSpec(ROLESPEC_CSTRING, @1);
+ n->rolename = pstrdup($1);
+ }
+ $$ = n;
+ }
+ | CURRENT_ROLE
+ {
+ $$ = makeRoleSpec(ROLESPEC_CURRENT_ROLE, @1);
+ }
+ | CURRENT_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1);
+ }
+ | SESSION_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_SESSION_USER, @1);
+ }
+ ;
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
+ ;
+
+
+/*****************************************************************************
+ *
+ * PL/pgSQL extensions
+ *
+ * You'd think a PL/pgSQL "expression" should be just an a_expr, but
+ * historically it can include just about anything that can follow SELECT.
+ * Therefore the returned struct is a SelectStmt.
+ *****************************************************************************/
+
+PLpgSQL_Expr: opt_distinct_clause opt_target_list
+ from_clause where_clause
+ group_clause having_clause window_clause
+ opt_sort_clause opt_select_limit opt_for_locking_clause
+ {
+ SelectStmt *n = makeNode(SelectStmt);
+
+ n->distinctClause = $1;
+ n->targetList = $2;
+ n->fromClause = $3;
+ n->whereClause = $4;
+ n->groupClause = ($5)->list;
+ n->groupDistinct = ($5)->distinct;
+ n->havingClause = $6;
+ n->windowClause = $7;
+ n->sortClause = $8;
+ if ($9)
+ {
+ n->limitOffset = $9->limitOffset;
+ n->limitCount = $9->limitCount;
+ if (!n->sortClause &&
+ $9->limitOption == LIMIT_OPTION_WITH_TIES)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("WITH TIES cannot be specified without ORDER BY clause")));
+ n->limitOption = $9->limitOption;
+ }
+ n->lockingClause = $10;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*
+ * PL/pgSQL Assignment statement: name opt_indirection := PLpgSQL_Expr
+ */
+
+PLAssignStmt: plassign_target opt_indirection plassign_equals PLpgSQL_Expr
+ {
+ PLAssignStmt *n = makeNode(PLAssignStmt);
+
+ n->name = $1;
+ n->indirection = check_indirection($2, yyscanner);
+ /* nnames will be filled by calling production */
+ n->val = (SelectStmt *) $4;
+ n->location = @1;
+ $$ = (Node *) n;
+ }
+ ;
+
+plassign_target: ColId { $$ = $1; }
+ | PARAM { $$ = psprintf("$%d", $1); }
+ ;
+
+plassign_equals: COLON_EQUALS
+ | '='
+ ;
+
+
+/*
+ * Name classification hierarchy.
+ *
+ * IDENT is the lexeme returned by the lexer for identifiers that match
+ * no known keyword. In most cases, we can accept certain keywords as
+ * names, not only IDENTs. We prefer to accept as many such keywords
+ * as possible to minimize the impact of "reserved words" on programmers.
+ * So, we divide names into several possible classes. The classification
+ * is chosen in part to make keywords acceptable as names wherever possible.
+ */
+
+/* Column identifier --- names that can be column, table, etc names.
+ */
+ColId: IDENT { $$ = $1; }
+ | unreserved_keyword { $$ = pstrdup($1); }
+ | col_name_keyword { $$ = pstrdup($1); }
+ ;
+
+/* Type/function identifier --- names that can be type or function names.
+ */
+type_function_name: IDENT { $$ = $1; }
+ | unreserved_keyword { $$ = pstrdup($1); }
+ | type_func_name_keyword { $$ = pstrdup($1); }
+ ;
+
+/* Any not-fully-reserved word --- these names can be, eg, role names.
+ */
+NonReservedWord: IDENT { $$ = $1; }
+ | unreserved_keyword { $$ = pstrdup($1); }
+ | col_name_keyword { $$ = pstrdup($1); }
+ | type_func_name_keyword { $$ = pstrdup($1); }
+ ;
+
+/* Column label --- allowed labels in "AS" clauses.
+ * This presently includes *all* Postgres keywords.
+ */
+ColLabel: IDENT { $$ = $1; }
+ | unreserved_keyword { $$ = pstrdup($1); }
+ | col_name_keyword { $$ = pstrdup($1); }
+ | type_func_name_keyword { $$ = pstrdup($1); }
+ | reserved_keyword { $$ = pstrdup($1); }
+ ;
+
+/* Bare column label --- names that can be column labels without writing "AS".
+ * This classification is orthogonal to the other keyword categories.
+ */
+BareColLabel: IDENT { $$ = $1; }
+ | bare_label_keyword { $$ = pstrdup($1); }
+ ;
+
+
+/*
+ * Keyword category lists. Generally, every keyword present in
+ * the Postgres grammar should appear in exactly one of these lists.
+ *
+ * Put a new keyword into the first list that it can go into without causing
+ * shift or reduce conflicts. The earlier lists define "less reserved"
+ * categories of keywords.
+ *
+ * Make sure that each keyword's category in kwlist.h matches where
+ * it is listed here. (Someday we may be able to generate these lists and
+ * kwlist.h's table from one source of truth.)
+ */
+
+/* "Unreserved" keywords --- available for use as any kind of name.
+ */
+unreserved_keyword:
+ ABORT_P
+ | ABSOLUTE_P
+ | ACCESS
+ | ACTION
+ | ADD_P
+ | ADMIN
+ | AFTER
+ | AGGREGATE
+ | ALSO
+ | ALTER
+ | ALWAYS
+ | ASENSITIVE
+ | ASSERTION
+ | ASSIGNMENT
+ | AT
+ | ATOMIC
+ | ATTACH
+ | ATTRIBUTE
+ | BACKWARD
+ | BEFORE
+ | BEGIN_P
+ | BREADTH
+ | BY
+ | CACHE
+ | CALL
+ | CALLED
+ | CASCADE
+ | CASCADED
+ | CATALOG_P
+ | CHAIN
+ | CHARACTERISTICS
+ | CHECKPOINT
+ | CLASS
+ | CLOSE
+ | CLUSTER
+ | COLUMNS
+ | COMMENT
+ | COMMENTS
+ | COMMIT
+ | COMMITTED
+ | COMPRESSION
+ | CONFIGURATION
+ | CONFLICT
+ | CONNECTION
+ | CONSTRAINTS
+ | CONTENT_P
+ | CONTINUE_P
+ | CONVERSION_P
+ | COPY
+ | COST
+ | CSV
+ | CUBE
+ | CURRENT_P
+ | CURSOR
+ | CYCLE
+ | DATA_P
+ | DATABASE
+ | DAY_P
+ | DEALLOCATE
+ | DECLARE
+ | DEFAULTS
+ | DEFERRED
+ | DEFINER
+ | DELETE_P
+ | DELIMITER
+ | DELIMITERS
+ | DEPENDS
+ | DEPTH
+ | DETACH
+ | DICTIONARY
+ | DISABLE_P
+ | DISCARD
+ | DOCUMENT_P
+ | DOMAIN_P
+ | DOUBLE_P
+ | DROP
+ | EACH
+ | ENABLE_P
+ | ENCODING
+ | ENCRYPTED
+ | ENUM_P
+ | ESCAPE
+ | EVENT
+ | EXCLUDE
+ | EXCLUDING
+ | EXCLUSIVE
+ | EXECUTE
+ | EXPLAIN
+ | EXPRESSION
+ | EXTENSION
+ | EXTERNAL
+ | FAMILY
+ | FILTER
+ | FINALIZE
+ | FIRST_P
+ | FOLLOWING
+ | FORCE
+ | FORWARD
+ | FUNCTION
+ | FUNCTIONS
+ | GENERATED
+ | GLOBAL
+ | GRANTED
+ | GROUPS
+ | HANDLER
+ | HEADER_P
+ | HOLD
+ | HOUR_P
+ | IDENTITY_P
+ | IF_P
+ | IMMEDIATE
+ | IMMUTABLE
+ | IMPLICIT_P
+ | IMPORT_P
+ | INCLUDE
+ | INCLUDING
+ | INCREMENT
+ | INDEX
+ | INDEXES
+ | INHERIT
+ | INHERITS
+ | INLINE_P
+ | INPUT_P
+ | INSENSITIVE
+ | INSERT
+ | INSTEAD
+ | INVOKER
+ | ISOLATION
+ | KEY
+ | LABEL
+ | LANGUAGE
+ | LARGE_P
+ | LAST_P
+ | LEAKPROOF
+ | LEVEL
+ | LISTEN
+ | LOAD
+ | LOCAL
+ | LOCATION
+ | LOCK_P
+ | LOCKED
+ | LOGGED
+ | MAPPING
+ | MATCH
+ | MATERIALIZED
+ | MAXVALUE
+ | METHOD
+ | MINUTE_P
+ | MINVALUE
+ | MODE
+ | MONTH_P
+ | MOVE
+ | NAME_P
+ | NAMES
+ | NEW
+ | NEXT
+ | NFC
+ | NFD
+ | NFKC
+ | NFKD
+ | NO
+ | NORMALIZED
+ | NOTHING
+ | NOTIFY
+ | NOWAIT
+ | NULLS_P
+ | OBJECT_P
+ | OF
+ | OFF
+ | OIDS
+ | OLD
+ | OPERATOR
+ | OPTION
+ | OPTIONS
+ | ORDINALITY
+ | OTHERS
+ | OVER
+ | OVERRIDING
+ | OWNED
+ | OWNER
+ | PARALLEL
+ | PARSER
+ | PARTIAL
+ | PARTITION
+ | PASSING
+ | PASSWORD
+ | PLANS
+ | POLICY
+ | PRECEDING
+ | PREPARE
+ | PREPARED
+ | PRESERVE
+ | PRIOR
+ | PRIVILEGES
+ | PROCEDURAL
+ | PROCEDURE
+ | PROCEDURES
+ | PROGRAM
+ | PUBLICATION
+ | QUOTE
+ | RANGE
+ | READ
+ | REASSIGN
+ | RECHECK
+ | RECURSIVE
+ | REF
+ | REFERENCING
+ | REFRESH
+ | REINDEX
+ | RELATIVE_P
+ | RELEASE
+ | RENAME
+ | REPEATABLE
+ | REPLACE
+ | REPLICA
+ | RESET
+ | RESTART
+ | RESTRICT
+ | RETURN
+ | RETURNS
+ | REVOKE
+ | ROLE
+ | ROLLBACK
+ | ROLLUP
+ | ROUTINE
+ | ROUTINES
+ | ROWS
+ | RULE
+ | SAVEPOINT
+ | SCHEMA
+ | SCHEMAS
+ | SCROLL
+ | SEARCH
+ | SECOND_P
+ | SECURITY
+ | SEQUENCE
+ | SEQUENCES
+ | SERIALIZABLE
+ | SERVER
+ | SESSION
+ | SET
+ | SETS
+ | SHARE
+ | SHOW
+ | SIMPLE
+ | SKIP
+ | SNAPSHOT
+ | SQL_P
+ | STABLE
+ | STANDALONE_P
+ | START
+ | STATEMENT
+ | STATISTICS
+ | STDIN
+ | STDOUT
+ | STORAGE
+ | STORED
+ | STRICT_P
+ | STRIP_P
+ | SUBSCRIPTION
+ | SUPPORT
+ | SYSID
+ | SYSTEM_P
+ | TABLES
+ | TABLESPACE
+ | TEMP
+ | TEMPLATE
+ | TEMPORARY
+ | TEXT_P
+ | TIES
+ | TRANSACTION
+ | TRANSFORM
+ | TRIGGER
+ | TRUNCATE
+ | TRUSTED
+ | TYPE_P
+ | TYPES_P
+ | UESCAPE
+ | UNBOUNDED
+ | UNCOMMITTED
+ | UNENCRYPTED
+ | UNKNOWN
+ | UNLISTEN
+ | UNLOGGED
+ | UNTIL
+ | UPDATE
+ | VACUUM
+ | VALID
+ | VALIDATE
+ | VALIDATOR
+ | VALUE_P
+ | VARYING
+ | VERSION_P
+ | VIEW
+ | VIEWS
+ | VOLATILE
+ | WHITESPACE_P
+ | WITHIN
+ | WITHOUT
+ | WORK
+ | WRAPPER
+ | WRITE
+ | XML_P
+ | YEAR_P
+ | YES_P
+ | ZONE
+ ;
+
+/* Column identifier --- keywords that can be column, table, etc names.
+ *
+ * Many of these keywords will in fact be recognized as type or function
+ * names too; but they have special productions for the purpose, and so
+ * can't be treated as "generic" type or function names.
+ *
+ * The type names appearing here are not usable as function names
+ * because they can be followed by '(' in typename productions, which
+ * looks too much like a function call for an LR(1) parser.
+ */
+col_name_keyword:
+ BETWEEN
+ | BIGINT
+ | BIT
+ | BOOLEAN_P
+ | CHAR_P
+ | CHARACTER
+ | COALESCE
+ | DEC
+ | DECIMAL_P
+ | EXISTS
+ | EXTRACT
+ | FLOAT_P
+ | GREATEST
+ | GROUPING
+ | INOUT
+ | INT_P
+ | INTEGER
+ | INTERVAL
+ | LEAST
+ | NATIONAL
+ | NCHAR
+ | NONE
+ | NORMALIZE
+ | NULLIF
+ | NUMERIC
+ | OUT_P
+ | OVERLAY
+ | POSITION
+ | PRECISION
+ | REAL
+ | ROW
+ | SETOF
+ | SMALLINT
+ | SUBSTRING
+ | TIME
+ | TIMESTAMP
+ | TREAT
+ | TRIM
+ | VALUES
+ | VARCHAR
+ | XMLATTRIBUTES
+ | XMLCONCAT
+ | XMLELEMENT
+ | XMLEXISTS
+ | XMLFOREST
+ | XMLNAMESPACES
+ | XMLPARSE
+ | XMLPI
+ | XMLROOT
+ | XMLSERIALIZE
+ | XMLTABLE
+ ;
+
+/* Type/function identifier --- keywords that can be type or function names.
+ *
+ * Most of these are keywords that are used as operators in expressions;
+ * in general such keywords can't be column names because they would be
+ * ambiguous with variables, but they are unambiguous as function identifiers.
+ *
+ * Do not include POSITION, SUBSTRING, etc here since they have explicit
+ * productions in a_expr to support the goofy SQL9x argument syntax.
+ * - thomas 2000-11-28
+ */
+type_func_name_keyword:
+ AUTHORIZATION
+ | BINARY
+ | COLLATION
+ | CONCURRENTLY
+ | CROSS
+ | CURRENT_SCHEMA
+ | FREEZE
+ | FULL
+ | ILIKE
+ | INNER_P
+ | IS
+ | ISNULL
+ | JOIN
+ | LEFT
+ | LIKE
+ | NATURAL
+ | NOTNULL
+ | OUTER_P
+ | OVERLAPS
+ | RIGHT
+ | SIMILAR
+ | TABLESAMPLE
+ | VERBOSE
+ ;
+
+/* Reserved keyword --- these keywords are usable only as a ColLabel.
+ *
+ * Keywords appear here if they could not be distinguished from variable,
+ * type, or function names in some contexts. Don't put things here unless
+ * forced to.
+ */
+reserved_keyword:
+ ALL
+ | ANALYSE
+ | ANALYZE
+ | AND
+ | ANY
+ | ARRAY
+ | AS
+ | ASC
+ | ASYMMETRIC
+ | BOTH
+ | CASE
+ | CAST
+ | CHECK
+ | COLLATE
+ | COLUMN
+ | CONSTRAINT
+ | CREATE
+ | CURRENT_CATALOG
+ | CURRENT_DATE
+ | CURRENT_ROLE
+ | CURRENT_TIME
+ | CURRENT_TIMESTAMP
+ | CURRENT_USER
+ | DEFAULT
+ | DEFERRABLE
+ | DESC
+ | DISTINCT
+ | DO
+ | ELSE
+ | END_P
+ | EXCEPT
+ | FALSE_P
+ | FETCH
+ | FOR
+ | FOREIGN
+ | FROM
+ | GRANT
+ | GROUP_P
+ | HAVING
+ | IN_P
+ | INITIALLY
+ | INTERSECT
+ | INTO
+ | LATERAL_P
+ | LEADING
+ | LIMIT
+ | LOCALTIME
+ | LOCALTIMESTAMP
+ | NOT
+ | NULL_P
+ | OFFSET
+ | ON
+ | ONLY
+ | OR
+ | ORDER
+ | PLACING
+ | PRIMARY
+ | REFERENCES
+ | RETURNING
+ | SELECT
+ | SESSION_USER
+ | SOME
+ | SYMMETRIC
+ | TABLE
+ | THEN
+ | TO
+ | TRAILING
+ | TRUE_P
+ | UNION
+ | UNIQUE
+ | USER
+ | USING
+ | VARIADIC
+ | WHEN
+ | WHERE
+ | WINDOW
+ | WITH
+ ;
+
+/*
+ * While all keywords can be used as column labels when preceded by AS,
+ * not all of them can be used as a "bare" column label without AS.
+ * Those that can be used as a bare label must be listed here,
+ * in addition to appearing in one of the category lists above.
+ *
+ * Always add a new keyword to this list if possible. Mark it BARE_LABEL
+ * in kwlist.h if it is included here, or AS_LABEL if it is not.
+ */
+bare_label_keyword:
+ ABORT_P
+ | ABSOLUTE_P
+ | ACCESS
+ | ACTION
+ | ADD_P
+ | ADMIN
+ | AFTER
+ | AGGREGATE
+ | ALL
+ | ALSO
+ | ALTER
+ | ALWAYS
+ | ANALYSE
+ | ANALYZE
+ | AND
+ | ANY
+ | ASC
+ | ASENSITIVE
+ | ASSERTION
+ | ASSIGNMENT
+ | ASYMMETRIC
+ | AT
+ | ATOMIC
+ | ATTACH
+ | ATTRIBUTE
+ | AUTHORIZATION
+ | BACKWARD
+ | BEFORE
+ | BEGIN_P
+ | BETWEEN
+ | BIGINT
+ | BINARY
+ | BIT
+ | BOOLEAN_P
+ | BOTH
+ | BREADTH
+ | BY
+ | CACHE
+ | CALL
+ | CALLED
+ | CASCADE
+ | CASCADED
+ | CASE
+ | CAST
+ | CATALOG_P
+ | CHAIN
+ | CHARACTERISTICS
+ | CHECK
+ | CHECKPOINT
+ | CLASS
+ | CLOSE
+ | CLUSTER
+ | COALESCE
+ | COLLATE
+ | COLLATION
+ | COLUMN
+ | COLUMNS
+ | COMMENT
+ | COMMENTS
+ | COMMIT
+ | COMMITTED
+ | COMPRESSION
+ | CONCURRENTLY
+ | CONFIGURATION
+ | CONFLICT
+ | CONNECTION
+ | CONSTRAINT
+ | CONSTRAINTS
+ | CONTENT_P
+ | CONTINUE_P
+ | CONVERSION_P
+ | COPY
+ | COST
+ | CROSS
+ | CSV
+ | CUBE
+ | CURRENT_P
+ | CURRENT_CATALOG
+ | CURRENT_DATE
+ | CURRENT_ROLE
+ | CURRENT_SCHEMA
+ | CURRENT_TIME
+ | CURRENT_TIMESTAMP
+ | CURRENT_USER
+ | CURSOR
+ | CYCLE
+ | DATA_P
+ | DATABASE
+ | DEALLOCATE
+ | DEC
+ | DECIMAL_P
+ | DECLARE
+ | DEFAULT
+ | DEFAULTS
+ | DEFERRABLE
+ | DEFERRED
+ | DEFINER
+ | DELETE_P
+ | DELIMITER
+ | DELIMITERS
+ | DEPENDS
+ | DEPTH
+ | 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
+ | EXCLUDE
+ | EXCLUDING
+ | EXCLUSIVE
+ | EXECUTE
+ | EXISTS
+ | EXPLAIN
+ | EXPRESSION
+ | EXTENSION
+ | EXTERNAL
+ | EXTRACT
+ | FALSE_P
+ | FAMILY
+ | FINALIZE
+ | FIRST_P
+ | FLOAT_P
+ | FOLLOWING
+ | FORCE
+ | FOREIGN
+ | FORWARD
+ | FREEZE
+ | FULL
+ | FUNCTION
+ | FUNCTIONS
+ | GENERATED
+ | GLOBAL
+ | GRANTED
+ | GREATEST
+ | GROUPING
+ | GROUPS
+ | HANDLER
+ | HEADER_P
+ | HOLD
+ | 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
+ | INTERVAL
+ | INVOKER
+ | IS
+ | ISOLATION
+ | JOIN
+ | KEY
+ | LABEL
+ | LANGUAGE
+ | LARGE_P
+ | LAST_P
+ | LATERAL_P
+ | LEADING
+ | LEAKPROOF
+ | LEAST
+ | LEFT
+ | LEVEL
+ | LIKE
+ | LISTEN
+ | LOAD
+ | LOCAL
+ | LOCALTIME
+ | LOCALTIMESTAMP
+ | LOCATION
+ | LOCK_P
+ | LOCKED
+ | LOGGED
+ | MAPPING
+ | MATCH
+ | MATERIALIZED
+ | MAXVALUE
+ | METHOD
+ | MINVALUE
+ | MODE
+ | MOVE
+ | NAME_P
+ | NAMES
+ | NATIONAL
+ | NATURAL
+ | NCHAR
+ | NEW
+ | NEXT
+ | NFC
+ | NFD
+ | NFKC
+ | NFKD
+ | NO
+ | NONE
+ | NORMALIZE
+ | NORMALIZED
+ | NOT
+ | NOTHING
+ | NOTIFY
+ | NOWAIT
+ | NULL_P
+ | NULLIF
+ | NULLS_P
+ | NUMERIC
+ | OBJECT_P
+ | OF
+ | OFF
+ | OIDS
+ | OLD
+ | ONLY
+ | OPERATOR
+ | OPTION
+ | OPTIONS
+ | OR
+ | ORDINALITY
+ | OTHERS
+ | OUT_P
+ | OUTER_P
+ | OVERLAY
+ | OVERRIDING
+ | OWNED
+ | OWNER
+ | PARALLEL
+ | PARSER
+ | PARTIAL
+ | PARTITION
+ | PASSING
+ | PASSWORD
+ | PLACING
+ | PLANS
+ | POLICY
+ | POSITION
+ | PRECEDING
+ | PREPARE
+ | PREPARED
+ | PRESERVE
+ | 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
+ | RETURN
+ | RETURNS
+ | REVOKE
+ | RIGHT
+ | ROLE
+ | ROLLBACK
+ | ROLLUP
+ | ROUTINE
+ | ROUTINES
+ | ROW
+ | ROWS
+ | RULE
+ | SAVEPOINT
+ | SCHEMA
+ | SCHEMAS
+ | SCROLL
+ | SEARCH
+ | SECURITY
+ | SELECT
+ | SEQUENCE
+ | SEQUENCES
+ | SERIALIZABLE
+ | SERVER
+ | SESSION
+ | SESSION_USER
+ | SET
+ | SETOF
+ | SETS
+ | 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
+ | TRAILING
+ | TRANSACTION
+ | TRANSFORM
+ | TREAT
+ | TRIGGER
+ | TRIM
+ | TRUE_P
+ | TRUNCATE
+ | TRUSTED
+ | TYPE_P
+ | TYPES_P
+ | UESCAPE
+ | UNBOUNDED
+ | UNCOMMITTED
+ | UNENCRYPTED
+ | UNIQUE
+ | UNKNOWN
+ | UNLISTEN
+ | UNLOGGED
+ | UNTIL
+ | UPDATE
+ | USER
+ | USING
+ | VACUUM
+ | VALID
+ | VALIDATE
+ | VALIDATOR
+ | VALUE_P
+ | VALUES
+ | VARCHAR
+ | VARIADIC
+ | VERBOSE
+ | VERSION_P
+ | VIEW
+ | VIEWS
+ | VOLATILE
+ | WHEN
+ | WHITESPACE_P
+ | WORK
+ | WRAPPER
+ | WRITE
+ | XML_P
+ | XMLATTRIBUTES
+ | XMLCONCAT
+ | XMLELEMENT
+ | XMLEXISTS
+ | XMLFOREST
+ | XMLNAMESPACES
+ | XMLPARSE
+ | XMLPI
+ | XMLROOT
+ | XMLSERIALIZE
+ | XMLTABLE
+ | YES_P
+ | ZONE
+ ;
+
+%%
+
+/*
+ * The signature of this function is required by bison. However, we
+ * ignore the passed yylloc and instead use the last token position
+ * available from the scanner.
+ */
+static void
+base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg)
+{
+ parser_yyerror(msg);
+}
+
+static RawStmt *
+makeRawStmt(Node *stmt, int stmt_location)
+{
+ RawStmt *rs = makeNode(RawStmt);
+
+ rs->stmt = stmt;
+ rs->stmt_location = stmt_location;
+ rs->stmt_len = 0; /* might get changed later */
+ return rs;
+}
+
+/* Adjust a RawStmt to reflect that it doesn't run to the end of the string */
+static void
+updateRawStmtEnd(RawStmt *rs, int end_location)
+{
+ /*
+ * If we already set the length, don't change it. This is for situations
+ * like "select foo ;; select bar" where the same statement will be last
+ * in the string for more than one semicolon.
+ */
+ if (rs->stmt_len > 0)
+ return;
+
+ /* OK, update length of RawStmt */
+ rs->stmt_len = end_location - rs->stmt_location;
+}
+
+static Node *
+makeColumnRef(char *colname, List *indirection,
+ int location, core_yyscan_t yyscanner)
+{
+ /*
+ * Generate a ColumnRef node, with an A_Indirection node added if there
+ * is any subscripting in the specified indirection list. However,
+ * any field selection at the start of the indirection list must be
+ * transposed into the "fields" part of the ColumnRef node.
+ */
+ ColumnRef *c = makeNode(ColumnRef);
+ int nfields = 0;
+ ListCell *l;
+
+ c->location = location;
+ foreach(l, indirection)
+ {
+ if (IsA(lfirst(l), A_Indices))
+ {
+ A_Indirection *i = makeNode(A_Indirection);
+
+ if (nfields == 0)
+ {
+ /* easy case - all indirection goes to A_Indirection */
+ c->fields = list_make1(makeString(colname));
+ i->indirection = check_indirection(indirection, yyscanner);
+ }
+ else
+ {
+ /* got to split the list in two */
+ i->indirection = check_indirection(list_copy_tail(indirection,
+ nfields),
+ yyscanner);
+ indirection = list_truncate(indirection, nfields);
+ c->fields = lcons(makeString(colname), indirection);
+ }
+ i->arg = (Node *) c;
+ return (Node *) i;
+ }
+ else if (IsA(lfirst(l), A_Star))
+ {
+ /* We only allow '*' at the end of a ColumnRef */
+ if (lnext(indirection, l) != NULL)
+ parser_yyerror("improper use of \"*\"");
+ }
+ nfields++;
+ }
+ /* No subscripting, so all indirection gets added to field list */
+ c->fields = lcons(makeString(colname), indirection);
+ return (Node *) c;
+}
+
+static Node *
+makeTypeCast(Node *arg, TypeName *typename, int location)
+{
+ TypeCast *n = makeNode(TypeCast);
+ n->arg = arg;
+ n->typeName = typename;
+ n->location = location;
+ return (Node *) n;
+}
+
+static Node *
+makeStringConst(char *str, int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_String;
+ n->val.val.str = str;
+ n->location = location;
+
+ return (Node *)n;
+}
+
+static Node *
+makeStringConstCast(char *str, int location, TypeName *typename)
+{
+ Node *s = makeStringConst(str, location);
+
+ return makeTypeCast(s, typename, -1);
+}
+
+static Node *
+makeIntConst(int val, int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_Integer;
+ n->val.val.ival = val;
+ n->location = location;
+
+ return (Node *)n;
+}
+
+static Node *
+makeFloatConst(char *str, int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_Float;
+ n->val.val.str = str;
+ n->location = location;
+
+ return (Node *)n;
+}
+
+static Node *
+makeBitStringConst(char *str, int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_BitString;
+ n->val.val.str = str;
+ n->location = location;
+
+ return (Node *)n;
+}
+
+static Node *
+makeNullAConst(int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_Null;
+ n->location = location;
+
+ return (Node *)n;
+}
+
+static Node *
+makeAConst(Value *v, int location)
+{
+ Node *n;
+
+ switch (v->type)
+ {
+ case T_Float:
+ n = makeFloatConst(v->val.str, location);
+ break;
+
+ case T_Integer:
+ n = makeIntConst(v->val.ival, location);
+ break;
+
+ case T_String:
+ default:
+ n = makeStringConst(v->val.str, location);
+ break;
+ }
+
+ return n;
+}
+
+/* makeBoolAConst()
+ * Create an A_Const string node and put it inside a boolean cast.
+ */
+static Node *
+makeBoolAConst(bool state, int location)
+{
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_String;
+ n->val.val.str = (state ? "t" : "f");
+ n->location = location;
+
+ return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
+}
+
+/* makeRoleSpec
+ * Create a RoleSpec with the given type
+ */
+static RoleSpec *
+makeRoleSpec(RoleSpecType type, int location)
+{
+ RoleSpec *spec = makeNode(RoleSpec);
+
+ spec->roletype = type;
+ spec->location = location;
+
+ return spec;
+}
+
+/* check_qualified_name --- check the result of qualified_name production
+ *
+ * It's easiest to let the grammar production for qualified_name allow
+ * subscripts and '*', which we then must reject here.
+ */
+static void
+check_qualified_name(List *names, core_yyscan_t yyscanner)
+{
+ ListCell *i;
+
+ foreach(i, names)
+ {
+ if (!IsA(lfirst(i), String))
+ parser_yyerror("syntax error");
+ }
+}
+
+/* check_func_name --- check the result of func_name production
+ *
+ * It's easiest to let the grammar production for func_name allow subscripts
+ * and '*', which we then must reject here.
+ */
+static List *
+check_func_name(List *names, core_yyscan_t yyscanner)
+{
+ ListCell *i;
+
+ foreach(i, names)
+ {
+ if (!IsA(lfirst(i), String))
+ parser_yyerror("syntax error");
+ }
+ return names;
+}
+
+/* check_indirection --- check the result of indirection production
+ *
+ * We only allow '*' at the end of the list, but it's hard to enforce that
+ * in the grammar, so do it here.
+ */
+static List *
+check_indirection(List *indirection, core_yyscan_t yyscanner)
+{
+ ListCell *l;
+
+ foreach(l, indirection)
+ {
+ if (IsA(lfirst(l), A_Star))
+ {
+ if (lnext(indirection, l) != NULL)
+ parser_yyerror("improper use of \"*\"");
+ }
+ }
+ return indirection;
+}
+
+/* extractArgTypes()
+ * Given a list of FunctionParameter nodes, extract a list of just the
+ * argument types (TypeNames) for input parameters only. This is what
+ * is needed to look up an existing function, which is what is wanted by
+ * the productions that use this call.
+ */
+static List *
+extractArgTypes(List *parameters)
+{
+ List *result = NIL;
+ ListCell *i;
+
+ foreach(i, parameters)
+ {
+ FunctionParameter *p = (FunctionParameter *) lfirst(i);
+
+ if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE)
+ result = lappend(result, p->argType);
+ }
+ return result;
+}
+
+/* extractAggrArgTypes()
+ * As above, but work from the output of the aggr_args production.
+ */
+static List *
+extractAggrArgTypes(List *aggrargs)
+{
+ Assert(list_length(aggrargs) == 2);
+ return extractArgTypes((List *) linitial(aggrargs));
+}
+
+/* makeOrderedSetArgs()
+ * Build the result of the aggr_args production (which see the comments for).
+ * This handles only the case where both given lists are nonempty, so that
+ * we have to deal with multiple VARIADIC arguments.
+ */
+static List *
+makeOrderedSetArgs(List *directargs, List *orderedargs,
+ core_yyscan_t yyscanner)
+{
+ FunctionParameter *lastd = (FunctionParameter *) llast(directargs);
+ Value *ndirectargs;
+
+ /* No restriction unless last direct arg is VARIADIC */
+ if (lastd->mode == FUNC_PARAM_VARIADIC)
+ {
+ FunctionParameter *firsto = (FunctionParameter *) linitial(orderedargs);
+
+ /*
+ * We ignore the names, though the aggr_arg production allows them;
+ * it doesn't allow default values, so those need not be checked.
+ */
+ if (list_length(orderedargs) != 1 ||
+ firsto->mode != FUNC_PARAM_VARIADIC ||
+ !equal(lastd->argType, firsto->argType))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("an ordered-set aggregate with a VARIADIC direct argument must have one VARIADIC aggregated argument of the same data type"),
+ parser_errposition(exprLocation((Node *) firsto))));
+
+ /* OK, drop the duplicate VARIADIC argument from the internal form */
+ orderedargs = NIL;
+ }
+
+ /* don't merge into the next line, as list_concat changes directargs */
+ ndirectargs = makeInteger(list_length(directargs));
+
+ return list_make2(list_concat(directargs, orderedargs),
+ ndirectargs);
+}
+
+/* insertSelectOptions()
+ * Insert ORDER BY, etc into an already-constructed SelectStmt.
+ *
+ * This routine is just to avoid duplicating code in SelectStmt productions.
+ */
+static void
+insertSelectOptions(SelectStmt *stmt,
+ List *sortClause, List *lockingClause,
+ SelectLimit *limitClause,
+ WithClause *withClause,
+ core_yyscan_t yyscanner)
+{
+ Assert(IsA(stmt, SelectStmt));
+
+ /*
+ * Tests here are to reject constructs like
+ * (SELECT foo ORDER BY bar) ORDER BY baz
+ */
+ if (sortClause)
+ {
+ if (stmt->sortClause)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple ORDER BY clauses not allowed"),
+ parser_errposition(exprLocation((Node *) sortClause))));
+ stmt->sortClause = sortClause;
+ }
+ /* We can handle multiple locking clauses, though */
+ stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
+ if (limitClause && limitClause->limitOffset)
+ {
+ if (stmt->limitOffset)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple OFFSET clauses not allowed"),
+ parser_errposition(exprLocation(limitClause->limitOffset))));
+ stmt->limitOffset = limitClause->limitOffset;
+ }
+ if (limitClause && limitClause->limitCount)
+ {
+ if (stmt->limitCount)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple LIMIT clauses not allowed"),
+ parser_errposition(exprLocation(limitClause->limitCount))));
+ stmt->limitCount = limitClause->limitCount;
+ }
+ if (limitClause && limitClause->limitOption != LIMIT_OPTION_DEFAULT)
+ {
+ if (stmt->limitOption)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple limit options not allowed")));
+ if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("WITH TIES cannot be specified without ORDER BY clause")));
+ if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause)
+ {
+ ListCell *lc;
+
+ foreach(lc, stmt->lockingClause)
+ {
+ LockingClause *lock = lfirst_node(LockingClause, lc);
+
+ if (lock->waitPolicy == LockWaitSkip)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s and %s options cannot be used together",
+ "SKIP LOCKED", "WITH TIES")));
+ }
+ }
+ stmt->limitOption = limitClause->limitOption;
+ }
+ if (withClause)
+ {
+ if (stmt->withClause)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple WITH clauses not allowed"),
+ parser_errposition(exprLocation((Node *) withClause))));
+ stmt->withClause = withClause;
+ }
+}
+
+static Node *
+makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg)
+{
+ SelectStmt *n = makeNode(SelectStmt);
+
+ n->op = op;
+ n->all = all;
+ n->larg = (SelectStmt *) larg;
+ n->rarg = (SelectStmt *) rarg;
+ return (Node *) n;
+}
+
+/* SystemFuncName()
+ * Build a properly-qualified reference to a built-in function.
+ */
+List *
+SystemFuncName(char *name)
+{
+ return list_make2(makeString("pg_catalog"), makeString(name));
+}
+
+/* SystemTypeName()
+ * Build a properly-qualified reference to a built-in type.
+ *
+ * typmod is defaulted, but may be changed afterwards by caller.
+ * Likewise for the location.
+ */
+TypeName *
+SystemTypeName(char *name)
+{
+ return makeTypeNameFromNameList(list_make2(makeString("pg_catalog"),
+ makeString(name)));
+}
+
+/* doNegate()
+ * Handle negation of a numeric constant.
+ *
+ * Formerly, we did this here because the optimizer couldn't cope with
+ * indexquals that looked like "var = -4" --- it wants "var = const"
+ * and a unary minus operator applied to a constant didn't qualify.
+ * As of Postgres 7.0, that problem doesn't exist anymore because there
+ * is a constant-subexpression simplifier in the optimizer. However,
+ * there's still a good reason for doing this here, which is that we can
+ * postpone committing to a particular internal representation for simple
+ * negative constants. It's better to leave "-123.456" in string form
+ * until we know what the desired type is.
+ */
+static Node *
+doNegate(Node *n, int location)
+{
+ if (IsA(n, A_Const))
+ {
+ A_Const *con = (A_Const *)n;
+
+ /* report the constant's location as that of the '-' sign */
+ con->location = location;
+
+ if (con->val.type == T_Integer)
+ {
+ con->val.val.ival = -con->val.val.ival;
+ return n;
+ }
+ if (con->val.type == T_Float)
+ {
+ doNegateFloat(&con->val);
+ return n;
+ }
+ }
+
+ return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location);
+}
+
+static void
+doNegateFloat(Value *v)
+{
+ char *oldval = v->val.str;
+
+ Assert(IsA(v, Float));
+ if (*oldval == '+')
+ oldval++;
+ if (*oldval == '-')
+ v->val.str = oldval+1; /* just strip the '-' */
+ else
+ v->val.str = psprintf("-%s", oldval);
+}
+
+static Node *
+makeAndExpr(Node *lexpr, Node *rexpr, int location)
+{
+ /* Flatten "a AND b AND c ..." to a single BoolExpr on sight */
+ if (IsA(lexpr, BoolExpr))
+ {
+ BoolExpr *blexpr = (BoolExpr *) lexpr;
+
+ if (blexpr->boolop == AND_EXPR)
+ {
+ blexpr->args = lappend(blexpr->args, rexpr);
+ return (Node *) blexpr;
+ }
+ }
+ return (Node *) makeBoolExpr(AND_EXPR, list_make2(lexpr, rexpr), location);
+}
+
+static Node *
+makeOrExpr(Node *lexpr, Node *rexpr, int location)
+{
+ /* Flatten "a OR b OR c ..." to a single BoolExpr on sight */
+ if (IsA(lexpr, BoolExpr))
+ {
+ BoolExpr *blexpr = (BoolExpr *) lexpr;
+
+ if (blexpr->boolop == OR_EXPR)
+ {
+ blexpr->args = lappend(blexpr->args, rexpr);
+ return (Node *) blexpr;
+ }
+ }
+ return (Node *) makeBoolExpr(OR_EXPR, list_make2(lexpr, rexpr), location);
+}
+
+static Node *
+makeNotExpr(Node *expr, int location)
+{
+ return (Node *) makeBoolExpr(NOT_EXPR, list_make1(expr), location);
+}
+
+static Node *
+makeAArrayExpr(List *elements, int location)
+{
+ A_ArrayExpr *n = makeNode(A_ArrayExpr);
+
+ n->elements = elements;
+ n->location = location;
+ return (Node *) n;
+}
+
+static Node *
+makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
+{
+ SQLValueFunction *svf = makeNode(SQLValueFunction);
+
+ svf->op = op;
+ /* svf->type will be filled during parse analysis */
+ svf->typmod = typmod;
+ svf->location = location;
+ return (Node *) svf;
+}
+
+static Node *
+makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
+ int location)
+{
+ XmlExpr *x = makeNode(XmlExpr);
+
+ x->op = op;
+ x->name = name;
+ /*
+ * named_args is a list of ResTarget; it'll be split apart into separate
+ * expression and name lists in transformXmlExpr().
+ */
+ x->named_args = named_args;
+ x->arg_names = NIL;
+ x->args = args;
+ /* xmloption, if relevant, must be filled in by caller */
+ /* type and typmod will be filled in during parse analysis */
+ x->type = InvalidOid; /* marks the node as not analyzed */
+ x->location = location;
+ return (Node *) x;
+}
+
+/*
+ * Merge the input and output parameters of a table function.
+ */
+static List *
+mergeTableFuncParameters(List *func_args, List *columns)
+{
+ ListCell *lc;
+
+ /* Explicit OUT and INOUT parameters shouldn't be used in this syntax */
+ foreach(lc, func_args)
+ {
+ FunctionParameter *p = (FunctionParameter *) lfirst(lc);
+
+ if (p->mode != FUNC_PARAM_DEFAULT &&
+ p->mode != FUNC_PARAM_IN &&
+ p->mode != FUNC_PARAM_VARIADIC)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("OUT and INOUT arguments aren't allowed in TABLE functions")));
+ }
+
+ return list_concat(func_args, columns);
+}
+
+/*
+ * Determine return type of a TABLE function. A single result column
+ * returns setof that column's type; otherwise return setof record.
+ */
+static TypeName *
+TableFuncTypeName(List *columns)
+{
+ TypeName *result;
+
+ if (list_length(columns) == 1)
+ {
+ FunctionParameter *p = (FunctionParameter *) linitial(columns);
+
+ result = copyObject(p->argType);
+ }
+ else
+ result = SystemTypeName("record");
+
+ result->setof = true;
+
+ return result;
+}
+
+/*
+ * Convert a list of (dotted) names to a RangeVar (like
+ * makeRangeVarFromNameList, but with position support). The
+ * "AnyName" refers to the any_name production in the grammar.
+ */
+static RangeVar *
+makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner)
+{
+ RangeVar *r = makeNode(RangeVar);
+
+ switch (list_length(names))
+ {
+ case 1:
+ r->catalogname = NULL;
+ r->schemaname = NULL;
+ r->relname = strVal(linitial(names));
+ break;
+ case 2:
+ r->catalogname = NULL;
+ r->schemaname = strVal(linitial(names));
+ r->relname = strVal(lsecond(names));
+ break;
+ case 3:
+ r->catalogname = strVal(linitial(names));
+ r->schemaname = strVal(lsecond(names));
+ r->relname = strVal(lthird(names));
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("improper qualified name (too many dotted names): %s",
+ NameListToString(names)),
+ parser_errposition(position)));
+ break;
+ }
+
+ r->relpersistence = RELPERSISTENCE_PERMANENT;
+ r->location = position;
+
+ return r;
+}
+
+/* Separate Constraint nodes from COLLATE clauses in a ColQualList */
+static void
+SplitColQualList(List *qualList,
+ List **constraintList, CollateClause **collClause,
+ core_yyscan_t yyscanner)
+{
+ ListCell *cell;
+
+ *collClause = NULL;
+ foreach(cell, qualList)
+ {
+ Node *n = (Node *) lfirst(cell);
+
+ if (IsA(n, Constraint))
+ {
+ /* keep it in list */
+ continue;
+ }
+ if (IsA(n, CollateClause))
+ {
+ CollateClause *c = (CollateClause *) n;
+
+ if (*collClause)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("multiple COLLATE clauses not allowed"),
+ parser_errposition(c->location)));
+ *collClause = c;
+ }
+ else
+ elog(ERROR, "unexpected node type %d", (int) n->type);
+ /* remove non-Constraint nodes from qualList */
+ qualList = foreach_delete_current(qualList, cell);
+ }
+ *constraintList = qualList;
+}
+
+/*
+ * Process result of ConstraintAttributeSpec, and set appropriate bool flags
+ * in the output command node. Pass NULL for any flags the particular
+ * command doesn't support.
+ */
+static void
+processCASbits(int cas_bits, int location, const char *constrType,
+ bool *deferrable, bool *initdeferred, bool *not_valid,
+ bool *no_inherit, core_yyscan_t yyscanner)
+{
+ /* defaults */
+ if (deferrable)
+ *deferrable = false;
+ if (initdeferred)
+ *initdeferred = false;
+ if (not_valid)
+ *not_valid = false;
+
+ if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED))
+ {
+ if (deferrable)
+ *deferrable = true;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is CHECK, UNIQUE, or similar */
+ errmsg("%s constraints cannot be marked DEFERRABLE",
+ constrType),
+ parser_errposition(location)));
+ }
+
+ if (cas_bits & CAS_INITIALLY_DEFERRED)
+ {
+ if (initdeferred)
+ *initdeferred = true;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is CHECK, UNIQUE, or similar */
+ errmsg("%s constraints cannot be marked DEFERRABLE",
+ constrType),
+ parser_errposition(location)));
+ }
+
+ if (cas_bits & CAS_NOT_VALID)
+ {
+ if (not_valid)
+ *not_valid = true;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is CHECK, UNIQUE, or similar */
+ errmsg("%s constraints cannot be marked NOT VALID",
+ constrType),
+ parser_errposition(location)));
+ }
+
+ if (cas_bits & CAS_NO_INHERIT)
+ {
+ if (no_inherit)
+ *no_inherit = true;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /* translator: %s is CHECK, UNIQUE, or similar */
+ errmsg("%s constraints cannot be marked NO INHERIT",
+ constrType),
+ parser_errposition(location)));
+ }
+}
+
+/*----------
+ * Recursive view transformation
+ *
+ * Convert
+ *
+ * CREATE RECURSIVE VIEW relname (aliases) AS query
+ *
+ * to
+ *
+ * CREATE VIEW relname (aliases) AS
+ * WITH RECURSIVE relname (aliases) AS (query)
+ * SELECT aliases FROM relname
+ *
+ * Actually, just the WITH ... part, which is then inserted into the original
+ * view definition as the query.
+ * ----------
+ */
+static Node *
+makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
+{
+ SelectStmt *s = makeNode(SelectStmt);
+ WithClause *w = makeNode(WithClause);
+ CommonTableExpr *cte = makeNode(CommonTableExpr);
+ List *tl = NIL;
+ ListCell *lc;
+
+ /* create common table expression */
+ cte->ctename = relname;
+ cte->aliascolnames = aliases;
+ cte->ctematerialized = CTEMaterializeDefault;
+ cte->ctequery = query;
+ cte->location = -1;
+
+ /* create WITH clause and attach CTE */
+ w->recursive = true;
+ w->ctes = list_make1(cte);
+ w->location = -1;
+
+ /* create target list for the new SELECT from the alias list of the
+ * recursive view specification */
+ foreach (lc, aliases)
+ {
+ ResTarget *rt = makeNode(ResTarget);
+
+ rt->name = NULL;
+ rt->indirection = NIL;
+ rt->val = makeColumnRef(strVal(lfirst(lc)), NIL, -1, 0);
+ rt->location = -1;
+
+ tl = lappend(tl, rt);
+ }
+
+ /* create new SELECT combining WITH clause, target list, and fake FROM
+ * clause */
+ s->withClause = w;
+ s->targetList = tl;
+ s->fromClause = list_make1(makeRangeVar(NULL, relname, -1));
+
+ return (Node *) s;
+}
+
+/* parser_init()
+ * Initialize to parse one query string
+ */
+void
+parser_init(base_yy_extra_type *yyext)
+{
+ yyext->parsetree = NIL; /* in case grammar forgets to set it */
+}