17266 lines
449 KiB
Plaintext
17266 lines
449 KiB
Plaintext
%{
|
|
|
|
/*#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_P 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;
|
|
(void) yynerrs; /* suppress compiler warning */
|
|
}
|
|
| MODE_TYPE_NAME Typename
|
|
{
|
|
pg_yyget_extra(yyscanner)->parsetree = list_make1($2);
|
|
}
|
|
| MODE_PLPGSQL_EXPR PLpgSQL_Expr
|
|
{
|
|
pg_yyget_extra(yyscanner)->parsetree =
|
|
list_make1(makeRawStmt($2, 0));
|
|
}
|
|
| MODE_PLPGSQL_ASSIGN1 PLAssignStmt
|
|
{
|
|
PLAssignStmt *n = (PLAssignStmt *) $2;
|
|
n->nnames = 1;
|
|
pg_yyget_extra(yyscanner)->parsetree =
|
|
list_make1(makeRawStmt((Node *) n, 0));
|
|
}
|
|
| MODE_PLPGSQL_ASSIGN2 PLAssignStmt
|
|
{
|
|
PLAssignStmt *n = (PLAssignStmt *) $2;
|
|
n->nnames = 2;
|
|
pg_yyget_extra(yyscanner)->parsetree =
|
|
list_make1(makeRawStmt((Node *) n, 0));
|
|
}
|
|
| MODE_PLPGSQL_ASSIGN3 PLAssignStmt
|
|
{
|
|
PLAssignStmt *n = (PLAssignStmt *) $2;
|
|
n->nnames = 3;
|
|
pg_yyget_extra(yyscanner)->parsetree =
|
|
list_make1(makeRawStmt((Node *) n, 0));
|
|
}
|
|
;
|
|
|
|
/*
|
|
* At top level, we wrap each stmt with a RawStmt node carrying start location
|
|
* and length of the stmt's text. Notice that the start loc/len are driven
|
|
* entirely from semicolon locations (@2). It would seem natural to use
|
|
* @1 or @3 to get the true start location of a stmt, but that doesn't work
|
|
* for statements that can start with empty nonterminals (opt_with_clause is
|
|
* the main offender here); as noted in the comments for YYLLOC_DEFAULT,
|
|
* we'd get -1 for the location in such cases.
|
|
* We also take care to discard empty statements entirely.
|
|
*/
|
|
stmtmulti: stmtmulti ';' toplevel_stmt
|
|
{
|
|
if ($1 != NIL)
|
|
{
|
|
/* update length of previous stmt */
|
|
updateRawStmtEnd(llast_node(RawStmt, $1), @2);
|
|
}
|
|
if ($3 != NULL)
|
|
$$ = lappend($1, makeRawStmt($3, @2 + 1));
|
|
else
|
|
$$ = $1;
|
|
}
|
|
| toplevel_stmt
|
|
{
|
|
if ($1 != NULL)
|
|
$$ = list_make1(makeRawStmt($1, 0));
|
|
else
|
|
$$ = NIL;
|
|
}
|
|
;
|
|
|
|
/*
|
|
* toplevel_stmt includes BEGIN and END. stmt does not include them, because
|
|
* those words have different meanings in function 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_P
|
|
| BY VALUE_P
|
|
;
|
|
|
|
|
|
/*
|
|
* Aggregate decoration clauses
|
|
*/
|
|
within_group_clause:
|
|
WITHIN GROUP_P '(' sort_clause ')' { $$ = $4; }
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
;
|
|
|
|
filter_clause:
|
|
FILTER '(' WHERE a_expr ')' { $$ = $4; }
|
|
| /*EMPTY*/ { $$ = NULL; }
|
|
;
|
|
|
|
|
|
/*
|
|
* Window Definitions
|
|
*/
|
|
window_clause:
|
|
WINDOW window_definition_list { $$ = $2; }
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
;
|
|
|
|
window_definition_list:
|
|
window_definition { $$ = list_make1($1); }
|
|
| window_definition_list ',' window_definition
|
|
{ $$ = lappend($1, $3); }
|
|
;
|
|
|
|
window_definition:
|
|
ColId AS window_specification
|
|
{
|
|
WindowDef *n = $3;
|
|
n->name = $1;
|
|
$$ = n;
|
|
}
|
|
;
|
|
|
|
over_clause: OVER window_specification
|
|
{ $$ = $2; }
|
|
| OVER ColId
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->name = $2;
|
|
n->refname = NULL;
|
|
n->partitionClause = NIL;
|
|
n->orderClause = NIL;
|
|
n->frameOptions = FRAMEOPTION_DEFAULTS;
|
|
n->startOffset = NULL;
|
|
n->endOffset = NULL;
|
|
n->location = @2;
|
|
$$ = n;
|
|
}
|
|
| /*EMPTY*/
|
|
{ $$ = NULL; }
|
|
;
|
|
|
|
window_specification: '(' opt_existing_window_name opt_partition_clause
|
|
opt_sort_clause opt_frame_clause ')'
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->name = NULL;
|
|
n->refname = $2;
|
|
n->partitionClause = $3;
|
|
n->orderClause = $4;
|
|
/* copy relevant fields of opt_frame_clause */
|
|
n->frameOptions = $5->frameOptions;
|
|
n->startOffset = $5->startOffset;
|
|
n->endOffset = $5->endOffset;
|
|
n->location = @1;
|
|
$$ = n;
|
|
}
|
|
;
|
|
|
|
/*
|
|
* If we see PARTITION, RANGE, ROWS or GROUPS as the first token after the '('
|
|
* of a window_specification, we want the assumption to be that there is
|
|
* no existing_window_name; but those keywords are unreserved and so could
|
|
* be ColIds. We fix this by making them have the same precedence as IDENT
|
|
* and giving the empty production here a slightly higher precedence, so
|
|
* that the shift/reduce conflict is resolved in favor of reducing the rule.
|
|
* These keywords are thus precluded from being an existing_window_name but
|
|
* are not reserved for any other purpose.
|
|
*/
|
|
opt_existing_window_name: ColId { $$ = $1; }
|
|
| /*EMPTY*/ %prec Op { $$ = NULL; }
|
|
;
|
|
|
|
opt_partition_clause: PARTITION BY expr_list { $$ = $3; }
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
;
|
|
|
|
/*
|
|
* For frame clauses, we return a WindowDef, but only some fields are used:
|
|
* frameOptions, startOffset, and endOffset.
|
|
*/
|
|
opt_frame_clause:
|
|
RANGE frame_extent opt_window_exclusion_clause
|
|
{
|
|
WindowDef *n = $2;
|
|
n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_RANGE;
|
|
n->frameOptions |= $3;
|
|
$$ = n;
|
|
}
|
|
| ROWS frame_extent opt_window_exclusion_clause
|
|
{
|
|
WindowDef *n = $2;
|
|
n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS;
|
|
n->frameOptions |= $3;
|
|
$$ = n;
|
|
}
|
|
| GROUPS frame_extent opt_window_exclusion_clause
|
|
{
|
|
WindowDef *n = $2;
|
|
n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_GROUPS;
|
|
n->frameOptions |= $3;
|
|
$$ = n;
|
|
}
|
|
| /*EMPTY*/
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_DEFAULTS;
|
|
n->startOffset = NULL;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
;
|
|
|
|
frame_extent: frame_bound
|
|
{
|
|
WindowDef *n = $1;
|
|
/* reject invalid cases */
|
|
if (n->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
|
|
parser_errposition(@1)));
|
|
if (n->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame starting from following row cannot end with current row"),
|
|
parser_errposition(@1)));
|
|
n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
|
|
$$ = n;
|
|
}
|
|
| BETWEEN frame_bound AND frame_bound
|
|
{
|
|
WindowDef *n1 = $2;
|
|
WindowDef *n2 = $4;
|
|
/* form merged options */
|
|
int frameOptions = n1->frameOptions;
|
|
/* shift converts START_ options to END_ options */
|
|
frameOptions |= n2->frameOptions << 1;
|
|
frameOptions |= FRAMEOPTION_BETWEEN;
|
|
/* reject invalid cases */
|
|
if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
|
|
parser_errposition(@2)));
|
|
if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame end cannot be UNBOUNDED PRECEDING"),
|
|
parser_errposition(@4)));
|
|
if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
|
|
(frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame starting from current row cannot have preceding rows"),
|
|
parser_errposition(@4)));
|
|
if ((frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) &&
|
|
(frameOptions & (FRAMEOPTION_END_OFFSET_PRECEDING |
|
|
FRAMEOPTION_END_CURRENT_ROW)))
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_WINDOWING_ERROR),
|
|
errmsg("frame starting from following row cannot have preceding rows"),
|
|
parser_errposition(@4)));
|
|
n1->frameOptions = frameOptions;
|
|
n1->endOffset = n2->startOffset;
|
|
$$ = n1;
|
|
}
|
|
;
|
|
|
|
/*
|
|
* This is used for both frame start and frame end, with output set up on
|
|
* the assumption it's frame start; the frame_extent productions must reject
|
|
* invalid cases.
|
|
*/
|
|
frame_bound:
|
|
UNBOUNDED PRECEDING
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_START_UNBOUNDED_PRECEDING;
|
|
n->startOffset = NULL;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
| UNBOUNDED FOLLOWING
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_START_UNBOUNDED_FOLLOWING;
|
|
n->startOffset = NULL;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
| CURRENT_P ROW
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_START_CURRENT_ROW;
|
|
n->startOffset = NULL;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
| a_expr PRECEDING
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_START_OFFSET_PRECEDING;
|
|
n->startOffset = $1;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
| a_expr FOLLOWING
|
|
{
|
|
WindowDef *n = makeNode(WindowDef);
|
|
n->frameOptions = FRAMEOPTION_START_OFFSET_FOLLOWING;
|
|
n->startOffset = $1;
|
|
n->endOffset = NULL;
|
|
$$ = n;
|
|
}
|
|
;
|
|
|
|
opt_window_exclusion_clause:
|
|
EXCLUDE CURRENT_P ROW { $$ = FRAMEOPTION_EXCLUDE_CURRENT_ROW; }
|
|
| EXCLUDE GROUP_P { $$ = FRAMEOPTION_EXCLUDE_GROUP; }
|
|
| EXCLUDE TIES { $$ = FRAMEOPTION_EXCLUDE_TIES; }
|
|
| EXCLUDE NO OTHERS { $$ = 0; }
|
|
| /*EMPTY*/ { $$ = 0; }
|
|
;
|
|
|
|
|
|
/*
|
|
* Supporting nonterminals for expressions.
|
|
*/
|
|
|
|
/* Explicit row production.
|
|
*
|
|
* SQL99 allows an optional ROW keyword, so we can now do single-element rows
|
|
* without conflicting with the parenthesized a_expr production. Without the
|
|
* ROW keyword, there must be more than one a_expr inside the parens.
|
|
*/
|
|
row: ROW '(' expr_list ')' { $$ = $3; }
|
|
| ROW '(' ')' { $$ = NIL; }
|
|
| '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); }
|
|
;
|
|
|
|
explicit_row: ROW '(' expr_list ')' { $$ = $3; }
|
|
| ROW '(' ')' { $$ = NIL; }
|
|
;
|
|
|
|
implicit_row: '(' expr_list ',' a_expr ')' { $$ = lappend($2, $4); }
|
|
;
|
|
|
|
sub_type: ANY { $$ = ANY_SUBLINK; }
|
|
| SOME { $$ = ANY_SUBLINK; }
|
|
| ALL { $$ = ALL_SUBLINK; }
|
|
;
|
|
|
|
all_Op: Op { $$ = $1; }
|
|
| MathOp { $$ = $1; }
|
|
;
|
|
|
|
MathOp: '+' { $$ = "+"; }
|
|
| '-' { $$ = "-"; }
|
|
| '*' { $$ = "*"; }
|
|
| '/' { $$ = "/"; }
|
|
| '%' { $$ = "%"; }
|
|
| '^' { $$ = "^"; }
|
|
| '<' { $$ = "<"; }
|
|
| '>' { $$ = ">"; }
|
|
| '=' { $$ = "="; }
|
|
| LESS_EQUALS { $$ = "<="; }
|
|
| GREATER_EQUALS { $$ = ">="; }
|
|
| NOT_EQUALS { $$ = "<>"; }
|
|
;
|
|
|
|
qual_Op: Op
|
|
{ $$ = list_make1(makeString($1)); }
|
|
| OPERATOR '(' any_operator ')'
|
|
{ $$ = $3; }
|
|
;
|
|
|
|
qual_all_Op:
|
|
all_Op
|
|
{ $$ = list_make1(makeString($1)); }
|
|
| OPERATOR '(' any_operator ')'
|
|
{ $$ = $3; }
|
|
;
|
|
|
|
subquery_Op:
|
|
all_Op
|
|
{ $$ = list_make1(makeString($1)); }
|
|
| OPERATOR '(' any_operator ')'
|
|
{ $$ = $3; }
|
|
| LIKE
|
|
{ $$ = list_make1(makeString("~~")); }
|
|
| NOT_LA LIKE
|
|
{ $$ = list_make1(makeString("!~~")); }
|
|
| ILIKE
|
|
{ $$ = list_make1(makeString("~~*")); }
|
|
| NOT_LA ILIKE
|
|
{ $$ = list_make1(makeString("!~~*")); }
|
|
/* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
|
|
* the regular expression is preprocessed by a function (similar_to_escape),
|
|
* and the ~ operator for posix regular expressions is used.
|
|
* x SIMILAR TO y -> x ~ similar_to_escape(y)
|
|
* this transformation is made on the fly by the parser upwards.
|
|
* however the SubLink structure which handles any/some/all stuff
|
|
* is not ready for such a thing.
|
|
*/
|
|
;
|
|
|
|
expr_list: a_expr
|
|
{
|
|
$$ = list_make1($1);
|
|
}
|
|
| expr_list ',' a_expr
|
|
{
|
|
$$ = lappend($1, $3);
|
|
}
|
|
;
|
|
|
|
/* function arguments can have names */
|
|
func_arg_list: func_arg_expr
|
|
{
|
|
$$ = list_make1($1);
|
|
}
|
|
| func_arg_list ',' func_arg_expr
|
|
{
|
|
$$ = lappend($1, $3);
|
|
}
|
|
;
|
|
|
|
func_arg_expr: a_expr
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| param_name COLON_EQUALS a_expr
|
|
{
|
|
NamedArgExpr *na = makeNode(NamedArgExpr);
|
|
na->name = $1;
|
|
na->arg = (Expr *) $3;
|
|
na->argnumber = -1; /* until determined */
|
|
na->location = @1;
|
|
$$ = (Node *) na;
|
|
}
|
|
| param_name EQUALS_GREATER a_expr
|
|
{
|
|
NamedArgExpr *na = makeNode(NamedArgExpr);
|
|
na->name = $1;
|
|
na->arg = (Expr *) $3;
|
|
na->argnumber = -1; /* until determined */
|
|
na->location = @1;
|
|
$$ = (Node *) na;
|
|
}
|
|
;
|
|
|
|
func_arg_list_opt: func_arg_list { $$ = $1; }
|
|
| /*EMPTY*/ { $$ = NIL; }
|
|
;
|
|
|
|
type_list: Typename { $$ = list_make1($1); }
|
|
| type_list ',' Typename { $$ = lappend($1, $3); }
|
|
;
|
|
|
|
array_expr: '[' expr_list ']'
|
|
{
|
|
$$ = makeAArrayExpr($2, @1);
|
|
}
|
|
| '[' array_expr_list ']'
|
|
{
|
|
$$ = makeAArrayExpr($2, @1);
|
|
}
|
|
| '[' ']'
|
|
{
|
|
$$ = makeAArrayExpr(NIL, @1);
|
|
}
|
|
;
|
|
|
|
array_expr_list: array_expr { $$ = list_make1($1); }
|
|
| array_expr_list ',' array_expr { $$ = lappend($1, $3); }
|
|
;
|
|
|
|
|
|
extract_list:
|
|
extract_arg FROM a_expr
|
|
{
|
|
$$ = list_make2(makeStringConst($1, @1), $3);
|
|
}
|
|
;
|
|
|
|
/* Allow delimited string Sconst in extract_arg as an SQL extension.
|
|
* - thomas 2001-04-12
|
|
*/
|
|
extract_arg:
|
|
IDENT { $$ = $1; }
|
|
| YEAR_P { $$ = "year"; }
|
|
| MONTH_P { $$ = "month"; }
|
|
| DAY_P { $$ = "day"; }
|
|
| HOUR_P { $$ = "hour"; }
|
|
| MINUTE_P { $$ = "minute"; }
|
|
| SECOND_P { $$ = "second"; }
|
|
| Sconst { $$ = $1; }
|
|
;
|
|
|
|
unicode_normal_form:
|
|
NFC { $$ = "NFC"; }
|
|
| NFD { $$ = "NFD"; }
|
|
| NFKC { $$ = "NFKC"; }
|
|
| NFKD { $$ = "NFKD"; }
|
|
;
|
|
|
|
/* OVERLAY() arguments */
|
|
overlay_list:
|
|
a_expr PLACING a_expr FROM a_expr FOR a_expr
|
|
{
|
|
/* overlay(A PLACING B FROM C FOR D) is converted to overlay(A, B, C, D) */
|
|
$$ = list_make4($1, $3, $5, $7);
|
|
}
|
|
| a_expr PLACING a_expr FROM a_expr
|
|
{
|
|
/* overlay(A PLACING B FROM C) is converted to overlay(A, B, C) */
|
|
$$ = list_make3($1, $3, $5);
|
|
}
|
|
;
|
|
|
|
/* position_list uses b_expr not a_expr to avoid conflict with general IN */
|
|
position_list:
|
|
b_expr IN_P b_expr { $$ = list_make2($3, $1); }
|
|
;
|
|
|
|
/*
|
|
* SUBSTRING() arguments
|
|
*
|
|
* Note that SQL:1999 has both
|
|
* text FROM int FOR int
|
|
* and
|
|
* text FROM pattern FOR escape
|
|
*
|
|
* In the parser we map them both to a call to the substring() function and
|
|
* rely on type resolution to pick the right one.
|
|
*
|
|
* In SQL:2003, the second variant was changed to
|
|
* text SIMILAR pattern ESCAPE escape
|
|
* We could in theory map that to a different function internally, but
|
|
* since we still support the SQL:1999 version, we don't. However,
|
|
* ruleutils.c will reverse-list the call in the newer style.
|
|
*/
|
|
substr_list:
|
|
a_expr FROM a_expr FOR a_expr
|
|
{
|
|
$$ = list_make3($1, $3, $5);
|
|
}
|
|
| a_expr FOR a_expr FROM a_expr
|
|
{
|
|
/* not legal per SQL, but might as well allow it */
|
|
$$ = list_make3($1, $5, $3);
|
|
}
|
|
| a_expr FROM a_expr
|
|
{
|
|
/*
|
|
* Because we aren't restricting data types here, this
|
|
* syntax can end up resolving to textregexsubstr().
|
|
* We've historically allowed that to happen, so continue
|
|
* to accept it. However, ruleutils.c will reverse-list
|
|
* such a call in regular function call syntax.
|
|
*/
|
|
$$ = list_make2($1, $3);
|
|
}
|
|
| a_expr FOR a_expr
|
|
{
|
|
/* not legal per SQL */
|
|
|
|
/*
|
|
* Since there are no cases where this syntax allows
|
|
* a textual FOR value, we forcibly cast the argument
|
|
* to int4. The possible matches in pg_proc are
|
|
* substring(text,int4) and substring(text,text),
|
|
* and we don't want the parser to choose the latter,
|
|
* which it is likely to do if the second argument
|
|
* is unknown or doesn't have an implicit cast to int4.
|
|
*/
|
|
$$ = list_make3($1, makeIntConst(1, -1),
|
|
makeTypeCast($3,
|
|
SystemTypeName("int4"), -1));
|
|
}
|
|
| a_expr SIMILAR a_expr ESCAPE a_expr
|
|
{
|
|
$$ = list_make3($1, $3, $5);
|
|
}
|
|
;
|
|
|
|
trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); }
|
|
| FROM expr_list { $$ = $2; }
|
|
| expr_list { $$ = $1; }
|
|
;
|
|
|
|
in_expr: select_with_parens
|
|
{
|
|
SubLink *n = makeNode(SubLink);
|
|
n->subselect = $1;
|
|
/* other fields will be filled later */
|
|
$$ = (Node *)n;
|
|
}
|
|
| '(' expr_list ')' { $$ = (Node *)$2; }
|
|
;
|
|
|
|
/*
|
|
* Define SQL-style CASE clause.
|
|
* - Full specification
|
|
* CASE WHEN a = b THEN c ... ELSE d END
|
|
* - Implicit argument
|
|
* CASE a WHEN b THEN c ... ELSE d END
|
|
*/
|
|
case_expr: CASE case_arg when_clause_list case_default END_P
|
|
{
|
|
CaseExpr *c = makeNode(CaseExpr);
|
|
c->casetype = InvalidOid; /* not analyzed yet */
|
|
c->arg = (Expr *) $2;
|
|
c->args = $3;
|
|
c->defresult = (Expr *) $4;
|
|
c->location = @1;
|
|
$$ = (Node *)c;
|
|
}
|
|
;
|
|
|
|
when_clause_list:
|
|
/* There must be at least one */
|
|
when_clause { $$ = list_make1($1); }
|
|
| when_clause_list when_clause { $$ = lappend($1, $2); }
|
|
;
|
|
|
|
when_clause:
|
|
WHEN 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_P
|
|
| 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_P
|
|
| 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 */
|
|
}
|