| %{ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /*#define YYDEBUG 1*/ |
| /*------------------------------------------------------------------------- |
| * |
| * gram.y |
| * POSTGRES SQL YACC rules/actions |
| * |
| * Portions Copyright (c) 2006-2010, Greenplum inc |
| * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * |
| * IDENTIFICATION |
| * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.568 2006/11/05 22:42:09 tgl Exp $ |
| * |
| * 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. |
| * SQL92-specific syntax is separated from plain SQL/Postgres syntax |
| * to help isolate the non-extensible portions of the parser. |
| * |
| * 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 SQL_inheritance 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. The handling of SQL_inheritance is |
| * a good example. |
| * |
| * 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. |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #undef REPEATABLE |
| #include "postgres.h" |
| |
| #include <ctype.h> |
| #include <limits.h> |
| |
| |
| #include "catalog/index.h" |
| #include "catalog/namespace.h" |
| #include "commands/defrem.h" |
| #include "nodes/makefuncs.h" |
| #include "nodes/nodeFuncs.h" |
| #include "nodes/print.h" |
| #include "parser/gramparse.h" |
| #include "storage/lmgr.h" |
| #include "utils/date.h" |
| #include "utils/datetime.h" |
| #include "utils/guc.h" |
| #include "utils/numeric.h" |
| #include "cdb/cdbvars.h" /* CDB *//* gp_enable_partitioned_tables */ |
| |
| #include "resourcemanager/resourcemanager.h" |
| |
| |
| /* Location tracking support --- simpler than bison's default */ |
| #define YYLLOC_DEFAULT(Current, Rhs, N) \ |
| do { \ |
| if (N) \ |
| (Current) = (Rhs)[1]; \ |
| else \ |
| (Current) = (Rhs)[0]; \ |
| } while (0) |
| |
| /* |
| * The %name-prefix option below will make bison call base_yylex, but we |
| * really want it to call filtered_base_yylex (see parser.c). |
| */ |
| #define base_yylex filtered_base_yylex |
| |
| /* |
| * 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 |
| |
| extern List *parsetree; /* final parse result is delivered here */ |
| |
| static bool QueryIsRule = FALSE; |
| |
| /* |
| * If you need access to certain yacc-generated variables and find that |
| * they're static by default, uncomment the next line. (this is not a |
| * problem, yet.) |
| */ |
| /*#define __YYSCLASS*/ |
| |
| static Node *makeAddPartitionCreateStmt(Node *n, Node *subSpec); |
| static Node *makeColumnRef(char *colname, List *indirection, int location); |
| static Node *makeTypeCast(Node *arg, TypeName *typname, int location); |
| static Node *makeStringConst(char *str, TypeName *typname, int location); |
| static Node *makeIntConst(int val, int location); |
| static Node *makeFloatConst(char *str, int location); |
| static Node *makeAConst(Value *v, int location); |
| static A_Const *makeBoolAConst(bool state, int location); |
| static FuncCall *makeOverlaps(List *largs, List *rargs, int location); |
| static void check_qualified_name(List *names); |
| static List *check_func_name(List *names); |
| static List *extractArgTypes(List *parameters); |
| static SelectStmt *findLeftmostSelect(SelectStmt *node); |
| static void insertSelectOptions(SelectStmt *stmt, |
| List *sortClause, List *lockingClause, |
| Node *limitOffset, Node *limitCount, |
| WithClause *withClause); |
| static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); |
| static Node *doNegate(Node *n, int location); |
| static void doNegateFloat(Value *v); |
| static List *mergeTableFuncParameters(List *func_args, List *columns); |
| static TypeName *TableFuncTypeName(List *columns); |
| static void setWindowExclude(WindowFrame *wframe, WindowExclusion exclude); |
| static Node *makeIsNotDistinctFromNode(Node *expr, int position); |
| |
| %} |
| |
| %expect 0 |
| %name-prefix="base_yy" |
| %locations |
| |
| %union |
| { |
| int ival; |
| char chr; |
| char *str; |
| const char *keyword; |
| 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; |
| FuncWithArgs *funwithargs; |
| DefElem *defelt; |
| SortBy *sortby; |
| JoinExpr *jexpr; |
| IndexElem *ielem; |
| Alias *alias; |
| RangeVar *range; |
| IntoClause *into; |
| A_Indices *aind; |
| ResTarget *target; |
| PrivTarget *privtarget; |
| |
| InsertStmt *istmt; |
| VariableSetStmt *vsetstmt; |
| WithClause *with; |
| } |
| |
| %type <node> stmt schema_stmt |
| AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt |
| AlterForeignServerStmt AlterGroupStmt |
| AlterObjectSchemaStmt AlterOwnerStmt AlterQueueStmt AlterSeqStmt |
| AlterTableStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt |
| AlterRoleSetStmt AnalyzeStmt ClosePortalStmt ClusterStmt |
| CommentStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt |
| CreateDomainStmt CreateExternalStmt CreateFileSpaceStmt CreateGroupStmt |
| CreateOpClassStmt CreatePLangStmt |
| CreateQueueStmt CreateSchemaStmt CreateSeqStmt CreateStmt |
| CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignStmt |
| CreateAssertStmt CreateTrigStmt |
| CreateUserStmt CreateUserMappingStmt CreateRoleStmt |
| CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt |
| DropGroupStmt DropOpClassStmt DropPLangStmt DropQueueStmt DropStmt |
| DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt |
| DropUserStmt DropdbStmt DropFdwStmt |
| DropForeignServerStmt DropUserMappingStmt ExplainStmt |
| ExtTypedesc FetchStmt |
| GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt |
| LockStmt NotifyStmt OptSingleRowErrorHandling ExplainableStmt PreparableStmt |
| CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt |
| RemoveFuncStmt RemoveOperStmt RenameStmt RevokeStmt RevokeRoleStmt |
| RuleActionStmt RuleActionStmtOrEmpty RuleStmt |
| SelectStmt TransactionStmt TruncateStmt |
| UnlistenStmt UpdateStmt VacuumStmt |
| VariableResetStmt VariableSetStmt VariableShowStmt |
| ViewStmt CheckPointStmt CreateConversionStmt |
| DeallocateStmt PrepareStmt ExecuteStmt |
| DropOwnedStmt ReassignOwnedStmt |
| AlterTypeStmt |
| |
| %type <node> deny_login_role deny_interval deny_point deny_day_specifier |
| |
| %type <node> select_no_parens select_with_parens select_clause |
| simple_select values_clause |
| |
| %type <node> alter_column_default opclass_item alter_using |
| %type <ival> add_drop |
| |
| %type <node> alter_table_cmd alter_rel_cmd alter_table_partition_id_spec |
| alter_table_partition_cmd |
| alter_table_partition_id_spec_with_opt_default |
| %type <list> alter_table_cmds alter_rel_cmds |
| part_values_clause multi_spec_value_list part_values_single |
| %type <ival> opt_table_partition_exchange_validate partition_hash_keyword |
| partition_coalesce_keyword |
| |
| %type <dbehavior> opt_drop_behavior |
| |
| %type <list> createdb_opt_list alterdb_opt_list copy_opt_list |
| ext_on_clause_list format_opt format_opt_list transaction_mode_list |
| ext_opt_encoding_list |
| %type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item |
| ext_on_clause_item format_opt_item transaction_mode_item |
| ext_opt_encoding_item |
| |
| %type <ival> opt_lock lock_type cast_context |
| %type <boolean> opt_force opt_or_replace |
| opt_grant_grant_option opt_grant_admin_option |
| opt_nowait opt_if_exists opt_with_data |
| |
| %type <list> OptRoleList |
| %type <defelt> OptRoleElem |
| |
| %type <list> OptAlterRoleList |
| %type <defelt> OptAlterRoleElem |
| |
| %type <str> opt_type |
| %type <str> foreign_server_version opt_foreign_server_version |
| %type <str> auth_ident |
| |
| %type <str> OptSchemaName |
| %type <list> OptSchemaEltList |
| |
| %type <boolean> TriggerActionTime TriggerForSpec opt_trusted |
| %type <str> opt_lancompiler |
| |
| %type <str> TriggerEvents |
| %type <value> TriggerFuncArg |
| |
| %type <str> relation_name copy_file_name |
| database_name access_method_clause access_method attr_name |
| index_name name function_name file_name |
| |
| %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op |
| opt_class opt_validator validator_clause |
| |
| %type <range> qualified_name OptConstrFromTable |
| |
| %type <str> all_Op MathOp SpecialRuleRelation |
| |
| %type <str> iso_level opt_encoding |
| %type <node> grantee |
| %type <list> grantee_list |
| %type <str> privilege |
| %type <list> privileges privilege_list |
| %type <privtarget> privilege_target |
| %type <funwithargs> function_with_argtypes |
| %type <list> function_with_argtypes_list |
| %type <chr> TriggerOneEvent |
| |
| %type <list> stmtblock stmtmulti |
| OptTableElementList OptExtTableElementList TableElementList ExtTableElementList |
| OptInherit definition |
| OptWith opt_distinct opt_definition func_args func_args_list |
| func_as createfunc_opt_list alterfunc_opt_list |
| aggr_args aggr_args_list old_aggr_definition old_aggr_list |
| oper_argtypes RuleActionList RuleActionMulti |
| cdb_string_list |
| opt_column_list columnList columnListPlus opt_name_list exttab_auth_list keyvalue_list |
| opt_inherited_column_list |
| sort_clause opt_sort_clause sortby_list index_params |
| name_list from_clause from_list opt_array_bounds |
| qualified_name_list any_name any_name_list |
| any_operator expr_list attrs |
| target_list insert_column_list set_target_list |
| set_clause_list set_clause multiple_set_clause |
| ctext_expr_list ctext_row def_list indirection opt_indirection |
| group_clause group_elem_list group_elem TriggerFuncArgs select_limit |
| opt_select_limit opclass_item_list |
| transaction_mode_list_or_empty |
| TableFuncElementList |
| prep_type_clause prep_type_list |
| create_generic_options alter_generic_options |
| execute_param_clause using_clause returning_clause |
| table_func_column_list scatter_clause |
| %type <node> table_value_select_clause |
| |
| %type <range> OptTempTableName OptErrorTableName |
| %type <into> into_clause create_as_target |
| |
| %type <defelt> createfunc_opt_item common_func_opt_item |
| %type <fun_param> func_arg table_func_column |
| %type <fun_param_mode> arg_class |
| %type <typnam> func_return func_type |
| |
| %type <boolean> TriggerForType OptTemp OptWeb OptWritable OptSrehLimitType OptSrehKeep |
| %type <oncommit> OnCommitOption |
| |
| %type <node> for_locking_item |
| %type <list> for_locking_clause opt_for_locking_clause for_locking_items |
| %type <list> locked_rels_list |
| %type <boolean> opt_all |
| |
| %type <node> join_outer join_qual |
| %type <jtype> join_type |
| |
| %type <list> extract_list overlay_list position_list |
| %type <list> substr_list trim_list |
| %type <ival> opt_interval |
| %type <node> overlay_placing substr_from substr_for |
| |
| %type <boolean> opt_instead opt_analyze |
| %type <boolean> index_opt_unique opt_verbose opt_full |
| %type <boolean> opt_freeze opt_default opt_ordered opt_recheck |
| %type <boolean> opt_rootonly_all |
| %type <boolean> opt_dxl |
| %type <defelt> opt_binary opt_oids copy_delimiter |
| |
| %type <boolean> copy_from opt_hold |
| |
| %type <ival> opt_column event cursor_options |
| %type <objtype> reindex_type drop_type comment_type |
| |
| %type <node> fetch_direction select_limit_value select_offset_value |
| select_offset_value2 opt_select_fetch_first_value |
| %type <ival> row_or_rows first_or_next |
| |
| %type <list> OptSeqList |
| %type <defelt> OptSeqElem |
| |
| %type <istmt> insert_rest |
| |
| %type <vsetstmt> set_rest |
| %type <node> TableElement ExtTableElement ConstraintElem TableFuncElement |
| %type <node> columnDef ExtcolumnDef |
| %type <node> cdb_string |
| %type <defelt> def_elem old_aggr_elem keyvalue_pair |
| %type <node> def_arg columnElem where_clause where_or_current_clause |
| a_expr b_expr c_expr simple_func func_expr AexprConst indirection_el |
| columnref in_expr having_clause func_table array_expr |
| %type <list> window_definition_list window_clause |
| %type <boolean> window_frame_units |
| %type <ival> window_frame_exclusion |
| %type <node> window_spec |
| %type <node> window_frame_extent |
| window_frame_start window_frame_preceding window_frame_between |
| window_frame_bound window_frame_following |
| window_frame_clause opt_window_frame_clause |
| %type <list> window_partition_clause opt_window_partition_clause |
| opt_window_order_clause |
| %type <str> opt_window_name window_name |
| |
| %type <list> row type_list array_expr_list |
| %type <node> case_expr case_arg when_clause when_operand case_default |
| %type <list> when_clause_list |
| %type <node> decode_expr search_result decode_default |
| %type <list> search_result_list |
| %type <ival> sub_type |
| %type <list> OptCreateAs CreateAsList |
| %type <node> CreateAsElement ctext_expr |
| %type <value> NumericOnly FloatOnly IntegerOnly |
| %type <alias> alias_clause |
| %type <sortby> sortby |
| %type <ielem> index_elem |
| %type <node> table_ref |
| %type <jexpr> joined_table |
| %type <range> relation_expr |
| %type <range> relation_expr_opt_alias |
| %type <target> target_el single_set_clause 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 <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 <str> opt_charset |
| %type <ival> opt_numeric opt_decimal |
| %type <boolean> opt_varying opt_timezone |
| |
| %type <ival> Iconst SignedIconst |
| %type <str> Sconst comment_text |
| %type <str> RoleId opt_granted_by opt_boolean ColId_or_Sconst |
| %type <str> QueueId |
| %type <list> var_list var_list_or_default |
| %type <str> ColId ColLabel ColLabelNoAs var_name type_name param_name |
| %type <keyword> PartitionIdentKeyword |
| %type <str> PartitionColId |
| %type <node> var_value zone_value |
| |
| %type <keyword> unreserved_keyword func_name_keyword |
| %type <keyword> col_name_keyword reserved_keyword format_opt_keyword |
| %type <keyword> keywords_ok_in_alias_no_as |
| |
| %type <node> TableConstraint TableLikeClause |
| %type <list> TableLikeOptionList |
| %type <ival> TableLikeOption |
| %type <list> ColQualList |
| %type <node> ColConstraint ColConstraintElem ConstraintAttr |
| %type <ival> key_actions key_delete key_match key_update key_action |
| %type <ival> ConstraintAttributeSpec ConstraintDeferrabilitySpec |
| ConstraintTimeSpec |
| |
| %type <list> constraints_set_list |
| %type <boolean> constraints_set_mode |
| %type <str> OptTableSpace OptConsTableSpace OptOwner |
| %type <str> OptStorage |
| %type <list> DistributedBy OptDistributedBy |
| %type <ival> TabPartitionByType OptTabPartitionRangeInclusive |
| %type <node> OptTabPartitionBy TabSubPartitionBy |
| tab_part_val tab_part_val_no_paran |
| %type <node> list_subparts opt_list_subparts |
| %type <list> opt_check_option |
| %type <node> OptTabPartitionsNumber OptTabSubPartitionsNumber |
| %type <node> OptTabPartitionSpec OptTabSubPartitionSpec TabSubPartitionTemplate /* PartitionSpec */ |
| %type <list> TabPartitionElemList TabSubPartitionElemList /* list of PartitionElem */ |
| |
| %type <node> TabPartitionElem TabSubPartitionElem /* PartitionElem */ |
| |
| %type <node> TabPartitionBoundarySpec OptTabPartitionBoundarySpec /* PartitionBoundSpec */ |
| %type <list> TabPartitionBoundarySpecValList |
| OptTabPartitionBoundarySpecValList |
| part_values_or_spec_list |
| %type <node> TabPartitionBoundarySpecStart TabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEnd /* PartitionRangeItem */ |
| %type <node> OptTabPartitionBoundarySpecEvery /* PartitionRangeItem */ |
| %type <node> TabPartitionNameDecl TabSubPartitionNameDecl /* string */ |
| TabPartitionDefaultNameDecl TabSubPartitionDefaultNameDecl |
| opt_table_partition_merge_into |
| table_partition_modify |
| opt_table_partition_split_into |
| %type <boolean> opt_comma |
| %type <node> OptTabPartitionStorageAttr |
| |
| %type <node> common_table_expr |
| %type <with> with_clause |
| %type <list> cte_list |
| %type <node> opt_time |
| |
| %type <node> column_reference_storage_directive |
| %type <list> opt_storage_encoding OptTabPartitionColumnEncList |
| TabPartitionColumnEncList |
| %type <value> size_unit |
| %type <list> resqueue_attr_definition resqueue_attr_def_list |
| %type <defelt> resqueue_attr_def_elem |
| |
| /* |
| * If you make any token changes, update the keyword table in |
| * parser/keywords.c and add new keywords to the appropriate one of |
| * the reserved-or-not-so-reserved keyword lists, below; search |
| * this file for "Name classification hierarchy". |
| */ |
| |
| /* ordinary key words in alphabetical order */ |
| %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ACTIVE ADD_P ADMIN AFTER |
| AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC |
| ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION |
| |
| BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT |
| BOOLEAN_P BOTH BY |
| |
| CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P |
| CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE |
| CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT |
| COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS CONTAINS CONTENT_P CONTINUE_P CONVERSION_P CONVERT COPY COST |
| CREATE CREATEDB CREATEEXTTABLE |
| CREATEROLE CREATEUSER CROSS CSV CUBE CURRENT 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 DECODE DEFAULT DEFAULTS |
| DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DENY |
| DESC DISABLE_P DISTINCT DISTRIBUTED DO DOMAIN_P DOUBLE_P DROP DXL |
| |
| EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERRORS ESCAPE EVERY EXCEPT |
| EXCHANGE EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT |
| |
| FALSE_P FETCH FIELDS FILESPACE FILESYSTEM FILL FILTER FIRST_P FLOAT_P FOLLOWING FOR |
| FORCE FOREIGN FORMAT FORMATTER FORWARD FREEZE FROM FULL FUNCTION |
| |
| GB GLOBAL GRANT GRANTED GREATEST GROUP_P GROUP_ID GROUPING |
| |
| HANDLER HASH HAVING HEADER_P HOLD HOST HOUR_P |
| |
| IDENTITY_P IF_P IGNORE_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING |
| INCLUSIVE |
| INCREMENT |
| INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P |
| INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT |
| INTERVAL INTO INVOKER IS ISNULL ISOLATION |
| |
| JOIN |
| |
| KB KEEP KEY |
| |
| LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL |
| LIKE LIMIT LIST LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION |
| LOCK_P LOG_P LOGIN_P |
| |
| MAPPING MASTER MATCH MAXVALUE MB MEDIAN MERGE MINUTE_P MINVALUE MIRROR |
| MISSING MODE MODIFIES MODIFY MONTH_P MOVE |
| |
| NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEWLINE NEXT NO NOCREATEDB NOCREATEEXTTABLE |
| NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOOVERCOMMIT NOSUPERUSER |
| NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLS_P NULLIF NUMERIC |
| |
| OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR |
| ORDER ORDERED OTHERS OUT_P OUTER_P OVER OVERCOMMIT OVERLAPS OVERLAY OWNED OWNER |
| |
| PARTIAL PARTITION PARTITIONS PASSWORD PB PERCENT PERCENTILE_CONT PERCENTILE_DISC |
| PLACING POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY |
| PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROTOCOL |
| |
| QUEUE QUOTE |
| |
| RANDOMLY RANGE READ READABLE READS REAL REASSIGN RECHECK RECURSIVE |
| REFERENCES REINDEX REJECT_P RELATIVE_P |
| RELEASE RENAME REPEATABLE REPLACE RESET RESOURCE RESTART RESTRICT |
| RETURNING RETURNS REVOKE RIGHT |
| ROLE ROLLBACK ROLLUP ROOTPARTITION ROW ROWS RULE |
| |
| SAVEPOINT SCATTER SCHEMA SCROLL SEARCH SECOND_P |
| SECURITY SEGMENT SELECT SEQUENCE |
| SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SETS SHARE |
| SHOW SIMILAR SIMPLE SMALLINT SOME SPLIT SQL STABLE START STATEMENT |
| STATISTICS STDIN STDOUT STORAGE STRICT_P |
| SUBPARTITION SUBPARTITIONS |
| SUBSTRING SUPERUSER_P SYMMETRIC |
| SYSID SYSTEM_P |
| |
| TABLE TABLESPACE TB TEMP TEMPLATE TEMPORARY THEN THRESHOLD TIES TIME TIMESTAMP |
| TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P |
| TRUNCATE TRUSTED TYPE_P |
| |
| UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL |
| UPDATE USER USING |
| |
| VACUUM VALID VALIDATION VALIDATOR VALUE_P VALUES VARCHAR VARYING |
| VERBOSE VERSION_P VIEW VOLATILE |
| |
| WEB WHEN WHERE WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITABLE WRITE |
| |
| YEAR_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. |
| */ |
| %token NULLS_FIRST NULLS_LAST WITH_CASCADED WITH_LOCAL WITH_CHECK WITH_TIME |
| |
| /* Special token types, not actually keywords - see the "lex" file */ |
| %token <str> IDENT FCONST SCONST BCONST XCONST Op |
| %token <ival> ICONST PARAM |
| |
| /* precedence: lowest to highest */ |
| %nonassoc SET /* see relation_expr_opt_alias */ |
| %left UNION EXCEPT |
| %left INTERSECT |
| %left OR |
| %left AND |
| %right NOT |
| %right '=' |
| %nonassoc '<' '>' |
| %nonassoc LIKE ILIKE SIMILAR |
| %nonassoc ESCAPE |
| %nonassoc OVERLAPS |
| %nonassoc BETWEEN |
| %nonassoc IN_P |
| %left POSTFIXOP /* dummy for postfix Op rules */ |
| /* |
| * To support target_el without AS, we must give IDENT an explicit priority |
| * between POSTFIXOP and Op. We can safely assign the same priority to |
| * various unreserved keywords as needed to resolve ambiguities (this can't |
| * have any bad effects since obviously the keywords will still behave the |
| * same as if they weren't keywords). We need to do this for PARTITION, |
| * RANGE, ROWS to support opt_existing_window_name; and for RANGE, ROWS |
| * so that they can follow a_expr without creating |
| * postfix-operator problems. |
| */ |
| %nonassoc IDENT PARTITION RANGE ROWS |
| /* |
| * This is a bit ugly... To allow these to be column aliases without |
| * the "AS" keyword, and not conflict with PostgreSQL's non-standard |
| * suffix operators, we need to give these a precidence. |
| */ |
| |
| %nonassoc ABORT_P |
| %nonassoc ABSOLUTE_P |
| %nonassoc ACCESS |
| %nonassoc ACTION |
| %nonassoc ACTIVE |
| %nonassoc ADD_P |
| %nonassoc ADMIN |
| %nonassoc AFTER |
| %nonassoc AGGREGATE |
| %nonassoc ALSO |
| %nonassoc ALTER |
| %nonassoc ASSERTION |
| %nonassoc ASSIGNMENT |
| %nonassoc BACKWARD |
| %nonassoc BEFORE |
| %nonassoc BEGIN_P |
| %nonassoc BY |
| %nonassoc CACHE |
| %nonassoc CALLED |
| %nonassoc CASCADE |
| %nonassoc CASCADED |
| %nonassoc CHAIN |
| %nonassoc CHARACTERISTICS |
| %nonassoc CHECKPOINT |
| %nonassoc CLASS |
| %nonassoc CLOSE |
| %nonassoc CLUSTER |
| %nonassoc COMMENT |
| %nonassoc COMMIT |
| %nonassoc COMMITTED |
| %nonassoc CONCURRENTLY |
| %nonassoc CONNECTION |
| %nonassoc CONSTRAINTS |
| %nonassoc CONTAINS |
| %nonassoc CONTENT_P |
| %nonassoc CONTINUE_P |
| %nonassoc CONVERSION_P |
| %nonassoc COPY |
| %nonassoc COST |
| %nonassoc CREATEDB |
| %nonassoc CREATEEXTTABLE |
| %nonassoc CREATEROLE |
| %nonassoc CREATEUSER |
| %nonassoc CSV |
| %nonassoc CURRENT |
| %nonassoc CURSOR |
| %nonassoc CYCLE |
| %nonassoc DATA_P |
| %nonassoc DATABASE |
| %nonassoc DAY_P |
| %nonassoc DEALLOCATE |
| %nonassoc DECLARE |
| %nonassoc DEFAULTS |
| %nonassoc DEFERRED |
| %nonassoc DEFINER |
| %nonassoc DELETE_P |
| %nonassoc DELIMITER |
| %nonassoc DELIMITERS |
| %nonassoc DISABLE_P |
| %nonassoc DOMAIN_P |
| %nonassoc DOUBLE_P |
| %nonassoc DROP |
| %nonassoc EACH |
| %nonassoc ENABLE_P |
| %nonassoc ENCODING |
| %nonassoc ENCRYPTED |
| %nonassoc END_P |
| %nonassoc ENUM_P |
| %nonassoc ERRORS |
| %nonassoc EVERY |
| %nonassoc EXCHANGE |
| %nonassoc EXCLUDING |
| %nonassoc EXCLUSIVE |
| %nonassoc EXECUTE |
| %nonassoc EXPLAIN |
| %nonassoc EXTERNAL |
| %nonassoc FETCH |
| %nonassoc FIELDS |
| %nonassoc FILL |
| %nonassoc FIRST_P |
| %nonassoc FORCE |
| %nonassoc FORMAT |
| %nonassoc FORMATTER |
| %nonassoc FORWARD |
| %nonassoc FUNCTION |
| %nonassoc GB |
| %nonassoc GLOBAL |
| %nonassoc GRANTED |
| %nonassoc HANDLER |
| %nonassoc HASH |
| %nonassoc HEADER_P |
| %nonassoc HOLD |
| %nonassoc HOST |
| %nonassoc HOUR_P |
| %nonassoc IF_P |
| %nonassoc IMMEDIATE |
| %nonassoc IMMUTABLE |
| %nonassoc IMPLICIT_P |
| %nonassoc INCLUDING |
| %nonassoc INCLUSIVE |
| %nonassoc INCREMENT |
| %nonassoc INDEX |
| %nonassoc INDEXES |
| %nonassoc INHERIT |
| %nonassoc INHERITS |
| %nonassoc INPUT_P |
| %nonassoc INSENSITIVE |
| %nonassoc INSERT |
| %nonassoc INSTEAD |
| %nonassoc INVOKER |
| %nonassoc ISOLATION |
| %nonassoc KB |
| %nonassoc KEEP |
| %nonassoc KEY |
| %nonassoc LANCOMPILER |
| %nonassoc LANGUAGE |
| %nonassoc LARGE_P |
| %nonassoc LAST_P |
| %nonassoc LEVEL |
| %nonassoc LIST |
| %nonassoc LISTEN |
| %nonassoc LOAD |
| %nonassoc LOCAL |
| %nonassoc LOCATION |
| %nonassoc LOCK_P |
| %nonassoc LOGIN_P |
| %nonassoc MASTER |
| %nonassoc MAPPING |
| %nonassoc MATCH |
| %nonassoc MAXVALUE |
| %nonassoc MB |
| %nonassoc MERGE |
| %nonassoc MINUTE_P |
| %nonassoc MINVALUE |
| %nonassoc MIRROR |
| %nonassoc MISSING |
| %nonassoc MODE |
| %nonassoc MODIFIES |
| %nonassoc MODIFY |
| %nonassoc MONTH_P |
| %nonassoc MOVE |
| %nonassoc NAME_P |
| %nonassoc NAMES |
| %nonassoc NEWLINE |
| %nonassoc NEXT |
| %nonassoc NO |
| %nonassoc NOCREATEDB |
| %nonassoc NOCREATEEXTTABLE |
| %nonassoc NOCREATEROLE |
| %nonassoc NOCREATEUSER |
| %nonassoc NOINHERIT |
| %nonassoc NOLOGIN_P |
| %nonassoc NOOVERCOMMIT |
| %nonassoc NOSUPERUSER |
| %nonassoc NOTHING |
| %nonassoc NOTIFY |
| %nonassoc NOWAIT |
| %nonassoc NULLS_P |
| %nonassoc OBJECT_P |
| %nonassoc OF |
| %nonassoc OIDS |
| %nonassoc OPTION |
| %nonassoc OPTIONS |
| %nonassoc OTHERS |
| %nonassoc OVER |
| %nonassoc OVERCOMMIT |
| %nonassoc OWNED |
| %nonassoc OWNER |
| %nonassoc PARTIAL |
| %nonassoc PARTITIONS |
| %nonassoc PASSWORD |
| %nonassoc PB |
| %nonassoc PERCENT |
| %nonassoc PREPARE |
| %nonassoc PREPARED |
| %nonassoc PRESERVE |
| %nonassoc PRIOR |
| %nonassoc PRIVILEGES |
| %nonassoc PROCEDURAL |
| %nonassoc PROCEDURE |
| %nonassoc FILESYSTEM |
| %nonassoc PROTOCOL |
| %nonassoc QUEUE |
| %nonassoc QUOTE |
| %nonassoc RANDOMLY |
| %nonassoc READ |
| %nonassoc READABLE |
| %nonassoc READS |
| %nonassoc REASSIGN |
| %nonassoc RECHECK |
| %nonassoc RECURSIVE |
| %nonassoc REINDEX |
| %nonassoc REJECT_P |
| %nonassoc RELATIVE_P |
| %nonassoc RELEASE |
| %nonassoc RENAME |
| %nonassoc REPEATABLE |
| %nonassoc REPLACE |
| %nonassoc RESET |
| %nonassoc RESOURCE |
| %nonassoc RESTART |
| %nonassoc RESTRICT |
| %nonassoc RETURNS |
| %nonassoc REVOKE |
| %nonassoc ROLE |
| %nonassoc ROLLBACK |
| %nonassoc RULE |
| %nonassoc SAVEPOINT |
| %nonassoc SCHEMA |
| %nonassoc SCROLL |
| %nonassoc SEARCH |
| %nonassoc SECOND_P |
| %nonassoc SECURITY |
| %nonassoc SEGMENT |
| %nonassoc SEQUENCE |
| %nonassoc SERIALIZABLE |
| %nonassoc SERVER |
| %nonassoc SESSION |
| %nonassoc SHARE |
| %nonassoc SHOW |
| %nonassoc SIMPLE |
| %nonassoc SPLIT |
| %nonassoc SQL |
| %nonassoc STABLE |
| %nonassoc START |
| %nonassoc STATEMENT |
| %nonassoc STATISTICS |
| %nonassoc STDIN |
| %nonassoc STDOUT |
| %nonassoc STORAGE |
| %nonassoc SUBPARTITION |
| %nonassoc SUBPARTITIONS |
| %nonassoc SUPERUSER_P |
| %nonassoc SYSID |
| %nonassoc SYSTEM_P |
| %nonassoc STRICT_P |
| %nonassoc TABLESPACE |
| %nonassoc TB |
| %nonassoc TEMP |
| %nonassoc TEMPLATE |
| %nonassoc TEMPORARY |
| %nonassoc THRESHOLD |
| %nonassoc TIES |
| %nonassoc TRANSACTION |
| %nonassoc TRIGGER |
| %nonassoc TRUNCATE |
| %nonassoc TRUSTED |
| %nonassoc TYPE_P |
| %nonassoc UNCOMMITTED |
| %nonassoc UNENCRYPTED |
| %nonassoc UNLISTEN |
| %nonassoc UNTIL |
| %nonassoc UPDATE |
| %nonassoc VACUUM |
| %nonassoc VALID |
| %nonassoc VALIDATION |
| %nonassoc VALIDATOR |
| %nonassoc VALUE_P |
| %nonassoc VARYING |
| %nonassoc VERSION_P |
| %nonassoc VIEW |
| %nonassoc VOLATILE |
| %nonassoc WEB |
| %nonassoc WITH |
| %nonassoc WITHIN |
| %nonassoc WITHOUT |
| %nonassoc WORK |
| %nonassoc WRAPPER |
| %nonassoc WRITABLE |
| %nonassoc WRITE |
| %nonassoc YEAR_P |
| %nonassoc BIGINT |
| %nonassoc BIT |
| %nonassoc BOOLEAN_P |
| %nonassoc CHAR_P |
| %nonassoc CHARACTER |
| %nonassoc COALESCE |
| %nonassoc CONVERT |
| %nonassoc CUBE |
| %nonassoc DEC |
| %nonassoc DECIMAL_P |
| %nonassoc EXISTS |
| %nonassoc EXTRACT |
| %nonassoc FLOAT_P |
| %nonassoc GREATEST |
| %nonassoc GROUP_ID |
| %nonassoc GROUPING |
| %nonassoc INOUT |
| %nonassoc INT_P |
| %nonassoc INTEGER |
| %nonassoc INTERVAL |
| %nonassoc LEAST |
| %nonassoc MEDIAN |
| %nonassoc NATIONAL |
| %nonassoc NCHAR |
| %nonassoc NONE |
| %nonassoc NULLIF |
| %nonassoc NUMERIC |
| %nonassoc OUT_P |
| %nonassoc OVERLAY |
| %nonassoc PERCENTILE_CONT |
| %nonassoc PERCENTILE_DISC |
| %nonassoc POSITION |
| %nonassoc PRECISION |
| %nonassoc REAL |
| %nonassoc ROLLUP |
| %nonassoc ROW |
| %nonassoc SETOF |
| %nonassoc SETS |
| %nonassoc SMALLINT |
| %nonassoc SUBSTRING |
| %nonassoc TIME |
| %nonassoc TIMESTAMP |
| %nonassoc TREAT |
| %nonassoc TRIM |
| %nonassoc VALUES |
| %nonassoc VARCHAR |
| %nonassoc AUTHORIZATION |
| %nonassoc BINARY |
| %nonassoc FREEZE |
| %nonassoc LOG_P |
| %nonassoc OUTER_P |
| %nonassoc VERBOSE |
| |
| |
| |
| %left Op OPERATOR /* multi-character ops and user-defined operators */ |
| %nonassoc NOTNULL |
| %nonassoc ISNULL |
| %nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */ |
| %left '+' '-' |
| %left '*' '/' '%' |
| %left '^' |
| /* Unary Operators */ |
| %left AT ZONE /* sets precedence for AT TIME ZONE */ |
| %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 |
| %% |
| |
| /* |
| * Handle comment-only lines, and ;; SELECT * FROM pg_class ;;; |
| * psql already handles such cases, but other interfaces don't. |
| * bjm 1999/10/05 |
| */ |
| stmtblock: stmtmulti { parsetree = $1; } |
| ; |
| |
| /* the thrashing around here is to discard "empty" statements... */ |
| stmtmulti: stmtmulti ';' stmt |
| { if ($3 != NULL) |
| $$ = lappend($1, $3); |
| else |
| $$ = $1; |
| } |
| | stmt |
| { if ($1 != NULL) |
| $$ = list_make1($1); |
| else |
| $$ = NIL; |
| } |
| ; |
| |
| stmt : |
| AlterDatabaseStmt |
| | AlterDatabaseSetStmt |
| | AlterDomainStmt |
| | AlterFdwStmt |
| | AlterForeignServerStmt |
| | AlterFunctionStmt |
| | AlterGroupStmt |
| | AlterObjectSchemaStmt |
| | AlterOwnerStmt |
| | AlterQueueStmt |
| | AlterRoleSetStmt |
| | AlterRoleStmt |
| | AlterSeqStmt |
| | AlterTableStmt |
| | AlterTypeStmt |
| | AlterUserMappingStmt |
| | AlterUserSetStmt |
| | AlterUserStmt |
| | AnalyzeStmt |
| | CheckPointStmt |
| | ClosePortalStmt |
| | ClusterStmt |
| | CommentStmt |
| | ConstraintsSetStmt |
| | CopyStmt |
| | CreateAsStmt |
| | CreateAssertStmt |
| | CreateCastStmt |
| | CreateConversionStmt |
| | CreateDomainStmt |
| | CreateExternalStmt |
| | CreateFdwStmt |
| | CreateFileSpaceStmt |
| | CreateForeignServerStmt |
| | CreateForeignStmt |
| | CreateFunctionStmt |
| | CreateGroupStmt |
| | CreateOpClassStmt |
| | CreatePLangStmt |
| | CreateQueueStmt |
| | CreateSchemaStmt |
| | CreateSeqStmt |
| | CreateStmt |
| | CreateTableSpaceStmt |
| | CreateTrigStmt |
| | CreateRoleStmt |
| | CreateUserStmt |
| | CreateUserMappingStmt |
| | CreatedbStmt |
| | DeallocateStmt |
| | DeclareCursorStmt |
| | DefineStmt |
| | DeleteStmt |
| | DropAssertStmt |
| | DropCastStmt |
| | DropFdwStmt |
| | DropForeignServerStmt |
| | DropGroupStmt |
| | DropOpClassStmt |
| | DropOwnedStmt |
| | DropPLangStmt |
| | DropQueueStmt |
| | DropRuleStmt |
| | DropStmt |
| | DropTrigStmt |
| | DropRoleStmt |
| | DropUserMappingStmt |
| | DropUserStmt |
| | DropdbStmt |
| | ExecuteStmt |
| | ExplainStmt |
| | FetchStmt |
| | GrantStmt |
| | GrantRoleStmt |
| | IndexStmt |
| | InsertStmt |
| | ListenStmt |
| | LoadStmt |
| | LockStmt |
| | NotifyStmt |
| | PrepareStmt |
| | ReassignOwnedStmt |
| | ReindexStmt |
| | RemoveAggrStmt |
| | RemoveFuncStmt |
| | RemoveOperStmt |
| | RenameStmt |
| | RevokeStmt |
| | RevokeRoleStmt |
| | RuleStmt |
| | SelectStmt |
| | TransactionStmt |
| | TruncateStmt |
| | UnlistenStmt |
| | UpdateStmt |
| | VacuumStmt |
| | VariableResetStmt |
| | VariableSetStmt |
| | VariableShowStmt |
| | ViewStmt |
| | /*EMPTY*/ |
| { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Create a new Postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| size_unit: '%' {$$ = makeString("%"); } | |
| KB {$$ = makeString("kb"); } | |
| MB {$$ = makeString("mb"); } | |
| GB {$$ = makeString("gb"); } | |
| TB {$$ = makeString("tb"); } | |
| PB {$$ = makeString("pb"); } |
| ; |
| |
| resqueue_attr_definition: |
| '(' resqueue_attr_def_list ')' |
| { |
| $$ = $2; |
| } |
| ; |
| |
| resqueue_attr_def_list: |
| resqueue_attr_def_elem |
| { |
| $$ = list_make1($1); |
| } |
| | resqueue_attr_def_list ',' resqueue_attr_def_elem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| resqueue_attr_def_elem: |
| ColLabel '=' Sconst |
| { |
| $$ = makeDefElem($1, (Node *)makeString($3)); |
| } |
| | ColLabel '=' '(' IntegerOnly size_unit ',' IntegerOnly size_unit ')' |
| { |
| char valuestr[256]; |
| snprintf(valuestr, sizeof(valuestr), "(%ld%s,%ld%s)", |
| $4->val.ival, $5->val.str, |
| $7->val.ival, $8->val.str); |
| char *permstr = palloc0(sizeof(char)*(strlen(valuestr)+1)); |
| strcpy(permstr, valuestr); |
| $$ = makeDefElem($1, (Node *)makeString(permstr)); |
| } |
| | ColLabel '=' IntegerOnly size_unit |
| { |
| char valuestr[256]; |
| /*snprintf(valuestr, sizeof(valuestr), "(0%s,%ld%s)", |
| $4->val.str, |
| $3->val.ival, |
| $4->val.str);*/ |
| snprintf(valuestr, sizeof(valuestr), "%ld%s", |
| $3->val.ival, |
| $4->val.str); |
| char *permstr = palloc0(sizeof(char)*(strlen(valuestr)+1)); |
| strcpy(permstr, valuestr); |
| $$ = makeDefElem($1, (Node *)makeString(permstr)); |
| } |
| | ColLabel '=' '(' IntegerOnly ',' IntegerOnly ')' |
| { |
| char valuestr[256]; |
| snprintf(valuestr, sizeof(valuestr), "(%ld,%ld)", |
| $4->val.ival, |
| $6->val.ival); |
| char *permstr = palloc0(sizeof(char)*(strlen(valuestr)+1)); |
| strcpy(permstr, valuestr); |
| $$ = makeDefElem($1, (Node *)makeString(permstr)); |
| } |
| | ColLabel '=' NumericOnly |
| { |
| /*char valuestr[256]; |
| snprintf(valuestr, sizeof(valuestr), "(0,%ld)", |
| $3->val.ival); |
| snprintf(valuestr, sizeof(valuestr), "%ld", |
| $3->val.ival); |
| char *permstr = palloc0(sizeof(char)*(strlen(valuestr)+1)); |
| strcpy(permstr, valuestr); |
| $$ = makeDefElem($1, (Node *)makeString(permstr));*/ |
| $$ = makeDefElem($1, (Node *)$3); |
| } |
| | ColLabel |
| { |
| $$ = makeDefElem($1, NULL); |
| } |
| ; |
| |
| |
| CreateQueueStmt: |
| CREATE RESOURCE QUEUE QueueId WITH resqueue_attr_definition |
| { |
| CreateQueueStmt *n = makeNode(CreateQueueStmt); |
| DefElem *def1 = |
| makeDefElem(WITHLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| n->queue = $4; /* Set queue name. */ |
| n->options = list_concat(list_make1(def1), $6); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Alter a postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| AlterQueueStmt: |
| ALTER RESOURCE QUEUE QueueId WITH resqueue_attr_definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem(WITHLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem(WITHOUTLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| n->queue = $4; |
| n->options = list_concat(list_make1(def1), $6); |
| n->options = lappend(n->options, def2); |
| $$ = (Node *)n; |
| } |
| | ALTER RESOURCE QUEUE QueueId WITHOUT resqueue_attr_definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem(WITHLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem(WITHOUTLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| n->queue = $4; |
| n->options = list_make1(def1); |
| n->options = list_concat(lappend(n->options, def2), $6); |
| $$ = (Node *)n; |
| } |
| | ALTER RESOURCE QUEUE QueueId WITH resqueue_attr_definition |
| WITHOUT definition |
| { |
| AlterQueueStmt *n = makeNode(AlterQueueStmt); |
| DefElem *def1 = /* mark start of WITH items */ |
| makeDefElem(WITHLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| DefElem *def2 = /* mark start of WITHOUT items */ |
| makeDefElem(WITHOUTLISTSTART_TAG, |
| (Node *)makeInteger(TRUE)); |
| n->queue = $4; |
| n->options = list_concat(list_make1(def1), $6); |
| n->options = list_concat(lappend(n->options, def2), $8); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Drop a postgres Resource Queue |
| * |
| *****************************************************************************/ |
| |
| DropQueueStmt: |
| DROP RESOURCE QUEUE QueueId |
| { |
| DropQueueStmt *n = makeNode(DropQueueStmt); |
| n->queue = $4; |
| $$ = (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; |
| n->roleOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| opt_with: WITH {} |
| | /*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 OptRoleElem { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptRoleElem: |
| PASSWORD Sconst |
| { |
| $$ = makeDefElem("password", |
| (Node *)makeString($2)); |
| } |
| | PASSWORD NULL_P |
| { |
| $$ = makeDefElem("password", NULL); |
| } |
| | ENCRYPTED PASSWORD Sconst |
| { |
| $$ = makeDefElem("encryptedPassword", |
| (Node *)makeString($3)); |
| } |
| | UNENCRYPTED PASSWORD Sconst |
| { |
| $$ = makeDefElem("unencryptedPassword", |
| (Node *)makeString($3)); |
| } |
| | SUPERUSER_P |
| { |
| $$ = makeDefElem("superuser", (Node *)makeInteger(TRUE)); |
| } |
| | NOSUPERUSER |
| { |
| $$ = makeDefElem("superuser", (Node *)makeInteger(FALSE)); |
| } |
| | INHERIT |
| { |
| $$ = makeDefElem("inherit", (Node *)makeInteger(TRUE)); |
| } |
| | NOINHERIT |
| { |
| $$ = makeDefElem("inherit", (Node *)makeInteger(FALSE)); |
| } |
| | CREATEDB |
| { |
| $$ = makeDefElem("createdb", (Node *)makeInteger(TRUE)); |
| } |
| | NOCREATEDB |
| { |
| $$ = makeDefElem("createdb", (Node *)makeInteger(FALSE)); |
| } |
| | CREATEROLE |
| { |
| $$ = makeDefElem("createrole", (Node *)makeInteger(TRUE)); |
| } |
| | NOCREATEROLE |
| { |
| $$ = makeDefElem("createrole", (Node *)makeInteger(FALSE)); |
| } |
| | CREATEUSER |
| { |
| /* For backwards compatibility, synonym for SUPERUSER */ |
| $$ = makeDefElem("superuser", (Node *)makeInteger(TRUE)); |
| } |
| | NOCREATEUSER |
| { |
| $$ = makeDefElem("superuser", (Node *)makeInteger(FALSE)); |
| } |
| | LOGIN_P |
| { |
| $$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE)); |
| } |
| | NOLOGIN_P |
| { |
| $$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE)); |
| } |
| | CONNECTION LIMIT SignedIconst |
| { |
| $$ = makeDefElem("connectionlimit", (Node *)makeInteger($3)); |
| } |
| | VALID UNTIL Sconst |
| { |
| $$ = makeDefElem("validUntil", (Node *)makeString($3)); |
| } |
| | RESOURCE QUEUE any_name |
| { |
| $$ = makeDefElem("resourceQueue", (Node *)$3); |
| } |
| /* Supported but not documented for roles, for use by ALTER GROUP. */ |
| | USER name_list |
| { |
| $$ = makeDefElem("rolemembers", (Node *)$2); |
| } |
| /* The following are not supported by ALTER ROLE/USER/GROUP */ |
| | SYSID Iconst |
| { |
| $$ = makeDefElem("sysid", (Node *)makeInteger($2)); |
| } |
| | ADMIN name_list |
| { |
| $$ = makeDefElem("adminmembers", (Node *)$2); |
| } |
| | ROLE name_list |
| { |
| $$ = makeDefElem("rolemembers", (Node *)$2); |
| } |
| | IN_P ROLE name_list |
| { |
| $$ = makeDefElem("addroleto", (Node *)$3); |
| } |
| | IN_P GROUP_P name_list |
| { |
| $$ = makeDefElem("addroleto", (Node *)$3); |
| } |
| | CREATEEXTTABLE exttab_auth_list |
| { |
| $$ = makeDefElem("exttabauth", (Node *)$2); |
| } |
| | NOCREATEEXTTABLE exttab_auth_list |
| { |
| $$ = makeDefElem("exttabnoauth", (Node *)$2); |
| } |
| | deny_login_role |
| { |
| $$ = makeDefElem("deny", (Node *)$1); |
| } |
| ; |
| |
| deny_login_role: DENY deny_interval { $$ = (Node *)$2; } |
| | DENY deny_point { $$ = (Node *)$2; } |
| ; |
| |
| deny_interval: BETWEEN deny_point AND deny_point |
| { |
| DenyLoginInterval *n = makeNode(DenyLoginInterval); |
| n->start = (DenyLoginPoint *)$2; |
| n->end = (DenyLoginPoint *)$4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| deny_day_specifier: Sconst { $$ = (Node *)makeString($1); } |
| | Iconst { $$ = (Node *)makeInteger($1); } |
| ; |
| |
| deny_point: DAY_P deny_day_specifier opt_time |
| { |
| DenyLoginPoint *n = makeNode(DenyLoginPoint); |
| n->day = (Value *)$2; |
| n->time = (Value *)$3; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_time: TIME Sconst { $$ = (Node *)makeString($2); } |
| | /* nothing */ { $$ = NULL; } |
| ; |
| |
| exttab_auth_list: |
| '(' keyvalue_list ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| keyvalue_list: |
| keyvalue_pair { $$ = list_make1($1); } |
| | keyvalue_list ',' keyvalue_pair { $$ = lappend($1, $3); } |
| ; |
| |
| keyvalue_pair: |
| ColLabel '=' Sconst |
| { |
| $$ = makeDefElem($1, (Node *)makeString($3)); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * 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; |
| n->roleOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql DBMS role |
| * |
| *****************************************************************************/ |
| |
| AlterRoleStmt: |
| ALTER ROLE RoleId opt_with OptAlterRoleList |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| n->role = $3; |
| n->action = +1; /* add, if there are members */ |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| AlterRoleSetStmt: |
| ALTER ROLE RoleId SET set_rest |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| n->role = $3; |
| n->variable = $5->name; |
| n->value = $5->args; |
| $$ = (Node *)n; |
| } |
| | ALTER ROLE RoleId VariableResetStmt |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| n->role = $3; |
| n->variable = ((VariableResetStmt *)$4)->name; |
| n->value = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* OptAlterRoleList is effectively OptRoleList with additional support for DROP DENY FOR. */ |
| OptAlterRoleList: |
| OptAlterRoleList OptAlterRoleElem { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptAlterRoleElem: |
| OptRoleElem { $$ = $1; } |
| | DROP DENY FOR deny_point { $$ = makeDefElem("drop_deny", $4); } |
| |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql DBMS user |
| * |
| *****************************************************************************/ |
| |
| AlterUserStmt: |
| ALTER USER RoleId opt_with OptAlterRoleList |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| n->role = $3; |
| n->action = +1; /* add, if there are members */ |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| AlterUserSetStmt: |
| ALTER USER RoleId SET set_rest |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| n->role = $3; |
| n->variable = $5->name; |
| n->value = $5->args; |
| $$ = (Node *)n; |
| } |
| | ALTER USER RoleId VariableResetStmt |
| { |
| AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); |
| n->role = $3; |
| n->variable = ((VariableResetStmt *)$4)->name; |
| n->value = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql DBMS role |
| * |
| * XXX Ideally this would have CASCADE/RESTRICT options, but since a role |
| * might own objects in multiple databases, there is presently no way to |
| * implement either cascading or restricting. Caveat DBA. |
| *****************************************************************************/ |
| |
| DropRoleStmt: |
| DROP ROLE name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->missing_ok = FALSE; |
| n->roles = $3; |
| $$ = (Node *)n; |
| } |
| | DROP ROLE IF_P EXISTS name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->missing_ok = TRUE; |
| n->roles = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql DBMS user |
| * |
| * XXX Ideally this would have CASCADE/RESTRICT options, but since a user |
| * might own objects in multiple databases, there is presently no way to |
| * implement either cascading or restricting. Caveat DBA. |
| *****************************************************************************/ |
| |
| DropUserStmt: |
| DROP USER name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->missing_ok = FALSE; |
| n->roles = $3; |
| $$ = (Node *)n; |
| } |
| | DROP USER IF_P EXISTS name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->roles = $5; |
| n->missing_ok = TRUE; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Create a postgresql group (role without login ability) |
| * |
| *****************************************************************************/ |
| |
| CreateGroupStmt: |
| CREATE GROUP_P RoleId opt_with OptRoleList |
| { |
| CreateRoleStmt *n = makeNode(CreateRoleStmt); |
| n->stmt_type = ROLESTMT_GROUP; |
| n->role = $3; |
| n->options = $5; |
| n->roleOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Alter a postgresql group |
| * |
| *****************************************************************************/ |
| |
| AlterGroupStmt: |
| ALTER GROUP_P RoleId add_drop USER name_list |
| { |
| AlterRoleStmt *n = makeNode(AlterRoleStmt); |
| n->role = $3; |
| n->action = $4; |
| n->options = list_make1(makeDefElem("rolemembers", |
| (Node *)$6)); |
| $$ = (Node *)n; |
| } |
| ; |
| |
| add_drop: ADD_P { $$ = +1; } |
| | DROP { $$ = -1; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Drop a postgresql group |
| * |
| * XXX see above notes about cascading DROP USER; groups have same problem. |
| *****************************************************************************/ |
| |
| DropGroupStmt: |
| DROP GROUP_P name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->missing_ok = FALSE; |
| n->roles = $3; |
| $$ = (Node *)n; |
| } |
| | DROP GROUP_P IF_P EXISTS name_list |
| { |
| DropRoleStmt *n = makeNode(DropRoleStmt); |
| n->missing_ok = TRUE; |
| n->roles = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a schema |
| * |
| *****************************************************************************/ |
| |
| CreateSchemaStmt: |
| CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| /* One can omit the schema name or the authorization id. */ |
| if ($3 != NULL) |
| n->schemaname = $3; |
| else |
| n->schemaname = $5; |
| n->authid = $5; |
| n->schemaElts = $6; |
| n->schemaOid = 0; |
| $$ = (Node *)n; |
| } |
| | CREATE SCHEMA ColId OptSchemaEltList |
| { |
| CreateSchemaStmt *n = makeNode(CreateSchemaStmt); |
| /* ...but not both */ |
| n->schemaname = $3; |
| n->authid = NULL; |
| n->schemaElts = $4; |
| n->schemaOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptSchemaName: |
| ColId { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptSchemaEltList: |
| OptSchemaEltList schema_stmt { $$ = 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 SQL92 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: var_name TO var_list_or_default |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = $1; |
| n->args = $3; |
| $$ = n; |
| } |
| | var_name '=' var_list_or_default |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = $1; |
| n->args = $3; |
| $$ = n; |
| } |
| | TIME ZONE zone_value |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "timezone"; |
| if ($3 != NULL) |
| n->args = list_make1($3); |
| $$ = n; |
| } |
| | TRANSACTION transaction_mode_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "TRANSACTION"; |
| n->args = $2; |
| $$ = n; |
| } |
| | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "SESSION CHARACTERISTICS"; |
| n->args = $5; |
| $$ = n; |
| } |
| | NAMES opt_encoding |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "client_encoding"; |
| if ($2 != NULL) |
| n->args = list_make1(makeStringConst($2, NULL, @2)); |
| $$ = n; |
| } |
| | ROLE ColId_or_Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "role"; |
| n->args = list_make1(makeStringConst($2, NULL, @2)); |
| $$ = n; |
| } |
| | SESSION AUTHORIZATION ColId_or_Sconst |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "session_authorization"; |
| n->args = list_make1(makeStringConst($3, NULL, @3)); |
| $$ = n; |
| } |
| | SESSION AUTHORIZATION DEFAULT |
| { |
| VariableSetStmt *n = makeNode(VariableSetStmt); |
| n->name = "session_authorization"; |
| n->args = NIL; |
| $$ = n; |
| } |
| ; |
| |
| var_name: |
| ColId { $$ = $1; } |
| | var_name '.' ColId |
| { |
| int qLen = strlen($1); |
| char* qualName = palloc(qLen + strlen($3) + 2); |
| strcpy(qualName, $1); |
| qualName[qLen] = '.'; |
| strcpy(qualName + qLen + 1, $3); |
| $$ = qualName; |
| } |
| ; |
| |
| var_list_or_default: |
| var_list { $$ = $1; } |
| | DEFAULT { $$ = NIL; } |
| ; |
| |
| var_list: var_value { $$ = list_make1($1); } |
| | var_list ',' var_value { $$ = lappend($1, $3); } |
| ; |
| |
| var_value: opt_boolean |
| { $$ = makeStringConst($1, NULL, @1); } |
| | ColId_or_Sconst |
| { $$ = makeStringConst($1, NULL, @1); } |
| | NumericOnly |
| { $$ = makeAConst($1, @1); } |
| ; |
| |
| iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; } |
| | READ COMMITTED { $$ = "read committed"; } |
| | REPEATABLE READ { $$ = "repeatable read"; } |
| | SERIALIZABLE { $$ = "serializable"; } |
| ; |
| |
| opt_boolean: |
| TRUE_P { $$ = "true"; } |
| | FALSE_P { $$ = "false"; } |
| | ON { $$ = "on"; } |
| | OFF { $$ = "off"; } |
| ; |
| |
| /* Timezone values can be: |
| * - a string such as 'pst8pdt' |
| * - an identifier such as "pst8pdt" |
| * - an integer or floating point number |
| * - a time interval per SQL99 |
| * ColId gives reduce/reduce errors against ConstInterval and LOCAL, |
| * so use IDENT and reject anything which is a reserved word. |
| */ |
| zone_value: |
| Sconst |
| { |
| $$ = makeStringConst($1, NULL, @1); |
| } |
| | IDENT |
| { |
| $$ = makeStringConst($1, NULL, @1); |
| } |
| | ConstInterval Sconst opt_interval |
| { |
| A_Const *n = (A_Const *) makeStringConst($2, $1, @2); |
| if ($3 != INTERVAL_FULL_RANGE) |
| { |
| if (($3 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("time zone interval must be HOUR or HOUR TO MINUTE"), |
| scanner_errposition(@3))); |
| n->typname->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3); |
| } |
| $$ = (Node *)n; |
| } |
| | ConstInterval '(' Iconst ')' Sconst opt_interval |
| { |
| A_Const *n = (A_Const *) makeStringConst($5, $1, @5); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision must not be negative", $3), |
| scanner_errposition(@3))); |
| if ($3 > MAX_INTERVAL_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_INTERVAL_PRECISION))); |
| $3 = MAX_INTERVAL_PRECISION; |
| } |
| |
| if (($6 != INTERVAL_FULL_RANGE) |
| && (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("time zone interval must be HOUR or HOUR TO MINUTE"))); |
| |
| n->typname->typmod = INTERVAL_TYPMOD($3, $6); |
| |
| $$ = (Node *)n; |
| } |
| | NumericOnly { $$ = makeAConst($1, @1); } |
| | DEFAULT { $$ = NULL; } |
| | LOCAL { $$ = NULL; } |
| ; |
| |
| opt_encoding: |
| Sconst { $$ = $1; } |
| | DEFAULT { $$ = NULL; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ColId_or_Sconst: |
| ColId { $$ = $1; } |
| | SCONST { $$ = $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; |
| } |
| ; |
| |
| VariableResetStmt: |
| RESET var_name |
| { |
| VariableResetStmt *n = makeNode(VariableResetStmt); |
| n->name = $2; |
| $$ = (Node *) n; |
| } |
| | RESET TIME ZONE |
| { |
| VariableResetStmt *n = makeNode(VariableResetStmt); |
| n->name = "timezone"; |
| $$ = (Node *) n; |
| } |
| | RESET TRANSACTION ISOLATION LEVEL |
| { |
| VariableResetStmt *n = makeNode(VariableResetStmt); |
| n->name = "transaction_isolation"; |
| $$ = (Node *) n; |
| } |
| | RESET SESSION AUTHORIZATION |
| { |
| VariableResetStmt *n = makeNode(VariableResetStmt); |
| n->name = "session_authorization"; |
| $$ = (Node *) n; |
| } |
| | RESET ALL |
| { |
| VariableResetStmt *n = makeNode(VariableResetStmt); |
| 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; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER [ TABLE | INDEX ] variations |
| * |
| *****************************************************************************/ |
| |
| AlterTableStmt: |
| ALTER TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| n->relation = $3; |
| n->cmds = $4; |
| n->relkind = OBJECT_TABLE; |
| $$ = (Node *)n; |
| } |
| | ALTER EXTERNAL TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| n->relation = $4; |
| n->cmds = $5; |
| n->relkind = OBJECT_EXTTABLE; |
| $$ = (Node *)n; |
| } |
| | ALTER FOREIGN TABLE relation_expr alter_table_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->relation = $4; |
| n->cmds = $5; |
| n->relkind = OBJECT_FOREIGNTABLE; |
| $$ = (Node *)n; |
| } |
| | ALTER INDEX relation_expr alter_rel_cmds |
| { |
| AlterTableStmt *n = makeNode(AlterTableStmt); |
| n->relation = $3; |
| n->cmds = $4; |
| n->relkind = OBJECT_INDEX; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_table_cmds: |
| alter_table_cmd { $$ = list_make1($1); } |
| | alter_table_cmds ',' alter_table_cmd { $$ = lappend($1, $3); } |
| ; |
| |
| /* Subcommands that are for ALTER TABLE only */ |
| alter_table_cmd: |
| /* ALTER TABLE <relation> ADD [COLUMN] <coldef> */ |
| ADD_P opt_column columnDef |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_AddColumn; |
| n->def = $3; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <relation> 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 <relation> 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 <relation> 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 <relation> ALTER [COLUMN] <colname> SET STATISTICS <IntegerOnly> */ |
| | ALTER opt_column ColId SET STATISTICS IntegerOnly |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetStatistics; |
| n->name = $3; |
| n->def = (Node *) $6; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <relation> 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 <relation> 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; |
| $$ = (Node *)n; |
| } |
| /* |
| * ALTER TABLE <relation> ALTER [COLUMN] <colname> TYPE <typename> |
| * [ USING <expression> ] |
| */ |
| | ALTER opt_column ColId TYPE_P Typename alter_using |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_AlterColumnType; |
| n->name = $3; |
| n->def = (Node *) $5; |
| n->transform = $6; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <relation> ADD CONSTRAINT ... */ |
| | ADD_P TableConstraint |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_AddConstraint; |
| n->def = $2; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <relation> 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; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <relation> SET WITHOUT OIDS */ |
| | 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> ENABLE TRIGGER <trig> */ |
| | ENABLE_P TRIGGER name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_EnableTrig; |
| n->name = $3; |
| $$ = (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> INHERIT <parent> [( column_list )] */ |
| | INHERIT qualified_name opt_inherited_column_list |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_AddInherit; |
| n->def = (Node *)list_make2($2, $3); |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> NO INHERIT <parent> */ |
| | NO INHERIT qualified_name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_DropInherit; |
| n->def = (Node *) $3; |
| $$ = (Node *)n; |
| } |
| /* ALTER TABLE <name> SET [WITH] [DISTRIBUTED BY] */ |
| /* distro only */ |
| | SET DistributedBy |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2(NULL, $2); |
| $$ = (Node *)n; |
| } |
| /* storage and distro */ |
| | SET WITH definition DistributedBy |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2($3, $4); |
| $$ = (Node *)n; |
| } |
| /* storage only */ |
| | SET WITH definition |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetDistributedBy; |
| n->def = (Node *) list_make2($3, NULL); |
| $$ = (Node *)n; |
| } |
| | alter_table_partition_cmd |
| { |
| $$ = $1; |
| } |
| | alter_rel_cmd |
| { |
| $$ = $1; |
| } |
| ; |
| |
| opt_table_partition_split_into: |
| INTO '(' |
| alter_table_partition_id_spec_with_opt_default ',' |
| alter_table_partition_id_spec_with_opt_default ')' |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| pc->partid = (Node *)$3; |
| pc->arg1 = (Node *)$5; |
| pc->arg2 = NULL; |
| pc->location = @5; |
| $$ = (Node *)pc; |
| } |
| | /*EMPTY*/ { $$ = NULL; /* default */ } |
| ; |
| |
| opt_table_partition_merge_into: |
| INTO |
| alter_table_partition_id_spec_with_opt_default |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| pc->partid = (Node *)$2; |
| pc->arg1 = NULL; |
| pc->arg2 = NULL; |
| pc->location = @2; |
| $$ = (Node *)pc; |
| } |
| |
| | /*EMPTY*/ { $$ = NULL; /* default */ } |
| ; |
| |
| table_partition_modify: |
| TabPartitionBoundarySpecStart |
| OptTabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| PartitionBoundSpec *bs = makeNode(PartitionBoundSpec); |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->partName = NULL; |
| n->boundSpec = (Node *)bs; |
| n->subSpec = NULL; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = NULL; |
| n->AddPartDesc = NULL; |
| |
| bs->partStart = $1; |
| bs->partEnd = $2; |
| bs->partEvery = $3; |
| bs->everyGenList = NIL; |
| bs->pWithTnameStr = NULL; |
| bs->location = @1; |
| |
| pc->partid = NULL; |
| pc->arg1 = (Node *)makeDefElem("START", NULL); |
| pc->arg2 = (Node *)n; |
| pc->location = @1; |
| $$ = (Node *)pc; |
| } |
| | TabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| PartitionBoundSpec *bs = makeNode(PartitionBoundSpec); |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->partName = NULL; |
| n->boundSpec = (Node *)bs; |
| n->subSpec = NULL; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = NULL; |
| n->AddPartDesc = NULL; |
| |
| bs->partStart = NULL; |
| bs->partEnd = $1; |
| bs->partEvery = $2; |
| bs->everyGenList = NIL; |
| bs->pWithTnameStr = NULL; |
| bs->location = @1; |
| |
| pc->partid = NULL; |
| pc->arg1 = (Node *)makeDefElem("END", NULL); |
| pc->arg2 = (Node *)n; |
| pc->location = @1; |
| $$ = (Node *)pc; |
| } |
| | add_drop part_values_clause |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| PartitionValuesSpec *vs = makeNode(PartitionValuesSpec); |
| PartitionElem *n = makeNode(PartitionElem); |
| |
| n->partName = NULL; |
| n->boundSpec = (Node *)vs; |
| n->subSpec = NULL; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = NULL; |
| n->AddPartDesc = NULL; |
| |
| vs->partValues = $2; |
| vs->location = @2; |
| |
| pc->partid = NULL; |
| if (1 == $1) |
| pc->arg1 = (Node *)makeDefElem("ADD", NULL); |
| else |
| pc->arg1 = (Node *)makeDefElem("DROP", NULL); |
| pc->arg2 = (Node *)n; |
| pc->location = @2; |
| $$ = (Node *)pc; |
| } |
| ; |
| |
| opt_table_partition_exchange_validate: |
| WITH VALIDATION { $$ = +1; } |
| | WITHOUT VALIDATION { $$ = +0; } |
| | /*EMPTY*/ { $$ = +1; /* default */ } |
| ; |
| |
| alter_table_partition_id_spec: |
| PartitionColId |
| { |
| AlterPartitionId *n = makeNode(AlterPartitionId); |
| n->idtype = AT_AP_IDName; |
| n->partiddef = (Node *)makeString($1); |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | FOR |
| '(' TabPartitionBoundarySpecValList ')' |
| { |
| AlterPartitionId *n = makeNode(AlterPartitionId); |
| n->idtype = AT_AP_IDValue; |
| n->partiddef = (Node *)$3; |
| n->location = @3; |
| $$ = (Node *)n; |
| } |
| | FOR '(' function_name '(' NumericOnly ')' ')' |
| { |
| AlterPartitionId *n = makeNode(AlterPartitionId); |
| n->idtype = AT_AP_IDRank; |
| n->partiddef = (Node *)$5; |
| n->location = @5; |
| |
| /* allow RANK only */ |
| if (!(strcmp($3, "rank") == 0)) |
| yyerror("syntax error"); |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_table_partition_id_spec_with_opt_default: |
| PARTITION alter_table_partition_id_spec |
| { |
| AlterPartitionId *n = (AlterPartitionId*)$2; |
| $$ = (Node *)n; |
| } |
| | DEFAULT PARTITION alter_table_partition_id_spec |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Cannot specify a name, rank, " |
| "or value for a DEFAULT partition " |
| "in this context"))); |
| } |
| | DEFAULT PARTITION |
| { |
| AlterPartitionId *n = makeNode(AlterPartitionId); |
| n->idtype = AT_AP_IDDefault; |
| n->partiddef = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_table_partition_cmd: |
| ADD_P PARTITION |
| OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabSubPartitionSpec |
| |
| { |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterPartitionCmd *pc2 = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Node *ct = makeAddPartitionCreateStmt($4, $5); |
| PartitionElem *pelem = makeNode(PartitionElem); |
| |
| pid->idtype = AT_AP_IDNone; |
| pid->location = @3; |
| pid->partiddef = NULL; |
| |
| pc->partid = (Node *)pid; |
| |
| pelem->partName = NULL; |
| pelem->boundSpec = $3; |
| pelem->subSpec = $5; |
| pelem->location = @3; |
| pelem->isDefault = 0; |
| pelem->storeAttr = $4; |
| pelem->AddPartDesc = NULL; |
| |
| pc2->arg1 = (Node *)pelem; |
| pc2->arg2 = (Node *)list_make1(ct); |
| pc2->location = @3; |
| |
| pc->arg1 = (Node *)makeInteger(FALSE); /* not default */ |
| pc->arg2 = (Node *)pc2; |
| pc->location = @3; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ADD_P DEFAULT PARTITION |
| alter_table_partition_id_spec |
| OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabSubPartitionSpec |
| { |
| AlterPartitionId *pid = (AlterPartitionId *)$4; |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterPartitionCmd *pc2 = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Node *ct = makeAddPartitionCreateStmt($6, $7); |
| PartitionElem *pelem = makeNode(PartitionElem); |
| |
| if (pid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Can only ADD a partition by name"), |
| errOmitLocation(true))); |
| |
| pc->partid = (Node *)pid; |
| |
| pelem->partName = NULL; |
| pelem->boundSpec = $5; |
| pelem->subSpec = $7; |
| pelem->location = @5; |
| pelem->isDefault = true; |
| pelem->storeAttr = $6; |
| pelem->AddPartDesc = NULL; |
| |
| pc2->arg1 = (Node *)pelem; |
| pc2->arg2 = (Node *)list_make1(ct); |
| pc2->location = @5; |
| |
| pc->arg1 = (Node *)makeInteger(true); |
| pc->arg2 = (Node *)pc2; |
| pc->location = @5; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ADD_P PARTITION |
| alter_table_partition_id_spec |
| OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabSubPartitionSpec |
| { |
| AlterPartitionId *pid = (AlterPartitionId *)$3; |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterPartitionCmd *pc2 = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Node *ct = makeAddPartitionCreateStmt($5, |
| $6); |
| PartitionElem *pelem = makeNode(PartitionElem); |
| |
| if (pid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Can only ADD a partition by name"))); |
| |
| pc->partid = (Node *)pid; |
| |
| pelem->partName = NULL; |
| pelem->boundSpec = $4; |
| pelem->subSpec = $6; |
| pelem->location = @4; |
| pelem->isDefault = false; |
| pelem->storeAttr = $5; |
| pelem->AddPartDesc = NULL; |
| |
| pc2->arg1 = (Node *)pelem; |
| pc2->arg2 = (Node *)list_make1(ct); |
| pc2->location = @4; |
| |
| pc->arg1 = (Node *)makeInteger(false); |
| pc->arg2 = (Node *)pc2; |
| pc->location = @4; |
| |
| n->subtype = AT_PartAdd; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | ALTER |
| alter_table_partition_id_spec_with_opt_default |
| alter_table_cmd |
| { |
| /* NOTE: only allow a subset of valid ALTER TABLE |
| cmds for partitions. |
| */ |
| |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)$3; |
| pc->arg2 = NULL; |
| pc->location = @3; |
| |
| n->subtype = AT_PartAlter; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | partition_coalesce_keyword PARTITION |
| { |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pid->idtype = AT_AP_IDNone; |
| pid->location = @2; |
| pid->partiddef = NULL; |
| |
| pc->partid = (Node *)pid; |
| pc->arg1 = NULL; |
| pc->arg2 = NULL; |
| pc->location = @2; |
| |
| n->subtype = AT_PartCoalesce; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | partition_coalesce_keyword PARTITION |
| alter_table_partition_id_spec |
| { |
| AlterPartitionId *pid = (AlterPartitionId *)$3; |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| if (pid->idtype != AT_AP_IDName) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Can only COALESCE a partition by name"))); |
| |
| pc->partid = (Node *)pid; |
| pc->arg1 = NULL; |
| pc->arg2 = NULL; |
| pc->location = @3; |
| |
| n->subtype = AT_PartCoalesce; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | DROP PARTITION IF_P EXISTS |
| alter_table_partition_id_spec |
| opt_drop_behavior |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| DropStmt *ds = makeNode(DropStmt); |
| |
| ds->missing_ok = TRUE; |
| ds->behavior = $6; |
| |
| /* |
| build an (incomplete) drop statement for arg1: |
| fill in the rest after the partition id spec is |
| validated |
| */ |
| |
| pc->partid = (Node *)$5; |
| pc->arg1 = (Node *)ds; |
| pc->arg2 = NULL; |
| pc->location = @5; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | DROP DEFAULT PARTITION IF_P EXISTS |
| opt_drop_behavior |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| DropStmt *ds = makeNode(DropStmt); |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| |
| pid->idtype = AT_AP_IDDefault; |
| pid->partiddef = NULL; |
| pid->location = @2; |
| |
| ds->missing_ok = TRUE; |
| ds->behavior = $6; |
| |
| /* |
| build an (incomplete) drop statement for arg1: |
| fill in the rest after the partition id spec is |
| validated |
| */ |
| |
| pc->partid = (Node *)pid; |
| pc->arg1 = (Node *)ds; |
| pc->arg2 = NULL; |
| pc->location = @3; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | DROP |
| alter_table_partition_id_spec_with_opt_default |
| opt_drop_behavior |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| DropStmt *ds = makeNode(DropStmt); |
| |
| ds->missing_ok = FALSE; |
| ds->behavior = $3; |
| |
| /* |
| build an (incomplete) drop statement for arg1: |
| fill in the rest after the partition id spec is |
| validated |
| */ |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)ds; |
| pc->arg2 = NULL; |
| pc->location = @2; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | DROP PARTITION |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| DropStmt *ds = makeNode(DropStmt); |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| |
| ds->missing_ok = FALSE; |
| ds->behavior = DROP_RESTRICT; /* default */ |
| |
| /* |
| build an (incomplete) drop statement for arg1: |
| fill in the rest after the partition id spec is |
| validated |
| */ |
| |
| /* just try to drop the first partition if not specified */ |
| pid->idtype = AT_AP_IDNone; |
| pid->location = @2; |
| |
| pc->partid = (Node *)pid; |
| pc->arg1 = (Node *)ds; |
| pc->arg2 = NULL; |
| pc->location = @2; |
| |
| n->subtype = AT_PartDrop; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | EXCHANGE |
| alter_table_partition_id_spec_with_opt_default |
| WITH TABLE qualified_name |
| opt_table_partition_exchange_validate |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterPartitionCmd *pc2 = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)$5; |
| pc->arg2 = (Node *)pc2; |
| pc2->arg1 = (Node *)makeInteger($6); |
| pc->location = @5; |
| |
| n->subtype = AT_PartExchange; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | MERGE |
| alter_table_partition_id_spec_with_opt_default ',' |
| alter_table_partition_id_spec_with_opt_default |
| opt_table_partition_merge_into |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| if (!gp_enable_hash_partitioned_tables) |
| { |
| yyerror("syntax error"); |
| } |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)$4; |
| pc->arg2 = (Node *)$5; |
| pc->location = @4; |
| |
| n->subtype = AT_PartMerge; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | MODIFY |
| alter_table_partition_id_spec_with_opt_default |
| table_partition_modify |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| if (!gp_enable_hash_partitioned_tables) |
| { |
| yyerror("syntax error"); |
| } |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)$3; |
| pc->arg2 = NULL; |
| pc->location = @3; |
| |
| n->subtype = AT_PartModify; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | RENAME |
| alter_table_partition_id_spec_with_opt_default TO IDENT |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)makeString($4); |
| pc->arg2 = NULL; |
| pc->location = @4; |
| |
| n->subtype = AT_PartRename; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SET SUBPARTITION TEMPLATE |
| '(' TabSubPartitionElemList ')' |
| { |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterPartitionCmd *pc2 = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| Node *ct = NULL; |
| PartitionElem *pelem = makeNode(PartitionElem); |
| PartitionSpec *ps = makeNode(PartitionSpec); |
| |
| /* treat this case as similar to ADD PARTITION */ |
| |
| pid->idtype = AT_AP_IDName; |
| pid->location = @3; |
| pid->partiddef = |
| (Node *)makeString("subpartition_template"); |
| |
| pc->partid = (Node *)pid; |
| |
| /* build a subpartition spec and add it to CREATE TABLE */ |
| ps->partElem = $5; |
| ps->subSpec = NULL; |
| ps->istemplate = true; |
| ps->location = @4; |
| |
| ct = makeAddPartitionCreateStmt(NULL, |
| (Node *)ps); |
| |
| pelem->partName = NULL; |
| pelem->boundSpec = NULL; |
| pelem->subSpec = (Node *)ps; |
| pelem->location = @4; |
| /* |
| pelem->isDefault = false; |
| */ |
| pelem->isDefault = true; |
| pelem->storeAttr = NULL; |
| pelem->AddPartDesc = NULL; |
| |
| /* a little (temporary?) syntax check on templates */ |
| if (ps->partElem) |
| { |
| List *elems; |
| ListCell *lc; |
| Assert(IsA(ps->partElem, List)); |
| |
| elems = (List *)ps->partElem; |
| foreach(lc, elems) |
| { |
| PartitionElem *e = lfirst(lc); |
| |
| if (!IsA(e, PartitionElem)) |
| continue; |
| |
| if (e->subSpec) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("template cannot contain " |
| "specification for child " |
| "partition"))); |
| } |
| } |
| |
| pc2->arg1 = (Node *)pelem; |
| pc2->arg2 = (Node *)list_make1(ct); |
| pc2->location = @5; |
| |
| /* |
| pc->arg1 = (Node *)makeInteger(false); |
| */ |
| pc->arg1 = (Node *)makeInteger(true); |
| pc->arg2 = (Node *)pc2; |
| pc->location = @5; |
| |
| n->subtype = AT_PartSetTemplate; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SET SUBPARTITION TEMPLATE |
| '(' ')' |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = NULL; |
| pc->arg1 = NULL; |
| pc->arg2 = NULL; |
| pc->location = @4; |
| |
| n->subtype = AT_PartSetTemplate; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SPLIT |
| DEFAULT PARTITION TabPartitionBoundarySpecStart |
| TabPartitionBoundarySpecEnd |
| opt_table_partition_split_into |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| AlterPartitionId *pid = makeNode(AlterPartitionId); |
| |
| pid->idtype = AT_AP_IDDefault; |
| pid->partiddef = NULL; |
| pid->location = @2; |
| |
| pc->partid = (Node *)pid; |
| pc->arg1 = (Node *)list_make2($4, $5); |
| pc->arg2 = (Node *)$6; |
| pc->location = @5; |
| |
| n->subtype = AT_PartSplit; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | SPLIT |
| alter_table_partition_id_spec_with_opt_default AT |
| '(' part_values_or_spec_list ')' |
| opt_table_partition_split_into |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| |
| pc->partid = (Node *)$2; |
| |
| /* |
| * The first element of the list is only defined if |
| * we're doing default splits for range partitioning. |
| */ |
| pc->arg1 = (Node *)list_make2(NULL, $5); |
| pc->arg2 = (Node *)$7; |
| pc->location = @5; |
| |
| n->subtype = AT_PartSplit; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| | TRUNCATE |
| alter_table_partition_id_spec_with_opt_default |
| opt_drop_behavior |
| { |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| TruncateStmt *ts = makeNode(TruncateStmt); |
| |
| /* |
| build an (incomplete) truncate statement for arg1: |
| fill in the rest after the partition id spec is |
| validated |
| */ |
| ts->relations = NULL; |
| ts->behavior = $3; |
| |
| pc->partid = (Node *)$2; |
| pc->arg1 = (Node *)ts; |
| pc->arg2 = NULL; |
| pc->location = @2; |
| |
| n->subtype = AT_PartTruncate; |
| n->def = (Node *)pc; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_rel_cmds: |
| alter_rel_cmd { $$ = list_make1($1); } |
| | alter_rel_cmds ',' alter_rel_cmd { $$ = lappend($1, $3); } |
| ; |
| |
| /* Subcommands that are for ALTER TABLE or ALTER INDEX */ |
| alter_rel_cmd: |
| /* ALTER [TABLE|INDEX] <name> OWNER TO RoleId */ |
| OWNER TO RoleId |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_ChangeOwner; |
| n->name = $3; |
| $$ = (Node *)n; |
| } |
| /* ALTER [TABLE|INDEX] <name> SET TABLESPACE <tablespacename> */ |
| | SET TABLESPACE name |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetTableSpace; |
| n->name = $3; |
| $$ = (Node *)n; |
| } |
| /* ALTER [TABLE|INDEX] <name> SET (...) */ |
| | SET definition |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_SetRelOptions; |
| n->def = (Node *)$2; |
| $$ = (Node *)n; |
| } |
| /* ALTER [TABLE|INDEX] <name> RESET (...) */ |
| | RESET definition |
| { |
| AlterTableCmd *n = makeNode(AlterTableCmd); |
| n->subtype = AT_ResetRelOptions; |
| n->def = (Node *)$2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| alter_column_default: |
| SET DEFAULT a_expr |
| { |
| /* Treat SET DEFAULT NULL the same as DROP DEFAULT */ |
| if (exprIsNullConstant($3)) |
| $$ = NULL; |
| else |
| $$ = $3; |
| } |
| | DROP DEFAULT { $$ = NULL; } |
| ; |
| |
| opt_drop_behavior: |
| CASCADE { $$ = DROP_CASCADE; } |
| | RESTRICT { $$ = DROP_RESTRICT; } |
| | /*EMPTY*/ { $$ = DROP_RESTRICT; /* default */ } |
| ; |
| |
| alter_using: |
| USING a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * close <portalname> |
| * |
| *****************************************************************************/ |
| |
| ClosePortalStmt: |
| CLOSE name |
| { |
| ClosePortalStmt *n = makeNode(ClosePortalStmt); |
| n->portalname = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * COPY relname ['(' columnList ')'] FROM/TO file [WITH options] |
| * |
| * BINARY, OIDS, and DELIMITERS kept in old locations |
| * for backward compatibility. 2002-06-18 |
| * |
| * COPY ( SELECT ... ) TO file [WITH options] |
| * This form doesn't have the backwards-compatible option |
| * syntax. |
| * |
| *****************************************************************************/ |
| |
| CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids |
| copy_from copy_file_name copy_delimiter opt_with copy_opt_list |
| OptSingleRowErrorHandling |
| { |
| CopyStmt *n = makeNode(CopyStmt); |
| n->relation = $3; |
| n->query = NULL; |
| n->attlist = $4; |
| n->is_from = $6; |
| n->filename = $7; |
| n->sreh = $11; |
| n->partitions = NULL; |
| n->ao_segnos = NIL; |
| n->options = NIL; |
| n->err_aosegnos = NIL; |
| |
| /* Concatenate user-supplied flags */ |
| if ($2) |
| n->options = lappend(n->options, $2); |
| if ($5) |
| n->options = lappend(n->options, $5); |
| if ($8) |
| n->options = lappend(n->options, $8); |
| if ($10) |
| n->options = list_concat(n->options, $10); |
| $$ = (Node *)n; |
| } |
| | COPY select_with_parens TO copy_file_name opt_with |
| copy_opt_list |
| { |
| CopyStmt *n = makeNode(CopyStmt); |
| n->relation = NULL; |
| n->query = (Query *) $2; |
| n->attlist = NIL; |
| n->is_from = false; |
| n->filename = $4; |
| n->options = $6; |
| n->partitions = NULL; |
| n->ao_segnos = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| copy_from: |
| FROM { $$ = TRUE; } |
| | TO { $$ = 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_opt_list: |
| copy_opt_list copy_opt_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| copy_opt_item: |
| BINARY |
| { |
| $$ = makeDefElem("binary", (Node *)makeInteger(TRUE)); |
| } |
| | OIDS |
| { |
| $$ = makeDefElem("oids", (Node *)makeInteger(TRUE)); |
| } |
| | DELIMITER opt_as Sconst |
| { |
| $$ = makeDefElem("delimiter", (Node *)makeString($3)); |
| } |
| | NULL_P opt_as Sconst |
| { |
| $$ = makeDefElem("null", (Node *)makeString($3)); |
| } |
| | CSV |
| { |
| $$ = makeDefElem("csv", (Node *)makeInteger(TRUE)); |
| } |
| | HEADER_P |
| { |
| $$ = makeDefElem("header", (Node *)makeInteger(TRUE)); |
| } |
| | QUOTE opt_as Sconst |
| { |
| $$ = makeDefElem("quote", (Node *)makeString($3)); |
| } |
| | ESCAPE opt_as Sconst |
| { |
| $$ = makeDefElem("escape", (Node *)makeString($3)); |
| } |
| | FORCE QUOTE columnList |
| { |
| $$ = makeDefElem("force_quote", (Node *)$3); |
| } |
| | FORCE NOT NULL_P columnList |
| { |
| $$ = makeDefElem("force_notnull", (Node *)$4); |
| } |
| | FILL MISSING FIELDS |
| { |
| $$ = makeDefElem("fill_missing_fields", (Node *)makeInteger(TRUE)); |
| } |
| | NEWLINE opt_as Sconst |
| { |
| $$ = makeDefElem("newline", (Node *)makeString($3)); |
| } |
| ; |
| |
| /* The following exist for backward compatibility */ |
| |
| opt_binary: |
| BINARY |
| { |
| $$ = makeDefElem("binary", (Node *)makeInteger(TRUE)); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| opt_oids: |
| WITH OIDS |
| { |
| $$ = makeDefElem("oids", (Node *)makeInteger(TRUE)); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| copy_delimiter: |
| /* USING DELIMITERS kept for backward compatibility. 2002-06-15 */ |
| opt_using DELIMITERS Sconst |
| { |
| $$ = makeDefElem("delimiter", (Node *)makeString($3)); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| opt_using: |
| USING {} |
| | /*EMPTY*/ {} |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE TABLE relname |
| * |
| *****************************************************************************/ |
| |
| CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' |
| OptInherit OptWith OnCommitOption OptTableSpace OptDistributedBy |
| OptTabPartitionBy |
| { |
| CreateStmt *n = makeNode(CreateStmt); |
| |
| $4->istemp = $2; |
| n->base.relation = $4; |
| n->base.tableElts = $6; |
| n->base.inhRelations = $8; |
| n->base.constraints = NIL; |
| n->base.options = $9; |
| n->base.oncommit = $10; |
| n->base.tablespacename = $11; |
| n->base.distributedBy = $12; |
| n->base.partitionBy = $13; |
| n->oidInfo.relOid = 0; |
| n->oidInfo.comptypeOid = 0; |
| n->oidInfo.toastOid = 0; |
| n->oidInfo.toastIndexOid = 0; |
| n->oidInfo.toastComptypeOid = 0; |
| n->base.relKind = RELKIND_RELATION; |
| n->policy = 0; |
| n->base.postCreate = NULL; |
| |
| $$ = (Node *)n; |
| } |
| | CREATE OptTemp TABLE qualified_name OF qualified_name |
| '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptDistributedBy OptTabPartitionBy |
| { |
| /* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied |
| * by our inheritance capabilities. Let's try it... |
| */ |
| CreateStmt *n = makeNode(CreateStmt); |
| $4->istemp = $2; |
| n->base.relation = $4; |
| n->base.tableElts = $8; |
| n->base.inhRelations = list_make1($6); |
| n->base.constraints = NIL; |
| n->base.options = $10; |
| n->base.oncommit = $11; |
| n->base.tablespacename = $12; |
| n->base.distributedBy = $13; |
| n->base.partitionBy = $14; |
| n->oidInfo.relOid = 0; |
| n->oidInfo.comptypeOid = 0; |
| n->oidInfo.toastOid = 0; |
| n->oidInfo.toastIndexOid = 0; |
| n->oidInfo.toastComptypeOid = 0; |
| n->base.relKind = RELKIND_RELATION; |
| n->policy = 0; |
| n->base.postCreate = NULL; |
| |
| $$ = (Node *)n; |
| } |
| | CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' |
| ExtTypedesc FORMAT Sconst format_opt ext_opt_encoding_list OptDistributedBy OptTabPartitionBy |
| { |
| CreateExternalStmt *n = makeNode(CreateExternalStmt); |
| n->iswritable = TRUE; |
| n->isexternal = FALSE; |
| n->isweb = FALSE; |
| $4->istemp = $2; |
| n->base.relation = $4; |
| n->base.tableElts = $6; |
| n->exttypedesc = $8; |
| n->format = $10; |
| n->base.options = $11; |
| n->encoding = $12; |
| n->sreh = NULL; |
| n->base.distributedBy = $13; |
| n->base.partitionBy = $14; |
| n->policy = 0; |
| |
| /* various syntax checks for internal table implemented using pluggable storage */ |
| if(((ExtTableTypeDesc *) n->exttypedesc)->exttabletype != EXTTBL_TYPE_UNKNOWN) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("LOCATION or EXECUTE may not be used for native table"), |
| errhint("Use CREATE TABLE FORMAT or CREATE EXTERNAL TABLE instead"), |
| errOmitLocation(true))); |
| } |
| |
| ListCell *cell; |
| foreach (cell, n->base.tableElts) |
| { |
| Node *node = (Node *)lfirst(cell); |
| switch (nodeTag(node)) |
| { |
| case T_ColumnDef: |
| { |
| if (((ColumnDef *)node)->constraints != NIL) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Do not support column constraint"))); |
| } |
| } |
| break; |
| |
| case T_Constraint: |
| { |
| if (((Constraint *)node)->contype != CONSTR_PRIMARY) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Do not support table constraint other than primary key"))); |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| $$ = (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; since we have no modules |
| * the LOCAL keyword is really meaningless. |
| */ |
| OptTemp: TEMPORARY { $$ = TRUE; } |
| | TEMP { $$ = TRUE; } |
| | LOCAL TEMPORARY { $$ = TRUE; } |
| | LOCAL TEMP { $$ = TRUE; } |
| | GLOBAL TEMPORARY { $$ = TRUE; } |
| | GLOBAL TEMP { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| OptTableElementList: |
| TableElementList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TableElementList: |
| TableElement |
| { |
| $$ = list_make1($1); |
| } |
| | TableElementList ',' TableElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| TableElement: |
| columnDef { $$ = $1; } |
| | TableLikeClause { $$ = $1; } |
| | TableConstraint { $$ = $1; } |
| | column_reference_storage_directive { $$ = $1; } |
| ; |
| |
| column_reference_storage_directive: |
| COLUMN columnElem ENCODING definition |
| { |
| ColumnReferenceStorageDirective *n = |
| makeNode(ColumnReferenceStorageDirective); |
| |
| n->column = (Value *)$2; |
| n->encoding = $4; |
| $$ = (Node *)n; |
| } |
| | DEFAULT COLUMN ENCODING definition |
| { |
| ColumnReferenceStorageDirective *n = |
| makeNode(ColumnReferenceStorageDirective); |
| |
| n->deflt = true; |
| n->encoding = $4; |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| columnDef: ColId Typename ColQualList opt_storage_encoding |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| n->colname = $1; |
| n->typname = $2; |
| n->constraints = $3; |
| n->is_local = true; |
| n->encoding = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ColQualList: |
| ColQualList ColConstraint { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ColConstraint: |
| CONSTRAINT name ColConstraintElem |
| { |
| switch (nodeTag($3)) |
| { |
| case T_Constraint: |
| { |
| Constraint *n = (Constraint *)$3; |
| n->name = $2; |
| } |
| break; |
| case T_FkConstraint: |
| { |
| FkConstraint *n = (FkConstraint *)$3; |
| n->constr_name = $2; |
| } |
| break; |
| default: |
| break; |
| } |
| $$ = $3; |
| } |
| | ColConstraintElem { $$ = $1; } |
| | ConstraintAttr { $$ = $1; } |
| ; |
| |
| opt_storage_encoding: ENCODING definition { $$ = $2; } |
| | /* nothing */ { $$ = NIL; } |
| ; |
| |
| /* DEFAULT NULL is already the default for Postgres. |
| * But define it here and carry it forward into the system |
| * to make it explicit. |
| * - thomas 1998-09-13 |
| * |
| * WITH NULL and NULL are not SQL92-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->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->indexspace = NULL; |
| $$ = (Node *)n; |
| } |
| | NULL_P |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_NULL; |
| n->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->indexspace = NULL; |
| $$ = (Node *)n; |
| } |
| | UNIQUE opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_UNIQUE; |
| n->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->options = $2; |
| n->indexspace = $3; |
| $$ = (Node *)n; |
| } |
| | PRIMARY KEY opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_PRIMARY; |
| n->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->options = $3; |
| n->indexspace = $4; |
| $$ = (Node *)n; |
| } |
| | CHECK '(' a_expr ')' |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_CHECK; |
| n->name = NULL; |
| n->raw_expr = $3; |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->indexspace = NULL; |
| $$ = (Node *)n; |
| } |
| | DEFAULT b_expr |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_DEFAULT; |
| n->name = NULL; |
| if (exprIsNullConstant($2)) |
| { |
| /* DEFAULT NULL should be reported as empty expr */ |
| n->raw_expr = NULL; |
| } |
| else |
| { |
| n->raw_expr = $2; |
| } |
| n->cooked_expr = NULL; |
| n->keys = NULL; |
| n->indexspace = NULL; |
| $$ = (Node *)n; |
| } |
| | REFERENCES qualified_name opt_column_list key_match key_actions |
| { |
| FkConstraint *n = makeNode(FkConstraint); |
| n->constr_name = NULL; |
| 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->deferrable = FALSE; |
| n->initdeferred = FALSE; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * 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). analyze.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. |
| */ |
| ConstraintAttr: |
| DEFERRABLE |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_ATTR_DEFERRABLE; |
| $$ = (Node *)n; |
| } |
| | NOT DEFERRABLE |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_ATTR_NOT_DEFERRABLE; |
| $$ = (Node *)n; |
| } |
| | INITIALLY DEFERRED |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_ATTR_DEFERRED; |
| $$ = (Node *)n; |
| } |
| | INITIALLY IMMEDIATE |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_ATTR_IMMEDIATE; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /* |
| * SQL99 supports wholesale borrowing of a table definition via the LIKE clause. |
| * This seems to be a poor man's inheritance capability, with the resulting |
| * tables completely decoupled except for the original commonality in definitions. |
| * |
| * This is very similar to CREATE TABLE AS except for the INCLUDING DEFAULTS extension |
| * which is a part of SQL:2003. |
| */ |
| TableLikeClause: |
| LIKE qualified_name TableLikeOptionList |
| { |
| InhRelation *n = makeNode(InhRelation); |
| n->relation = $2; |
| n->options = $3; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| TableLikeOptionList: |
| TableLikeOptionList TableLikeOption { $$ = lappend_int($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TableLikeOption: |
| INCLUDING DEFAULTS { $$ = CREATE_TABLE_LIKE_INCLUDING_DEFAULTS; } |
| | EXCLUDING DEFAULTS { $$ = CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS; } |
| | INCLUDING CONSTRAINTS { $$ = CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS; } |
| | EXCLUDING CONSTRAINTS { $$ = CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS; } |
| | INCLUDING INDEXES { $$ = CREATE_TABLE_LIKE_INCLUDING_INDEXES; } |
| | EXCLUDING INDEXES { $$ = CREATE_TABLE_LIKE_EXCLUDING_INDEXES; } |
| ; |
| |
| |
| /* 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 |
| { |
| switch (nodeTag($3)) |
| { |
| case T_Constraint: |
| { |
| Constraint *n = (Constraint *)$3; |
| n->name = $2; |
| } |
| break; |
| case T_FkConstraint: |
| { |
| FkConstraint *n = (FkConstraint *)$3; |
| n->constr_name = $2; |
| } |
| break; |
| default: |
| break; |
| } |
| $$ = $3; |
| } |
| | ConstraintElem { $$ = $1; } |
| ; |
| |
| ConstraintElem: |
| CHECK '(' a_expr ')' |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_CHECK; |
| n->name = NULL; |
| n->raw_expr = $3; |
| n->cooked_expr = NULL; |
| n->indexspace = NULL; |
| $$ = (Node *)n; |
| } |
| | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_UNIQUE; |
| n->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = $3; |
| n->options = $5; |
| n->indexspace = $6; |
| $$ = (Node *)n; |
| } |
| | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace |
| { |
| Constraint *n = makeNode(Constraint); |
| n->contype = CONSTR_PRIMARY; |
| n->name = NULL; |
| n->raw_expr = NULL; |
| n->cooked_expr = NULL; |
| n->keys = $4; |
| n->options = $6; |
| n->indexspace = $7; |
| $$ = (Node *)n; |
| } |
| | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name |
| opt_column_list key_match key_actions ConstraintAttributeSpec |
| { |
| FkConstraint *n = makeNode(FkConstraint); |
| n->constr_name = NULL; |
| 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); |
| n->deferrable = ($11 & 1) != 0; |
| n->initdeferred = ($11 & 2) != 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_column_list: |
| '(' columnList ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_inherited_column_list: |
| '(' |
| { |
| /* Allowed only when |
| * gp_enable_alter_table_inherit_cols is true |
| */ |
| if (!gp_enable_alter_table_inherit_cols) |
| { |
| yyerror("syntax error"); |
| } |
| } |
| columnList ')' { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| columnList: |
| columnElem { $$ = list_make1($1); } |
| | columnList ',' columnElem { $$ = lappend($1, $3); } |
| ; |
| columnListPlus: |
| columnElem ',' columnElem |
| { |
| $$ = list_make1($1); |
| $$ = lappend($$, $3); |
| } |
| | columnListPlus ',' columnElem |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| columnElem: ColId |
| { |
| $$ = (Node *) makeString($1); |
| } |
| ; |
| |
| key_match: MATCH FULL |
| { |
| $$ = FKCONSTR_MATCH_FULL; |
| } |
| | MATCH PARTIAL |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("MATCH PARTIAL not yet implemented"), |
| scanner_errposition(@1))); |
| $$ = FKCONSTR_MATCH_PARTIAL; |
| } |
| | MATCH SIMPLE |
| { |
| $$ = FKCONSTR_MATCH_UNSPECIFIED; |
| } |
| | /*EMPTY*/ |
| { |
| $$ = FKCONSTR_MATCH_UNSPECIFIED; |
| } |
| ; |
| |
| /* |
| * 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; } |
| ; |
| |
| /* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */ |
| OptWith: |
| WITH definition { $$ = $2; } |
| | WITH OIDS { $$ = list_make1(defWithOids(true)); } |
| | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); } |
| | /*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; } |
| ; |
| |
| DistributedBy: DISTRIBUTED BY '(' columnList ')' { $$ = $4; } |
| | DISTRIBUTED RANDOMLY { $$ = list_make1(NULL); } |
| ; |
| |
| OptDistributedBy: DistributedBy { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* START PARTITION RULES */ |
| |
| OptTabPartitionColumnEncList: TabPartitionColumnEncList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| TabPartitionColumnEncList: |
| column_reference_storage_directive { $$ = list_make1($1); } |
| | TabPartitionColumnEncList column_reference_storage_directive |
| { |
| $$ = lappend($1, $2); |
| } |
| ; |
| |
| OptTabPartitionStorageAttr: WITH definition TABLESPACE name |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| pc->partid = NULL; |
| pc->arg1 = (Node *)$2; |
| pc->arg2 = (Node *)makeString($4); |
| pc->location = @1; |
| $$ = (Node *)pc; |
| } |
| | WITH definition |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| pc->partid = NULL; |
| pc->arg1 = (Node *)$2; |
| pc->arg2 = NULL; |
| pc->location = @1; |
| $$ = (Node *)pc; |
| } |
| | TABLESPACE name |
| { |
| /* re-use alterpartitioncmd struct here... */ |
| AlterPartitionCmd *pc = makeNode(AlterPartitionCmd); |
| pc->partid = NULL; |
| pc->arg1 = NULL; |
| pc->arg2 = (Node *)makeString($2); |
| pc->location = @1; |
| $$ = (Node *)pc; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabPartitionsNumber: PARTITIONS IntegerOnly |
| { |
| /* special rule to disable the use of HASH partitioned |
| tables with nice syntax error. |
| |
| XXX XXX REMOVE when HASH partitions are in |
| production |
| */ |
| |
| if (!gp_enable_hash_partitioned_tables) |
| { |
| yyerror("syntax error"); |
| } |
| |
| $$ = makeAConst($2, @2); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabSubPartitionsNumber: SUBPARTITIONS IntegerOnly |
| { |
| /* special rule to disable the use of HASH partitioned |
| tables with nice syntax error. |
| |
| XXX XXX REMOVE when HASH partitions are in |
| production |
| */ |
| |
| if (!gp_enable_hash_partitioned_tables) |
| { |
| yyerror("syntax error"); |
| } |
| |
| $$ = makeAConst($2, @2); |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabPartitionSpec: '(' TabPartitionElemList ')' |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| n->partElem = $2; |
| n->subSpec = NULL; |
| n->location = @2; |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabSubPartitionSpec: |
| '(' TabSubPartitionElemList ')' |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| n->partElem = $2; |
| n->subSpec = NULL; |
| n->location = @2; |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| TabPartitionElemList: |
| TabPartitionElem { $$ = list_make1($1); } |
| | TabPartitionElemList ',' |
| TabPartitionElem { $$ = lappend($1, $3); } |
| ; |
| TabSubPartitionElemList: |
| TabSubPartitionElem { $$ = list_make1($1); } |
| | TabSubPartitionElemList ',' |
| TabSubPartitionElem { $$ = lappend($1, $3); } |
| ; |
| |
| tab_part_val_no_paran: AexprConst { $$ = $1; } |
| | CAST '(' tab_part_val AS Typename ')' |
| { |
| $$ = makeTypeCast($3, $5, @4); |
| } |
| | tab_part_val_no_paran TYPECAST Typename |
| { |
| $$ = makeTypeCast($1, $3, @2); |
| } |
| | '-' tab_part_val_no_paran { $$ = doNegate($2, @1); } |
| ; |
| |
| tab_part_val: tab_part_val_no_paran { $$ = $1; } |
| | '(' tab_part_val_no_paran ')' { $$ = $2; } |
| | '(' tab_part_val_no_paran ')' TYPECAST Typename |
| { |
| $$ = makeTypeCast($2, $5, @4); |
| } |
| ; |
| |
| |
| TabPartitionBoundarySpecValList: |
| tab_part_val { $$ = list_make1($1); } |
| | TabPartitionBoundarySpecValList ',' |
| tab_part_val { $$ = lappend($1, $3); } |
| ; |
| |
| /* only optional for START and END in ALTER TABLE...MODIFY PARTITION */ |
| OptTabPartitionBoundarySpecValList: |
| TabPartitionBoundarySpecValList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabPartitionRangeInclusive: |
| INCLUSIVE { $$ = PART_EDGE_INCLUSIVE; } |
| | EXCLUSIVE { $$ = PART_EDGE_EXCLUSIVE; } |
| | /*EMPTY*/ { $$ = PART_EDGE_UNSPECIFIED; } |
| ; |
| |
| TabPartitionBoundarySpecStart: |
| START |
| '(' OptTabPartitionBoundarySpecValList ')' |
| OptTabPartitionRangeInclusive |
| { |
| PartitionRangeItem *n = makeNode(PartitionRangeItem); |
| n->partRangeVal = $3; |
| if (!($5)) |
| n->partedge = PART_EDGE_INCLUSIVE; |
| else |
| n->partedge = $5; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| TabPartitionBoundarySpecEnd: |
| END_P |
| '(' OptTabPartitionBoundarySpecValList ')' |
| OptTabPartitionRangeInclusive |
| { |
| PartitionRangeItem *n = makeNode(PartitionRangeItem); |
| n->partRangeVal = $3; |
| if (!($5)) |
| n->partedge = PART_EDGE_EXCLUSIVE; |
| else |
| n->partedge = $5; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptTabPartitionBoundarySpecEvery: |
| EVERY '(' TabPartitionBoundarySpecValList ')' |
| { |
| PartitionRangeItem *n = makeNode(PartitionRangeItem); |
| n->partRangeVal = $3; |
| n->location = @1; |
| |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptTabPartitionBoundarySpecEnd: |
| TabPartitionBoundarySpecEnd { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* VALUES for LIST, start..end for RANGE. */ |
| TabPartitionBoundarySpec: |
| part_values_clause |
| { |
| PartitionValuesSpec *n = makeNode(PartitionValuesSpec); |
| |
| n->partValues = $1; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecStart |
| OptTabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| n->partStart = $1; |
| n->partEnd = $2; |
| n->partEvery = $3; |
| n->everyGenList = NIL; |
| n->pWithTnameStr = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpecEnd |
| OptTabPartitionBoundarySpecEvery |
| { |
| PartitionBoundSpec *n = makeNode(PartitionBoundSpec); |
| n->partStart = NULL; |
| n->partEnd = $1; |
| n->partEvery = $2; |
| n->everyGenList = NIL; |
| n->pWithTnameStr = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptTabPartitionBoundarySpec: |
| TabPartitionBoundarySpec { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| multi_spec_value_list: '(' part_values_single ')' |
| { |
| ListCell *lc; |
| List *out = NIL; |
| |
| foreach(lc, $2) |
| out = lappend(out, linitial(lfirst(lc))); |
| |
| $$ = list_make1(out); |
| } |
| | multi_spec_value_list ',' '(' part_values_single ')' |
| { |
| ListCell *lc; |
| List *out = NIL; |
| |
| foreach(lc, $4) |
| out = lappend(out, linitial(lfirst(lc))); |
| |
| $$ = lappend($1, out); |
| } |
| ; |
| |
| part_values_single: tab_part_val_no_paran |
| { |
| $$ = list_make1(list_make1($1)); |
| } |
| | part_values_single ',' tab_part_val_no_paran |
| { |
| $$ = lappend($1, list_make1($3)); |
| } |
| ; |
| |
| part_values_clause: |
| VALUES '(' part_values_single ')' |
| { |
| $$ = $3; |
| } |
| | VALUES '(' multi_spec_value_list ')' |
| { |
| $$ = $3; |
| } |
| ; |
| |
| part_values_or_spec_list: TabPartitionBoundarySpecValList { $$ = $1; } |
| | part_values_clause { $$ = $1; } |
| ; |
| |
| /* a "Partition Element" closely corresponds to a "Partition Declaration" */ |
| TabPartitionElem: |
| TabPartitionNameDecl |
| OptTabPartitionBoundarySpec OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = $3; |
| n->colencs = $4; |
| n->AddPartDesc = NULL; |
| $$ = (Node *)n; |
| } |
| |
| /* allow boundary spec for default partition in parser, but complain later */ |
| | TabPartitionDefaultNameDecl |
| OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = true; |
| n->storeAttr = $3; |
| n->colencs = $4; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = NULL; |
| n->boundSpec = $1; |
| n->subSpec = $4; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = $2; |
| n->colencs = $3; |
| n->AddPartDesc = NULL; |
| $$ = (Node *)n; |
| } |
| | column_reference_storage_directive |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| TabSubPartitionElem: |
| TabSubPartitionNameDecl OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = 0; |
| n->storeAttr = $3; |
| n->colencs = $4; |
| n->AddPartDesc = NULL; |
| $$ = (Node *)n; |
| } |
| /* allow boundary spec for default partition in parser, but complain later */ |
| | TabSubPartitionDefaultNameDecl OptTabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = $1; |
| n->boundSpec = $2; |
| n->subSpec = $5; |
| n->location = @1; |
| n->isDefault = true; |
| n->storeAttr = $3; |
| n->colencs = $4; |
| n->AddPartDesc = NULL; |
| $$ = (Node *)n; |
| } |
| | TabPartitionBoundarySpec |
| OptTabPartitionStorageAttr |
| OptTabPartitionColumnEncList |
| OptTabSubPartitionSpec |
| { |
| PartitionElem *n = makeNode(PartitionElem); |
| n->partName = NULL; |
| n->boundSpec = $1; |
| n->subSpec = $4; |
| n->location = @1; |
| n->isDefault = false; |
| n->colencs = $3; |
| n->storeAttr = $2; |
| n->AddPartDesc = NULL; |
| $$ = (Node *)n; |
| } |
| | column_reference_storage_directive |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| TabPartitionNameDecl: PARTITION PartitionColId |
| { |
| $$ = (Node *) makeString($2); |
| } |
| ; |
| TabPartitionDefaultNameDecl: DEFAULT PARTITION PartitionColId |
| { |
| $$ = (Node *) makeString($3); |
| } |
| ; |
| |
| TabSubPartitionNameDecl: SUBPARTITION PartitionColId |
| { |
| $$ = (Node *) makeString($2); |
| } |
| ; |
| |
| TabSubPartitionDefaultNameDecl: DEFAULT SUBPARTITION PartitionColId |
| { |
| $$ = (Node *) makeString($3); |
| } |
| ; |
| |
| partition_hash_keyword: HASH |
| { |
| /* special rule to disable the use of HASH partitioned |
| tables with nice syntax error. |
| |
| XXX XXX REMOVE when HASH partitions are in |
| production |
| */ |
| |
| if (!gp_enable_hash_partitioned_tables) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("PARTITION BY must specify RANGE or LIST"), |
| errOmitLocation(true))); |
| |
| $$ = 1; |
| } |
| ; |
| |
| partition_coalesce_keyword: COALESCE |
| { |
| /* special rule to disable the use of HASH partitioned |
| tables with nice syntax error. |
| |
| XXX XXX REMOVE when HASH partitions are in |
| production |
| */ |
| |
| if (!gp_enable_hash_partitioned_tables) |
| { |
| yyerror("syntax error"); |
| } |
| |
| $$ = 1; |
| } |
| ; |
| |
| TabPartitionByType: |
| RANGE { $$ = PARTTYP_RANGE; } |
| | partition_hash_keyword { $$ = PARTTYP_HASH; } |
| | LIST { $$ = PARTTYP_LIST; } |
| | /*EMPTY*/ |
| { |
| $$ = PARTTYP_RANGE; |
| |
| if (!gp_enable_hash_partitioned_tables) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("PARTITION BY must specify RANGE or LIST"))); |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("PARTITION BY must specify RANGE, HASH, or LIST"))); |
| |
| |
| } |
| ; |
| |
| OptTabPartitionBy: |
| PARTITION BY |
| TabPartitionByType '(' columnList ')' |
| OptTabPartitionsNumber |
| opt_list_subparts |
| OptTabPartitionSpec |
| { |
| PartitionBy *n = makeNode(PartitionBy); |
| |
| n->partType = $3; |
| n->keys = $5; |
| n->partNum = $7; |
| n->subPart = $8; |
| if (PointerIsValid(n->subPart) && |
| !IsA(n->subPart, PartitionBy)) |
| yyerror("syntax error"); |
| |
| n->partSpec = $9; |
| n->partDepth = 0; |
| n->partQuiet = PART_VERBO_NODISTRO; |
| n->location = @3; |
| n->partDefault = NULL; |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| TabSubPartitionTemplate: |
| SUBPARTITION TEMPLATE |
| '(' TabSubPartitionElemList ')' |
| { |
| PartitionSpec *n = makeNode(PartitionSpec); |
| n->partElem = $4; |
| n->subSpec = NULL; |
| n->istemplate = true; |
| n->location = @3; |
| $$ = (Node *)n; |
| |
| /* a little (temporary?) syntax check on templates */ |
| if (n->partElem) |
| { |
| List *elems; |
| ListCell *lc; |
| Assert(IsA(n->partElem, List)); |
| |
| elems = (List *)n->partElem; |
| foreach(lc, elems) |
| { |
| PartitionElem *e = lfirst(lc); |
| |
| if (!IsA(e, PartitionElem)) continue; |
| |
| if (e->subSpec) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("template cannot contain " |
| "specification for child " |
| "partition"), |
| errOmitLocation(true))); |
| } |
| |
| } |
| } |
| ; |
| |
| opt_list_subparts: list_subparts { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| opt_comma: ',' { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| list_subparts: TabSubPartitionBy { $$ = $1; } |
| | list_subparts opt_comma TabSubPartitionBy |
| { |
| PartitionBy *pby = (PartitionBy *)$1; |
| $$ = $1; |
| |
| while (pby->subPart) |
| pby = (PartitionBy *)pby->subPart; |
| |
| if (IsA($3, PartitionSpec)) |
| { |
| Assert(((PartitionSpec *)$3)->istemplate); |
| Assert(IsA(pby, PartitionBy)); |
| |
| /* find deepesh subpart and add it there */ |
| if (((PartitionBy *)pby)->partSpec != NULL) |
| yyerror("syntax error"); |
| |
| ((PartitionBy *)pby)->partSpec = $3; |
| } |
| else |
| ((PartitionBy *)pby)->subPart = $3; |
| } |
| ; |
| |
| TabSubPartitionBy: |
| SUBPARTITION BY |
| TabPartitionByType '(' columnList ')' |
| OptTabSubPartitionsNumber |
| { |
| PartitionBy *n = makeNode(PartitionBy); |
| n->partType = $3; |
| n->keys = $5; |
| n->partNum = $7; |
| n->subPart = NULL; |
| n->partSpec = NULL; |
| n->partDepth = 0; |
| n->partQuiet = PART_VERBO_NODISTRO; |
| n->location = @3; |
| n->partDefault = NULL; |
| $$ = (Node *)n; |
| } |
| | TabSubPartitionTemplate |
| { |
| $$ = $1; |
| } |
| ; |
| /* END PARTITION RULES */ |
| |
| /* |
| * Note: CREATE TABLE ... AS SELECT ... is just another spelling for |
| * SELECT ... INTO. |
| */ |
| |
| CreateAsStmt: |
| CREATE OptTemp TABLE create_as_target AS SelectStmt opt_with_data OptDistributedBy OptTabPartitionBy |
| { |
| /* |
| * When the SelectStmt is a set-operation tree, we must |
| * stuff the INTO information into the leftmost component |
| * Select, because that's where analyze.c will expect |
| * to find it. Similarly, the output column names must |
| * be attached to that Select's target list. |
| */ |
| SelectStmt *n = findLeftmostSelect((SelectStmt *) $6); |
| if (n->intoClause != NULL) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("CREATE TABLE AS cannot specify INTO"), |
| scanner_errposition(exprLocation((Node *) n->intoClause)))); |
| $4->rel->istemp = $2; |
| n->intoClause = $4; |
| /* Implement WITH NO DATA by forcing top-level LIMIT 0 */ |
| if (!$7) |
| ((SelectStmt *) $6)->limitCount = makeIntConst(0, -1); |
| n->distributedBy = $8; |
| |
| if ($9) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("Cannot create a partitioned table using CREATE TABLE AS SELECT"), |
| errhint("Use CREATE TABLE...LIKE (followed by INSERT...SELECT) instead"), |
| errOmitLocation(true))); |
| |
| $$ = $6; |
| } |
| ; |
| |
| create_as_target: |
| qualified_name OptCreateAs OptWith OnCommitOption OptTableSpace |
| { |
| $$ = makeNode(IntoClause); |
| $$->rel = $1; |
| $$->colNames = $2; |
| $$->options = $3; |
| $$->onCommit = $4; |
| $$->tableSpaceName = $5; |
| } |
| ; |
| |
| OptCreateAs: |
| '(' CreateAsList ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| CreateAsList: |
| CreateAsElement { $$ = list_make1($1); } |
| | CreateAsList ',' CreateAsElement { $$ = lappend($1, $3); } |
| ; |
| |
| CreateAsElement: |
| ColId |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| n->colname = $1; |
| n->typname = NULL; |
| n->inhcount = 0; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->raw_default = NULL; |
| n->cooked_default = NULL; |
| n->constraints = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_with_data: |
| WITH DATA_P { $$ = TRUE; } |
| | WITH NO DATA_P { $$ = FALSE; } |
| | /*EMPTY*/ { $$ = TRUE; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE FOREIGN TABLE relname SERVER srvname [OPTIONS] |
| * |
| * NOTE: we use OptExtTableElementList, to enforce no constraints. |
| *****************************************************************************/ |
| |
| CreateForeignStmt: CREATE FOREIGN OptTemp TABLE qualified_name '(' OptExtTableElementList ')' |
| SERVER name create_generic_options |
| { |
| CreateForeignStmt *n = makeNode(CreateForeignStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->relation = $5; |
| $5->istemp = $3; |
| n->tableElts = $7; |
| n->srvname = $10; |
| n->options = $11; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE EXTERNAL [WEB] TABLE relname |
| * |
| *****************************************************************************/ |
| |
| CreateExternalStmt: CREATE OptWritable EXTERNAL OptWeb OptTemp TABLE qualified_name '(' OptExtTableElementList ')' |
| ExtTypedesc FORMAT Sconst format_opt ext_opt_encoding_list OptSingleRowErrorHandling OptDistributedBy |
| { |
| CreateExternalStmt *n = makeNode(CreateExternalStmt); |
| n->iswritable = $2; |
| n->isexternal = TRUE; |
| n->isweb = $4; |
| $7->istemp = $5; |
| n->base.relation = $7; |
| n->base.tableElts = $9; |
| n->exttypedesc = $11; |
| n->format = $13; |
| n->base.options = $14; |
| n->encoding = $15; |
| n->sreh = $16; |
| n->base.distributedBy = $17; |
| n->policy = 0; |
| |
| /* various syntax checks for EXECUTE external table */ |
| if(((ExtTableTypeDesc *) n->exttypedesc)->exttabletype == EXTTBL_TYPE_EXECUTE) |
| { |
| ExtTableTypeDesc *extdesc = (ExtTableTypeDesc *) n->exttypedesc; |
| |
| if(!n->isweb) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("EXECUTE may not be used with a regular external table"), |
| errhint("Use CREATE EXTERNAL WEB TABLE instead"), |
| errOmitLocation(true))); |
| |
| /* if no ON clause specified, default to "ON ALL" */ |
| if(extdesc->on_clause == NIL) |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("ON clause must be specified in external table"), |
| errhint("Use ON number instread"), |
| errOmitLocation(true))); |
| } |
| } |
| |
| if(n->sreh && n->iswritable) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("Single row error handling may not be used with a writable external table"))); |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptWritable: WRITABLE { $$ = TRUE; } |
| | READABLE { $$ = FALSE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| OptWeb: WEB { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| ExtTypedesc: |
| LOCATION '(' cdb_string_list ')' |
| { |
| ExtTableTypeDesc *n = makeNode(ExtTableTypeDesc); |
| n->exttabletype = EXTTBL_TYPE_LOCATION; |
| n->location_list = $3; |
| n->on_clause = NIL; |
| n->command_string = NULL; |
| $$ = (Node *)n; |
| |
| } |
| | EXECUTE Sconst ext_on_clause_list |
| { |
| ExtTableTypeDesc *n = makeNode(ExtTableTypeDesc); |
| n->exttabletype = EXTTBL_TYPE_EXECUTE; |
| n->location_list = NIL; |
| n->command_string = $2; |
| n->on_clause = $3; /* default will get set later if needed */ |
| |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ |
| { |
| ExtTableTypeDesc *n = makeNode(ExtTableTypeDesc); |
| n->exttabletype = EXTTBL_TYPE_UNKNOWN; |
| n->location_list = NIL; |
| n->command_string = NULL; |
| n->on_clause = NIL; |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ext_on_clause_list: |
| ext_on_clause_list ext_on_clause_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ext_on_clause_item: |
| ON ALL |
| { |
| $$ = makeDefElem("all", (Node *)makeInteger(TRUE)); |
| } |
| | ON HOST Sconst |
| { |
| $$ = makeDefElem("hostname", (Node *)makeString($3)); |
| } |
| | ON HOST |
| { |
| $$ = makeDefElem("eachhost", (Node *)makeInteger(TRUE)); |
| } |
| | ON MASTER |
| { |
| $$ = makeDefElem("master", (Node *)makeInteger(TRUE)); |
| } |
| | ON SEGMENT Iconst |
| { |
| $$ = makeDefElem("segment", (Node *)makeInteger($3)); |
| } |
| | ON Iconst |
| { |
| $$ = makeDefElem("random", (Node *)makeInteger($2)); |
| } |
| ; |
| |
| format_opt: |
| '(' format_opt_list ')' { $$ = $2; } |
| | '(' ')' { $$ = NIL; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| format_opt_list: |
| format_opt_item |
| { |
| $$ = list_make1($1); |
| } |
| | format_opt_list format_opt_item |
| { |
| $$ = lappend($1, $2); |
| } |
| ; |
| |
| format_opt_keyword: |
| AS |
| | DELIMITER |
| | NULL_P |
| | CSV |
| | HEADER_P |
| | QUOTE |
| | ESCAPE |
| | FORCE |
| | NOT |
| | FILL |
| | MISSING |
| | FIELDS |
| | NEWLINE |
| ; |
| |
| |
| format_opt_item: |
| IDENT |
| { |
| $$ = makeDefElem("#ident", (Node *)makeString($1)); |
| } |
| | Sconst |
| { |
| $$ = makeDefElem("#string", (Node *)makeString($1)); |
| } |
| | SignedIconst |
| { |
| $$ = makeDefElem("#int", (Node *)makeInteger($1)); |
| } |
| | format_opt_keyword |
| { |
| $$ = makeDefElem("#ident", (Node *)makeString($1)); |
| } |
| | columnListPlus |
| { |
| $$ = makeDefElem("#collist", (Node *)$1); |
| } |
| ; |
| |
| OptExtTableElementList: |
| ExtTableElementList { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ExtTableElementList: |
| ExtTableElement |
| { |
| $$ = list_make1($1); |
| } |
| | ExtTableElementList ',' ExtTableElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| ExtTableElement: |
| ExtcolumnDef { $$ = $1; } |
| | TableLikeClause { $$ = $1; } |
| ; |
| |
| /* column def for ext table - doesn't have room for constraints */ |
| ExtcolumnDef: ColId Typename |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| n->colname = $1; |
| n->typname = $2; |
| n->is_local = true; |
| n->is_not_null = false; |
| n->constraints = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Single row error handling SQL |
| */ |
| OptSingleRowErrorHandling: |
| OptErrorTableName OptSrehKeep SEGMENT REJECT_P LIMIT Iconst OptSrehLimitType |
| { |
| SingleRowErrorDesc *n = makeNode(SingleRowErrorDesc); |
| n->errtable = $1; |
| n->is_keep = $2; |
| n->rejectlimit = $6; |
| n->is_limit_in_rows = $7; /* true for ROWS false for PERCENT */ |
| |
| /* PERCENT value check */ |
| if(!n->is_limit_in_rows && (n->rejectlimit < 1 || n->rejectlimit > 100)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid PERCENT value. Should be (1 - 100)"))); |
| |
| /* ROW values check */ |
| if(n->is_limit_in_rows && n->rejectlimit < 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("invalid (ROWS) reject limit. Should be 2 or larger"))); |
| |
| $$ = (Node *)n; |
| } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptErrorTableName: |
| LOG_P ERRORS INTO qualified_name { $$ = $4; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptSrehLimitType: |
| ROWS { $$ = TRUE; } |
| | PERCENT { $$ = FALSE; } |
| | /* default is ROWS */ { $$ = TRUE; } |
| ; |
| |
| OptSrehKeep: |
| KEEP { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| /* |
| * ENCODING. (we cheat a little and use a list, even though it's 1 item max). |
| */ |
| ext_opt_encoding_list: |
| ext_opt_encoding_list ext_opt_encoding_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| ext_opt_encoding_item: |
| ENCODING opt_equal Sconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeString($3)); |
| } |
| | ENCODING opt_equal Iconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeInteger($3)); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * CREATE SEQUENCE seqname |
| * ALTER SEQUENCE seqname |
| * |
| *****************************************************************************/ |
| |
| CreateSeqStmt: |
| CREATE OptTemp SEQUENCE qualified_name OptSeqList |
| { |
| CreateSeqStmt *n = makeNode(CreateSeqStmt); |
| $4->istemp = $2; |
| n->sequence = $4; |
| n->options = $5; |
| n->relOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| AlterSeqStmt: |
| ALTER SEQUENCE qualified_name OptSeqList |
| { |
| AlterSeqStmt *n = makeNode(AlterSeqStmt); |
| n->sequence = $3; |
| n->options = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| OptSeqList: OptSeqList OptSeqElem { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| OptSeqElem: CACHE NumericOnly |
| { |
| $$ = makeDefElem("cache", (Node *)$2); |
| } |
| | CYCLE |
| { |
| $$ = makeDefElem("cycle", (Node *)makeInteger(TRUE)); |
| } |
| | NO CYCLE |
| { |
| $$ = makeDefElem("cycle", (Node *)makeInteger(FALSE)); |
| } |
| | INCREMENT opt_by NumericOnly |
| { |
| $$ = makeDefElem("increment", (Node *)$3); |
| } |
| | MAXVALUE NumericOnly |
| { |
| $$ = makeDefElem("maxvalue", (Node *)$2); |
| } |
| | MINVALUE NumericOnly |
| { |
| $$ = makeDefElem("minvalue", (Node *)$2); |
| } |
| | NO MAXVALUE |
| { |
| $$ = makeDefElem("maxvalue", NULL); |
| } |
| | NO MINVALUE |
| { |
| $$ = makeDefElem("minvalue", NULL); |
| } |
| | OWNED BY any_name |
| { |
| $$ = makeDefElem("owned_by", (Node *)$3); |
| } |
| | START opt_with NumericOnly |
| { |
| $$ = makeDefElem("start", (Node *)$3); |
| } |
| | RESTART opt_with NumericOnly |
| { |
| $$ = makeDefElem("restart", (Node *)$3); |
| } |
| ; |
| |
| opt_by: BY {} |
| | /*EMPTY*/ {} |
| ; |
| |
| NumericOnly: |
| FloatOnly { $$ = $1; } |
| | IntegerOnly { $$ = $1; } |
| ; |
| |
| FloatOnly: FCONST { $$ = makeFloat($1); } |
| | '-' FCONST |
| { |
| $$ = makeFloat($2); |
| doNegateFloat($$); |
| } |
| ; |
| |
| IntegerOnly: SignedIconst { $$ = makeInteger($1); }; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE PROCEDURAL LANGUAGE ... |
| * DROP PROCEDURAL LANGUAGE ... |
| * |
| *****************************************************************************/ |
| |
| CreatePLangStmt: |
| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst |
| { |
| CreatePLangStmt *n = makeNode(CreatePLangStmt); |
| n->plname = $5; |
| /* parameters are all to be supplied by system */ |
| n->plhandler = NIL; |
| n->plvalidator = NIL; |
| n->pltrusted = false; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst |
| HANDLER handler_name opt_validator opt_lancompiler |
| { |
| CreatePLangStmt *n = makeNode(CreatePLangStmt); |
| n->plname = $5; |
| n->plhandler = $7; |
| n->plvalidator = $8; |
| n->pltrusted = $2; |
| /* LANCOMPILER is now ignored entirely */ |
| $$ = (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); } |
| ; |
| |
| validator_clause: |
| VALIDATOR handler_name { $$ = $2; } |
| | NO VALIDATOR { $$ = NIL; } |
| ; |
| |
| opt_validator: |
| validator_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_lancompiler: |
| LANCOMPILER Sconst { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| DropPLangStmt: |
| DROP opt_procedural LANGUAGE ColId_or_Sconst opt_drop_behavior |
| { |
| DropPLangStmt *n = makeNode(DropPLangStmt); |
| n->plname = $4; |
| n->behavior = $5; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP opt_procedural LANGUAGE IF_P EXISTS ColId_or_Sconst opt_drop_behavior |
| { |
| DropPLangStmt *n = makeNode(DropPLangStmt); |
| n->plname = $6; |
| n->behavior = $7; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_procedural: |
| PROCEDURAL {} |
| | /*EMPTY*/ {} |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE FILESPACE filespace ( ... ) |
| * |
| *****************************************************************************/ |
| |
| CreateFileSpaceStmt: |
| CREATE FILESPACE name OptOwner OptStorage '(' Sconst ')' opt_definition |
| { |
| CreateFileSpaceStmt *n = makeNode(CreateFileSpaceStmt); |
| n->filespacename = $3; |
| n->owner = $4; |
| n->fsysname = $5; |
| n->location = $7; |
| n->options = $9; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| OptOwner: |
| OWNER name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| OptStorage: |
| ON name { $$ = $2; } |
| | /*EMPTY*/ { $$ = "local"; } |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE TABLESPACE tablespace FILESPACE filespace |
| * |
| *****************************************************************************/ |
| |
| CreateTableSpaceStmt: CREATE TABLESPACE name OptOwner FILESPACE name |
| { |
| CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); |
| n->tablespacename = $3; |
| n->owner = $4; |
| n->filespacename = $6; |
| n->tsoid = 0; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ] |
| * |
| *****************************************************************************/ |
| |
| CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_validator create_generic_options |
| { |
| CreateFdwStmt *n = makeNode(CreateFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $5; |
| n->validator = $6; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP FOREIGN DATA WRAPPER name |
| * |
| ****************************************************************************/ |
| |
| DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior |
| { |
| DropFdwStmt *n = makeNode(DropFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $5; |
| n->missing_ok = false; |
| n->behavior = $6; |
| $$ = (Node *) n; |
| } |
| | DROP FOREIGN DATA_P WRAPPER IF_P EXISTS name opt_drop_behavior |
| { |
| DropFdwStmt *n = makeNode(DropFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $7; |
| n->missing_ok = true; |
| n->behavior = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER FOREIGN DATA WRAPPER name |
| * |
| ****************************************************************************/ |
| |
| AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name validator_clause alter_generic_options |
| { |
| AlterFdwStmt *n = makeNode(AlterFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $5; |
| n->validator = $6; |
| n->change_validator = true; |
| n->options = $7; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name validator_clause |
| { |
| AlterFdwStmt *n = makeNode(AlterFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $5; |
| n->validator = $6; |
| n->change_validator = true; |
| $$ = (Node *) n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name alter_generic_options |
| { |
| AlterFdwStmt *n = makeNode(AlterFdwStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->fdwname = $5; |
| n->options = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* Options definition for CREATE FDW, SERVER, USER MAPPING and FOREIGN TABLE */ |
| 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, USER MAPPING and FOREIGN TABLE */ |
| 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($2, NULL, DEFELEM_DROP); |
| } |
| ; |
| |
| generic_option_elem: |
| generic_option_name generic_option_arg |
| { |
| $$ = makeDefElem($1, $2); |
| } |
| ; |
| |
| 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); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->servername = $3; |
| n->servertype = $4; |
| n->version = $5; |
| n->fdwname = $9; |
| n->options = $10; |
| $$ = (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 : |
| * DROP SERVER name |
| * |
| ****************************************************************************/ |
| |
| DropForeignServerStmt: DROP SERVER name opt_drop_behavior |
| { |
| DropForeignServerStmt *n = makeNode(DropForeignServerStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->servername = $3; |
| n->missing_ok = false; |
| n->behavior = $4; |
| $$ = (Node *) n; |
| } |
| | DROP SERVER IF_P EXISTS name opt_drop_behavior |
| { |
| DropForeignServerStmt *n = makeNode(DropForeignServerStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->servername = $5; |
| n->missing_ok = true; |
| n->behavior = $6; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * ALTER SERVER name [VERSION] [OPTIONS] |
| * |
| ****************************************************************************/ |
| |
| AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_options |
| { |
| AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| 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); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->servername = $3; |
| n->version = $4; |
| n->has_version = true; |
| $$ = (Node *) n; |
| } |
| | ALTER SERVER name alter_generic_options |
| { |
| AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt); |
| |
| if (!gp_foreign_data_access) |
| { |
| yyerror("syntax error"); |
| } |
| n->servername = $3; |
| n->options = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * CREATE USER MAPPING FOR auth_ident SERVER name [OPTIONS] |
| * |
| *****************************************************************************/ |
| |
| CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options |
| { |
| CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt); |
| n->username = $5; |
| n->servername = $7; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* User mapping authorization identifier */ |
| auth_ident: |
| CURRENT_USER { $$ = "current_user"; } |
| | USER { $$ = "current_user"; } |
| | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * DROP USER MAPPING FOR auth_ident SERVER name |
| * |
| ****************************************************************************/ |
| |
| DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name |
| { |
| DropUserMappingStmt *n = makeNode(DropUserMappingStmt); |
| n->username = $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->username = $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->username = $5; |
| n->servername = $7; |
| n->options = $8; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE TRIGGER ... |
| * DROP TRIGGER ... |
| * |
| *****************************************************************************/ |
| |
| CreateTrigStmt: |
| CREATE TRIGGER name TriggerActionTime TriggerEvents ON |
| qualified_name TriggerForSpec EXECUTE PROCEDURE |
| func_name '(' TriggerFuncArgs ')' |
| { |
| CreateTrigStmt *n = makeNode(CreateTrigStmt); |
| n->trigname = $3; |
| n->relation = $7; |
| n->funcname = $11; |
| n->args = $13; |
| n->before = $4; |
| n->row = $8; |
| memcpy(n->actions, $5, 4); |
| n->isconstraint = FALSE; |
| n->deferrable = FALSE; |
| n->initdeferred = FALSE; |
| n->constrrel = NULL; |
| $$ = (Node *)n; |
| } |
| | CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON |
| qualified_name OptConstrFromTable |
| ConstraintAttributeSpec |
| FOR EACH ROW EXECUTE PROCEDURE |
| func_name '(' TriggerFuncArgs ')' |
| { |
| CreateTrigStmt *n = makeNode(CreateTrigStmt); |
| n->trigname = $4; |
| n->relation = $8; |
| n->funcname = $16; |
| n->args = $18; |
| n->before = FALSE; |
| n->row = TRUE; |
| memcpy(n->actions, $6, 4); |
| n->isconstraint = TRUE; |
| n->deferrable = ($10 & 1) != 0; |
| n->initdeferred = ($10 & 2) != 0; |
| |
| n->constrrel = $9; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| TriggerActionTime: |
| BEFORE { $$ = TRUE; } |
| | AFTER { $$ = FALSE; } |
| ; |
| |
| TriggerEvents: |
| TriggerOneEvent |
| { |
| char *e = palloc(4); |
| e[0] = $1; e[1] = '\0'; |
| $$ = e; |
| } |
| | TriggerOneEvent OR TriggerOneEvent |
| { |
| char *e = palloc(4); |
| e[0] = $1; e[1] = $3; e[2] = '\0'; |
| $$ = e; |
| } |
| | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent |
| { |
| char *e = palloc(4); |
| e[0] = $1; e[1] = $3; e[2] = $5; e[3] = '\0'; |
| $$ = e; |
| } |
| ; |
| |
| TriggerOneEvent: |
| INSERT { $$ = 'i'; } |
| | DELETE_P { $$ = 'd'; } |
| | UPDATE { $$ = 'u'; } |
| ; |
| |
| TriggerForSpec: |
| FOR TriggerForOpt TriggerForType |
| { |
| $$ = $3; |
| } |
| | /*EMPTY*/ |
| { |
| /* |
| * If ROW/STATEMENT not specified, default to |
| * STATEMENT, per SQL |
| */ |
| $$ = FALSE; |
| } |
| ; |
| |
| TriggerForOpt: |
| EACH {} |
| | /*EMPTY*/ {} |
| ; |
| |
| TriggerForType: |
| ROW { $$ = TRUE; } |
| | STATEMENT { $$ = FALSE; } |
| ; |
| |
| TriggerFuncArgs: |
| TriggerFuncArg { $$ = list_make1($1); } |
| | TriggerFuncArgs ',' TriggerFuncArg { $$ = lappend($1, $3); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| TriggerFuncArg: |
| ICONST |
| { |
| char buf[64]; |
| snprintf(buf, sizeof(buf), "%d", $1); |
| $$ = makeString(pstrdup(buf)); |
| } |
| | FCONST { $$ = makeString($1); } |
| | Sconst { $$ = makeString($1); } |
| | BCONST { $$ = makeString($1); } |
| | XCONST { $$ = makeString($1); } |
| | ColId { $$ = makeString($1); } |
| ; |
| |
| OptConstrFromTable: |
| FROM qualified_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| ConstraintAttributeSpec: |
| ConstraintDeferrabilitySpec |
| { $$ = $1; } |
| | ConstraintDeferrabilitySpec ConstraintTimeSpec |
| { |
| if ($1 == 0 && $2 != 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), |
| scanner_errposition(@1))); |
| $$ = $1 | $2; |
| } |
| | ConstraintTimeSpec |
| { |
| if ($1 != 0) |
| $$ = 3; |
| else |
| $$ = 0; |
| } |
| | ConstraintTimeSpec ConstraintDeferrabilitySpec |
| { |
| if ($2 == 0 && $1 != 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), |
| scanner_errposition(@1))); |
| $$ = $1 | $2; |
| } |
| | /*EMPTY*/ |
| { $$ = 0; } |
| ; |
| |
| ConstraintDeferrabilitySpec: |
| NOT DEFERRABLE { $$ = 0; } |
| | DEFERRABLE { $$ = 1; } |
| ; |
| |
| ConstraintTimeSpec: |
| INITIALLY IMMEDIATE { $$ = 0; } |
| | INITIALLY DEFERRED { $$ = 2; } |
| ; |
| |
| |
| DropTrigStmt: |
| DROP TRIGGER name ON qualified_name opt_drop_behavior |
| { |
| DropPropertyStmt *n = makeNode(DropPropertyStmt); |
| n->relation = $5; |
| n->property = $3; |
| n->behavior = $6; |
| n->removeType = OBJECT_TRIGGER; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP TRIGGER IF_P EXISTS name ON qualified_name opt_drop_behavior |
| { |
| DropPropertyStmt *n = makeNode(DropPropertyStmt); |
| n->relation = $7; |
| n->property = $5; |
| n->behavior = $8; |
| n->removeType = OBJECT_TRIGGER; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE ASSERTION ... |
| * DROP ASSERTION ... |
| * |
| *****************************************************************************/ |
| |
| CreateAssertStmt: |
| CREATE ASSERTION name CHECK '(' a_expr ')' |
| ConstraintAttributeSpec |
| { |
| CreateTrigStmt *n = makeNode(CreateTrigStmt); |
| n->trigname = $3; |
| n->args = list_make1($6); |
| n->isconstraint = TRUE; |
| n->deferrable = ($8 & 1) != 0; |
| n->initdeferred = ($8 & 2) != 0; |
| |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE ASSERTION is not yet implemented"))); |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| DropAssertStmt: |
| DROP ASSERTION name opt_drop_behavior |
| { |
| DropPropertyStmt *n = makeNode(DropPropertyStmt); |
| n->relation = NULL; |
| n->property = $3; |
| n->behavior = $4; |
| n->removeType = OBJECT_TRIGGER; /* XXX */ |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("DROP ASSERTION is not yet implemented"))); |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY : |
| * define (aggregate,operator,type) |
| * |
| *****************************************************************************/ |
| |
| DefineStmt: |
| CREATE opt_ordered AGGREGATE func_name aggr_args definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| n->kind = OBJECT_AGGREGATE; |
| n->oldstyle = false; |
| n->defnames = $4; |
| n->args = $5; |
| n->definition = $6; |
| n->ordered = $2; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_ordered AGGREGATE func_name old_aggr_definition |
| { |
| /* old-style (pre-8.2) syntax for CREATE AGGREGATE */ |
| DefineStmt *n = makeNode(DefineStmt); |
| n->kind = OBJECT_AGGREGATE; |
| n->oldstyle = true; |
| n->defnames = $4; |
| n->args = NIL; |
| n->definition = $5; |
| n->newOid = 0; |
| n->ordered = $2; |
| $$ = (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; |
| n->newOid = 0; |
| $$ = (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; |
| n->newOid = 0; |
| $$ = (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 '(' TableFuncElementList ')' |
| { |
| CompositeTypeStmt *n = makeNode(CompositeTypeStmt); |
| RangeVar *r = makeNode(RangeVar); |
| r->location = @3; |
| |
| /* can't use qualified_name, sigh */ |
| switch (list_length($3)) |
| { |
| case 1: |
| r->catalogname = NULL; |
| r->schemaname = NULL; |
| r->relname = strVal(linitial($3)); |
| break; |
| case 2: |
| r->catalogname = NULL; |
| r->schemaname = strVal(linitial($3)); |
| r->relname = strVal(lsecond($3)); |
| break; |
| case 3: |
| r->catalogname = strVal(linitial($3)); |
| r->schemaname = strVal(lsecond($3)); |
| r->relname = strVal(lthird($3)); |
| break; |
| default: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("improper qualified name (too many dotted names): %s", |
| NameListToString($3)), |
| scanner_errposition(@3))); |
| break; |
| } |
| n->typevar = r; |
| n->coldeflist = $6; |
| n->relOid = 0; |
| n->comptypeOid = 0; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_trusted PROTOCOL name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| n->kind = OBJECT_EXTPROTOCOL; |
| n->oldstyle = false; |
| n->trusted = $2; |
| n->defnames = list_make1(makeString($4)); |
| n->args = NIL; |
| n->newOid = 0; |
| n->definition = $5; |
| n->ordered = false; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_trusted FILESYSTEM any_name definition |
| { |
| DefineStmt *n = makeNode(DefineStmt); |
| n->kind = OBJECT_FILESYSTEM; |
| n->oldstyle = false; |
| n->trusted = $2; |
| n->defnames = $4; |
| n->args = NIL; |
| n->newOid = 0; |
| n->definition = $5; |
| n->ordered = false; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_ordered: ORDERED { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| 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); |
| } |
| | ColLabel |
| { |
| $$ = makeDefElem($1, NULL); |
| } |
| ; |
| |
| /* Note: any simple identifier will be returned as a type name! */ |
| def_arg: func_type { $$ = (Node *)$1; } |
| /* MPP-6685: allow unquoted ROW keyword as "orientation" option */ |
| | ROW { $$ = (Node *)makeString(pstrdup("row")); } |
| | func_name_keyword { $$ = (Node *)makeString(pstrdup($1)); } |
| | reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); } |
| | qual_all_Op { $$ = (Node *)$1; } |
| | NumericOnly { $$ = (Node *)$1; } |
| | Sconst { $$ = (Node *)makeString($1); } |
| |
| /* |
| * For compresstype=none in ENCODING clauses. Allows us to avoid |
| * promoting that to a reserved word or adding the column reserved |
| * list here which could get tricky. |
| */ |
| | NONE { $$ = (Node *)makeString(pstrdup("none")); } |
| ; |
| |
| aggr_args: '(' aggr_args_list ')' { $$ = $2; } |
| | '(' '*' ')' { $$ = NIL; } |
| ; |
| |
| aggr_args_list: |
| Typename { $$ = list_make1($1); } |
| | aggr_args_list ',' Typename { $$ = lappend($1, $3); } |
| ; |
| |
| 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); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERIES : |
| * CREATE OPERATOR CLASS ... |
| * DROP OPERATOR CLASS ... |
| * |
| *****************************************************************************/ |
| |
| CreateOpClassStmt: |
| CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename |
| USING access_method AS opclass_item_list |
| { |
| CreateOpClassStmt *n = makeNode(CreateOpClassStmt); |
| n->opclassname = $4; |
| n->isDefault = $5; |
| n->datatype = $8; |
| n->amname = $10; |
| n->items = $12; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| opclass_item_list: |
| opclass_item { $$ = list_make1($1); } |
| | opclass_item_list ',' opclass_item { $$ = lappend($1, $3); } |
| ; |
| |
| opclass_item: |
| OPERATOR Iconst any_operator opt_recheck |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| n->itemtype = OPCLASS_ITEM_OPERATOR; |
| n->name = $3; |
| n->args = NIL; |
| n->number = $2; |
| n->recheck = $4; |
| $$ = (Node *) n; |
| } |
| | OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| n->itemtype = OPCLASS_ITEM_OPERATOR; |
| n->name = $3; |
| n->args = $5; |
| n->number = $2; |
| n->recheck = $7; |
| $$ = (Node *) n; |
| } |
| | FUNCTION Iconst func_name func_args |
| { |
| CreateOpClassItem *n = makeNode(CreateOpClassItem); |
| n->itemtype = OPCLASS_ITEM_FUNCTION; |
| n->name = $3; |
| n->args = extractArgTypes($4); |
| n->number = $2; |
| $$ = (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_recheck: RECHECK { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| |
| DropOpClassStmt: |
| DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior |
| { |
| RemoveOpClassStmt *n = makeNode(RemoveOpClassStmt); |
| n->opclassname = $4; |
| n->amname = $6; |
| n->behavior = $7; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior |
| { |
| RemoveOpClassStmt *n = makeNode(RemoveOpClassStmt); |
| n->opclassname = $6; |
| n->amname = $8; |
| n->behavior = $9; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ] |
| * REASSIGN OWNED BY username [, username ...] TO username |
| * |
| *****************************************************************************/ |
| DropOwnedStmt: |
| DROP OWNED BY name_list opt_drop_behavior |
| { |
| DropOwnedStmt *n = makeNode(DropOwnedStmt); |
| n->roles = $4; |
| n->behavior = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ReassignOwnedStmt: |
| REASSIGN OWNED BY name_list TO name |
| { |
| ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt); |
| n->roles = $4; |
| n->newrole = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * DROP itemtype [ IF EXISTS ] itemname [, itemname ...] |
| * [ RESTRICT | CASCADE ] |
| * |
| *****************************************************************************/ |
| |
| DropStmt: DROP drop_type 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; |
| $$ = (Node *)n; |
| } |
| | DROP drop_type any_name_list opt_drop_behavior |
| { |
| DropStmt *n = makeNode(DropStmt); |
| n->removeType = $2; |
| n->missing_ok = FALSE; |
| n->objects = $3; |
| n->behavior = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| drop_type: TABLE { $$ = OBJECT_TABLE; } |
| | EXTERNAL TABLE { $$ = OBJECT_EXTTABLE; } |
| | EXTERNAL WEB TABLE { $$ = OBJECT_EXTTABLE; } |
| | SEQUENCE { $$ = OBJECT_SEQUENCE; } |
| | VIEW { $$ = OBJECT_VIEW; } |
| | INDEX { $$ = OBJECT_INDEX; } |
| | TYPE_P { $$ = OBJECT_TYPE; } |
| | DOMAIN_P { $$ = OBJECT_DOMAIN; } |
| | CONVERSION_P { $$ = OBJECT_CONVERSION; } |
| | SCHEMA { $$ = OBJECT_SCHEMA; } |
| | FILESPACE { $$ = OBJECT_FILESPACE; } |
| | FILESYSTEM { $$ = OBJECT_FILESYSTEM; } |
| | TABLESPACE { $$ = OBJECT_TABLESPACE; } |
| | FOREIGN TABLE { $$ = OBJECT_FOREIGNTABLE; } |
| | PROTOCOL { $$ = OBJECT_EXTPROTOCOL; } |
| ; |
| |
| 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)); } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * truncate table relname1, relname2, ... |
| * |
| *****************************************************************************/ |
| |
| TruncateStmt: |
| TRUNCATE opt_table qualified_name_list opt_drop_behavior |
| { |
| TruncateStmt *n = makeNode(TruncateStmt); |
| n->relations = $3; |
| n->behavior = $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * The COMMENT ON statement can take different forms based upon the type of |
| * the object associated with the comment. The form of the statement is: |
| * |
| * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW | |
| * CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT | |
| * CAST | COLUMN | SCHEMA | TABLESPACE | ROLE ] <objname> | |
| * AGGREGATE <aggname> (arg1, ...) | |
| * FUNCTION <funcname> (arg1, arg2, ...) | |
| * OPERATOR <op> (leftoperand_typ, rightoperand_typ) | |
| * TRIGGER <triggername> ON <relname> | |
| * CONSTRAINT <constraintname> ON <relname> | |
| * RULE <rulename> ON <relname> ] |
| * IS 'text' |
| * |
| *****************************************************************************/ |
| |
| CommentStmt: |
| COMMENT ON comment_type any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = $3; |
| n->objname = $4; |
| n->objargs = NIL; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON AGGREGATE func_name aggr_args IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_AGGREGATE; |
| n->objname = $4; |
| n->objargs = $5; |
| n->comment = $7; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON FUNCTION func_name func_args IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_FUNCTION; |
| n->objname = $4; |
| n->objargs = extractArgTypes($5); |
| n->comment = $7; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON OPERATOR any_operator '(' oper_argtypes ')' |
| IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_OPERATOR; |
| n->objname = $4; |
| n->objargs = $6; |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON CONSTRAINT name ON any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_CONSTRAINT; |
| n->objname = lappend($6, makeString($4)); |
| n->objargs = NIL; |
| n->comment = $8; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON RULE name ON any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_RULE; |
| n->objname = lappend($6, makeString($4)); |
| n->objargs = NIL; |
| n->comment = $8; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON RULE name IS comment_text |
| { |
| /* Obsolete syntax supported for awhile for compatibility */ |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_RULE; |
| n->objname = list_make1(makeString($4)); |
| n->objargs = NIL; |
| n->comment = $6; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON TRIGGER name ON any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_TRIGGER; |
| n->objname = lappend($6, makeString($4)); |
| n->objargs = NIL; |
| n->comment = $8; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON OPERATOR CLASS any_name USING access_method IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_OPCLASS; |
| n->objname = $5; |
| n->objargs = list_make1(makeString($7)); |
| n->comment = $9; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_LARGEOBJECT; |
| n->objname = list_make1($5); |
| n->objargs = NIL; |
| n->comment = $7; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_CAST; |
| n->objname = list_make1($5); |
| n->objargs = list_make1($7); |
| n->comment = $10; |
| $$ = (Node *) n; |
| } |
| | COMMENT ON opt_procedural LANGUAGE any_name IS comment_text |
| { |
| CommentStmt *n = makeNode(CommentStmt); |
| n->objtype = OBJECT_LANGUAGE; |
| n->objname = $5; |
| n->objargs = NIL; |
| n->comment = $7; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| comment_type: |
| COLUMN { $$ = OBJECT_COLUMN; } |
| | DATABASE { $$ = OBJECT_DATABASE; } |
| | SCHEMA { $$ = OBJECT_SCHEMA; } |
| | INDEX { $$ = OBJECT_INDEX; } |
| | SEQUENCE { $$ = OBJECT_SEQUENCE; } |
| | TABLE { $$ = OBJECT_TABLE; } |
| | DOMAIN_P { $$ = OBJECT_TYPE; } |
| | TYPE_P { $$ = OBJECT_TYPE; } |
| | VIEW { $$ = OBJECT_VIEW; } |
| | CONVERSION_P { $$ = OBJECT_CONVERSION; } |
| | TABLESPACE { $$ = OBJECT_TABLESPACE; } |
| | ROLE { $$ = OBJECT_ROLE; } |
| | FILESPACE { $$ = OBJECT_FILESPACE; } |
| | RESOURCE QUEUE { $$ = OBJECT_RESQUEUE; } |
| ; |
| |
| comment_text: |
| Sconst { $$ = $1; } |
| | NULL_P { $$ = NULL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * fetch/move |
| * |
| *****************************************************************************/ |
| |
| FetchStmt: FETCH fetch_direction from_in name |
| { |
| FetchStmt *n = (FetchStmt *) $2; |
| n->portalname = $4; |
| n->ismove = FALSE; |
| $$ = (Node *)n; |
| } |
| | FETCH name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| n->portalname = $2; |
| n->ismove = FALSE; |
| $$ = (Node *)n; |
| } |
| | MOVE fetch_direction from_in name |
| { |
| FetchStmt *n = (FetchStmt *) $2; |
| n->portalname = $4; |
| n->ismove = TRUE; |
| $$ = (Node *)n; |
| } |
| | MOVE name |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| n->portalname = $2; |
| n->ismove = TRUE; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| fetch_direction: |
| /*EMPTY*/ |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | NEXT |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | PRIOR |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_BACKWARD; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | FIRST_P |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | LAST_P |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = -1; |
| $$ = (Node *)n; |
| } |
| | ABSOLUTE_P SignedIconst |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_ABSOLUTE; |
| n->howMany = $2; |
| $$ = (Node *)n; |
| } |
| | RELATIVE_P SignedIconst |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_RELATIVE; |
| n->howMany = $2; |
| $$ = (Node *)n; |
| } |
| | SignedIconst |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = $1; |
| $$ = (Node *)n; |
| } |
| | ALL |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *)n; |
| } |
| | FORWARD |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | FORWARD SignedIconst |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = $2; |
| $$ = (Node *)n; |
| } |
| | FORWARD ALL |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_FORWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *)n; |
| } |
| | BACKWARD |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_BACKWARD; |
| n->howMany = 1; |
| $$ = (Node *)n; |
| } |
| | BACKWARD SignedIconst |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_BACKWARD; |
| n->howMany = $2; |
| $$ = (Node *)n; |
| } |
| | BACKWARD ALL |
| { |
| FetchStmt *n = makeNode(FetchStmt); |
| n->direction = FETCH_BACKWARD; |
| n->howMany = FETCH_ALL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| from_in: FROM {} |
| | IN_P {} |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * GRANT and REVOKE statements |
| * |
| *****************************************************************************/ |
| |
| GrantStmt: GRANT privileges ON privilege_target TO grantee_list |
| opt_grant_grant_option |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| n->is_grant = true; |
| n->privileges = $2; |
| n->objtype = ($4)->objtype; |
| n->objects = ($4)->objs; |
| n->grantees = $6; |
| n->grant_option = $7; |
| $$ = (Node*)n; |
| } |
| ; |
| |
| RevokeStmt: |
| REVOKE privileges ON privilege_target |
| FROM grantee_list opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| n->is_grant = false; |
| n->grant_option = false; |
| n->privileges = $2; |
| n->objtype = ($4)->objtype; |
| n->objects = ($4)->objs; |
| n->grantees = $6; |
| n->behavior = $7; |
| $$ = (Node *)n; |
| } |
| | REVOKE GRANT OPTION FOR privileges ON privilege_target |
| FROM grantee_list opt_drop_behavior |
| { |
| GrantStmt *n = makeNode(GrantStmt); |
| n->is_grant = false; |
| n->grant_option = true; |
| n->privileges = $5; |
| n->objtype = ($7)->objtype; |
| n->objects = ($7)->objs; |
| n->grantees = $9; |
| n->behavior = $10; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /* |
| * A privilege list is represented as a list of 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; } |
| ; |
| |
| privilege_list: privilege |
| { $$ = list_make1(makeString($1)); } |
| | privilege_list ',' privilege |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| privilege: SELECT { $$ = pstrdup($1); } |
| | REFERENCES { $$ = pstrdup($1); } |
| | CREATE { $$ = pstrdup($1); } |
| | ColId { $$ = $1; } |
| ; |
| |
| |
| /* 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 = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_RELATION; |
| n->objs = $1; |
| $$ = n; |
| } |
| | TABLE qualified_name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_RELATION; |
| n->objs = $2; |
| $$ = n; |
| } |
| | SEQUENCE qualified_name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_SEQUENCE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | FOREIGN DATA_P WRAPPER name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_FDW; |
| n->objs = $4; |
| $$ = n; |
| } |
| | FOREIGN SERVER name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_FOREIGN_SERVER; |
| n->objs = $3; |
| $$ = n; |
| } |
| | FUNCTION function_with_argtypes_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_FUNCTION; |
| n->objs = $2; |
| $$ = n; |
| } |
| | DATABASE name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_DATABASE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | LANGUAGE name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_LANGUAGE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | SCHEMA name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_NAMESPACE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | TABLESPACE name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_TABLESPACE; |
| n->objs = $2; |
| $$ = n; |
| } |
| | PROTOCOL name_list |
| { |
| PrivTarget *n = makeNode(PrivTarget); |
| n->objtype = ACL_OBJECT_EXTPROTOCOL; |
| n->objs = $2; |
| $$ = n; |
| } |
| ; |
| |
| |
| grantee_list: |
| grantee { $$ = list_make1($1); } |
| | grantee_list ',' grantee { $$ = lappend($1, $3); } |
| ; |
| |
| grantee: RoleId |
| { |
| PrivGrantee *n = makeNode(PrivGrantee); |
| /* This hack lets us avoid reserving PUBLIC as a keyword*/ |
| if (strcmp($1, "public") == 0) |
| n->rolname = NULL; |
| else |
| n->rolname = $1; |
| $$ = (Node *)n; |
| } |
| | GROUP_P RoleId |
| { |
| PrivGrantee *n = makeNode(PrivGrantee); |
| /* Treat GROUP PUBLIC as a synonym for PUBLIC */ |
| if (strcmp($2, "public") == 0) |
| n->rolname = NULL; |
| else |
| n->rolname = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| opt_grant_grant_option: |
| WITH GRANT OPTION { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| 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 |
| { |
| FuncWithArgs *n = makeNode(FuncWithArgs); |
| n->funcname = $1; |
| n->funcargs = extractArgTypes($2); |
| $$ = n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * GRANT and REVOKE ROLE statements |
| * |
| *****************************************************************************/ |
| |
| GrantRoleStmt: |
| GRANT privilege_list TO name_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 name_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 name_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 RoleId { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: CREATE INDEX |
| * |
| * Note: we can't factor CONCURRENTLY into a separate production without |
| * making it a reserved word. |
| * |
| * Note: we cannot put TABLESPACE clause after WHERE clause unless we are |
| * willing to make TABLESPACE a fully reserved word. |
| *****************************************************************************/ |
| |
| IndexStmt: CREATE index_opt_unique INDEX index_name |
| ON qualified_name access_method_clause '(' index_params ')' |
| opt_definition OptTableSpace where_clause |
| { |
| IndexStmt *n = makeNode(IndexStmt); |
| n->unique = $2; |
| n->concurrent = false; |
| n->idxname = $4; |
| n->relation = $6; |
| n->accessMethod = $7; |
| n->indexParams = $9; |
| n->options = $11; |
| n->tableSpace = $12; |
| n->whereClause = $13; |
| n->idxOids = NULL; |
| $$ = (Node *)n; |
| } |
| | CREATE index_opt_unique INDEX CONCURRENTLY index_name |
| ON qualified_name access_method_clause '(' index_params ')' |
| opt_definition OptTableSpace where_clause |
| { |
| IndexStmt *n = makeNode(IndexStmt); |
| n->unique = $2; |
| n->concurrent = true; |
| n->idxname = $5; |
| n->relation = $7; |
| n->accessMethod = $8; |
| n->indexParams = $10; |
| n->options = $12; |
| n->tableSpace = $13; |
| n->whereClause = $14; |
| |
| if (!gp_create_index_concurrently) |
| { |
| /* MPP-9772, MPP-9773: remove support for |
| CREATE INDEX CONCURRENTLY */ |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("CREATE INDEX CONCURRENTLY is not supported"))); |
| |
| } |
| |
| $$ = (Node *)n; |
| } |
| ; |
| |
| index_opt_unique: |
| UNIQUE { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| access_method_clause: |
| USING access_method { $$ = $2; } |
| | /*EMPTY*/ { $$ = DEFAULT_INDEX_TYPE; } |
| ; |
| |
| index_params: index_elem { $$ = list_make1($1); } |
| | index_params ',' index_elem { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * 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 opt_class |
| { |
| $$ = makeNode(IndexElem); |
| $$->name = $1; |
| $$->expr = NULL; |
| $$->opclass = $2; |
| } |
| | func_expr opt_class |
| { |
| $$ = makeNode(IndexElem); |
| $$->name = NULL; |
| $$->expr = $1; |
| $$->opclass = $2; |
| } |
| | '(' a_expr ')' opt_class |
| { |
| $$ = makeNode(IndexElem); |
| $$->name = NULL; |
| $$->expr = $2; |
| $$->opclass = $4; |
| } |
| ; |
| |
| opt_class: any_name { $$ = $1; } |
| | USING any_name { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * 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 |
| RETURNS func_return createfunc_opt_list opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = $5; |
| n->returnType = $7; |
| n->options = $8; |
| n->withClause = $9; |
| n->funcOid = 0; |
| n->shelltypeOid = 0; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_or_replace FUNCTION func_name func_args |
| RETURNS TABLE '(' table_func_column_list ')' |
| createfunc_opt_list opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = mergeTableFuncParameters($5, $9); |
| n->returnType = TableFuncTypeName($9); |
| n->returnType->location = @7; |
| n->options = $11; |
| n->withClause = $12; |
| n->funcOid = 0; |
| n->shelltypeOid = 0; |
| $$ = (Node *)n; |
| } |
| | CREATE opt_or_replace FUNCTION func_name func_args |
| createfunc_opt_list opt_definition |
| { |
| CreateFunctionStmt *n = makeNode(CreateFunctionStmt); |
| n->replace = $2; |
| n->funcname = $4; |
| n->parameters = $5; |
| n->returnType = NULL; |
| n->options = $6; |
| n->withClause = $7; |
| n->funcOid = 0; |
| n->shelltypeOid = 0; |
| $$ = (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); } |
| ; |
| |
| /* |
| * 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; |
| } |
| | param_name arg_class func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| n->name = $1; |
| n->argType = $3; |
| n->mode = $2; |
| $$ = n; |
| } |
| | param_name func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| n->name = $1; |
| n->argType = $2; |
| n->mode = FUNC_PARAM_IN; |
| $$ = n; |
| } |
| | arg_class func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| n->name = NULL; |
| n->argType = $2; |
| n->mode = $1; |
| $$ = n; |
| } |
| | func_type |
| { |
| FunctionParameter *n = makeNode(FunctionParameter); |
| n->name = NULL; |
| n->argType = $1; |
| n->mode = FUNC_PARAM_IN; |
| $$ = 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; } |
| ; |
| |
| /* |
| * Ideally param_name should be ColId, but that causes too many conflicts. |
| */ |
| param_name: 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_name is next best choice. |
| */ |
| func_type: Typename { $$ = $1; } |
| | type_name attrs '%' TYPE_P |
| { |
| $$ = makeNode(TypeName); |
| $$->names = lcons(makeString($1), $2); |
| $$->pct_type = true; |
| $$->typmod = -1; |
| $$->location = @1; |
| } |
| | SETOF type_name attrs '%' TYPE_P |
| { |
| $$ = makeNode(TypeName); |
| $$->names = lcons(makeString($2), $3); |
| $$->pct_type = true; |
| $$->typmod = -1; |
| $$->setof = TRUE; |
| $$->location = @2; |
| } |
| ; |
| |
| |
| 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)); |
| } |
| | RETURNS NULL_P ON NULL_P INPUT_P |
| { |
| $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); |
| } |
| | STRICT_P |
| { |
| $$ = makeDefElem("strict", (Node *)makeInteger(TRUE)); |
| } |
| | IMMUTABLE |
| { |
| $$ = makeDefElem("volatility", (Node *)makeString("immutable")); |
| } |
| | STABLE |
| { |
| $$ = makeDefElem("volatility", (Node *)makeString("stable")); |
| } |
| | VOLATILE |
| { |
| $$ = makeDefElem("volatility", (Node *)makeString("volatile")); |
| } |
| | EXTERNAL SECURITY DEFINER |
| { |
| $$ = makeDefElem("security", (Node *)makeInteger(TRUE)); |
| } |
| | EXTERNAL SECURITY INVOKER |
| { |
| $$ = makeDefElem("security", (Node *)makeInteger(FALSE)); |
| } |
| | SECURITY DEFINER |
| { |
| $$ = makeDefElem("security", (Node *)makeInteger(TRUE)); |
| } |
| | SECURITY INVOKER |
| { |
| $$ = makeDefElem("security", (Node *)makeInteger(FALSE)); |
| } |
| | NO SQL |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("none")); |
| } |
| | CONTAINS SQL |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("contains")); |
| } |
| | READS SQL DATA_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("reads")); |
| } |
| | MODIFIES SQL DATA_P |
| { |
| $$ = makeDefElem("data_access", (Node *)makeString("modifies")); |
| } |
| ; |
| |
| createfunc_opt_item: |
| AS func_as |
| { |
| $$ = makeDefElem("as", (Node *)$2); |
| } |
| | LANGUAGE ColId_or_Sconst |
| { |
| $$ = makeDefElem("language", (Node *)makeString($2)); |
| } |
| | common_func_opt_item |
| { |
| $$ = $1; |
| } |
| ; |
| |
| func_as: Sconst { $$ = list_make1(makeString($1)); } |
| | Sconst ',' Sconst |
| { |
| $$ = list_make2(makeString($1), makeString($3)); |
| } |
| ; |
| |
| 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; |
| } |
| ; |
| |
| table_func_column_list: |
| table_func_column |
| { |
| $$ = list_make1($1); |
| } |
| | table_func_column_list ',' table_func_column |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| /***************************************************************************** |
| * ALTER FUNCTION |
| * |
| * 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->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 AGGREGATE aggname (arg1, ...) [ RESTRICT | CASCADE ] |
| * DROP OPERATOR opname (leftoperand_typ, rightoperand_typ) [ RESTRICT | CASCADE ] |
| * |
| *****************************************************************************/ |
| |
| RemoveFuncStmt: |
| DROP FUNCTION func_name func_args opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_FUNCTION; |
| n->name = $3; |
| n->args = extractArgTypes($4); |
| n->behavior = $5; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP FUNCTION IF_P EXISTS func_name func_args opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_FUNCTION; |
| n->name = $5; |
| n->args = extractArgTypes($6); |
| n->behavior = $7; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| RemoveAggrStmt: |
| DROP AGGREGATE func_name aggr_args opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_AGGREGATE; |
| n->name = $3; |
| n->args = $4; |
| n->behavior = $5; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP AGGREGATE IF_P EXISTS func_name aggr_args opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_AGGREGATE; |
| n->name = $5; |
| n->args = $6; |
| n->behavior = $7; |
| n->missing_ok = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| RemoveOperStmt: |
| DROP OPERATOR any_operator '(' oper_argtypes ')' opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_OPERATOR; |
| n->name = $3; |
| n->args = $5; |
| n->behavior = $7; |
| n->missing_ok = false; |
| $$ = (Node *)n; |
| } |
| | DROP OPERATOR IF_P EXISTS any_operator '(' oper_argtypes ')' opt_drop_behavior |
| { |
| RemoveFuncStmt *n = makeNode(RemoveFuncStmt); |
| n->kind = OBJECT_OPERATOR; |
| n->name = $5; |
| n->args = $7; |
| n->behavior = $9; |
| n->missing_ok = true; |
| $$ = (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."), |
| errOmitLocation(true), |
| scanner_errposition(@1))); |
| } |
| | Typename ',' Typename |
| { $$ = list_make2($1, $3); } |
| | NONE ',' Typename /* left unary */ |
| { $$ = list_make2(NULL, $3); } |
| | Typename ',' NONE /* right unary */ |
| { $$ = list_make2($1, NULL); } |
| ; |
| |
| any_operator: |
| all_Op |
| { $$ = list_make1(makeString($1)); } |
| | ColId '.' any_operator |
| { $$ = lcons(makeString($1), $3); } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * 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; |
| $$ = (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; |
| $$ = (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 |
| { |
| DropCastStmt *n = makeNode(DropCastStmt); |
| n->sourcetype = $5; |
| n->targettype = $7; |
| n->behavior = $9; |
| n->missing_ok = $3; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_if_exists: IF_P EXISTS { $$ = true; } |
| | /*EMPTY*/ { $$ = false; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * |
| * REINDEX type <name> [FORCE] |
| * |
| * FORCE no longer does anything, but we accept it for backwards compatibility |
| *****************************************************************************/ |
| |
| ReindexStmt: |
| REINDEX reindex_type qualified_name opt_force |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| n->kind = $2; |
| n->relation = $3; |
| n->name = NULL; |
| $$ = (Node *)n; |
| } |
| | REINDEX SYSTEM_P name opt_force |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| n->kind = OBJECT_DATABASE; |
| n->name = $3; |
| n->relation = NULL; |
| n->do_system = true; |
| n->do_user = false; |
| $$ = (Node *)n; |
| } |
| | REINDEX DATABASE name opt_force |
| { |
| ReindexStmt *n = makeNode(ReindexStmt); |
| n->kind = OBJECT_DATABASE; |
| n->name = $3; |
| n->relation = NULL; |
| n->do_system = true; |
| n->do_user = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| reindex_type: |
| INDEX { $$ = OBJECT_INDEX; } |
| | TABLE { $$ = OBJECT_TABLE; } |
| ; |
| |
| opt_force: FORCE { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| /* |
| * ALTER TYPE ... SET DEFAULT ENCODING |
| * |
| * Used to set storage parameter defaults for types. |
| */ |
| AlterTypeStmt: ALTER TYPE_P SimpleTypename SET DEFAULT ENCODING definition |
| { |
| AlterTypeStmt *n = makeNode(AlterTypeStmt); |
| |
| n->typname = $3; |
| n->encoding = $7; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name RENAME TO newname |
| * |
| *****************************************************************************/ |
| |
| RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_AGGREGATE; |
| n->object = $3; |
| n->objarg = $4; |
| n->newname = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER CONVERSION_P any_name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_CONVERSION; |
| n->object = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER DATABASE database_name RENAME TO database_name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_DATABASE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FILESPACE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_FILESPACE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FILESYSTEM name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_FILESYSTEM; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FUNCTION func_name func_args RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_FUNCTION; |
| n->object = $3; |
| n->objarg = extractArgTypes($4); |
| n->newname = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER GROUP_P RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER LANGUAGE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_LANGUAGE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER OPERATOR CLASS any_name USING access_method RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_OPCLASS; |
| n->object = $4; |
| n->subname = $6; |
| n->newname = $9; |
| $$ = (Node *)n; |
| } |
| | ALTER SCHEMA name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_SCHEMA; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (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; |
| $$ = (Node *)n; |
| } |
| | ALTER INDEX relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_INDEX; |
| n->relation = $3; |
| n->subname = NULL; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TABLE relation_expr RENAME opt_column name TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_COLUMN; |
| n->relation = $3; |
| n->subname = $6; |
| n->newname = $8; |
| $$ = (Node *)n; |
| } |
| | ALTER TRIGGER name ON relation_expr RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_TRIGGER; |
| n->relation = $5; |
| n->subname = $3; |
| n->newname = $8; |
| $$ = (Node *)n; |
| } |
| | ALTER ROLE RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER USER RoleId RENAME TO RoleId |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_ROLE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TABLESPACE name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_TABLESPACE; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER PROTOCOL name RENAME TO name |
| { |
| RenameStmt *n = makeNode(RenameStmt); |
| n->renameType = OBJECT_EXTPROTOCOL; |
| n->subname = $3; |
| n->newname = $6; |
| $$ = (Node *)n; |
| } |
| |
| ; |
| |
| opt_column: COLUMN { $$ = COLUMN; } |
| | /*EMPTY*/ { $$ = 0; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name SET SCHEMA name |
| * |
| *****************************************************************************/ |
| |
| AlterObjectSchemaStmt: |
| ALTER AGGREGATE func_name aggr_args SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_AGGREGATE; |
| n->object = $3; |
| n->objarg = $4; |
| n->newschema = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER DOMAIN_P any_name SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_DOMAIN; |
| n->object = $3; |
| n->newschema = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FUNCTION func_name func_args SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_FUNCTION; |
| n->object = $3; |
| n->objarg = extractArgTypes($4); |
| n->newschema = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER SEQUENCE relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_SEQUENCE; |
| n->relation = $3; |
| n->newschema = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TABLE relation_expr SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_TABLE; |
| n->relation = $3; |
| n->newschema = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TYPE_P SimpleTypename SET SCHEMA name |
| { |
| AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); |
| n->objectType = OBJECT_TYPE; |
| n->object = $3->names; |
| n->newschema = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * ALTER THING name OWNER TO newname |
| * |
| *****************************************************************************/ |
| |
| AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_AGGREGATE; |
| n->object = $3; |
| n->objarg = $4; |
| n->newowner = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER CONVERSION_P any_name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_CONVERSION; |
| n->object = $3; |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER DATABASE database_name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_DATABASE; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER DOMAIN_P any_name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_DOMAIN; |
| n->object = $3; |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FILESPACE name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_FILESPACE; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FILESYSTEM name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_FILESYSTEM; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FUNCTION func_name func_args OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_FUNCTION; |
| n->object = $3; |
| n->objarg = extractArgTypes($4); |
| n->newowner = $7; |
| $$ = (Node *)n; |
| } |
| | ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_OPERATOR; |
| n->object = $3; |
| n->objarg = $5; |
| n->newowner = $9; |
| $$ = (Node *)n; |
| } |
| | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_OPCLASS; |
| n->object = $4; |
| n->addname = $6; |
| n->newowner = $9; |
| $$ = (Node *)n; |
| } |
| | ALTER SCHEMA name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_SCHEMA; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TYPE_P SimpleTypename OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_TYPE; |
| n->object = $3->names; |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER TABLESPACE name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_TABLESPACE; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_FDW; |
| n->object = list_make1(makeString($5)); |
| n->newowner = $8; |
| $$ = (Node *)n; |
| } |
| | ALTER SERVER name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_FOREIGN_SERVER; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| | ALTER PROTOCOL name OWNER TO RoleId |
| { |
| AlterOwnerStmt *n = makeNode(AlterOwnerStmt); |
| n->objectType = OBJECT_EXTPROTOCOL; |
| n->object = list_make1(makeString($3)); |
| n->newowner = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: Define Rewrite Rule |
| * |
| *****************************************************************************/ |
| |
| RuleStmt: CREATE opt_or_replace RULE name AS |
| { QueryIsRule=TRUE; } |
| ON event TO qualified_name where_clause |
| DO opt_instead RuleActionList |
| { |
| RuleStmt *n = makeNode(RuleStmt); |
| n->replace = $2; |
| n->relation = $10; |
| n->rulename = $4; |
| n->whereClause = $11; |
| n->event = $8; |
| n->instead = $13; |
| n->actions = $14; |
| $$ = (Node *)n; |
| QueryIsRule=FALSE; |
| } |
| ; |
| |
| 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; } |
| ; |
| |
| |
| DropRuleStmt: |
| DROP RULE name ON qualified_name opt_drop_behavior |
| { |
| DropPropertyStmt *n = makeNode(DropPropertyStmt); |
| n->relation = $5; |
| n->property = $3; |
| n->behavior = $6; |
| n->removeType = OBJECT_RULE; |
| n->missing_ok = false; |
| $$ = (Node *) n; |
| } |
| | DROP RULE IF_P EXISTS name ON qualified_name opt_drop_behavior |
| { |
| DropPropertyStmt *n = makeNode(DropPropertyStmt); |
| n->relation = $7; |
| n->property = $5; |
| n->behavior = $8; |
| n->removeType = OBJECT_RULE; |
| n->missing_ok = true; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * NOTIFY <qualified_name> can appear both in rule bodies and |
| * as a query-level command |
| * |
| *****************************************************************************/ |
| |
| NotifyStmt: NOTIFY qualified_name |
| { |
| NotifyStmt *n = makeNode(NotifyStmt); |
| n->relation = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ListenStmt: LISTEN qualified_name |
| { |
| ListenStmt *n = makeNode(ListenStmt); |
| n->relation = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| UnlistenStmt: |
| UNLISTEN qualified_name |
| { |
| UnlistenStmt *n = makeNode(UnlistenStmt); |
| n->relation = $2; |
| $$ = (Node *)n; |
| } |
| | UNLISTEN '*' |
| { |
| UnlistenStmt *n = makeNode(UnlistenStmt); |
| n->relation = makeNode(RangeVar); |
| n->relation->relname = "*"; |
| n->relation->schemaname = NULL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Transactions: |
| * |
| * BEGIN / COMMIT / ROLLBACK |
| * (also older versions END / ABORT) |
| * |
| *****************************************************************************/ |
| |
| TransactionStmt: |
| ABORT_P opt_transaction |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_ROLLBACK; |
| n->options = NIL; |
| $$ = (Node *)n; |
| } |
| | BEGIN_P opt_transaction transaction_mode_list_or_empty |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_BEGIN; |
| n->options = $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 |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_COMMIT; |
| n->options = NIL; |
| $$ = (Node *)n; |
| } |
| | END_P opt_transaction |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_COMMIT; |
| n->options = NIL; |
| $$ = (Node *)n; |
| } |
| | ROLLBACK opt_transaction |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_ROLLBACK; |
| n->options = NIL; |
| $$ = (Node *)n; |
| } |
| | SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_SAVEPOINT; |
| n->options = list_make1(makeDefElem("savepoint_name", |
| (Node *)makeString($2))); |
| $$ = (Node *)n; |
| } |
| | RELEASE SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_RELEASE; |
| n->options = list_make1(makeDefElem("savepoint_name", |
| (Node *)makeString($3))); |
| $$ = (Node *)n; |
| } |
| | RELEASE ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_RELEASE; |
| n->options = list_make1(makeDefElem("savepoint_name", |
| (Node *)makeString($2))); |
| $$ = (Node *)n; |
| } |
| | ROLLBACK opt_transaction TO SAVEPOINT ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_ROLLBACK_TO; |
| n->options = list_make1(makeDefElem("savepoint_name", |
| (Node *)makeString($5))); |
| $$ = (Node *)n; |
| } |
| | ROLLBACK opt_transaction TO ColId |
| { |
| TransactionStmt *n = makeNode(TransactionStmt); |
| n->kind = TRANS_STMT_ROLLBACK_TO; |
| n->options = list_make1(makeDefElem("savepoint_name", |
| (Node *)makeString($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; |
| } |
| ; |
| |
| opt_transaction: WORK {} |
| | TRANSACTION {} |
| | /*EMPTY*/ {} |
| ; |
| |
| transaction_mode_item: |
| ISOLATION LEVEL iso_level |
| { $$ = makeDefElem("transaction_isolation", |
| makeStringConst($3, NULL, @3)); } |
| | READ ONLY |
| { $$ = makeDefElem("transaction_read_only", |
| makeIntConst(TRUE, @1)); } |
| | READ WRITE |
| { $$ = makeDefElem("transaction_read_only", |
| makeIntConst(FALSE, @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; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * 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 |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| n->relOid = 0; |
| n->replace = false; |
| n->view = $4; |
| n->view->istemp = $2; |
| n->aliases = $5; |
| n->query = (Query *) $7; |
| $$ = (Node *) n; |
| } |
| | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list |
| AS SelectStmt opt_check_option |
| { |
| ViewStmt *n = makeNode(ViewStmt); |
| n->replace = true; |
| n->view = $6; |
| n->view->istemp = $4; |
| n->aliases = $7; |
| n->query = (Query *) $9; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * We use merged tokens here to avoid creating shift/reduce conflicts against |
| * a whole lot of other uses of WITH. |
| */ |
| opt_check_option: |
| WITH_CHECK OPTION |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("WITH CHECK OPTION is not implemented"))); |
| } |
| | WITH_CASCADED CHECK OPTION |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("WITH CHECK OPTION is not implemented"))); |
| } |
| | WITH_LOCAL CHECK OPTION |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("WITH CHECK OPTION is not implemented"))); |
| } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * LOAD "filename" |
| * |
| *****************************************************************************/ |
| |
| LoadStmt: LOAD file_name |
| { |
| LoadStmt *n = makeNode(LoadStmt); |
| n->filename = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * CREATE DATABASE |
| * |
| *****************************************************************************/ |
| |
| CreatedbStmt: |
| CREATE DATABASE database_name opt_with createdb_opt_list |
| { |
| CreatedbStmt *n = makeNode(CreatedbStmt); |
| n->dbname = $3; |
| n->options = $5; |
| n->dbOid = 0; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| createdb_opt_list: |
| createdb_opt_list createdb_opt_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| createdb_opt_item: |
| TABLESPACE opt_equal name |
| { |
| $$ = makeDefElem("tablespace", (Node *)makeString($3)); |
| } |
| | TABLESPACE opt_equal DEFAULT |
| { |
| $$ = makeDefElem("tablespace", NULL); |
| } |
| | LOCATION opt_equal Sconst |
| { |
| $$ = makeDefElem("location", (Node *)makeString($3)); |
| } |
| | LOCATION opt_equal DEFAULT |
| { |
| $$ = makeDefElem("location", NULL); |
| } |
| | TEMPLATE opt_equal name |
| { |
| $$ = makeDefElem("template", (Node *)makeString($3)); |
| } |
| | TEMPLATE opt_equal DEFAULT |
| { |
| $$ = makeDefElem("template", NULL); |
| } |
| | ENCODING opt_equal Sconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeString($3)); |
| } |
| | ENCODING opt_equal Iconst |
| { |
| $$ = makeDefElem("encoding", (Node *)makeInteger($3)); |
| } |
| | ENCODING opt_equal DEFAULT |
| { |
| $$ = makeDefElem("encoding", NULL); |
| } |
| | CONNECTION LIMIT opt_equal SignedIconst |
| { |
| $$ = makeDefElem("connectionlimit", (Node *)makeInteger($4)); |
| } |
| | OWNER opt_equal name |
| { |
| $$ = makeDefElem("owner", (Node *)makeString($3)); |
| } |
| | OWNER opt_equal DEFAULT |
| { |
| $$ = makeDefElem("owner", NULL); |
| } |
| ; |
| |
| /* |
| * 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 database_name opt_with alterdb_opt_list |
| { |
| AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); |
| n->dbname = $3; |
| n->options = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| AlterDatabaseSetStmt: |
| ALTER DATABASE database_name SET set_rest |
| { |
| AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); |
| n->dbname = $3; |
| n->variable = $5->name; |
| n->value = $5->args; |
| $$ = (Node *)n; |
| } |
| | ALTER DATABASE database_name VariableResetStmt |
| { |
| AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); |
| n->dbname = $3; |
| n->variable = ((VariableResetStmt *)$4)->name; |
| n->value = NIL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| alterdb_opt_list: |
| alterdb_opt_list alterdb_opt_item { $$ = lappend($1, $2); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| alterdb_opt_item: |
| CONNECTION LIMIT opt_equal SignedIconst |
| { |
| $$ = makeDefElem("connectionlimit", (Node *)makeInteger($4)); |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * DROP DATABASE [ IF EXISTS ] |
| * |
| * This is implicitly CASCADE, no need for drop behavior |
| *****************************************************************************/ |
| |
| DropdbStmt: DROP DATABASE database_name |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| n->dbname = $3; |
| n->missing_ok = FALSE; |
| $$ = (Node *)n; |
| } |
| | DROP DATABASE IF_P EXISTS database_name |
| { |
| DropdbStmt *n = makeNode(DropdbStmt); |
| n->dbname = $5; |
| n->missing_ok = TRUE; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Manipulate a domain |
| * |
| *****************************************************************************/ |
| |
| CreateDomainStmt: |
| CREATE DOMAIN_P any_name opt_as Typename ColQualList |
| { |
| CreateDomainStmt *n = makeNode(CreateDomainStmt); |
| n->domainname = $3; |
| n->typname = $5; |
| n->constraints = $6; |
| n->domainOid = 0; |
| $$ = (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->typname = $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->typname = $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->typname = $3; |
| $$ = (Node *)n; |
| } |
| /* ALTER DOMAIN <domain> ADD CONSTRAINT ... */ |
| | ALTER DOMAIN_P any_name ADD_P TableConstraint |
| { |
| AlterDomainStmt *n = makeNode(AlterDomainStmt); |
| n->subtype = 'C'; |
| n->typname = $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->typname = $3; |
| n->name = $6; |
| n->behavior = $7; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_as: AS {} |
| | /*EMPTY*/ {} |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * 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 [VERBOSE] |
| * CLUSTER [VERBOSE] <index_name> ON <qualified_name> (for pre-8.3) |
| * |
| *****************************************************************************/ |
| |
| ClusterStmt: |
| CLUSTER opt_verbose index_name ON qualified_name |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| n->relation = $5; |
| n->indexname = $3; |
| $$ = (Node*)n; |
| } |
| | CLUSTER opt_verbose qualified_name |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| n->relation = $3; |
| n->indexname = NULL; |
| $$ = (Node*)n; |
| } |
| | CLUSTER opt_verbose |
| { |
| ClusterStmt *n = makeNode(ClusterStmt); |
| n->relation = NULL; |
| n->indexname = NULL; |
| $$ = (Node*)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * VACUUM |
| * ANALYZE |
| * |
| *****************************************************************************/ |
| |
| VacuumStmt: VACUUM opt_full opt_freeze opt_verbose |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->vacuum = true; |
| n->analyze = false; |
| n->full = $2; |
| n->freeze_min_age = $3 ? 0 : -1; |
| n->verbose = $4; |
| n->relation = NULL; |
| n->va_cols = NIL; |
| $$ = (Node *)n; |
| } |
| | VACUUM opt_full opt_freeze opt_verbose qualified_name |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->vacuum = true; |
| n->analyze = false; |
| n->full = $2; |
| n->freeze_min_age = $3 ? 0 : -1; |
| n->verbose = $4; |
| n->relation = $5; |
| n->va_cols = NIL; |
| $$ = (Node *)n; |
| } |
| | VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt |
| { |
| VacuumStmt *n = (VacuumStmt *) $5; |
| n->vacuum = true; |
| n->full = $2; |
| n->freeze_min_age = $3 ? 0 : -1; |
| n->verbose |= $4; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| AnalyzeStmt: |
| analyze_keyword opt_verbose opt_rootonly_all |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->vacuum = false; |
| n->analyze = true; |
| n->full = false; |
| n->freeze_min_age = -1; |
| n->verbose = $2; |
| n->rootonly = $3; |
| n->relation = NULL; |
| n->va_cols = NIL; |
| $$ = (Node *)n; |
| } |
| | analyze_keyword opt_verbose qualified_name opt_name_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->vacuum = false; |
| n->analyze = true; |
| n->full = false; |
| n->freeze_min_age = -1; |
| n->verbose = $2; |
| n->rootonly = false; |
| n->relation = $3; |
| n->va_cols = $4; |
| $$ = (Node *)n; |
| } |
| | analyze_keyword opt_verbose ROOTPARTITION qualified_name opt_name_list |
| { |
| VacuumStmt *n = makeNode(VacuumStmt); |
| n->vacuum = false; |
| n->analyze = true; |
| n->full = false; |
| n->freeze_min_age = -1; |
| n->verbose = $2; |
| n->rootonly = true; |
| n->relation = $4; |
| n->va_cols = $5; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| analyze_keyword: |
| ANALYZE {} |
| | ANALYSE /* British */ {} |
| ; |
| |
| opt_verbose: |
| VERBOSE { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_rootonly_all: |
| ROOTPARTITION ALL { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_full: FULL { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_freeze: FREEZE { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_name_list: |
| '(' name_list ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * EXPLAIN [ANALYZE] [VERBOSE] query |
| * |
| *****************************************************************************/ |
| |
| ExplainStmt: EXPLAIN opt_analyze opt_verbose opt_dxl opt_force ExplainableStmt |
| { |
| ExplainStmt *n = makeNode(ExplainStmt); |
| n->analyze = $2; |
| n->verbose = $3; |
| n->dxl = $4; |
| if($5) |
| ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("cannot use force with explain statement") |
| )); |
| n->query = (Query*)$6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| ExplainableStmt: |
| SelectStmt |
| | InsertStmt |
| | UpdateStmt |
| | DeleteStmt |
| | DeclareCursorStmt |
| | ExecuteStmt /* by default all are $$=$1 */ |
| | CreateAsStmt |
| | CreateStmt |
| { |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("cannot EXPLAIN CREATE TABLE without AS " |
| "clause"))); |
| } |
| ; |
| |
| opt_dxl: DXL { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_analyze: |
| analyze_keyword { $$ = TRUE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * PREPARE <plan_name> [(args, ...)] AS <query> |
| * |
| *****************************************************************************/ |
| |
| PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt |
| { |
| PrepareStmt *n = makeNode(PrepareStmt); |
| n->name = $2; |
| n->argtypes = $3; |
| n->query = (Query *) $5; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| prep_type_clause: '(' prep_type_list ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| prep_type_list: Typename { $$ = list_make1($1); } |
| | prep_type_list ',' Typename |
| { $$ = lappend($1, $3); } |
| ; |
| |
| 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; |
| n->into = NULL; |
| $$ = (Node *) n; |
| } |
| | CREATE OptTemp TABLE create_as_target AS |
| EXECUTE name execute_param_clause |
| { |
| ExecuteStmt *n = makeNode(ExecuteStmt); |
| n->name = $7; |
| n->params = $8; |
| $4->rel->istemp = $2; |
| n->into = $4; |
| if ($4->colNames) |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("column name list not allowed in CREATE TABLE / AS EXECUTE"))); |
| /* ... because it's not implemented, but it could be */ |
| $$ = (Node *) n; |
| } |
| ; |
| |
| 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; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| */ |
| |
| |
| |
| |
| cdb_string_list: |
| cdb_string { $$ = list_make1($1); } |
| | cdb_string_list ',' cdb_string { $$ = lappend($1, $3); } |
| ; |
| |
| |
| cdb_string: |
| Sconst |
| { |
| $$ = (Node *) makeString($1); |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * INSERT STATEMENTS |
| * |
| *****************************************************************************/ |
| |
| InsertStmt: |
| INSERT INTO qualified_name insert_rest returning_clause |
| { |
| $4->relation = $3; |
| $4->returningList = $5; |
| $$ = (Node *) $4; |
| } |
| ; |
| |
| insert_rest: |
| SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = NIL; |
| $$->selectStmt = $1; |
| } |
| | '(' insert_column_list ')' SelectStmt |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = $2; |
| $$->selectStmt = $4; |
| } |
| | DEFAULT VALUES |
| { |
| $$ = makeNode(InsertStmt); |
| $$->cols = NIL; |
| $$->selectStmt = NULL; |
| } |
| ; |
| |
| 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 = $2; |
| $$->val = NULL; |
| $$->location = @1; |
| } |
| ; |
| |
| returning_clause: |
| RETURNING target_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * DELETE STATEMENTS |
| * |
| *****************************************************************************/ |
| |
| DeleteStmt: DELETE_P FROM relation_expr_opt_alias |
| using_clause where_or_current_clause returning_clause |
| { |
| DeleteStmt *n = makeNode(DeleteStmt); |
| n->relation = $3; |
| n->usingClause = $4; |
| n->whereClause = $5; |
| n->returningList = $6; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| using_clause: |
| USING from_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * LOCK TABLE |
| * |
| *****************************************************************************/ |
| |
| LockStmt: LOCK_P opt_table qualified_name_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; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * QUERY: |
| * UpdateStmt (UPDATE) |
| * |
| *****************************************************************************/ |
| |
| UpdateStmt: UPDATE relation_expr_opt_alias |
| SET set_clause_list |
| from_clause |
| where_or_current_clause |
| returning_clause |
| { |
| UpdateStmt *n = makeNode(UpdateStmt); |
| n->relation = $2; |
| n->targetList = $4; |
| n->fromClause = $5; |
| n->whereClause = $6; |
| n->returningList = $7; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| set_clause_list: |
| set_clause { $$ = $1; } |
| | set_clause_list ',' set_clause { $$ = list_concat($1,$3); } |
| ; |
| |
| set_clause: |
| single_set_clause { $$ = list_make1($1); } |
| | multiple_set_clause { $$ = $1; } |
| ; |
| |
| single_set_clause: |
| set_target '=' ctext_expr |
| { |
| $$ = $1; |
| $$->val = (Node *) $3; |
| } |
| ; |
| |
| multiple_set_clause: |
| '(' set_target_list ')' '=' ctext_row |
| { |
| ListCell *col_cell; |
| ListCell *val_cell; |
| |
| /* |
| * Break the ctext_row apart, merge individual expressions |
| * into the destination ResTargets. XXX this approach |
| * cannot work for general row expressions as sources. |
| */ |
| if (list_length($2) != list_length($5)) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("number of columns does not match number of values"), |
| scanner_errposition(@1))); |
| forboth(col_cell, $2, val_cell, $5) |
| { |
| ResTarget *res_col = (ResTarget *) lfirst(col_cell); |
| Node *res_val = (Node *) lfirst(val_cell); |
| |
| res_col->val = res_val; |
| } |
| |
| $$ = $2; |
| } |
| ; |
| |
| set_target: |
| ColId opt_indirection |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $1; |
| $$->indirection = $2; |
| $$->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 name cursor_options CURSOR opt_hold FOR SelectStmt |
| { |
| DeclareCursorStmt *n = makeNode(DeclareCursorStmt); |
| n->portalname = $2; |
| n->options = $3; |
| n->query = $7; |
| if ($5) |
| n->options |= CURSOR_OPT_HOLD; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| 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 INSENSITIVE { $$ = $1 | CURSOR_OPT_INSENSITIVE; } |
| ; |
| |
| opt_hold: /*EMPTY*/ { $$ = FALSE; } |
| | WITH HOLD { $$ = TRUE; } |
| | WITHOUT HOLD { $$ = FALSE; } |
| ; |
| |
| /***************************************************************************** |
| * |
| * 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 yacc 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. |
| * |
| * FOR UPDATE/SHARE 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 FOR UPDATE/SHARE |
| * 2002-08-28 bjm |
| */ |
| select_no_parens: |
| simple_select { $$ = $1; } |
| | select_clause sort_clause |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, NIL, |
| NULL, NULL, NULL); |
| $$ = $1; |
| } |
| | select_clause opt_sort_clause for_locking_clause opt_select_limit |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, $3, |
| list_nth($4, 0), list_nth($4, 1), NULL); |
| $$ = $1; |
| } |
| | select_clause opt_sort_clause select_limit opt_for_locking_clause |
| { |
| insertSelectOptions((SelectStmt *) $1, $2, $4, |
| list_nth($3, 0), list_nth($3, 1), NULL); |
| $$ = $1; |
| } |
| | with_clause select_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, NULL, NIL, |
| NULL, NULL, |
| $1); |
| $$ = $2; |
| } |
| | with_clause select_clause sort_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, NIL, |
| NULL, NULL, |
| $1); |
| $$ = $2; |
| } |
| | with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, $4, |
| list_nth($5, 0), list_nth($5, 1), |
| $1); |
| $$ = $2; |
| } |
| | with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause |
| { |
| insertSelectOptions((SelectStmt *) $2, $3, $5, |
| list_nth($4, 0), list_nth($4, 1), |
| $1); |
| $$ = $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. |
| * |
| * Note that sort clauses cannot be included at this level --- SQL92 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 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 sort and |
| * limit 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_distinct 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; |
| n->havingClause = $8; |
| n->windowClause = $9; |
| $$ = (Node *)n; |
| } |
| | values_clause { $$ = $1; } |
| | select_clause UNION opt_all select_clause |
| { |
| $$ = makeSetOp(SETOP_UNION, $3, $1, $4); |
| } |
| | select_clause INTERSECT opt_all select_clause |
| { |
| $$ = makeSetOp(SETOP_INTERSECT, $3, $1, $4); |
| } |
| | select_clause EXCEPT opt_all select_clause |
| { |
| $$ = makeSetOp(SETOP_EXCEPT, $3, $1, $4); |
| } |
| ; |
| |
| /* |
| * SQL standard WITH clause looks like: |
| * |
| * WITH [ RECURSIVE ] <query name> [ (<column>,...) ] |
| * AS (query) [ SEARCH or CYCLE clause ] |
| * |
| * We don't currently support the SEARCH or CYCLE clause. |
| */ |
| with_clause: |
| WITH 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 select_with_parens |
| { |
| CommonTableExpr *n = makeNode(CommonTableExpr); |
| n->ctename = $1; |
| n->aliascolnames = $2; |
| n->ctequery = $4; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| into_clause: |
| INTO OptTempTableName |
| { |
| $$ = makeNode(IntoClause); |
| $$->rel = $2; |
| $$->colNames = NIL; |
| $$->options = NIL; |
| $$->onCommit = ONCOMMIT_NOOP; |
| $$->tableSpaceName = NULL; |
| } |
| | /*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; |
| $$->istemp = true; |
| } |
| | TEMP opt_table qualified_name |
| { |
| $$ = $3; |
| $$->istemp = true; |
| } |
| | LOCAL TEMPORARY opt_table qualified_name |
| { |
| $$ = $4; |
| $$->istemp = true; |
| } |
| | LOCAL TEMP opt_table qualified_name |
| { |
| $$ = $4; |
| $$->istemp = true; |
| } |
| | GLOBAL TEMPORARY opt_table qualified_name |
| { |
| $$ = $4; |
| $$->istemp = true; |
| } |
| | GLOBAL TEMP opt_table qualified_name |
| { |
| $$ = $4; |
| $$->istemp = true; |
| } |
| | TABLE qualified_name |
| { |
| $$ = $2; |
| $$->istemp = false; |
| } |
| | qualified_name |
| { |
| $$ = $1; |
| $$->istemp = false; |
| } |
| ; |
| |
| opt_table: TABLE {} |
| | /*EMPTY*/ {} |
| ; |
| |
| opt_all: ALL { $$ = TRUE; } |
| | DISTINCT { $$ = FALSE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| /* We use (NIL) as a placeholder to indicate that all target expressions |
| * should be placed in the DISTINCT list during parsetree analysis. |
| */ |
| opt_distinct: |
| DISTINCT { $$ = list_make1(NIL); } |
| | DISTINCT ON '(' expr_list ')' { $$ = $4; } |
| | ALL { $$ = NIL; } |
| | /*EMPTY*/ { $$ = 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 |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_kind = SORTBY_USING; |
| $$->useOp = $3; |
| } |
| | a_expr ASC |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_kind = SORTBY_ASC; |
| $$->useOp = NIL; |
| } |
| | a_expr DESC |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_kind = SORTBY_DESC; |
| $$->useOp = NIL; |
| } |
| | a_expr |
| { |
| $$ = makeNode(SortBy); |
| $$->node = $1; |
| $$->sortby_kind = SORTBY_ASC; /* default */ |
| $$->useOp = NIL; |
| } |
| ; |
| |
| |
| select_limit: |
| LIMIT select_limit_value OFFSET select_offset_value |
| { $$ = list_make2($4, $2); } |
| | OFFSET select_offset_value LIMIT select_limit_value |
| { $$ = list_make2($2, $4); } |
| | LIMIT select_limit_value |
| { $$ = list_make2(NULL, $2); } |
| | OFFSET select_offset_value |
| { $$ = list_make2($2, NULL); } |
| | 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."), |
| scanner_errposition(@1))); |
| } |
| /* SQL:2008 syntax variants */ |
| | OFFSET select_offset_value2 row_or_rows |
| { $$ = list_make2($2, NULL); } |
| | FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY |
| { $$ = list_make2(NULL, $3); } |
| | OFFSET select_offset_value2 row_or_rows FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY |
| { $$ = list_make2($2, $6); } |
| ; |
| |
| opt_select_limit: |
| select_limit { $$ = $1; } |
| | /*EMPTY*/ |
| { $$ = list_make2(NULL,NULL); } |
| ; |
| |
| select_limit_value: |
| a_expr { $$ = $1; } |
| | ALL |
| { |
| /* LIMIT ALL is represented as a NULL constant */ |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_Null; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * Allowing full expressions without parentheses causes various parsing |
| * problems with the trailing ROW/ROWS key words. SQL only calls for |
| * constants, so we allow the rest only with parentheses. |
| */ |
| opt_select_fetch_first_value: |
| SignedIconst { $$ = makeIntConst($1, @1); } |
| | '(' a_expr ')' { $$ = $2; } |
| | /*EMPTY*/ { $$ = makeIntConst(1, -1); } |
| ; |
| |
| select_offset_value: |
| a_expr { $$ = $1; } |
| ; |
| |
| /* |
| * Again, the trailing ROW/ROWS in this case prevent the full expression |
| * syntax. c_expr is the best we can do. |
| */ |
| select_offset_value2: |
| c_expr { $$ = $1; } |
| ; |
| |
| /* noise words */ |
| row_or_rows: |
| ROW { $$ = 0; } |
| | ROWS { $$ = 0; } |
| ; |
| |
| /* noise words */ |
| first_or_next: |
| FIRST_P { $$ = 0; } |
| | NEXT { $$ = 0; } |
| ; |
| |
| group_clause: |
| GROUP_P BY group_elem_list { $$ = $3; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| group_elem_list: |
| group_elem { $$ = $1; } |
| | group_elem_list ',' group_elem { $$ = list_concat($1, $3); } |
| ; |
| |
| group_elem: |
| a_expr { $$ = list_make1($1); } |
| | ROLLUP '(' expr_list ')' |
| { |
| GroupingClause *n = makeNode(GroupingClause); |
| n->groupType = GROUPINGTYPE_ROLLUP; |
| n->groupsets = $3; |
| $$ = list_make1 ((Node*)n); |
| } |
| | CUBE '(' expr_list ')' |
| { |
| GroupingClause *n = makeNode(GroupingClause); |
| n->groupType = GROUPINGTYPE_CUBE; |
| n->groupsets = $3; |
| $$ = list_make1 ((Node*)n); |
| } |
| | GROUPING SETS '(' group_elem_list ')' |
| { |
| GroupingClause *n = makeNode(GroupingClause); |
| n->groupType = GROUPINGTYPE_GROUPING_SETS; |
| n->groupsets = $4; |
| $$ = list_make1 ((Node*)n); |
| } |
| | '(' ')' |
| { $$ = list_make1(NIL); } |
| ; |
| |
| having_clause: |
| HAVING a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| window_clause: |
| WINDOW window_definition_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| window_definition_list: |
| window_name AS '(' window_spec ')' |
| { |
| ((WindowSpec *)$4)->name = $1; |
| ((WindowSpec *)$4)->location = @3; |
| $$ = list_make1($4); |
| } |
| | window_definition_list ',' window_name AS '(' window_spec ')' |
| { |
| ((WindowSpec *)$6)->name = $3; |
| ((WindowSpec *)$6)->location = @5; |
| $$ = lappend($1, $6); |
| } |
| ; |
| |
| window_spec: opt_window_name opt_window_partition_clause |
| opt_window_order_clause opt_window_frame_clause |
| { |
| WindowSpec *n = makeNode(WindowSpec); |
| n->parent = $1; |
| n->partition = $2; |
| n->order = $3; |
| n->frame = (WindowFrame *)$4; |
| n->location = -1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| opt_window_name: window_name { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| opt_window_partition_clause: window_partition_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| window_partition_clause: PARTITION BY sortby_list { $$ = (List *)$3; } |
| ; |
| |
| opt_window_order_clause: sort_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| opt_window_frame_clause: window_frame_clause { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| window_frame_clause: window_frame_units window_frame_extent |
| window_frame_exclusion |
| { |
| WindowFrame *n = makeNode(WindowFrame); |
| n->is_rows = $1; |
| setWindowExclude(n, $3); |
| |
| if (IsA($2, List)) |
| { |
| List *ex = (List *)$2; |
| |
| n->trail = (WindowFrameEdge *)linitial(ex); |
| n->lead = (WindowFrameEdge *)lsecond(ex); |
| n->is_between = true; |
| } |
| else |
| { |
| Assert(IsA($2, WindowFrameEdge)); |
| n->trail = (WindowFrameEdge *)$2; |
| n->lead = NULL; |
| n->is_between = false; |
| } |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* units are either rows (true) otherwise false */ |
| window_frame_units: ROWS { $$ = true; } |
| | RANGE { $$ = false; } |
| ; |
| |
| window_frame_extent: |
| window_frame_start { $$ = $1; } |
| | window_frame_between { $$ = $1; } |
| ; |
| |
| window_frame_start: |
| UNBOUNDED PRECEDING |
| { |
| WindowFrameEdge *n = makeNode(WindowFrameEdge); |
| n->kind = WINDOW_UNBOUND_PRECEDING; |
| n->val = NULL; |
| $$ = (Node *)n; |
| } |
| | window_frame_preceding |
| { |
| WindowFrameEdge *n = makeNode(WindowFrameEdge); |
| n->kind = WINDOW_BOUND_PRECEDING; |
| n->val = $1; |
| $$ = (Node *)n; |
| } |
| | CURRENT ROW |
| { |
| WindowFrameEdge *n = makeNode(WindowFrameEdge); |
| n->kind = WINDOW_CURRENT_ROW; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| window_frame_preceding: a_expr PRECEDING |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| window_frame_between: |
| BETWEEN window_frame_bound AND window_frame_bound |
| { |
| /* slightly dodgy hack */ |
| $$ = (Node *)list_make2($2, $4); |
| } |
| ; |
| |
| /* |
| * Be careful that we don't allow BETWEEN UNBOUND PRECEDING AND |
| * UNBOUND PRECEDING |
| */ |
| |
| window_frame_bound: |
| window_frame_start { $$ = $1; } |
| | UNBOUNDED FOLLOWING |
| { |
| WindowFrameEdge *n = makeNode(WindowFrameEdge); |
| n->kind = WINDOW_UNBOUND_FOLLOWING; |
| n->val = NULL; |
| $$ = (Node *)n; |
| } |
| | window_frame_following |
| { |
| WindowFrameEdge *n = makeNode(WindowFrameEdge); |
| n->kind = WINDOW_BOUND_FOLLOWING; |
| n->val = $1; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| window_frame_following: a_expr FOLLOWING |
| { |
| $$ = (Node *)$1; |
| } |
| ; |
| |
| window_frame_exclusion: EXCLUDE CURRENT ROW { $$ = WINDOW_EXCLUSION_CUR_ROW; } |
| | EXCLUDE GROUP_P { $$ = WINDOW_EXCLUSION_GROUP; } |
| | EXCLUDE TIES { $$ = WINDOW_EXCLUSION_TIES; } |
| | EXCLUDE NO OTHERS { $$ = WINDOW_EXCLUSION_NO_OTHERS; } |
| | /*EMPTY*/ { $$ = WINDOW_EXCLUSION_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 UPDATE locked_rels_list opt_nowait |
| { |
| LockingClause *n = makeNode(LockingClause); |
| n->lockedRels = $3; |
| n->forUpdate = TRUE; |
| n->noWait = $4; |
| $$ = (Node *) n; |
| } |
| | FOR SHARE locked_rels_list opt_nowait |
| { |
| LockingClause *n = makeNode(LockingClause); |
| n->lockedRels = $3; |
| n->forUpdate = FALSE; |
| n->noWait = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| locked_rels_list: |
| OF name_list { $$ = $2; } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| |
| values_clause: |
| VALUES ctext_row |
| { |
| SelectStmt *n = makeNode(SelectStmt); |
| n->valuesLists = list_make1($2); |
| $$ = (Node *) n; |
| } |
| | values_clause ',' ctext_row |
| { |
| SelectStmt *n = (SelectStmt *) $1; |
| n->valuesLists = lappend(n->valuesLists, $3); |
| $$ = (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. Note we cannot make |
| * alias_clause have an empty production because that causes parse conflicts |
| * between table_ref := '(' joined_table ')' alias_clause |
| * and joined_table := '(' joined_table ')'. So, we must have the |
| * redundant-looking productions here instead. |
| */ |
| table_ref: relation_expr |
| { |
| $$ = (Node *) $1; |
| } |
| | relation_expr alias_clause |
| { |
| $1->alias = $2; |
| $$ = (Node *) $1; |
| } |
| | func_table |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| n->funccallnode = $1; |
| n->coldeflist = NIL; |
| $$ = (Node *) n; |
| } |
| | func_table alias_clause |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| n->funccallnode = $1; |
| n->alias = $2; |
| n->coldeflist = NIL; |
| $$ = (Node *) n; |
| } |
| | func_table AS '(' TableFuncElementList ')' |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| n->funccallnode = $1; |
| n->coldeflist = $4; |
| $$ = (Node *) n; |
| } |
| | func_table AS ColId '(' TableFuncElementList ')' |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| Alias *a = makeNode(Alias); |
| n->funccallnode = $1; |
| a->aliasname = $3; |
| n->alias = a; |
| n->coldeflist = $5; |
| $$ = (Node *) n; |
| } |
| | func_table ColId '(' TableFuncElementList ')' |
| { |
| RangeFunction *n = makeNode(RangeFunction); |
| Alias *a = makeNode(Alias); |
| n->funccallnode = $1; |
| a->aliasname = $2; |
| n->alias = a; |
| n->coldeflist = $4; |
| $$ = (Node *) n; |
| } |
| | select_with_parens |
| { |
| /* |
| * 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 (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."), |
| scanner_errposition(@1))); |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("subquery in FROM must have an alias"), |
| errhint("For example, FROM (SELECT ...) [AS] foo."), |
| scanner_errposition(@1))); |
| $$ = NULL; |
| } |
| | select_with_parens alias_clause |
| { |
| RangeSubselect *n = makeNode(RangeSubselect); |
| n->subquery = $1; |
| n->alias = $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 SQL92'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->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)) |
| n->usingClause = (List *) $5; /* USING clause */ |
| else |
| n->quals = $5; /* ON clause */ |
| $$ = 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)) |
| n->usingClause = (List *) $4; /* USING clause */ |
| else |
| n->quals = $4; /* ON clause */ |
| $$ = 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->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->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; |
| } |
| ; |
| |
| join_type: FULL join_outer { $$ = JOIN_FULL; } |
| | LEFT join_outer { $$ = JOIN_LEFT; } |
| | RIGHT join_outer { $$ = JOIN_RIGHT; } |
| | INNER_P { $$ = JOIN_INNER; } |
| ; |
| |
| /* OUTER is just noise... */ |
| join_outer: OUTER_P { $$ = NULL; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* JOIN qualification clauses |
| * Possibilities are: |
| * USING ( column list ) allows only unqualified column names, |
| * which must match between tables. |
| * ON expr allows more general qualifications. |
| * |
| * We return USING as a List node, while an ON-expr will not be a List. |
| */ |
| |
| join_qual: USING '(' name_list ')' { $$ = (Node *) $3; } |
| | ON a_expr { $$ = $2; } |
| ; |
| |
| |
| relation_expr: |
| qualified_name |
| { |
| /* default inheritance */ |
| $$ = $1; |
| $$->inhOpt = INH_DEFAULT; |
| $$->alias = NULL; |
| } |
| | qualified_name '*' |
| { |
| /* inheritance query */ |
| $$ = $1; |
| $$->inhOpt = INH_YES; |
| $$->alias = NULL; |
| } |
| | ONLY qualified_name |
| { |
| /* no inheritance */ |
| $$ = $2; |
| $$->inhOpt = INH_NO; |
| $$->alias = NULL; |
| } |
| | ONLY '(' qualified_name ')' |
| { |
| /* no inheritance, SQL99-style syntax */ |
| $$ = $3; |
| $$->inhOpt = INH_NO; |
| $$->alias = NULL; |
| } |
| ; |
| |
| |
| /* |
| * 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; |
| } |
| ; |
| |
| |
| func_table: func_expr { $$ = $1; } |
| ; |
| |
| |
| where_clause: |
| WHERE a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* variant for UPDATE and DELETE */ |
| where_or_current_clause: |
| where_clause { $$ = $1; } |
| | WHERE CURRENT OF name |
| { |
| CurrentOfExpr *n = makeNode(CurrentOfExpr); |
| n->cursor_name = $4; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| |
| TableFuncElementList: |
| TableFuncElement |
| { |
| $$ = list_make1($1); |
| } |
| | TableFuncElementList ',' TableFuncElement |
| { |
| $$ = lappend($1, $3); |
| } |
| ; |
| |
| TableFuncElement: ColId Typename |
| { |
| ColumnDef *n = makeNode(ColumnDef); |
| n->colname = $1; |
| n->typname = $2; |
| n->constraints = NIL; |
| n->is_local = true; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /***************************************************************************** |
| * |
| * Type syntax |
| * SQL92 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; |
| } |
| ; |
| |
| 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; |
| if ($2 != INTERVAL_FULL_RANGE) |
| $$->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $2); |
| } |
| | ConstInterval '(' Iconst ')' opt_interval |
| { |
| $$ = $1; |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision must not be negative", $3), |
| scanner_errposition(@3))); |
| if ($3 > MAX_INTERVAL_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_INTERVAL_PRECISION), |
| scanner_errposition(@3))); |
| $3 = MAX_INTERVAL_PRECISION; |
| } |
| $$->typmod = INTERVAL_TYPMOD($3, $5); |
| } |
| | type_name attrs |
| { |
| $$ = makeNode(TypeName); |
| $$->names = lcons(makeString($1), $2); |
| $$->typmod = -1; |
| $$->location = @1; |
| } |
| ; |
| |
| /* 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 accomodate the postfix |
| * options (e.g. INTERVAL '1' YEAR). |
| */ |
| ConstTypename: |
| GenericType { $$ = $1; } |
| | Numeric { $$ = $1; } |
| | ConstBit { $$ = $1; } |
| | ConstCharacter { $$ = $1; } |
| | ConstDatetime { $$ = $1; } |
| ; |
| |
| GenericType: |
| type_name |
| { |
| $$ = makeTypeName($1); |
| $$->location = @1; |
| } |
| ; |
| |
| /* SQL92 numeric data types |
| * Check FLOAT() precision limits assuming IEEE floating types. |
| * - thomas 1997-09-18 |
| * Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30 |
| */ |
| 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_decimal |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmod = $2; |
| } |
| | DEC opt_decimal |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmod = $2; |
| } |
| | NUMERIC opt_numeric |
| { |
| $$ = SystemTypeName("numeric"); |
| $$->typmod = $2; |
| } |
| | 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"), |
| scanner_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"), |
| scanner_errposition(@2))); |
| } |
| | /*EMPTY*/ |
| { |
| $$ = SystemTypeName("float8"); |
| } |
| ; |
| |
| opt_numeric: |
| '(' Iconst ',' Iconst ')' |
| { |
| if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("NUMERIC precision %d must be between 1 and %d", |
| $2, NUMERIC_MAX_PRECISION))); |
| if ($4 < 0 || $4 > $2) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("NUMERIC scale %d must be between 0 and precision %d", |
| $4, $2))); |
| |
| $$ = (($2 << 16) | $4) + VARHDRSZ; |
| } |
| | '(' Iconst ')' |
| { |
| if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("NUMERIC precision %d must be between 1 and %d", |
| $2, NUMERIC_MAX_PRECISION))); |
| |
| $$ = ($2 << 16) + VARHDRSZ; |
| } |
| | /*EMPTY*/ |
| { |
| /* Insert "-1" meaning "no limit" */ |
| $$ = -1; |
| } |
| ; |
| |
| opt_decimal: |
| '(' Iconst ',' Iconst ')' |
| { |
| if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("DECIMAL precision %d must be between 1 and %d", |
| $2, NUMERIC_MAX_PRECISION))); |
| if ($4 < 0 || $4 > $2) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("DECIMAL scale %d must be between 0 and precision %d", |
| $4, $2))); |
| |
| $$ = (($2 << 16) | $4) + VARHDRSZ; |
| } |
| | '(' Iconst ')' |
| { |
| if ($2 < 1 || $2 > NUMERIC_MAX_PRECISION) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("DECIMAL precision %d must be between 1 and %d", |
| $2, NUMERIC_MAX_PRECISION))); |
| |
| $$ = ($2 << 16) + VARHDRSZ; |
| } |
| | /*EMPTY*/ |
| { |
| /* Insert "-1" meaning "no limit" */ |
| $$ = -1; |
| } |
| ; |
| |
| |
| /* |
| * SQL92 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; |
| $$->typmod = -1; |
| } |
| ; |
| |
| BitWithLength: |
| BIT opt_varying '(' Iconst ')' |
| { |
| char *typname; |
| |
| typname = $2 ? "varbit" : "bit"; |
| $$ = SystemTypeName(typname); |
| if ($4 < 1) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("length for type %s must be at least 1", |
| typname))); |
| else if ($4 > (MaxAttrSize * BITS_PER_BYTE)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("length for type %s cannot exceed %d", |
| typname, MaxAttrSize * BITS_PER_BYTE))); |
| $$->typmod = $4; |
| } |
| ; |
| |
| BitWithoutLength: |
| BIT opt_varying |
| { |
| /* bit defaults to bit(1), varbit to no limit */ |
| if ($2) |
| { |
| $$ = SystemTypeName("varbit"); |
| $$->typmod = -1; |
| } |
| else |
| { |
| $$ = SystemTypeName("bit"); |
| $$->typmod = 1; |
| } |
| $$->location = @1; |
| } |
| ; |
| |
| |
| /* |
| * SQL92 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; |
| $$->typmod = -1; |
| } |
| ; |
| |
| CharacterWithLength: character '(' Iconst ')' opt_charset |
| { |
| if (($5 != NULL) && (strcmp($5, "sql_text") != 0)) |
| { |
| char *type; |
| |
| type = palloc(strlen($1) + 1 + strlen($5) + 1); |
| strcpy(type, $1); |
| strcat(type, "_"); |
| strcat(type, $5); |
| $1 = type; |
| } |
| |
| $$ = SystemTypeName($1); |
| |
| if ($3 < 1) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("length for type %s must be at least 1", |
| $1))); |
| else if ($3 > MaxAttrSize) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("length for type %s cannot exceed %d", |
| $1, MaxAttrSize))); |
| |
| /* we actually implement these like a varlen, so |
| * the first 4 bytes is the length. (the difference |
| * between these and "text" is that we blank-pad and |
| * truncate where necessary) |
| */ |
| $$->typmod = VARHDRSZ + $3; |
| } |
| ; |
| |
| CharacterWithoutLength: character opt_charset |
| { |
| if (($2 != NULL) && (strcmp($2, "sql_text") != 0)) |
| { |
| char *type; |
| |
| type = palloc(strlen($1) + 1 + strlen($2) + 1); |
| strcpy(type, $1); |
| strcat(type, "_"); |
| strcat(type, $2); |
| $1 = type; |
| } |
| |
| $$ = SystemTypeName($1); |
| |
| /* char defaults to char(1), varchar to no limit */ |
| if (strcmp($1, "bpchar") == 0) |
| $$->typmod = VARHDRSZ + 1; |
| else |
| $$->typmod = -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; } |
| ; |
| |
| opt_charset: |
| CHARACTER SET ColId { $$ = $3; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| /* |
| * SQL92 date/time types |
| */ |
| ConstDatetime: |
| TIMESTAMP '(' Iconst ')' opt_timezone |
| { |
| if ($5) |
| $$ = SystemTypeName("timestamptz"); |
| else |
| $$ = SystemTypeName("timestamp"); |
| /* XXX the timezone field seems to be unused |
| * - thomas 2001-09-06 |
| */ |
| $$->timezone = $5; |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("TIMESTAMP(%d)%s precision must not be negative", |
| $3, ($5 ? " WITH TIME ZONE": "")))); |
| if ($3 > MAX_TIMESTAMP_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d", |
| $3, ($5 ? " WITH TIME ZONE": ""), |
| MAX_TIMESTAMP_PRECISION))); |
| $3 = MAX_TIMESTAMP_PRECISION; |
| } |
| $$->typmod = $3; |
| $$->location = @1; |
| } |
| | TIMESTAMP opt_timezone |
| { |
| if ($2) |
| $$ = SystemTypeName("timestamptz"); |
| else |
| $$ = SystemTypeName("timestamp"); |
| /* XXX the timezone field seems to be unused |
| * - thomas 2001-09-06 |
| */ |
| $$->timezone = $2; |
| $$->location = @1; |
| } |
| | TIME '(' Iconst ')' opt_timezone |
| { |
| if ($5) |
| $$ = SystemTypeName("timetz"); |
| else |
| $$ = SystemTypeName("time"); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("TIME(%d)%s precision must not be negative", |
| $3, ($5 ? " WITH TIME ZONE": "")))); |
| if ($3 > MAX_TIME_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("TIME(%d)%s precision reduced to maximum allowed, %d", |
| $3, ($5 ? " WITH TIME ZONE": ""), |
| MAX_TIME_PRECISION))); |
| $3 = MAX_TIME_PRECISION; |
| } |
| $$->typmod = $3; |
| $$->location = @1; |
| } |
| | TIME opt_timezone |
| { |
| if ($2) |
| $$ = SystemTypeName("timetz"); |
| else |
| $$ = SystemTypeName("time"); |
| $$->location = @1; |
| } |
| ; |
| |
| ConstInterval: |
| INTERVAL |
| { |
| $$ = SystemTypeName("interval"); |
| $$->location = @1; |
| } |
| ; |
| |
| opt_timezone: |
| WITH_TIME ZONE { $$ = TRUE; } |
| | WITHOUT TIME ZONE { $$ = FALSE; } |
| | /*EMPTY*/ { $$ = FALSE; } |
| ; |
| |
| opt_interval: |
| YEAR_P { $$ = INTERVAL_MASK(YEAR); } |
| | MONTH_P { $$ = INTERVAL_MASK(MONTH); } |
| | DAY_P { $$ = INTERVAL_MASK(DAY); } |
| | HOUR_P { $$ = INTERVAL_MASK(HOUR); } |
| | MINUTE_P { $$ = INTERVAL_MASK(MINUTE); } |
| | SECOND_P { $$ = INTERVAL_MASK(SECOND); } |
| | YEAR_P TO MONTH_P |
| { $$ = INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH); } |
| | DAY_P TO HOUR_P |
| { $$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR); } |
| | DAY_P TO MINUTE_P |
| { $$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) |
| | INTERVAL_MASK(MINUTE); } |
| | DAY_P TO SECOND_P |
| { $$ = INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) |
| | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND); } |
| | HOUR_P TO MINUTE_P |
| { $$ = INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE); } |
| | HOUR_P TO SECOND_P |
| { $$ = INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) |
| | INTERVAL_MASK(SECOND); } |
| | MINUTE_P TO SECOND_P |
| { $$ = INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND); } |
| | /*EMPTY*/ { $$ = INTERVAL_FULL_RANGE; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * 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. |
| */ |
| a_expr: c_expr { $$ = $1; } |
| | a_expr TYPECAST Typename |
| { $$ = makeTypeCast($1, $3, @2); } |
| | a_expr AT TIME ZONE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("timezone"); |
| n->args = list_make2($5, $1); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @2; |
| $$ = (Node *) n; |
| } |
| /* |
| * These operators must be called out explicitly in order to make use |
| * of yacc/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 above. |
| */ |
| | '+' 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 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 qual_Op %prec POSTFIXOP |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); } |
| |
| | a_expr AND a_expr |
| { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2); } |
| | a_expr OR a_expr |
| { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2); } |
| | NOT a_expr |
| { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1); } |
| |
| | a_expr LIKE a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); } |
| | a_expr LIKE a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("like_escape"); |
| n->args = list_make2($3, $5); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @4; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2); |
| } |
| | a_expr NOT LIKE a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); } |
| | a_expr NOT LIKE a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("like_escape"); |
| n->args = list_make2($4, $6); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @5; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2); |
| } |
| | a_expr ILIKE a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); } |
| | a_expr ILIKE a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("like_escape"); |
| n->args = list_make2($3, $5); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @4; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2); |
| } |
| | a_expr NOT ILIKE a_expr |
| { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); } |
| | a_expr NOT ILIKE a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("like_escape"); |
| n->args = list_make2($4, $6); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @5; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2); |
| } |
| |
| | a_expr SIMILAR TO a_expr %prec SIMILAR |
| { |
| A_Const *c = makeNode(A_Const); |
| FuncCall *n = makeNode(FuncCall); |
| c->val.type = T_Null; |
| n->funcname = SystemFuncName("similar_escape"); |
| n->args = list_make2($4, (Node *) c); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @2; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2); |
| } |
| | a_expr SIMILAR TO a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("similar_escape"); |
| n->args = list_make2($4, $6); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @5; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2); |
| } |
| | a_expr NOT SIMILAR TO a_expr %prec SIMILAR |
| { |
| A_Const *c = makeNode(A_Const); |
| FuncCall *n = makeNode(FuncCall); |
| c->val.type = T_Null; |
| n->funcname = SystemFuncName("similar_escape"); |
| n->args = list_make2($5, (Node *) c); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @5; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2); |
| } |
| | a_expr NOT SIMILAR TO a_expr ESCAPE a_expr |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("similar_escape"); |
| n->args = list_make2($5, $7); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @6; |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2); |
| } |
| |
| /* NullTest clause |
| * Define SQL92-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 |
| { |
| NullTest *n = makeNode(NullTest); |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NULL; |
| $$ = (Node *)n; |
| } |
| | a_expr ISNULL |
| { |
| NullTest *n = makeNode(NullTest); |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NULL; |
| $$ = (Node *)n; |
| } |
| | a_expr IS NOT NULL_P |
| { |
| NullTest *n = makeNode(NullTest); |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NOT_NULL; |
| $$ = (Node *)n; |
| } |
| | a_expr NOTNULL |
| { |
| NullTest *n = makeNode(NullTest); |
| n->arg = (Expr *) $1; |
| n->nulltesttype = IS_NOT_NULL; |
| $$ = (Node *)n; |
| } |
| | row OVERLAPS row |
| { |
| $$ = (Node *)makeOverlaps($1, $3, @2); |
| } |
| | a_expr IS TRUE_P |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_TRUE; |
| $$ = (Node *)b; |
| } |
| | a_expr IS NOT TRUE_P |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_TRUE; |
| $$ = (Node *)b; |
| } |
| | a_expr IS FALSE_P |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_FALSE; |
| $$ = (Node *)b; |
| } |
| | a_expr IS NOT FALSE_P |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_FALSE; |
| $$ = (Node *)b; |
| } |
| | a_expr IS UNKNOWN |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_UNKNOWN; |
| $$ = (Node *)b; |
| } |
| | a_expr IS NOT UNKNOWN |
| { |
| BooleanTest *b = makeNode(BooleanTest); |
| b->arg = (Expr *) $1; |
| b->booltesttype = IS_NOT_UNKNOWN; |
| $$ = (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 *) makeA_Expr(AEXPR_NOT, NIL, NULL, |
| (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, |
| "=", $1, $6, @2), |
| @2); |
| |
| } |
| | a_expr IS OF '(' type_list ')' %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2); |
| } |
| | a_expr IS NOT OF '(' type_list ')' %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2); |
| } |
| /* |
| * Ideally we would not use hard-wired operators below but instead use |
| * opclasses. However, mixed data types and other issues make this |
| * difficult: http://archives.postgresql.org/pgsql-hackers/2008-08/msg01142.php |
| */ |
| | a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2), |
| @2); |
| } |
| | a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2), |
| @2); |
| } |
| | a_expr BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, |
| (Node *) makeA_Expr(AEXPR_AND, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2), |
| @2), |
| (Node *) makeA_Expr(AEXPR_AND, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2), |
| @2), |
| @2); |
| } |
| | a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN |
| { |
| $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, |
| (Node *) makeA_Expr(AEXPR_OR, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2), |
| @2), |
| (Node *) makeA_Expr(AEXPR_OR, NIL, |
| (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2), |
| (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2), |
| @2), |
| @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->testexpr = $1; |
| n->operName = list_make1(makeString("=")); |
| n->location = @2; |
| $$ = (Node *)n; |
| } |
| else |
| { |
| /* generate scalar IN expression */ |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2); |
| } |
| } |
| | a_expr NOT IN_P in_expr |
| { |
| /* 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->testexpr = $1; |
| n->operName = list_make1(makeString("=")); |
| n->location = @3; |
| /* Stick a NOT on top */ |
| $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (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->testexpr = $1; |
| n->operName = $2; |
| n->subselect = $4; |
| n->location = @3; |
| $$ = (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"), |
| scanner_errposition(@1))); |
| } |
| ; |
| |
| /* |
| * 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 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 qual_Op %prec POSTFIXOP |
| { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); } |
| | 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 *) makeA_Expr(AEXPR_NOT, NIL, |
| NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2), @2); |
| } |
| | b_expr IS OF '(' type_list ')' %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2); |
| } |
| | b_expr IS NOT OF '(' type_list ')' %prec IS |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @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; } |
| | func_expr OVER '(' window_spec ')' |
| { |
| /* |
| * We break out the window function from func_expr |
| * to avoid shift/reduce errors. |
| */ |
| if (IsA($1, FuncCall)) |
| ((FuncCall *)$1)->over = $4; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("window OVER clause can only be used " |
| "with an aggregate"))); |
| |
| $$ = (Node *)$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 = $2; |
| $$ = (Node *) n; |
| } |
| else |
| $$ = (Node *) p; |
| } |
| | '(' a_expr ')' opt_indirection |
| { |
| if ($4) |
| { |
| A_Indirection *n = makeNode(A_Indirection); |
| n->arg = $2; |
| n->indirection = $4; |
| $$ = (Node *)n; |
| } |
| else |
| $$ = $2; |
| } |
| | case_expr |
| { $$ = $1; } |
| | decode_expr |
| { $$ = $1; } |
| | func_expr |
| { $$ = $1; } |
| | select_with_parens %prec UMINUS |
| { |
| SubLink *n = makeNode(SubLink); |
| n->subLinkType = EXPR_SUBLINK; |
| n->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $1; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | EXISTS select_with_parens |
| { |
| SubLink *n = makeNode(SubLink); |
| n->subLinkType = EXISTS_SUBLINK; |
| 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->testexpr = NULL; |
| n->operName = NIL; |
| n->subselect = $2; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | ARRAY array_expr |
| { $$ = $2; } |
| | TABLE '(' table_value_select_clause ')' |
| { |
| TableValueExpr *n = makeNode(TableValueExpr); |
| n->subquery = $3; |
| n->location = @1; |
| $$ = (Node*) n; |
| } |
| | row |
| { |
| RowExpr *r = makeNode(RowExpr); |
| r->args = $1; |
| r->row_typeid = InvalidOid; /* not analyzed yet */ |
| r->location = @1; |
| $$ = (Node *)r; |
| } |
| ; |
| |
| scatter_clause: |
| /* EMPTY */ { $$ = NIL; } |
| | SCATTER RANDOMLY { $$ = list_make1(NULL); } |
| | SCATTER BY expr_list { $$ = $3; } |
| ; |
| |
| table_value_select_clause: |
| SelectStmt scatter_clause |
| { |
| SelectStmt *s = (SelectStmt *) $1; |
| s->scatterClause = $2; |
| $$ = (Node *) s; |
| } |
| ; |
| |
| /* |
| * Users can write their own inline specification or refer to a |
| * specification made after the WHERE clause |
| */ |
| |
| window_name: ColId { $$ = $1; } |
| ; |
| |
| |
| simple_func: func_name '(' ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = $1; |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->agg_filter = NULL; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *)n; |
| } |
| | func_name '(' expr_list opt_sort_clause ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = $1; |
| n->args = $3; |
| n->agg_order = $4; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->agg_filter = NULL; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *)n; |
| } |
| | func_name '(' ALL expr_list opt_sort_clause')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = $1; |
| n->args = $4; |
| n->agg_order = $5; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->agg_filter = NULL; |
| /* Ideally we'd mark the FuncCall node to indicate |
| * "must be an aggregate", but there's no provision |
| * for that in FuncCall at the moment. |
| */ |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *)n; |
| } |
| | func_name '(' DISTINCT expr_list opt_sort_clause')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = $1; |
| n->args = $4; |
| n->agg_order = $5; |
| n->agg_star = FALSE; |
| n->agg_distinct = TRUE; |
| n->agg_filter = NULL; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (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 SQL92 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 = makeNode(FuncCall); |
| n->funcname = $1; |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = TRUE; |
| n->agg_distinct = FALSE; |
| n->agg_filter = NULL; |
| n->location = @1; |
| n->over = NULL; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* |
| * func_expr is split out from c_expr just so that we have a classification |
| * 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 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: simple_func FILTER '(' WHERE a_expr ')' |
| { |
| FuncCall *f = (FuncCall *) $1; |
| f->agg_filter = $5; |
| $$ = (Node *)f; |
| } |
| | simple_func |
| { $$ = $1; } |
| | CURRENT_DATE |
| { |
| /* |
| * Translate as "'now'::text::date". |
| * |
| * We cannot use "'now'::date" because coerce_type() will |
| * immediately reduce that to a constant representing |
| * today's date. We need to delay the conversion until |
| * runtime, else the wrong things will happen when |
| * CURRENT_DATE is used in a column default value or rule. |
| * |
| * This could be simplified if we had a way to generate |
| * an expression tree representing runtime application |
| * of type-input conversion functions. (As of PG 7.3 |
| * that is actually possible, but not clear that we want |
| * to rely on it.) |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("date"); |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | CURRENT_TIME |
| { |
| /* |
| * Translate as "'now'::text::timetz". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("timetz"); |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | CURRENT_TIME '(' Iconst ')' |
| { |
| /* |
| * Translate as "'now'::text::timetz(n)". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| d = SystemTypeName("timetz"); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("CURRENT_TIME(%d) precision must not be negative", |
| $3))); |
| if ($3 > MAX_TIME_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("CURRENT_TIME(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_TIME_PRECISION))); |
| $3 = MAX_TIME_PRECISION; |
| } |
| d->typmod = $3; |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | CURRENT_TIMESTAMP |
| { |
| /* |
| * Translate as "now()", since we have a function that |
| * does exactly what is needed. |
| */ |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("now"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CURRENT_TIMESTAMP '(' Iconst ')' |
| { |
| /* |
| * Translate as "'now'::text::timestamptz(n)". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("timestamptz"); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("CURRENT_TIMESTAMP(%d) precision must not be negative", |
| $3))); |
| if ($3 > MAX_TIMESTAMP_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("CURRENT_TIMESTAMP(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_TIMESTAMP_PRECISION))); |
| $3 = MAX_TIMESTAMP_PRECISION; |
| } |
| d->typmod = $3; |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | LOCALTIME |
| { |
| /* |
| * Translate as "'now'::text::time". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("time"); |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | LOCALTIME '(' Iconst ')' |
| { |
| /* |
| * Translate as "'now'::text::time(n)". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| d = SystemTypeName("time"); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("LOCALTIME(%d) precision must not be negative", |
| $3))); |
| if ($3 > MAX_TIME_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("LOCALTIME(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_TIME_PRECISION))); |
| $3 = MAX_TIME_PRECISION; |
| } |
| d->typmod = $3; |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | LOCALTIMESTAMP |
| { |
| /* |
| * Translate as "'now'::text::timestamp". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("timestamp"); |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | LOCALTIMESTAMP '(' Iconst ')' |
| { |
| /* |
| * Translate as "'now'::text::timestamp(n)". |
| * See comments for CURRENT_DATE. |
| */ |
| A_Const *s = makeNode(A_Const); |
| TypeName *d; |
| |
| s->val.type = T_String; |
| s->val.val.str = "now"; |
| s->typname = SystemTypeName("text"); |
| |
| d = SystemTypeName("timestamp"); |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("LOCALTIMESTAMP(%d) precision must not be negative", |
| $3))); |
| if ($3 > MAX_TIMESTAMP_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("LOCALTIMESTAMP(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_TIMESTAMP_PRECISION))); |
| $3 = MAX_TIMESTAMP_PRECISION; |
| } |
| d->typmod = $3; |
| |
| $$ = (Node *)makeTypeCast((Node *)s, d, -1); |
| } |
| | CURRENT_ROLE |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("current_user"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CURRENT_USER |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("current_user"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | SESSION_USER |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("session_user"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | USER |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("current_user"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CURRENT_CATALOG |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("current_database"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| /*n->func_variadic = FALSE;*/ |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CURRENT_SCHEMA |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("current_schema"); |
| n->args = NIL; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| /*n->func_variadic = FALSE;*/ |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CAST '(' a_expr AS Typename ')' |
| { $$ = makeTypeCast($3, $5, @1); } |
| | EXTRACT '(' extract_list ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("date_part"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | OVERLAY '(' overlay_list ')' |
| { |
| /* overlay(A PLACING B FROM C FOR D) is converted to |
| * substring(A, 1, C-1) || B || substring(A, C+1, C+D) |
| * overlay(A PLACING B FROM C) is converted to |
| * substring(A, 1, C-1) || B || substring(A, C+1, C+char_length(B)) |
| */ |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("overlay"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | POSITION '(' position_list ')' |
| { |
| /* position(A in B) is converted to position(B, A) */ |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("position"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | SUBSTRING '(' substr_list ')' |
| { |
| /* substring(A from B for C) is converted to |
| * substring(A, B, C) - thomas 2000-11-28 |
| */ |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("substring"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | 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. |
| */ |
| FuncCall *n = makeNode(FuncCall); |
| /* Convert SystemTypeName() to SystemFuncName() even though |
| * at the moment they result in the same thing. |
| */ |
| n->funcname = SystemFuncName(((Value *)llast($5->names))->val.str); |
| n->args = list_make1($3); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TRIM '(' BOTH trim_list ')' |
| { |
| /* various trim expressions are defined in SQL92 |
| * - thomas 1997-07-19 |
| */ |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("btrim"); |
| n->args = $4; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TRIM '(' LEADING trim_list ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("ltrim"); |
| n->args = $4; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TRIM '(' TRAILING trim_list ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("rtrim"); |
| n->args = $4; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | TRIM '(' trim_list ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("btrim"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CONVERT '(' a_expr USING any_name ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| A_Const *c = makeNode(A_Const); |
| |
| c->val.type = T_String; |
| c->val.val.str = NameListToQuotedString($5); |
| |
| n->funcname = SystemFuncName("convert_using"); |
| n->args = list_make2($3, c); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | CONVERT '(' expr_list ')' |
| { |
| FuncCall *n = makeNode(FuncCall); |
| n->funcname = SystemFuncName("convert"); |
| n->args = $3; |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = @1; |
| $$ = (Node *)n; |
| } |
| | NULLIF '(' a_expr ',' a_expr ')' |
| { |
| $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1); |
| } |
| | COALESCE '(' expr_list ')' |
| { |
| CoalesceExpr *c = makeNode(CoalesceExpr); |
| c->args = $3; |
| $$ = (Node *)c; |
| } |
| | GREATEST '(' expr_list ')' |
| { |
| MinMaxExpr *v = makeNode(MinMaxExpr); |
| v->args = $3; |
| v->op = IS_GREATEST; |
| $$ = (Node *)v; |
| } |
| | LEAST '(' expr_list ')' |
| { |
| MinMaxExpr *v = makeNode(MinMaxExpr); |
| v->args = $3; |
| v->op = IS_LEAST; |
| $$ = (Node *)v; |
| } |
| | GROUPING '(' expr_list ')' |
| { |
| GroupingFunc *f = makeNode(GroupingFunc); |
| f->args = $3; |
| $$ = (Node*)f; |
| } |
| |
| | GROUP_ID '(' ')' |
| { |
| GroupId *gid = makeNode(GroupId); |
| $$ = (Node *)gid; |
| } |
| | MEDIAN '(' a_expr ')' |
| { |
| /* |
| * MEDIAN is parsed as an alias to percentile_cont(0.5). |
| * We keep track of original expression to deparse |
| * it later in views, etc. |
| */ |
| PercentileExpr *n = makeNode(PercentileExpr); |
| SortBy *sortby; |
| |
| n->perctype = UNKNOWNOID; |
| n->args = list_make1(makeAConst(makeFloat(pstrdup("0.5")), @1)); |
| n->perckind = PERC_MEDIAN; |
| sortby = makeNode(SortBy); |
| sortby->node = $3; |
| sortby->sortby_kind = SORTBY_ASC; |
| sortby->useOp = NIL; |
| n->sortClause = list_make1(sortby); |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | PERCENTILE_CONT '(' a_expr ')' WITHIN GROUP_P '(' ORDER BY sortby_list ')' |
| { |
| /* |
| * PERCENTILE_CONT and PERCENTILE_DISC are supported as |
| * grammer for now. When it comes to catalog support, |
| * we'll be able to remove this grammer. |
| */ |
| PercentileExpr *n = makeNode(PercentileExpr); |
| n->perctype = UNKNOWNOID; |
| n->args = list_make1($3); |
| n->perckind = PERC_CONT; |
| n->sortClause = $10; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| | PERCENTILE_DISC '(' a_expr ')' WITHIN GROUP_P '(' ORDER BY sortby_list ')' |
| { |
| PercentileExpr *n = makeNode(PercentileExpr); |
| n->perctype = UNKNOWNOID; |
| n->args = list_make1($3); |
| n->perckind = PERC_DISC; |
| n->sortClause = $10; |
| n->location = @1; |
| $$ = (Node *) n; |
| } |
| ; |
| |
| /* |
| * 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); } |
| ; |
| |
| sub_type: ANY { $$ = ANY_SUBLINK; } |
| | SOME { $$ = ANY_SUBLINK; } |
| | ALL { $$ = ALL_SUBLINK; } |
| ; |
| |
| all_Op: Op { $$ = $1; } |
| | MathOp { $$ = $1; } |
| ; |
| |
| MathOp: '+' { $$ = "+"; } |
| | '-' { $$ = "-"; } |
| | '*' { $$ = "*"; } |
| | '/' { $$ = "/"; } |
| | '%' { $$ = "%"; } |
| | '^' { $$ = "^"; } |
| | '<' { $$ = "<"; } |
| | '>' { $$ = ">"; } |
| | '=' { $$ = "="; } |
| ; |
| |
| 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 LIKE |
| { $$ = list_make1(makeString("!~~")); } |
| | ILIKE |
| { $$ = list_make1(makeString("~~*")); } |
| | NOT ILIKE |
| { $$ = list_make1(makeString("!~~*")); } |
| /* cannot put SIMILAR TO here, because SIMILAR TO is a hack. |
| * the regular expression is preprocessed by a function (similar_escape), |
| * and the ~ operator for posix regular expressions is used. |
| * x SIMILAR TO y -> x ~ similar_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); |
| } |
| ; |
| |
| extract_list: |
| extract_arg FROM a_expr |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_String; |
| n->val.val.str = $1; |
| $$ = list_make2((Node *) n, $3); |
| } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| type_list: type_list ',' Typename |
| { |
| $$ = lappend($1, $3); |
| } |
| | Typename |
| { |
| $$ = list_make1($1); |
| } |
| ; |
| |
| array_expr_list: array_expr |
| { $$ = list_make1($1); } |
| | array_expr_list ',' array_expr |
| { $$ = lappend($1, $3); } |
| ; |
| |
| array_expr: '[' expr_list ']' |
| { |
| ArrayExpr *n = makeNode(ArrayExpr); |
| n->elements = $2; |
| $$ = (Node *)n; |
| } |
| | '[' array_expr_list ']' |
| { |
| ArrayExpr *n = makeNode(ArrayExpr); |
| n->elements = $2; |
| $$ = (Node *)n; |
| } |
| ; |
| |
| /* 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; } |
| ; |
| |
| /* OVERLAY() arguments |
| * SQL99 defines the OVERLAY() function: |
| * o overlay(text placing text from int for int) |
| * o overlay(text placing text from int) |
| */ |
| overlay_list: |
| a_expr overlay_placing substr_from substr_for |
| { |
| $$ = list_make4($1, $2, $3, $4); |
| } |
| | a_expr overlay_placing substr_from |
| { |
| $$ = list_make3($1, $2, $3); |
| } |
| ; |
| |
| overlay_placing: |
| PLACING a_expr |
| { $$ = $2; } |
| ; |
| |
| /* 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); } |
| | /*EMPTY*/ { $$ = NIL; } |
| ; |
| |
| /* SUBSTRING() arguments |
| * SQL9x defines a specific syntax for arguments to SUBSTRING(): |
| * o substring(text from int for int) |
| * o substring(text from int) get entire string from starting point "int" |
| * o substring(text for int) get first "int" characters of string |
| * o substring(text from pattern) get entire string matching pattern |
| * o substring(text from pattern for escape) same with specified escape char |
| * We also want to support generic substring functions which accept |
| * the usual generic list of arguments. So we will accept both styles |
| * here, and convert the SQL9x style to the generic list for further |
| * processing. - thomas 2000-11-28 |
| */ |
| substr_list: |
| a_expr substr_from substr_for |
| { |
| $$ = list_make3($1, $2, $3); |
| } |
| | a_expr substr_for substr_from |
| { |
| /* not legal per SQL99, but might as well allow it */ |
| $$ = list_make3($1, $3, $2); |
| } |
| | a_expr substr_from |
| { |
| $$ = list_make2($1, $2); |
| } |
| | a_expr substr_for |
| { |
| /* |
| * 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. |
| */ |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_Integer; |
| n->val.val.ival = 1; |
| $$ = list_make3($1, (Node *) n, |
| makeTypeCast($2, SystemTypeName("int4"), -1)); |
| } |
| | expr_list |
| { |
| $$ = $1; |
| } |
| | /*EMPTY*/ |
| { $$ = NIL; } |
| ; |
| |
| substr_from: |
| FROM a_expr { $$ = $2; } |
| ; |
| |
| substr_for: FOR a_expr { $$ = $2; } |
| ; |
| |
| 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 SQL92-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; |
| $$ = (Node *)c; |
| } |
| ; |
| |
| when_clause_list: |
| /* There must be at least one */ |
| when_clause { $$ = list_make1($1); } |
| | when_clause_list when_clause { $$ = lappend($1, $2); } |
| ; |
| |
| when_clause: |
| WHEN when_operand THEN a_expr |
| { |
| CaseWhen *w = makeNode(CaseWhen); |
| w->expr = (Expr *) $2; |
| w->result = (Expr *) $4; |
| $$ = (Node *) w; |
| } |
| ; |
| |
| when_operand: |
| a_expr { $$ = $1; } |
| | IS NOT DISTINCT FROM a_expr { $$ = makeIsNotDistinctFromNode($5,@2); } |
| ; |
| |
| case_default: |
| ELSE a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| case_arg: a_expr { $$ = $1; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /* |
| * Oracle-compatible DECODE function: |
| * DECODE(lhs, rhs, res [, rhs2, res2 ]... [, def_res]): |
| * returns resX if lhs = rhsX, or def_res if no match found |
| * It is transformed into: |
| * CASE lhs WHEN IS NOT DISTINCT FROM rhs THEN res |
| * [WHEN IS NOT DISTINCT FROM rhs2 THEN res2] ... |
| * ELSE def_res END |
| */ |
| decode_expr: |
| DECODE '(' a_expr search_result_list decode_default ')' |
| { |
| CaseExpr *c = makeNode(CaseExpr); |
| c->casetype = InvalidOid; /* not analyzed yet */ |
| c->arg = (Expr *) $3; |
| c->args = $4; |
| c->defresult = (Expr *) $5; |
| $$ = (Node *) c; |
| } |
| ; |
| |
| search_result_list: |
| search_result { $$ = list_make1($1); } |
| | search_result_list search_result { $$ = lappend($1, $2); } |
| ; |
| |
| search_result: |
| ',' a_expr ',' a_expr |
| { |
| Node *n = makeIsNotDistinctFromNode($2,@2); |
| CaseWhen *w = makeNode(CaseWhen); |
| w->expr = (Expr *) n; |
| w->result = (Expr *) $4; |
| $$ = (Node *) w; |
| } |
| ; |
| |
| decode_default: |
| ',' a_expr { $$ = $2; } |
| | /*EMPTY*/ { $$ = NULL; } |
| ; |
| |
| |
| /* |
| * columnref starts with relation_name not ColId, so that OLD and NEW |
| * references can be accepted. Note that when there are more than two |
| * dotted names, the first name is not actually a relation name... |
| */ |
| columnref: relation_name |
| { |
| $$ = makeColumnRef($1, NIL, @1); |
| } |
| | relation_name indirection |
| { |
| $$ = makeColumnRef($1, $2, @1); |
| } |
| ; |
| |
| indirection_el: |
| '.' attr_name |
| { |
| $$ = (Node *) makeString($2); |
| } |
| | '.' '*' |
| { |
| $$ = (Node *) makeString("*"); |
| } |
| | '[' a_expr ']' |
| { |
| A_Indices *ai = makeNode(A_Indices); |
| ai->lidx = NULL; |
| ai->uidx = $2; |
| $$ = (Node *) ai; |
| } |
| | '[' a_expr ':' a_expr ']' |
| { |
| A_Indices *ai = makeNode(A_Indices); |
| ai->lidx = $2; |
| ai->uidx = $4; |
| $$ = (Node *) ai; |
| } |
| ; |
| |
| 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*/ |
| ; |
| |
| /* |
| * The SQL spec defines "contextually typed value expressions" and |
| * "contextually typed row value constructors", which for our purposes |
| * are the same as "a_expr" and "row" except that DEFAULT can appear at |
| * the top level. |
| */ |
| |
| ctext_expr: |
| a_expr { $$ = (Node *) $1; } |
| | DEFAULT { $$ = (Node *) makeNode(SetToDefault); } |
| ; |
| |
| ctext_expr_list: |
| ctext_expr { $$ = list_make1($1); } |
| | ctext_expr_list ',' ctext_expr { $$ = lappend($1, $3); } |
| ; |
| |
| /* |
| * We should allow ROW '(' ctext_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. |
| */ |
| ctext_row: '(' ctext_expr_list ')' { $$ = $2; } |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * target list for SELECT |
| * |
| *****************************************************************************/ |
| |
| target_list: |
| target_el { $$ = list_make1($1); } |
| | target_list ',' target_el { $$ = lappend($1, $3); } |
| ; |
| |
| target_el: a_expr AS ColLabel |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $3; |
| $$->indirection = NIL; |
| $$->val = (Node *)$1; |
| $$->location = @1; |
| } |
| /* |
| * Postgres supports omitting AS only for column labels that aren't |
| * any known keyword. There is an ambiguity against postfix |
| * operators: is "a ! b" an infix expression, or a postfix |
| * expression and a column label? We prefer to resolve this |
| * as an infix expression, which we accomplish by assigning |
| * IDENT a precedence higher than POSTFIXOP. |
| * |
| * In GPDB, we extent this to allow most |
| * unreserved_keywords by also assigning them a |
| * precedence. There are certain keywords that can't work |
| * without the as: reserved_keywords, the date modifier |
| * suffixes (DAY, MONTH, YEAR, etc) and a few other |
| * obscure cases. |
| */ |
| | a_expr IDENT |
| { |
| $$ = makeNode(ResTarget); |
| $$->name = $2; |
| $$->indirection = NIL; |
| $$->val = (Node *)$1; |
| $$->location = @1; |
| } |
| | a_expr ColLabelNoAs |
| { |
| $$ = 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(makeString("*")); |
| n->location = @1; |
| |
| $$ = makeNode(ResTarget); |
| $$->name = NULL; |
| $$->indirection = NIL; |
| $$->val = (Node *)n; |
| $$->location = @1; |
| } |
| |
| ; |
| |
| |
| /***************************************************************************** |
| * |
| * Names and constants |
| * |
| *****************************************************************************/ |
| |
| relation_name: |
| SpecialRuleRelation { $$ = $1; } |
| | ColId { $$ = $1; } |
| ; |
| |
| 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: |
| relation_name |
| { |
| $$ = makeNode(RangeVar); |
| $$->catalogname = NULL; |
| $$->schemaname = NULL; |
| $$->relname = $1; |
| $$->location = @1; |
| } |
| | relation_name indirection |
| { |
| check_qualified_name($2); |
| $$ = makeNode(RangeVar); |
| 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))))); |
| break; |
| } |
| $$->location = @1; |
| } |
| ; |
| |
| name_list: name |
| { $$ = list_make1(makeString($1)); } |
| | name_list ',' name |
| { $$ = lappend($1, makeString($3)); } |
| ; |
| |
| |
| name: ColId { $$ = $1; }; |
| |
| database_name: |
| ColId { $$ = $1; }; |
| |
| access_method: |
| ColId { $$ = $1; }; |
| |
| attr_name: ColLabel { $$ = $1; }; |
| |
| index_name: ColId { $$ = $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 ('(' 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: function_name |
| { $$ = list_make1(makeString($1)); } |
| | relation_name indirection |
| { $$ = check_func_name(lcons(makeString($1), $2)); } |
| ; |
| |
| |
| /* |
| * Constants |
| */ |
| AexprConst: Iconst |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_Integer; |
| n->val.val.ival = $1; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | FCONST |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_Float; |
| n->val.val.str = $1; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | Sconst |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_String; |
| n->val.val.str = $1; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | BCONST |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_BitString; |
| n->val.val.str = $1; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | 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>. |
| */ |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_BitString; |
| n->val.val.str = $1; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | ConstTypename Sconst |
| { |
| A_Const *n = makeNode(A_Const); |
| n->typname = $1; |
| n->val.type = T_String; |
| n->val.val.str = $2; |
| n->location = @2; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| | ConstInterval Sconst opt_interval |
| { |
| A_Const *n = makeNode(A_Const); |
| n->typname = $1; |
| n->val.type = T_String; |
| n->val.val.str = $2; |
| n->location = @2; /*CDB*/ |
| /* precision is not specified, but fields may be... */ |
| if ($3 != INTERVAL_FULL_RANGE) |
| n->typname->typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, $3); |
| $$ = (Node *)n; |
| } |
| | ConstInterval '(' Iconst ')' Sconst opt_interval |
| { |
| A_Const *n = makeNode(A_Const); |
| n->typname = $1; |
| n->val.type = T_String; |
| n->val.val.str = $5; |
| n->location = @5; /*CDB*/ |
| /* precision specified, and fields may be... */ |
| if ($3 < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision must not be negative", |
| $3))); |
| if ($3 > MAX_INTERVAL_PRECISION) |
| { |
| ereport(WARNING, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d", |
| $3, MAX_INTERVAL_PRECISION))); |
| $3 = MAX_INTERVAL_PRECISION; |
| } |
| n->typname->typmod = INTERVAL_TYPMOD($3, $6); |
| $$ = (Node *)n; |
| } |
| | TRUE_P |
| { |
| $$ = (Node *)makeBoolAConst(TRUE, @1); |
| } |
| | FALSE_P |
| { |
| $$ = (Node *)makeBoolAConst(FALSE, @1); |
| } |
| | NULL_P |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_Null; |
| n->location = @1; /*CDB*/ |
| $$ = (Node *)n; |
| } |
| ; |
| |
| Iconst: ICONST { $$ = $1; }; |
| Sconst: SCONST { $$ = $1; }; |
| RoleId: ColId { $$ = $1; }; |
| QueueId: ColId { $$ = $1; }; |
| |
| SignedIconst: ICONST { $$ = $1; } |
| | '+' ICONST { $$ = + $2; } |
| | '-' ICONST { $$ = - $2; } |
| ; |
| |
| /* |
| * 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 identifier --- names that can be type names. |
| */ |
| type_name: IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| ; |
| |
| /* Function identifier --- names that can be function names. |
| */ |
| function_name: |
| IDENT { $$ = $1; } |
| | unreserved_keyword { $$ = pstrdup($1); } |
| | 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); } |
| | func_name_keyword { $$ = pstrdup($1); } |
| | reserved_keyword { $$ = pstrdup($1); } |
| ; |
| |
| |
| /* |
| * Keyword category lists. Generally, every keyword present in |
| * the Postgres grammar should appear in exactly one of these lists. |
| * |
| * Put a new keyword into the first list that it can go into without causing |
| * shift or reduce conflicts. The earlier lists define "less reserved" |
| * categories of keywords. |
| * |
| * Make sure that each keyword's category in parser/kwlist.h matches where |
| * it is listed here. (Someday we may be able to generate these lists and |
| * kwlist.h's table from a common master list.) |
| */ |
| |
| /* "Unreserved" keywords --- available for use as any kind of name. |
| */ |
| unreserved_keyword: |
| ABORT_P |
| | ABSOLUTE_P |
| | ACCESS |
| | ACTION |
| | ACTIVE |
| | ADD_P |
| | ADMIN |
| | AFTER |
| | AGGREGATE |
| | ALSO |
| | ALTER |
| | ASSERTION |
| | ASSIGNMENT |
| | AT |
| | BACKWARD |
| | BEFORE |
| | BEGIN_P |
| | BY |
| | CACHE |
| | CALLED |
| | CASCADE |
| | CASCADED |
| | CHAIN |
| | CHARACTERISTICS |
| | CHECKPOINT |
| | CLASS |
| | CLOSE |
| | CLUSTER |
| | COMMENT |
| | COMMIT |
| | COMMITTED |
| | CONCURRENTLY |
| | CONNECTION |
| | CONSTRAINTS |
| | CONTAINS |
| | CONTENT_P |
| | CONTINUE_P |
| | CONVERSION_P |
| | COPY |
| | COST |
| | CREATEDB |
| | CREATEEXTTABLE |
| | CREATEROLE |
| | CREATEUSER |
| | CSV |
| | CURRENT |
| | CURSOR |
| | CYCLE |
| | DATA_P |
| | DATABASE |
| | DAY_P |
| | DEALLOCATE |
| | DECLARE |
| | DEFAULTS |
| | DEFERRED |
| | DEFINER |
| | DELETE_P |
| | DELIMITER |
| | DELIMITERS |
| | DENY |
| | DISABLE_P |
| | DOMAIN_P |
| | DOUBLE_P |
| | DROP |
| | DXL |
| | EACH |
| | ENABLE_P |
| | ENCODING |
| | ENCRYPTED |
| | ENUM_P |
| | ERRORS |
| | ESCAPE |
| | EVERY |
| | EXCHANGE |
| | EXCLUDING |
| | EXCLUSIVE |
| | EXECUTE |
| | EXPLAIN |
| | EXTERNAL |
| | FIELDS |
| | FILESPACE |
| | FILESYSTEM |
| | FILL |
| | FIRST_P |
| | FORCE |
| | FORMAT |
| | FORMATTER |
| | FORWARD |
| | FUNCTION |
| | GB |
| | GLOBAL |
| | GRANTED |
| | HANDLER |
| | HASH |
| | HEADER_P |
| | HOLD |
| | HOST |
| | HOUR_P |
| | IDENTITY_P |
| | IF_P |
| | IGNORE_P |
| | IMMEDIATE |
| | IMMUTABLE |
| | IMPLICIT_P |
| | INCLUDING |
| | INCLUSIVE |
| | INCREMENT |
| | INDEX |
| | INDEXES |
| | INHERIT |
| | INHERITS |
| | INPUT_P |
| | INSENSITIVE |
| | INSERT |
| | INSTEAD |
| | INVOKER |
| | ISOLATION |
| | KB |
| | KEEP /* gp */ |
| | KEY |
| | LANCOMPILER |
| | LANGUAGE |
| | LARGE_P |
| | LAST_P |
| | LEVEL |
| | LIST |
| | LISTEN |
| | LOAD |
| | LOCAL |
| | LOCATION |
| | LOCK_P |
| | LOGIN_P |
| | MAPPING |
| | MASTER |
| | MATCH |
| | MAXVALUE |
| | MB |
| | MERGE |
| | MINUTE_P |
| | MINVALUE |
| | MIRROR |
| | MISSING |
| | MODE |
| | MODIFIES |
| | MODIFY |
| | MONTH_P |
| | MOVE |
| | NAME_P |
| | NAMES |
| | NEWLINE |
| | NEXT |
| | NO |
| | NOCREATEDB |
| | NOCREATEEXTTABLE |
| | NOCREATEROLE |
| | NOCREATEUSER |
| | NOINHERIT |
| | NOLOGIN_P |
| | NOOVERCOMMIT |
| | NOSUPERUSER |
| | NOTHING |
| | NOTIFY |
| | NOWAIT |
| | NULLS_P |
| | OBJECT_P |
| | OF |
| | OIDS |
| | OPERATOR |
| | OPTION |
| | OPTIONS |
| | ORDERED |
| | OTHERS |
| | OVER |
| | OVERCOMMIT |
| | OWNED |
| | OWNER |
| | PARTIAL |
| | PARTITIONS |
| | PASSWORD |
| | PB |
| | PERCENT |
| | PREPARE |
| | PREPARED |
| | PRESERVE |
| | PRIOR |
| | PRIVILEGES |
| | PROCEDURAL |
| | PROCEDURE |
| | PROTOCOL |
| | QUEUE |
| | QUOTE |
| | RANDOMLY /* gp */ |
| | READ |
| | READABLE |
| | READS |
| | REASSIGN |
| | RECHECK |
| | RECURSIVE |
| | REINDEX |
| | REJECT_P /* gp */ |
| | RELATIVE_P |
| | RELEASE |
| | RENAME |
| | REPEATABLE |
| | REPLACE |
| | RESET |
| | RESOURCE |
| | RESTART |
| | RESTRICT |
| | RETURNS |
| | REVOKE |
| | ROLE |
| | ROLLBACK |
| | ROOTPARTITION |
| | RULE |
| | SAVEPOINT |
| | SEARCH |
| | SERVER |
| | SCHEMA |
| | SCROLL |
| | SECOND_P |
| | SECURITY |
| | SEGMENT |
| | SEQUENCE |
| | SERIALIZABLE |
| | SESSION |
| | SET |
| | SHARE |
| | SHOW |
| | SIMPLE |
| | SPLIT |
| | SQL |
| | STABLE |
| | START |
| | STATEMENT |
| | STATISTICS |
| | STDIN |
| | STDOUT |
| | STORAGE |
| | STRICT_P |
| | SUBPARTITION |
| | SUBPARTITIONS |
| | SUPERUSER_P |
| | SYSID |
| | SYSTEM_P |
| | TABLESPACE |
| | TB |
| | TEMP |
| | TEMPLATE |
| | TEMPORARY |
| | THRESHOLD |
| | TIES |
| | TRANSACTION |
| | TRIGGER |
| | TRUNCATE |
| | TRUSTED |
| | TYPE_P |
| | UNCOMMITTED |
| | UNENCRYPTED |
| | UNKNOWN |
| | UNLISTEN |
| | UNTIL |
| | UPDATE |
| | VACUUM |
| | VALID |
| | VALIDATION /* gp */ |
| | VALIDATOR |
| | VALUE_P |
| | VARYING |
| | VERSION_P |
| | VIEW |
| | VOLATILE |
| | WEB /* gp */ |
| | WITHIN |
| | WITHOUT |
| | WORK |
| | WRAPPER |
| | WRITABLE |
| | WRITE |
| | YEAR_P |
| | ZONE |
| ; |
| |
| /* |
| * ColLabelNoAs is used for SELECT element aliases that don't have the |
| * AS keyword. We always allow IDENT, so anything in double-quotes is |
| * also OK. Beyond that, any keywords listed here can be a column |
| * alias even when you omit the AS keyword. |
| * |
| * We could add some of the reserved_keywords to this list, but I'm |
| * reluctant to do so because it might restrict future enhancements to |
| * the grammar. |
| */ |
| |
| ColLabelNoAs: keywords_ok_in_alias_no_as { $$=pstrdup($1); } |
| ; |
| |
| keywords_ok_in_alias_no_as: PartitionIdentKeyword |
| | TABLESPACE |
| | ADD_P |
| | ALTER |
| | AT |
| ; |
| |
| PartitionColId: PartitionIdentKeyword { $$ = pstrdup($1); } |
| | IDENT { $$ = pstrdup($1); } |
| ; |
| |
| PartitionIdentKeyword: ABORT_P |
| | ABSOLUTE_P |
| | ACCESS |
| | ACTION |
| | ACTIVE |
| | ADMIN |
| | AFTER |
| | AGGREGATE |
| | ALSO |
| | ASSERTION |
| | ASSIGNMENT |
| | BACKWARD |
| | BEFORE |
| | BEGIN_P |
| | BY |
| | CACHE |
| | CALLED |
| | CASCADE |
| | CASCADED |
| | CHAIN |
| | CHARACTERISTICS |
| | CHECKPOINT |
| | CLASS |
| | CLOSE |
| | CLUSTER |
| | COMMENT |
| | COMMIT |
| | COMMITTED |
| | CONCURRENTLY |
| | CONNECTION |
| | CONSTRAINTS |
| | CONTAINS |
| | CONVERSION_P |
| | COPY |
| | COST |
| | CREATEDB |
| | CREATEEXTTABLE |
| | CREATEROLE |
| | CREATEUSER |
| | CSV |
| | CURRENT |
| | CURSOR |
| | CYCLE |
| | DATABASE |
| | DEALLOCATE |
| | DECLARE |
| | DEFAULTS |
| | DEFERRED |
| | DEFINER |
| | DELETE_P |
| | DELIMITER |
| | DELIMITERS |
| | DISABLE_P |
| | DOMAIN_P |
| | DOUBLE_P |
| | DROP |
| | EACH |
| | ENABLE_P |
| | ENCODING |
| | ENCRYPTED |
| | ERRORS |
| | ESCAPE |
| | EVERY |
| | EXCHANGE |
| | EXCLUDING |
| | EXCLUSIVE |
| | EXECUTE |
| | EXPLAIN |
| | EXTERNAL |
| | FIELDS |
| | FILL |
| | FIRST_P |
| | FORCE |
| | FORMAT |
| | FORMATTER |
| | FORWARD |
| | FUNCTION |
| | GB |
| | GLOBAL |
| | GRANTED |
| | HANDLER |
| | HASH |
| | HEADER_P |
| | HOLD |
| | HOST |
| | IF_P |
| | IMMEDIATE |
| | IMMUTABLE |
| | IMPLICIT_P |
| | INCLUDING |
| | INCLUSIVE |
| | INCREMENT |
| | INDEX |
| | INDEXES |
| | INHERIT |
| | INHERITS |
| | INPUT_P |
| | INSENSITIVE |
| | INSERT |
| | INSTEAD |
| | INVOKER |
| | ISOLATION |
| | KB |
| | KEY |
| | LANCOMPILER |
| | LANGUAGE |
| | LARGE_P |
| | LAST_P |
| | LEVEL |
| | LIST |
| | LISTEN |
| | LOAD |
| | LOCAL |
| | LOCATION |
| | LOCK_P |
| | LOGIN_P |
| | MASTER |
| | MATCH |
| | MAXVALUE |
| | MB |
| | MERGE |
| | MINVALUE |
| | MIRROR |
| | MISSING |
| | MODE |
| | MODIFIES |
| | MODIFY |
| | MOVE |
| | NAMES |
| | NEWLINE |
| | NEXT |
| | NO |
| | NOCREATEDB |
| | NOCREATEROLE |
| | NOCREATEUSER |
| | NOINHERIT |
| | NOLOGIN_P |
| | NOOVERCOMMIT |
| | NOSUPERUSER |
| | NOTHING |
| | NOTIFY |
| | NOWAIT |
| | OBJECT_P |
| | OF |
| | OIDS |
| | OPERATOR |
| | OPTION |
| | OTHERS |
| | OVERCOMMIT |
| | OWNED |
| | OWNER |
| | PARTIAL |
| | PARTITIONS |
| | PASSWORD |
| | PB |
| | PERCENT |
| | PREPARE |
| | PREPARED |
| | PRESERVE |
| | PRIOR |
| | PRIVILEGES |
| | PROCEDURAL |
| | PROCEDURE |
| | PROTOCOL |
| | QUEUE |
| | QUOTE |
| | READ |
| | REASSIGN |
| | RECHECK |
| | REINDEX |
| | RELATIVE_P |
| | RELEASE |
| | RENAME |
| | REPEATABLE |
| | REPLACE |
| | RESET |
| | RESOURCE |
| | RESTART |
| | RESTRICT |
| | RETURNS |
| | REVOKE |
| | ROLE |
| | ROLLBACK |
| | RULE |
| | SAVEPOINT |
| | SCHEMA |
| | SCROLL |
| | SECURITY |
| | SEGMENT |
| | SEQUENCE |
| | SERIALIZABLE |
| | SESSION |
| | SET |
| | SHARE |
| | SHOW |
| | SIMPLE |
| | SPLIT |
| | SQL |
| | STABLE |
| | START |
| | STATEMENT |
| | STATISTICS |
| | STDIN |
| | STDOUT |
| | STORAGE |
| | STRICT_P |
| | SUBPARTITION |
| | SUBPARTITIONS |
| | SUPERUSER_P |
| | SYSID |
| | SYSTEM_P |
| | TB |
| | TEMP |
| | TEMPLATE |
| | TEMPORARY |
| | THRESHOLD |
| | TIES |
| | TRANSACTION |
| | TRIGGER |
| | TRUNCATE |
| | TRUSTED |
| | TYPE_P |
| | UNCOMMITTED |
| | UNENCRYPTED |
| | UNKNOWN |
| | UNLISTEN |
| | UNTIL |
| | UPDATE |
| | VACUUM |
| | VALID |
| | VALIDATOR |
| | VIEW |
| | VOLATILE |
| | WORK |
| | WRITE |
| | ZONE |
| | BIGINT |
| | BIT |
| | BOOLEAN_P |
| | COALESCE |
| | CONVERT |
| | CUBE |
| | DEC |
| | DECIMAL_P |
| | EXISTS |
| | EXTRACT |
| | FLOAT_P |
| | GREATEST |
| | GROUP_ID |
| | GROUPING |
| | INOUT |
| | INT_P |
| | INTEGER |
| | INTERVAL |
| | LEAST |
| | NATIONAL |
| | NCHAR |
| | NONE |
| | NULLIF |
| | NUMERIC |
| | OUT_P |
| | OVERLAY |
| | POSITION |
| | PRECISION |
| | REAL |
| | ROLLUP |
| | ROW |
| | SETOF |
| | SETS |
| | SMALLINT |
| | SUBSTRING |
| | TIME |
| | TIMESTAMP |
| | TREAT |
| | TRIM |
| | VALUES |
| | VARCHAR |
| | AUTHORIZATION |
| | BINARY |
| | FREEZE |
| | LOG_P |
| | OUTER_P |
| | VERBOSE |
| ; |
| |
| /* 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: |
| BIGINT |
| | BIT |
| | BOOLEAN_P |
| | CHAR_P |
| | CHARACTER |
| | COALESCE |
| | CONVERT |
| | CUBE |
| | DEC |
| | DECIMAL_P |
| | EXISTS |
| | EXTRACT |
| | FLOAT_P |
| | GREATEST |
| | GROUP_ID |
| | GROUPING |
| | INOUT |
| | INT_P |
| | INTEGER |
| | INTERVAL |
| | LEAST |
| | MEDIAN |
| | NATIONAL |
| | NCHAR |
| | NONE |
| | NULLIF |
| | NUMERIC |
| | OUT_P |
| | OVERLAY |
| | PERCENTILE_CONT |
| | PERCENTILE_DISC |
| | POSITION |
| | PRECISION |
| | REAL |
| | ROLLUP |
| | ROW |
| | SETOF |
| | SETS |
| | SMALLINT |
| | SUBSTRING |
| | TIME |
| | TIMESTAMP |
| | TREAT |
| | TRIM |
| | VALUES |
| | VARCHAR |
| ; |
| |
| /* Function identifier --- keywords that can be 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 |
| */ |
| func_name_keyword: |
| AUTHORIZATION |
| | BINARY |
| | CROSS |
| | CURRENT_SCHEMA |
| | FREEZE |
| | FULL |
| | ILIKE |
| | INNER_P |
| | IS |
| | ISNULL |
| | JOIN |
| | LEFT |
| | LIKE |
| | LOG_P |
| | NATURAL |
| | NOTNULL |
| | OUTER_P |
| | OVERLAPS |
| | RIGHT |
| | SIMILAR |
| | 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 |
| | BETWEEN |
| | BOTH |
| | CASE |
| | CAST |
| | CHECK |
| | COLLATE |
| | COLUMN |
| | CONSTRAINT |
| | CREATE |
| | CURRENT_CATALOG |
| | CURRENT_DATE |
| | CURRENT_ROLE |
| | CURRENT_TIME |
| | CURRENT_TIMESTAMP |
| | CURRENT_USER |
| | DECODE |
| | DEFAULT |
| | DEFERRABLE |
| | DESC |
| | DISTINCT |
| | DISTRIBUTED /* gp */ |
| | DO |
| | ELSE |
| | END_P |
| | EXCEPT |
| | EXCLUDE |
| | FALSE_P |
| | FETCH |
| | FILTER |
| | FOLLOWING |
| | FOR |
| | FOREIGN |
| | FROM |
| | GRANT |
| | GROUP_P |
| | HAVING |
| | IN_P |
| | INITIALLY |
| | INTERSECT |
| | INTO |
| | LEADING |
| | LIMIT |
| | LOCALTIME |
| | LOCALTIMESTAMP |
| | NEW |
| | NOT |
| | NULL_P |
| | OFF |
| | OFFSET |
| | OLD |
| | ON |
| | ONLY |
| | OR |
| | ORDER |
| | PARTITION |
| | PLACING |
| | PRECEDING |
| | PRIMARY |
| | RANGE |
| | REFERENCES |
| | RETURNING |
| | ROWS |
| | SCATTER /* gp */ |
| | SELECT |
| | SESSION_USER |
| | SOME |
| | SYMMETRIC |
| | TABLE |
| | THEN |
| | TO |
| | TRAILING |
| | TRUE_P |
| | UNBOUNDED |
| | UNION |
| | UNIQUE |
| | USER |
| | USING |
| | WINDOW |
| | WITH |
| | WHEN |
| | WHERE |
| ; |
| |
| |
| SpecialRuleRelation: |
| OLD |
| { |
| if (QueryIsRule) |
| $$ = "*OLD*"; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("OLD used in query that is not in a rule"))); |
| } |
| | NEW |
| { |
| if (QueryIsRule) |
| $$ = "*NEW*"; |
| else |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("NEW used in query that is not in a rule"))); |
| } |
| ; |
| |
| %% |
| |
| static Node * |
| makeAddPartitionCreateStmt(Node *n, Node *subSpec) |
| { |
| AlterPartitionCmd *pc_StAttr = (AlterPartitionCmd *)n; |
| CreateStmt *ct = makeNode(CreateStmt); |
| PartitionBy *pBy = NULL; |
| |
| ct->base.relation = makeRangeVar(NULL /*catalogname*/, NULL, "fake_partition_name", -1); |
| |
| /* in analyze.c, fill in tableelts with a list of inhrelation of |
| the partition parent table, and fill in inhrelations with copy |
| of rangevar for parent table */ |
| |
| ct->base.tableElts = NIL; /* fill in later */ |
| ct->base.inhRelations = NIL; /* fill in later */ |
| |
| ct->base.constraints = NIL; |
| |
| if (pc_StAttr) |
| ct->base.options = (List *)pc_StAttr->arg1; |
| else |
| ct->base.options = NIL; |
| |
| ct->base.oncommit = ONCOMMIT_NOOP; |
| |
| if (pc_StAttr && pc_StAttr->arg2) |
| ct->base.tablespacename = strVal(pc_StAttr->arg2); |
| else |
| ct->base.tablespacename = NULL; |
| |
| if (subSpec) /* treat subspec as partition by... */ |
| { |
| pBy = makeNode(PartitionBy); |
| |
| pBy->partSpec = subSpec; |
| pBy->partDepth = 0; |
| pBy->partQuiet = PART_VERBO_NODISTRO; |
| pBy->location = -1; |
| pBy->partDefault = NULL; |
| pBy->parentRel = copyObject(ct->base.relation); |
| } |
| |
| ct->base.distributedBy = NULL; |
| ct->base.partitionBy = (Node *)pBy; |
| ct->oidInfo.relOid = 0; |
| ct->oidInfo.comptypeOid = 0; |
| ct->oidInfo.toastOid = 0; |
| ct->oidInfo.toastIndexOid = 0; |
| ct->oidInfo.toastComptypeOid = 0; |
| ct->base.relKind = RELKIND_RELATION; |
| ct->policy = 0; |
| ct->base.postCreate = NULL; |
| |
| return (Node *)ct; |
| } |
| |
| static Node * |
| makeColumnRef(char *colname, List *indirection, int location) |
| { |
| /* |
| * 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 = indirection; |
| } |
| else |
| { |
| /* got to split the list in two */ |
| i->indirection = list_copy_tail(indirection, nfields); |
| indirection = list_truncate(indirection, nfields); |
| c->fields = lcons(makeString(colname), indirection); |
| } |
| i->arg = (Node *) c; |
| return (Node *) i; |
| } |
| 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 *typname, int location) |
| { |
| /* |
| * Simply generate a TypeCast node. |
| * |
| * Earlier we would determine whether an A_Const would |
| * be acceptable, however Domains require coerce_type() |
| * to process them -- applying constraints as required. |
| */ |
| TypeCast *n = makeNode(TypeCast); |
| n->arg = arg; |
| n->typname = typname; |
| n->location = location; |
| return (Node *) n; |
| } |
| |
| static Node * |
| makeStringConst(char *str, TypeName *typname, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| |
| n->val.type = T_String; |
| n->val.val.str = str; |
| n->typname = typname; |
| n->location = location; |
| |
| return (Node *)n; |
| } |
| |
| 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; |
| n->typname = SystemTypeName("int4"); |
| |
| 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; |
| n->typname = SystemTypeName("float8"); |
| |
| 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, NULL, location); |
| break; |
| } |
| |
| return n; |
| } |
| |
| /* makeBoolAConst() |
| * Create an A_Const node and initialize to a boolean constant. |
| */ |
| static A_Const * |
| makeBoolAConst(bool state, int location) |
| { |
| A_Const *n = makeNode(A_Const); |
| n->val.type = T_String; |
| n->val.val.str = (state? "t": "f"); |
| n->typname = SystemTypeName("bool"); |
| n->location = location; |
| return n; |
| } |
| |
| /* makeOverlaps() |
| * Create and populate a FuncCall node to support the OVERLAPS operator. |
| */ |
| static FuncCall * |
| makeOverlaps(List *largs, List *rargs, int location) |
| { |
| FuncCall *n = makeNode(FuncCall); |
| |
| n->funcname = SystemFuncName("overlaps"); |
| if (list_length(largs) == 1) |
| largs = lappend(largs, largs); |
| else if (list_length(largs) != 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("wrong number of parameters on left side of OVERLAPS expression"), |
| scanner_errposition(location))); |
| if (list_length(rargs) == 1) |
| rargs = lappend(rargs, rargs); |
| else if (list_length(rargs) != 2) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("wrong number of parameters on right side of OVERLAPS expression"), |
| scanner_errposition(location))); |
| n->args = list_concat(largs, rargs); |
| n->agg_order = NIL; |
| n->agg_star = FALSE; |
| n->agg_distinct = FALSE; |
| n->over = NULL; |
| n->location = location; |
| return n; |
| } |
| |
| /* 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) |
| { |
| ListCell *i; |
| |
| foreach(i, names) |
| { |
| if (!IsA(lfirst(i), String)) |
| yyerror("syntax error"); |
| else if (strcmp(strVal(lfirst(i)), "*") == 0) |
| 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) |
| { |
| ListCell *i; |
| |
| foreach(i, names) |
| { |
| if (!IsA(lfirst(i), String)) |
| yyerror("syntax error"); |
| else if (strcmp(strVal(lfirst(i)), "*") == 0) |
| yyerror("syntax error"); |
| } |
| return names; |
| } |
| |
| /* 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); |
| |
| /* keep if IN or INOUT */ |
| if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE) |
| result = lappend(result, p->argType); |
| } |
| return result; |
| } |
| |
| /* findLeftmostSelect() |
| * Find the leftmost component SelectStmt in a set-operation parsetree. |
| */ |
| static SelectStmt * |
| findLeftmostSelect(SelectStmt *node) |
| { |
| while (node && node->op != SETOP_NONE) |
| node = node->larg; |
| Assert(node && IsA(node, SelectStmt) && node->larg == NULL); |
| return node; |
| } |
| |
| /* 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, |
| Node *limitOffset, Node *limitCount, |
| WithClause *withClause) |
| { |
| 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("syntax error at or near \"ORDER BY\""), |
| scanner_errposition(exprLocation((Node *) sortClause)))); |
| stmt->sortClause = sortClause; |
| } |
| /* We can handle multiple locking clauses, though */ |
| stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause); |
| if (limitOffset) |
| { |
| if (stmt->limitOffset) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("syntax error at or near \"OFFSET\""), |
| scanner_errposition(exprLocation(limitOffset)))); |
| stmt->limitOffset = limitOffset; |
| } |
| if (limitCount) |
| { |
| if (stmt->limitCount) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("syntax error at or near \"LIMIT\""), |
| scanner_errposition(exprLocation(limitCount)))); |
| stmt->limitCount = limitCount; |
| } |
| if (withClause) |
| { |
| if (stmt->withClause) |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("syntax error at or near \"WITH\""), |
| scanner_errposition(exprLocation((Node *)withClause)))); |
| stmt->withClause = (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) |
| { |
| TypeName *n = makeNode(TypeName); |
| |
| n->names = list_make2(makeString("pg_catalog"), makeString(name)); |
| n->typmod = -1; |
| n->location = -1; |
| return n; |
| } |
| |
| /* parser_init() |
| * Initialize to parse one query string |
| */ |
| void |
| parser_init(void) |
| { |
| QueryIsRule = FALSE; |
| } |
| |
| /* exprIsNullConstant() |
| * Test whether an a_expr is a plain NULL constant or not. |
| */ |
| bool |
| exprIsNullConstant(Node *arg) |
| { |
| if (arg && IsA(arg, A_Const)) |
| { |
| A_Const *con = (A_Const *) arg; |
| |
| if (con->val.type == T_Null && |
| con->typname == NULL) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /* 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 |
| { |
| char *newval = (char *) palloc(strlen(oldval) + 2); |
| |
| *newval = '-'; |
| strcpy(newval+1, oldval); |
| v->val.str = newval; |
| } |
| } |
| |
| /* |
| * Merge the input and output parameters of a table function. |
| */ |
| static List * |
| mergeTableFuncParameters(List *func_args, List *columns) |
| { |
| ListCell *lc; |
| |
| /* Explicit OUT and INOUT parameters shouldn't be used in this syntax */ |
| foreach(lc, func_args) |
| { |
| FunctionParameter *p = (FunctionParameter *) lfirst(lc); |
| |
| switch (p->mode) |
| { |
| /* Input modes */ |
| case FUNC_PARAM_IN: |
| case FUNC_PARAM_VARIADIC: |
| break; |
| |
| /* Output modes */ |
| case FUNC_PARAM_TABLE: |
| Insist(false); /* not feasible */ |
| break; |
| case FUNC_PARAM_OUT: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("OUT arguments aren't allowed in TABLE functions"))); |
| break; |
| case FUNC_PARAM_INOUT: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("INOUT arguments aren't allowed in TABLE functions"))); |
| break; |
| } |
| } |
| |
| return list_concat(func_args, columns); |
| } |
| |
| /* |
| * Determine return type of a TABLE function. A single result column |
| * returns setof that column's type; otherwise return setof record. |
| */ |
| static TypeName * |
| TableFuncTypeName(List *columns) |
| { |
| TypeName *result; |
| |
| if (list_length(columns) == 1) |
| { |
| FunctionParameter *p = (FunctionParameter *) linitial(columns); |
| |
| result = (TypeName *) copyObject(p->argType); |
| } |
| else |
| result = SystemTypeName("record"); |
| |
| result->setof = true; |
| |
| return result; |
| } |
| |
| static void |
| setWindowExclude(WindowFrame *wframe, WindowExclusion exclude) |
| { |
| switch (exclude) |
| { |
| case WINDOW_EXCLUSION_NULL: |
| wframe->exclude = exclude; |
| return; |
| |
| case WINDOW_EXCLUSION_CUR_ROW: /* exclude current row */ |
| case WINDOW_EXCLUSION_GROUP: /* exclude rows matching us */ |
| case WINDOW_EXCLUSION_TIES: /* exclude rows matching us, and current row */ |
| case WINDOW_EXCLUSION_NO_OTHERS: /* don't exclude */ |
| |
| /* |
| * because the syntax has historically existed without doing anything |
| * we have chosen to add a guc to allow simply ignoring the exclude clause |
| * rather than raising an error. |
| */ |
| if (gp_ignore_window_exclude) |
| { |
| wframe->exclude = WINDOW_EXCLUSION_NULL; |
| return; |
| } |
| |
| /* MPP-13628 */ |
| ereport(ERROR, |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| errmsg("window EXCLUDE clause not yet implemented"))); |
| break; |
| |
| default: |
| ereport(ERROR, |
| (errcode(ERRCODE_SYNTAX_ERROR), |
| errmsg("invalid window EXCLUDE clause"))); |
| break; |
| } |
| } |
| |
| /* |
| * Create the IS_NOT_DISTINCT_FROM expression node |
| * used by CASE x WHEN IS NOT DISTINCT FROM and DECODE() |
| */ |
| static Node* |
| makeIsNotDistinctFromNode(Node *expr, int position) |
| { |
| Node *n = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, |
| (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, |
| "=", NULL, expr, position), position); |
| return n; |
| } |
| |
| /* |
| * Must undefine base_yylex before including scan.c, since we want it |
| * to create the function base_yylex not filtered_base_yylex. |
| */ |
| #undef base_yylex |
| |
| #include "scan.c" |