%{

/*#define YYDEBUG 1*/
/* -------------------------------------------------------------------------
 *
 * gram.y
 *	  POSTGRESQL BISON rules/actions
 *
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 * Portions Copyright (c) 2010-2012 Postgres-XC Development Group
 * Portions Copyright (c) 2021, openGauss Contributors
 *
 *
 * IDENTIFICATION
 *	  src/backend/parser/gram.y
 *
 * HISTORY
 *	  AUTHOR			DATE			MAJOR EVENT
 *	  Andrew Yu			Sept, 1994		POSTQUEL to SQL conversion
 *	  Andrew Yu			Oct, 1994		lispy code conversion
 *
 * NOTES
 *	  CAPITALS are used to represent terminal symbols.
 *	  non-capitals are used to represent non-terminals.
 *	  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.
 *
 * -------------------------------------------------------------------------
 */
#include "postgres.h"
#include "knl/knl_variable.h"

#include <ctype.h>
#include <limits.h>

#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/gs_package.h"
#include "catalog/pg_am.h"
#include "catalog/pg_object.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type_fn.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#ifdef ENABLE_MULTIPLE_NODES
#include "distribute_core.h"
#endif
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/print.h"
#include "optimizer/planner.h"
#include "parser/gramparse.h"
#include "parser/parse_type.h"
#include "parser/parse_hint.h"
#include "parser/scansup.h"
#include "pgxc/pgxc.h"
#include "nodes/nodes.h"
#include "pgxc/poolmgr.h"
#include "parser/parser.h"
#include "storage/lmgr.h"
#include "storage/tcap.h"
#include "storage/lock/waitpolicy.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/rel.h"
#include "utils/numeric.h"
#include "utils/syscache.h"
#include "utils/xml.h"
#include "utils/pl_package.h"
#include "catalog/pg_streaming_fn.h"
#include "mb/pg_wchar.h"
#include "utils/varbit.h"

#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wunused-variable"

#define MAX_ERROR_COUNT 65535
#define MAXFNAMELEN		64
#define isquote(C) ((C) == '\"')
#ifndef ENABLE_MULTIPLE_NODES
DB_CompatibilityAttr g_dbCompatArray[] = {
    {DB_CMPT_A, "A"},
    {DB_CMPT_B, "B"},
    {DB_CMPT_C, "C"},
    {DB_CMPT_PG, "PG"},
	{DB_CMPT_D, "D"}
};

IntervalStylePack g_interStyleVal = {"a"};
#endif

/* 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)

/*
 * 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
#ifdef YYLEX_PARAM
# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
#else
# define YYLEX yylex (&yylval, &yylloc, yyscanner)
#endif

/* Private struct for the result of privilege_target production */
typedef struct PrivTarget
{
	GrantTargetType targtype;
	GrantObjectType objtype;
	List	   *objs;
} PrivTarget;

typedef struct TrgCharacter {
	bool is_follows;
	char* trigger_name;
} TrgCharacter;

typedef struct FetchLimit
{
	Node *limitOffset;
	Node *limitCount;
	bool isPercent;
	bool isWithTies;
	bool isFetch;
    bool isTop;
} FetchLimit;


/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
#define CAS_NOT_DEFERRABLE			0x01
#define CAS_DEFERRABLE				0x02
#define CAS_INITIALLY_IMMEDIATE		0x04
#define CAS_INITIALLY_DEFERRED		0x08
#define CAS_NOT_VALID				0x10
#define CAS_NO_INHERIT				0x20

#define CAS_DISABLE_VALIDATE        0x40
#define CAS_DISABLE_NO_VALIDATE     0x80

#define CAS_NO_VALIDATE             0x00
#define CAS_VALIDATE                0x01
#define CAS_VALIDATE_EMPTY          0x02

/*
 * In the IntoClause structure there is a char value which will eventually be
 * set to RELKIND_RELATION or RELKIND_MATVIEW based on the relkind field in
 * the statement-level structure, which is an ObjectType. Define the default
 * here, which should always be overridden later.
 */
#define INTO_CLAUSE_RELKIND_DEFAULT    '\0'

#define parser_yyerror(msg)  scanner_yyerror(msg, yyscanner)
#define parser_errposition(pos)  scanner_errposition(pos, yyscanner)

static void base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner,
						 const char *msg);
static Node *makeColumnRef(char *colname, List *indirection,
						   int location, core_yyscan_t yyscanner);
static Node *makeTypeCast(Node *arg, TypeName *typname, Node *fmt_list, Node *nls_fmt, Node *default_expr, int location);
static Node *makeStringConst(char *str, int location);
static Node *makeStringConstCast(char *str, int location, TypeName *typname);
static Node *makeIntConst(int val, int location);
static Node *makeFloatConst(char *str, int location);
static Node *makeBitStringConst(char *str, int location);
Node *makeAConst(Value *v, int location);
Node *makeBoolAConst(bool state, int location);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
static List *check_func_name(List *names, core_yyscan_t yyscanner);
static List *check_setting_name(List *names, core_yyscan_t yyscanner);
static List *check_indirection(List *indirection, core_yyscan_t yyscanner);
static List *extractArgTypes(List *parameters);
static void insertSelectOptions(SelectStmt *stmt,
								List *sortClause, List *lockingClause,
								FetchLimit *limitClause,
								WithClause *withClause,
								core_yyscan_t yyscanner);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
static Node *makeAArrayExpr(List *elements, int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
						 List *args, int location);
static Node *makeCallFuncStmt(List* funcname, List* parameters, bool is_call = false);
static List *mergeTableFuncParameters(List *func_args, List *columns);
static TypeName *TableFuncTypeName(List *columns);
static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner);
static void SplitColQualList(List *qualList,
							 List **constraintList, CollateClause **collClause,
							 core_yyscan_t yyscanner);
static void SplitColQualList(List *qualList,
							 List **constraintList, CollateClause **collClause, ClientLogicColumnRef **clientLogicColumnRef,
							 core_yyscan_t yyscanner);
static void processCASbits(int cas_bits, int location, const char *constrType,
			   bool *deferrable, bool *initdeferred, bool *not_valid,
			   bool *no_inherit, core_yyscan_t yyscanner);
static Node *processIntoClauseInSelectStmt(SelectStmt *stmt, IntoClause *itc);
static char* GetPkgName(char* pkgName);
static Expr *makeNodeDecodeCondtion(Expr* firstCond,Expr* secondCond);
static List *make_action_func(List *arguments);
static List *get_func_args(char *sid);
static char *pg_strsep(char **stringp, const char *delim);
static long long get_pid(const char *strsid);
static Node *MakeAnonyBlockFuncStmt(int flag, const char * str);
static CharsetCollateOptions* MakeCharsetCollateOptions(CharsetCollateOptions *options, CharsetCollateOptions *option);
static Node *checkNullNode(Node *n);
static Node *make_AStar_subquery(RangeVar *rangeVar);
#define  TYPE_LEN     4 /* strlen("TYPE") */
#define  DATE_LEN     4 /* strlen("DATE") */
#define  DECLARE_LEN     9 /* strlen(" DECLARE ") */
#define  DECLARE_STR     " DECLARE "
#define  PACKAGE_STR     " PACKAGE "
#define  PACKAGE_LEN     9 /* strlen(" PACKAGE ") */
#define  INSTANTIATION_STR   " INSTANTIATION "
#define  INSTANTIATION_LEN     15
#define  END_STR         "\nEND\n"
#define  END_LEN         6
static int get_outarg_num(List *fun_args);
static int get_table_modes(int nargs, const char *p_argmodes);
static void get_arg_mode_by_name(const char *argname, const char * const *argnames,
				const char *argmodes, const int proargnum,
				bool *have_assigend, char *argmode);
static void get_arg_mode_by_pos(const int pos, const char *argmodes, const int narg,
				bool *have_assigend, char *argmode);
static List *append_inarg_list(const char argmode, const ListCell *cell,List *in_parameter);
static void check_outarg_info(const bool *have_assigend,
				const char *argmodes,const int proargnum);
bool IsValidIdentClientKey(const char *input);
bool IsValidIdent(char *input);
bool IsValidIdentUsername(char *input);
bool IsValidGroupname(const char *input);
static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yyscan_t yyscanner);
static char *GetTargetFuncArgTypeName(char *typeString, TypeName* t);
static char *FormatFuncArgType(core_yyscan_t yyscanner, char *argsString, List* parameters);
static char *ParseFunctionArgSrc(core_yyscan_t yyscanner);
static char *ParseFuncHeadSrc(core_yyscan_t yyscanner, bool isFunction = true);
static void parameter_check_execute_direct(const char* query);
static Node *make_node_from_scanbuf(int start_pos, int end_pos, core_yyscan_t yyscanner);
static int64 SequenceStrGetInt64(const char *str);
static int GetLoadType(int load_type_f, int load_type_s);
static Node *MakeSqlLoadNode(char *colname);
static void checkDeleteRelationError();
static TypeName *ParseFloatByExtentedPrecision(int ival, int location, core_yyscan_t yyscanner);
static void CheckTypmodScale(List* arglist, int location, core_yyscan_t yyscanner);

/* start with .. connect by related utilities */
static bool IsConnectByRootIdent(Node* node);
static void ValidateTripleTuple(Node* node, core_yyscan_t yyscanner, int location, char* token);
static Node* MakeConnectByRootNode(ColumnRef* cr, int location);
static char* MakeConnectByRootColName(char* tabname, char* colname);
static void FilterStartWithUseCases(SelectStmt* stmt, List* locking_clause, core_yyscan_t yyscanner, int location);
static FuncCall* MakePriorAsFunc();

/* B Compatibility Check */
static void BCompatibilityOptionSupportCheck(const char* keyword);

#ifndef ENABLE_MULTIPLE_NODES
static bool CheckWhetherInColList(char *colname, List *col_list);
#endif
static int GetFillerColIndex(char *filler_col_name, List *col_list);
static void RemoveFillerCol(List *filler_list, List *col_list);
static int errstate;
static void CheckPartitionExpr(Node* expr, int* colCount);
static void CheckPartitionExprInner(Node* expr, int* colCount, bool checkTypeCast);
static char* transformIndexOptions(List* list);
static void setAccessMethod(Constraint *n);
static char* GetValidUserHostId(char* userName, char* hostId);
static void CheckHostId(char* hostId);
static void CheckUserHostIsValid();

static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStmt*n);
static Node* MakeNoArgFunctionCall(List* funcName, int location);
static char* IdentResolveToChar(char *ident, core_yyscan_t yyscanner);
static void contain_unsupport_node(Node* node, bool* has_unsupport_default_node);
static List* TransformToConstStrNode(List *inExprList, char* raw_str);
static Alias* generate_alias(Alias* clone_target, const char* default_alias_name);

/* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */
/*$$include "gram-tsql-prologue.y.h"*/
%}

%define api.pure
%expect 0
%name-prefix "base_yy"
%locations

%parse-param {core_yyscan_t yyscanner}
%lex-param   {core_yyscan_t yyscanner}

%union
{
	core_YYSTYPE		core_yystype;
	/* these fields must match core_YYSTYPE: */
	int					ival;
	char				*str;
	const char			*keyword;

	char				chr;
	bool				boolean;
	int64				ival64;
	JoinType			jtype;
	DropBehavior		dbehavior;
	OnCommitAction		oncommit;
	List				*list;
	Node				*node;
	Value				*value;
	ObjectType			objtype;
	TypeName			*typnam;
	FunctionSources		*fun_src;
	FunctionParameter   *fun_param;
	FunctionParameterMode fun_param_mode;
	FuncWithArgs		*funwithargs;
	DefElem				*defelt;
	SortBy				*sortby;
	WindowDef			*windef;
        KeepClause                      *keep;
	JoinExpr			*jexpr;
	IndexElem			*ielem;
	Alias				*alias;
	RangeVar			*range;
	IntoClause			*into;
	WithClause			*with;
	A_Indices			*aind;
	ResTarget			*target;
	struct PrivTarget	*privtarget;
	struct TrgCharacter *trgcharacter;
	struct FetchLimit	*fetchlimit;
	AccessPriv			*accesspriv;
	DbPriv				*dbpriv;
	InsertStmt			*istmt;
	VariableSetStmt		*vsetstmt;
/* PGXC_BEGIN */
	DistributeBy		*distby;
	PGXCSubCluster		*subclus;
/* PGXC_END */
    ForeignPartState    *foreignpartby;
	MergeWhenClause		*mergewhen;
	UpsertClause *upsert;
	EncryptionType algtype;
	LockClauseStrength lockstrength;
	CharsetCollateOptions *charsetcollateopt;
	OnDuplicateAction onduplicate;
	struct CondInfo*	condinfo;
	RotateClause         *rotateinfo;
	UnrotateClause       *unrotateinfo;
	FunctionPartitionInfo *funcPartInfo;
}

%type <node>	stmt schema_stmt
		AlterEventTrigStmt
		AlterDatabaseStmt AlterDatabaseSetStmt AlterDataSourceStmt AlterDomainStmt AlterEnumStmt AlterEventStmt
		AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterSchemaStmt
		AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
		AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
		AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
		AlterSystemStmt
		AlterTriggerStmt
		AlterRoleStmt AlterRoleSetStmt AlterRlsPolicyStmt
		AlterDefaultPrivilegesStmt DefACLAction AlterSessionStmt
		AnalyzeStmt CleanConnStmt ClosePortalStmt ClusterStmt CommentStmt
		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt CreateContQueryStmt CreateDirectoryStmt 
		CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateKeyStmt CreateOpClassStmt
		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
		CreateSchemaStmt CreateSeqStmt CreateStmt CreateStreamStmt CreateTableSpaceStmt
		CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
		CreateDataSourceStmt
		CreateAssertStmt CreateTrigStmt CreateEventTrigStmt
		CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreateRlsPolicyStmt CreateSynonymStmt
		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt DropEventStmt ShowEventStmt
		DropAssertStmt DropSynonymStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt DropRlsPolicyStmt
		DropUserStmt DropdbStmt DropTableSpaceStmt DropDataSourceStmt DropDirectoryStmt DropFdwStmt
		DropForeignServerStmt DropUserMappingStmt ExplainStmt ExecDirectStmt FetchStmt
		GetDiagStmt GrantStmt GrantRoleStmt GrantDbStmt IndexStmt InsertStmt ListenStmt LoadStmt
		LockStmt NotifyStmt ExplainableStmt PreparableStmt
		CreateFunctionStmt CreateEventStmt CreateProcedureStmt CreatePackageStmt CreatePackageBodyStmt  AlterFunctionStmt CompileStmt AlterProcedureStmt ReindexStmt RemoveAggrStmt
		RemoveFuncStmt RemoveOperStmt RemovePackageStmt RenameStmt RevokeStmt RevokeRoleStmt RevokeDbStmt
		RuleActionStmt RuleActionStmtOrEmpty RuleStmt
		SecLabelStmt SelectStmt TimeCapsuleStmt TransactionStmt TruncateStmt CallFuncStmt
		UnlistenStmt UpdateStmt VacuumStmt
		VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt ShutdownStmt VariableMultiSetStmt
		ViewStmt CheckPointStmt CreateConversionStmt
		DeallocateStmt PrepareStmt ExecuteStmt
		DropOwnedStmt ReassignOwnedStmt
		AlterTSConfigurationStmt AlterTSDictionaryStmt AnonyBlockStmt
		BarrierStmt AlterNodeStmt CreateNodeStmt DropNodeStmt AlterCoordinatorStmt
		CreateNodeGroupStmt AlterNodeGroupStmt DropNodeGroupStmt 
		CreatePolicyLabelStmt AlterPolicyLabelStmt DropPolicyLabelStmt 
		CreateAuditPolicyStmt AlterAuditPolicyStmt DropAuditPolicyStmt 
		CreateMaskingPolicyStmt AlterMaskingPolicyStmt DropMaskingPolicyStmt
		CreateResourcePoolStmt AlterResourcePoolStmt DropResourcePoolStmt
		CreateWorkloadGroupStmt AlterWorkloadGroupStmt DropWorkloadGroupStmt
		CreateAppWorkloadGroupMappingStmt AlterAppWorkloadGroupMappingStmt DropAppWorkloadGroupMappingStmt
		MergeStmt PurgeStmt CreateMatViewStmt RefreshMatViewStmt CreateMatViewLogStmt DropMatViewLogStmt CreateAmStmt
		CreateWeakPasswordDictionaryStmt DropWeakPasswordDictionaryStmt
		AlterGlobalConfigStmt DropGlobalConfigStmt
		CreatePublicationStmt AlterPublicationStmt
		CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt DelimiterStmt
		ShrinkStmt

/* <DB4AI> */
/* SNAPSHOTS */
%type <node>	SnapshotStmt
%type <list>	AlterSnapshotCmdOrEmpty AlterSnapshotCmdList AlterSnapshotCmdListNoParens
%type <list>	AlterSnapshotCmdListWithParens SnapshotSample SnapshotSampleList OptSnapshotStratify
%type <str>		SnapshotVersion OptSnapshotVersion OptSnapshotComment
%type <boolean>	OptSnapshotAlias AlterSnapshotDdl AlterSnapshotDdlList
%type <boolean>	OptAlterUpdateSnapshot OptInsertIntoSnapshot OptDeleteFromSnapshot

/* TRAIN MODEL */
%type <node>    CreateModelStmt	hyperparameter_name_value DropModelStmt
%type <list>	features_clause hyperparameter_name_value_list target_clause with_hyperparameters_clause
/* </DB4AI> */

/* oracle object type */
%type <list>	type_body_subprogram Method_specList object_func_args_with_defaults object_proc_args method_decl_in_type_list
%type <node>	element_spec element_decl_in_type subprogram_decl_in_type constructor_decl_in_type map_order_decl_in_type
%type <boolean> final_clause inheritance_clause



%type <node>	select_no_parens select_with_parens select_clause
				simple_select values_clause

%type <node>	alter_column_default opclass_item opclass_drop alter_using AutoIncrementValue
%type <ival>	add_drop opt_asc_desc opt_nulls_order con_asc_desc
%type <ival>	OptNoLog

%type <node>	alter_table_cmd alter_partition_cmd alter_type_cmd opt_collate_clause exchange_partition_cmd move_partition_cmd
				modify_column_cmd reset_partition_cmd modify_partition_cmd
				replica_identity add_column_first_after event_from_clause 
%type <list>	alter_table_cmds alter_partition_cmds alter_table_or_partition alter_type_cmds add_column_cmds modify_column_cmds

%type <dbehavior>	opt_drop_behavior

%type <list>	createdb_opt_list alterdb_opt_list copy_opt_list
				transaction_mode_list weak_password_string_list
				create_extension_opt_list alter_extension_opt_list
				pgxcnode_list pgxcnodes bucket_maps bucket_list lines_options_fin
				opt_pgxcnodes fields_options_list fields_options_fin lines_options_list
%type <defelt>	createdb_opt_item alterdb_opt_item copy_opt_item characterset_option
				transaction_mode_item lines_option_item fields_options_item
				create_extension_opt_item alter_extension_opt_item
				start_opt preserve_opt rename_opt status_opt comments_opt action_opt
				end_opt definer_name_opt

%type <ival>	opt_lock lock_type cast_context opt_wait compile_pkg_opt
%type <ival>	vacuum_option_list vacuum_option_elem opt_verify_options
%type <boolean>	opt_check opt_force opt_or_replace opt_public
				opt_grant_grant_option opt_grant_admin_option
				opt_nowait opt_if_exists opt_with_data opt_large_seq opt_cancelable
%type <ival>	opt_nowait_or_skip

%type <list>	OptRoleList AlterOptRoleList
%type <defelt>	CreateOptRoleElem AlterOptRoleElem

%type <str>		opt_type
%type <str>		foreign_server_version opt_foreign_server_version
%type <str>		data_source_version opt_data_source_version data_source_type opt_data_source_type
%type <str>		auth_ident
%type <str>		opt_in_database opt_rename

%type <str>		OptSchemaName
%type <list>	OptSchemaEltList
%type <boolean>	OptBlockchainWith OptAlterToBlockchain

%type <boolean> TriggerForSpec TriggerForType ForeignTblWritable
%type <ival>	TriggerActionTime
%type <list>	TriggerEvents TriggerOneEvent
%type <value>	TriggerFuncArg
%type <node>	TriggerWhen
%type <list>   event_trigger_when_list event_trigger_value_list
%type <defelt> event_trigger_when_item
%type <chr>        enable_trigger

%type <str>		copy_file_name definer_opt user ev_body ev_where_body event_where_clause
				database_name access_method_clause access_method access_method_clause_without_keyword attr_name
				name namedata_string fdwName cursor_name file_name imcs_partition_name
				index_name cluster_index_specification
				pgxcnode_name pgxcgroup_name resource_pool_name workload_group_name
				application_name password_string hint_string
%type <list>	func_name func_name_opt_arg pkg_name  handler_name qual_Op qual_all_Op subquery_Op
				opt_class opt_inline_handler opt_validator validator_clause
				opt_collation

%type <range>	qualified_name insert_target OptConstrFromTable opt_index_name insert_partition_clause update_delete_partition_clause
				qualified_trigger_name qualified_name_for_delete

%type <str>		all_Op MathOp

%type <str>		RowLevelSecurityPolicyName row_level_security_cmd RLSDefaultForCmd row_level_security_role
%type <boolean>	RLSDefaultPermissive
%type <node>	RLSOptionalUsingExpr
%type <list>	row_level_security_role_list RLSDefaultToRole RLSOptionalToRole

%type <str>		iso_level opt_encoding
%type <node>	grantee
%type <list>	grantee_list
%type <accesspriv> privilege
%type <list>	privileges privilege_list db_privileges db_privilege_list
%type <dbpriv>  db_privilege
%type <str>		privilege_str
%type <privtarget> privilege_target
%type <funwithargs> function_with_argtypes
%type <list>	function_with_argtypes_list
%type <ival>	defacl_privilege_target
%type <defelt>	DefACLOption
%type <list>	DefACLOptionList
%type <node>	opt_default_fmt_clause opt_default_nls_clause

%type <list>	stmtblock stmtmulti
				OptTableElementList TableElementList OptInherit definition tsconf_definition
				OptTypedTableElementList TypedTableElementList
				OptForeignTableElementList ForeignTableElementList
				reloptions opt_reloptions opt_tblspc_options tblspc_options opt_cfoptions cfoptions
				OptWith opt_distinct opt_definition func_args func_args_list
				func_args_with_defaults func_args_with_defaults_list proc_args
				func_as createfunc_opt_list opt_createproc_opt_list alterfunc_opt_list
				aggr_args old_aggr_definition old_aggr_list
				oper_argtypes RuleActionList RuleActionMulti
				opt_column_list columnList opt_name_list opt_analyze_column_define opt_multi_name_list
				opt_include opt_c_include index_including_params
				sort_clause opt_sort_clause sortby_list index_params constraint_params
				name_list UserIdList from_clause from_list opt_array_bounds
				from_list_for_no_table_function
				qualified_name_list any_name any_name_list type_name_list collate_name
				any_operator expr_list attrs callfunc_args
				target_list insert_column_list set_target_list rename_clause_list rename_clause
				set_clause_list set_clause multiple_set_clause
				ctext_expr_list ctext_row def_list tsconf_def_list indirection opt_indirection
				reloption_list tblspc_option_list cfoption_list group_clause TriggerFuncArgs 
				opt_delete_limit opclass_item_list opclass_drop_list
				opclass_purpose opt_opfamily transaction_mode_list_or_empty
				OptTableFuncElementList TableFuncElementList opt_type_modifiers
				prep_type_clause
				execute_param_clause using_clause returning_clause
				opt_enum_val_list enum_val_list table_func_column_list
				create_generic_options alter_generic_options
				relation_expr_list dostmt_opt_list
				merge_values_clause publication_name_list
				relation_expr_opt_alias_list into_user_var_list

%type <fetchlimit> select_limit opt_select_limit limit_clause

/* b compatibility: comment start */
%type <list>	opt_index_options index_options opt_table_options table_options opt_column_options column_options
%type <node>	index_option table_option column_option table_index_option
%type <list>	opt_table_index_options table_index_options

%type <str>     opt_part_options
%type <list>    part_options
%type <node>    part_option
/* b compatibility: comment end */

%type <boolean>		opt_charbyte

%type <list>	key_usage_list index_hint_list opt_index_hint_list
%type <node>	index_hint_definition
%type <list>	group_by_list
%type <node>	group_by_item empty_grouping_set rollup_clause cube_clause
%type <node>	grouping_sets_clause OptAutoIncrement
%type <node>	opt_publication_for_tables publication_for_tables
%type <value>	publication_name_item

%type <list>	opt_fdw_options fdw_options
%type <defelt>	fdw_option

%type <range>	OptTempTableName
%type <into>	into_clause create_as_target create_mv_target opt_into_clause

%type <defelt>	createfunc_opt_item createproc_opt_item common_func_opt_item dostmt_opt_item
%type <fun_param> func_arg func_arg_with_default table_func_column
%type <fun_param_mode> arg_class
%type <typnam>	func_return func_type

%type <boolean>  opt_trusted opt_restart_seqs opt_purge invoker_rights
%type <ival>	 OptTemp OptKind
%type <oncommit> OnCommitOption
%type <onduplicate>	OptDuplicate
%type <lockstrength> for_locking_strength
%type <node>	for_locking_item
%type <list>	for_locking_clause opt_for_locking_clause for_locking_items
%type <list>	locked_rels_list colid_list
%type <boolean>	opt_all

%type <funcPartInfo> parallel_partition_opt
%type <node>	join_outer join_qual
%type <jtype>	join_type

%type <list>	extract_list timestamp_arg_list overlay_list position_list
%type <list>	substr_list trim_list
%type <list>	opt_interval interval_second event_interval_unit opt_evtime_unit
%type <node>	overlay_placing substr_from substr_for

%type <boolean> opt_instead opt_incremental
%type <boolean> opt_unique opt_concurrently opt_verbose opt_full opt_deltamerge opt_compact opt_hdfsdirectory opt_verify
%type <boolean> opt_freeze opt_default opt_recheck opt_cascade
%type <defelt>	opt_binary opt_oids copy_delimiter opt_noescaping
%type <defelt>	OptCopyLogError OptCopyRejectLimit opt_load

%type <boolean> opt_processed
%type <defelt> opt_useeof

%type <str>		DirectStmt CleanConnDbName CleanConnUserName
/* PGXC_END */
%type <boolean> copy_from

%type <ival>	opt_column event cursor_options opt_hold opt_set_data
%type <objtype>	reindex_type drop_type comment_type security_label_type

%type <node>	fetch_args select_limit_value
				offset_clause select_offset_value
				select_offset_value2 opt_select_fetch_first_value
%type <list>	limit_offcnt_clause
%type <ival>	row_or_rows first_or_next
%type <boolean> opt_percent only_or_ties

%type <list>	OptSeqOptList SeqOptList
%type <boolean> ignNulls fromLast
%type <defelt>	SeqOptElem

/* INSERT */
%type <istmt>	insert_rest
%type <list>    rotate_for_clause rotate_in_clause unrotate_in_clause func_application_list unrotate_name_list rotatein_list_single rotatein_list_multi
%type <list>    unrotatein_list_single unrotatein_list_multi in_expr_list unrotatein_alias_clause unrotatein_alias
%type <rotateinfo> rotate_clause
%type <unrotateinfo> unrotate_clause
%type <boolean> include_exclude_null_clause
%type <node>    filter_clause
%type <node>	upsert_clause

%type <mergewhen>	merge_insert merge_update

%type <vsetstmt> generic_set set_rest set_rest_more SetResetClause FunctionSetResetClause set_session_extension set_global_extension guc_variable_set generic_set_extension
%type <list>	VariableSetElemsList
%type <node>	set_global VariableSetElem

%type <node>	TableElement TypedTableElement ConstraintElem TableFuncElement
				ForeignTableElement
%type <node>	columnDef columnOptions
%type <defelt>	def_elem tsconf_def_elem reloption_elem tblspc_option_elem old_aggr_elem cfoption_elem
%type <node>	def_arg columnElem where_clause where_or_current_clause start_with_expr connect_by_expr
                                a_expr b_expr c_expr c_expr_noparen AexprConst indirection_el siblings_clause
                                columnref in_expr start_with_clause having_clause func_table array_expr set_ident_expr set_expr set_expr_extension
				ExclusionWhereClause func_table_with_table default_on_err_expr
%type <list>	ExclusionConstraintList ExclusionConstraintElem
%type <list>	func_arg_list
%type <node>	func_arg_expr on_error_clause opt_on_error_clause
%type <list>	row explicit_row implicit_row type_list array_expr_list
%type <node>	case_expr case_arg when_clause case_default
%type <list>	when_clause_list
%type <ival>	sub_type opt_materialized
%type <node>	ctext_expr
%type <value>	NumericOnly
%type <list>	NumericOnly_list
%type <alias>	alias_clause opt_alias_clause
%type <sortby>	sortby
%type <ielem>	index_elem constraint_elem
%type <node>	table_ref
%type <node>	table_ref_for_no_table_function
%type <jexpr>	joined_table
%type <range>	relation_expr relation_expr_for_delete relation_expr_common
%type <range>	relation_expr_opt_alias delete_relation_expr_opt_alias relation_expr_opt_alias_for_delete
%type <target>	target_el single_set_clause set_target insert_column_item connect_by_root_expr
%type <node>	tablesample_clause timecapsule_clause opt_timecapsule_clause opt_repeatable_clause end_expr start_expr

%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 <str>		explain_option_name
%type <node>	explain_option_arg
%type <defelt>	explain_option_elem
%type <list>	explain_option_list
%type <node>	copy_generic_opt_arg copy_generic_opt_arg_list_item
%type <defelt>	copy_generic_opt_elem
%type <list>	copy_generic_opt_list copy_generic_opt_arg_list
%type <list>	copy_options
%type <node>    rotate_table unrotate_table

%type <typnam>	Typename SimpleTypename ConstTypename
				GenericType Numeric opt_float
				Character ConstCharacter
				CharacterWithLength CharacterWithoutLength
				ConstDatetime ConstSet ConstInterval
				Bit ConstBit BitWithLength BitWithoutLength client_logic_type
				datatypecl OptCopyColTypename
%type <str>		character
%type <str>		character_national
%type <str>		extract_arg
%type <str>		timestamp_units

%type <keyword> character_set
%type <ival>	charset opt_charset convert_charset default_charset
%type <str>		collate opt_collate default_collate set_names_collate
%type <charsetcollateopt> CharsetCollate charset_collate optCharsetCollate

%type <boolean> opt_varying opt_timezone opt_no_inherit

%type <ival>	Iconst SignedIconst opt_partitions_num opt_subpartitions_num
%type <str>		Sconst comment_text notify_payload
%type <str>		RoleId TypeOwner opt_granted_by opt_boolean_or_string ColId_or_Sconst definer_user definer_expression UserId
%type <list>	var_list guc_value_extension_list
%type <str>		ColId ColLabel ColLabel_with_rownum var_name type_function_name param_name charset_collate_name
%type <node>	var_value zone_value

%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword col_name_keyword_nonambiguous

%type <node>	TableConstraint TableLikeClause ForeignTableLikeClause
%type <ival>	excluding_option_list TableLikeOptionList TableLikeIncludingOption TableLikeExcludingOption
%type <list>	ColQualList WithOptions
%type <node>	ColConstraint ColConstraintElem ConstraintAttr InformationalConstraintElem
%type <ival>	key_actions key_delete key_match key_update key_action
%type <ival>	ConstraintAttributeSpec ConstraintAttributeElem
%type <ival>	ConstraintAttr_isValidate
%type <str>		ExistingIndex

%type <list>	constraints_set_list
%type <boolean> constraints_set_mode
%type <boolean> OptRelative
%type <boolean> OptGPI
%type <str>		OptTableSpace OptConsTableSpace OptConsTableSpaceWithEmpty OptTableSpaceOwner LoggingStr size_clause OptMaxSize OptDatafileSize OptReuse OptAuto OptNextStr OptDatanodeName
%type <ival>	opt_check_option view_security_expression view_security_option

%type <str>		opt_provider security_label

%type <target>	xml_attribute_el
%type <list>	xml_attribute_list xml_attributes
%type <node>	xml_root_version opt_xml_root_standalone
%type <node>	xmlexists_argument
%type <ival>	document_or_content
%type <boolean> xml_whitespace_option

%type <node>	func_application func_with_separator func_expr_common_subexpr index_functional_expr_key func_application_special functime_app
%type <node>	func_expr func_expr_windowless analytic_func_expr
%type <node>	common_table_expr
%type <keep>    keep_clause
%type <with>	with_clause opt_with_clause
%type <list>	cte_list

%type <node>	uservar_name user_defined_single

%type <list>	within_group_clause pkg_body_subprogram
%type <list>	window_clause window_definition_list opt_partition_clause
%type <windef>	window_definition over_clause window_specification opt_over_clause
				opt_frame_clause frame_extent frame_bound
%type <str>		opt_existing_window_name opt_unique_key
%type <boolean>	opt_if_not_exists
%type <chr>		OptCompress generated_column_option
%type <ival>	KVType
%type <ival>		ColCmprsMode
%type <fun_src>		subprogram_body
%type <keyword> as_is as_empty
%type <node>	column_item opt_table_partitioning_clause
				opt_partition_index_def  range_partition_index_item  range_partition_index_list
				range_partitioning_clause value_partitioning_clause opt_interval_partition_clause
				interval_expr maxValueItem list_partitioning_clause hash_partitioning_clause
				range_start_end_item range_less_than_item list_partition_item hash_partition_item
				subpartitioning_clause range_subpartitioning_clause hash_subpartitioning_clause
				list_subpartitioning_clause subpartition_item opt_subpartition_index_def
                range_subpartition_index_list range_subpartition_index_item
%type <list>	range_partition_definition_list list_partition_definition_list hash_partition_definition_list maxValueList listValueList
			column_item_list tablespaceList opt_interval_tablespaceList opt_hash_partition_definition_list
			split_dest_partition_define_list split_dest_listsubpartition_define_list split_dest_rangesubpartition_define_list
			range_start_end_list range_less_than_list opt_range_every_list subpartition_definition_list range_partition_boundary
%type <range> partition_name
%type <str>	opt_columns opt_in_p

%type <ival> opt_row_movement_clause
/* PGXC_BEGIN */
%type <str>		opt_barrier_id OptDistributeType SliceReferenceClause
%type <distby>	OptDistributeBy OptDistributeByInternal distribute_by_range_clause
				distribute_by_list_clause
%type <list>	range_slice_definition_list range_slice_less_than_list range_slice_start_end_list
				list_distribution_rules_list list_distribution_rule_row list_distribution_rule_single
%type <node>	range_slice_less_than_item range_slice_start_end_item
				list_dist_state OptListDistribution list_dist_value  interval_intexpr functime_expr initime
				interval_list every_interval interval_cell ev_timeexpr 

%type <subclus> OptSubCluster OptSubClusterInternal
/* PGXC_END */

%type <str>		OptPartitionElement
%type <node>	OptForeignTableLogError OptForeignTableLogRemote OptCopyColExpr
%type <node> 	ForeignPosition ForeignColDef copy_col_format_def copy_column_expr_item
%type <node> 	OptPerNodeRejectLimit
%type <list> 	copy_foramtter_opt copy_column_expr_list

/* FOREIGN_PARTITION */
%type <foreignpartby> OptForeignPartBy OptForeignPartAuto
%type <node>	partition_item
%type <list>	partition_item_list

/* NODE GROUP */
%type <boolean> opt_vcgroup opt_to_elastic_group
%type <ival>	opt_set_vcgroup
%type <str>	opt_redistributed opt_internal_data internal_data_body
%type <ival>	bucket_cnt
%type <str>	pgxcgroup_parent

/* MERGE INTO */
%type <node> merge_when_clause opt_merge_where_condition
%type <list> merge_when_list

/* ENCRYPTION */
%type <node> algorithm_desc CreateMasterKeyStmt CreateColumnKeyStmt master_key_elem column_key_elem with_algorithm
%type <list> master_key_params column_key_params
%type <list> columnEncryptionKey 
%type <algtype> encryptionType

/* CLIENT_LOGIC */
%type <list> setting_name

/* POLICY LABEL */
%type <str> 	policy_label_name policy_label_resource_type
				policy_label_filter_type policy_label_any_resource
%type <list> 	resources_to_label_list filters_to_label_list
				policy_label_items opt_add_resources_to_label
				resources_or_filters_to_label_list policy_labels_list
%type <defelt> resources_to_label_list_item filters_to_label_list_item
%type <range> policy_label_item policy_label_any_resource_item
/* AUDIT POLICY */
%type <list> alter_policy_filter_list alter_policy_privileges_list alter_policy_access_list
%type <str> policy_name policy_privilege_type policy_access_type policy_filter_type policy_filter_name policy_target_type
%type <range> policy_target_name
%type <boolean> policy_status_opt opt_ev_on_completion 
%type <defelt> policy_privilege_elem policy_access_elem policy_target_elem_opt
%type <node> policy_filter_elem pp_policy_filter_elem filter_term pp_filter_term filter_expr pp_filter_expr filter_paren filter_expr_list filter_set policy_filter_value 
%type <list> policy_filters_list policy_filter_opt policy_privileges_list policy_access_list policy_targets_list
%type <list> policy_names_list
%type <defelt>  policy_status_alter_clause 
%type <str> alter_policy_action_clause policy_comments_alter_clause

/* MASKING POLICY */
%type <str> 	masking_func masking_func_nsp masking_policy_target_type alter_masking_policy_action_clause
				masking_policy_condition_operator
%type <list> 	masking_clause masking_func_params_opt masking_func_params_list
				alter_masking_policy_func_items_list
%type <defelt> 	masking_clause_elem masking_target
%type <defelt> 	masking_func_param alter_masking_policy_func_item
%type <node> 	policy_condition_opt
%type <node> 	alter_policy_condition
%type <node> 	masking_policy_condition_value

/* LOAD DATA */
%type <list>	load_options_list load_table_options_list opt_load_data_options_list load_when_option_list
%type <ival>	load_type_set load_oper_table_type opt_ev_status
%type <defelt>	load_table_options_item opt_load_data_options_item load_when_option load_options_item
%type <str>     load_quote_str load_col_nullif_spec

%type <node>    load_column_expr_item load_col_sequence load_col_scalar_spec load_col_position_spec load_col_sql_str
%type <node>    copy_column_sequence_item copy_column_filler_item copy_column_constant_item load_when_option_item
%type <list>    load_column_expr_list copy_column_sequence_list copy_column_filler_list copy_column_constant_list 
%type <typnam>  load_col_data_type
%type <ival64>  load_col_sequence_item_sart column_sequence_item_step column_sequence_item_sart
%type <str>  comment_opt
%type <trgcharacter> trigger_order
%type <str> delimiter_str_name delimiter_str_names

%type <ival>	statement_information_item_name condition_information_item_name
%type <condinfo> statement_information_item condition_information_item
%type <node>	condition_number
%type <list>	condition_information statement_information

/* MATVIEW */
%type <boolean> build_deferred

/* IMCS */
%type <node>    imcstored_clause

/*
 * Non-keyword token types.  These are hard-wired into the "flex" lexer.
 * They must be listed first so that their numeric codes do not depend on
 * the set of keywords.  PL/pgsql depends on this so that it can share the
 * same lexer.  If you add/change tokens here, fix PL/pgsql to match!
 *
 * DOT_DOT is unused in the core SQL grammar, and so will always provoke
 * parse errors.  It is needed by PL/pgsql.
 */
%token <str>	IDENT FCONST SCONST BCONST VCONST XCONST Op CmpOp CmpNullOp COMMENTSTRING SET_USER_IDENT SET_IDENT UNDERSCORE_CHARSET FCONST_F FCONST_D
%token <ival>	ICONST PARAM
%token			TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS SET_IDENT_SESSION SET_IDENT_GLOBAL

%token          DIALECT_TSQL
%token <str>	TSQL_XCONST

/*
 * If you want to make any keyword changes, update the keyword table in
 * src/include/parser/kwlist.h and add new keywords to the appropriate one
 * of the reserved-or-not-so-reserved keyword lists, below; search
 * this file for "Keyword category lists".
 */

/* ordinary key words in alphabetical order */
/* PGXC - added DISTRIBUTE, DIRECT, COORDINATOR, CLEAN,  NODE, BARRIER, SLICE, DATANODE */
%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACCOUNT ACTION ADD_P ADMIN AFTER
	AGGREGATE ALGORITHM ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY APP APPEND APPLY ARCHIVE ARRAY AS ASC ASOF_P
        ASSERTION ASSIGNMENT ASYMMETRIC AT ATTRIBUTE AUDIT AUTHID AUTHORIZATION AUTOEXTEND AUTOMAPPED AUTO_INCREMENT

	BACKWARD BARRIER BEFORE BEGIN_NON_ANOYBLOCK BEGIN_P BETWEEN BIGINT BINARY BINARY_DOUBLE BINARY_DOUBLE_INF BINARY_DOUBLE_NAN BINARY_INTEGER BIT BLANKS
	BLOB_P BLOCKCHAIN BODY_P BOGUS BOOLEAN_P BOTH BUCKETCNT BUCKETS BUILD BY BYTE_P BYTEAWITHOUTORDER BYTEAWITHOUTORDERWITHEQUAL

	CACHE CALL CALLED CANCELABLE CASCADE CASCADED CASE CAST CATALOG_P CATALOG_NAME CHAIN CHANGE CHAR_P
	CHARACTER CHARACTERISTICS CHARACTERSET CHARSET CHECK CHECKPOINT CLASS CLASS_ORIGIN CLEAN CLIENT CLIENT_MASTER_KEY CLIENT_MASTER_KEYS CLOB CLOSE
	CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMN_ENCRYPTION_KEY COLUMN_ENCRYPTION_KEYS COLUMN_NAME COLUMNS COMMENT COMMENTS COMMIT
	COMMITTED COMPACT COMPATIBLE_ILLEGAL_CHARS COMPILE COMPLETE COMPLETION COMPRESS CONCURRENTLY CONDITION CONFIGURATION CONNECTION CONSISTENT CONSTANT CONSTRAINT CONSTRAINT_CATALOG CONSTRAINT_NAME CONSTRAINT_SCHEMA CONSTRAINTS
	CONTENT_P CONTINUE_P CONTVIEW CONVERSION_P CONVERT_P CONNECT COORDINATOR COORDINATORS COPY COST CREATE
	CROSS CSN CSV CUBE CURRENT_P
	CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA
	CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CURSOR_NAME CYCLE
	SHRINK USE_P

	DATA_P DATABASE DATAFILE DATANODE DATANODES DATATYPE_CL DATE_P DATE_FORMAT_P DAY_P DAY_HOUR_P DAY_MINUTE_P DAY_SECOND_P DBCOMPATIBILITY_P DEALLOCATE DEC DECIMAL_P DECLARE DECODE DEFAULT DEFAULTS
	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DELTA DELTAMERGE DENSE_RANK DESC DETERMINISTIC
/* PGXC_BEGIN */
	DIAGNOSTICS DICTIONARY DIRECT DIRECTORY DISABLE_P DISCARD DISTINCT DISTRIBUTE DISTRIBUTION DO DOCUMENT_P DOMAIN_P DOUBLE_P
/* PGXC_END */
	DROP DUPLICATE DISCONNECT DUMPFILE

	EACH ELASTIC ELSE ENABLE_P ENCLOSED ENCODING ENCRYPTED ENCRYPTED_VALUE ENCRYPTION ENCRYPTION_TYPE END_P ENDS ENFORCED ENUM_P ERROR_P ERRORS ESCAPE EOL ESCAPING EVENT EVENTS EVERY EXCEPT EXCHANGE
	EXCLUDE EXCLUDED EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPIRED_P EXPLAIN
	EXTENSION EXTERNAL EXTRACT ESCAPED

	FALSE_P FAMILY FAST FENCED FETCH FIELDS FILEHEADER_P FILL_MISSING_FIELDS FILLER FILTER FIRST_P FIXED_P FLOAT_P FOLLOWING FOLLOWS_P FOR FORCE FOREIGN FORMATTER FORWARD
	FEATURES // DB4AI
	FREEZE FROM FULL FUNCTION FUNCTIONS

	GENERATED GET GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING_P GROUPPARENT

	HANDLER HAVING HDFSDIRECTORY HEADER_P HOLD HOUR_P HOUR_MINUTE_P HOUR_SECOND_P

	IDENTIFIED IDENTITY_P IF_P IGNORE IGNORE_EXTRA_DATA ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDE IMCSTORED
	INCLUDING INCREMENT INCREMENTAL INDEX INDEXES INFILE INFINITE_P INHERIT INHERITS INITIAL_P INITIALLY INITRANS INLINE_P

	INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERNAL
	INTERSECT INTERVAL INTO INVISIBLE INVOKER IP IS ISNULL ISOLATION

	JOIN JSON_EXISTS

	KEEP KEY KILL KEY_PATH KEY_STORE

	LABEL LANGUAGE LARGE_P LAST_P LATERAL_P LC_COLLATE_P LC_CTYPE_P LEADING LEAKPROOF LINES
	LEAST LESS LEFT LEVEL LIKE LIMIT LIST LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
	LOCATION LOCK_P LOCKED LOG_P LOGGING LOGIN_ANY LOGIN_FAILURE LOGIN_SUCCESS LOGOUT LOOP
	MAPPING MASKING MASTER MATCH MATERIALIZED MATCHED MAXEXTENTS MAXSIZE MAXTRANS MAXVALUE MERGE MESSAGE_TEXT METHOD MINUS_P MINUTE_P MINUTE_SECOND_P MINVALUE MINEXTENTS MODE
	MODEL MODIFY_P MONTH_P MOVE MOVEMENT MYSQL_ERRNO
	// DB4AI
	NAME_P NAMES NAN_P NATIONAL NATURAL NCHAR NEXT NO NOCOMPRESS NOCYCLE NODE NOLOGGING NOMAXVALUE NOMINVALUE NONE
	NOT NOTHING NOTIFY NOTNULL NOVALIDATE NOWAIT NTH_VALUE_P NULL_P NULLCOLS NULLIF NULLS_P NUMBER_P NUMERIC NUMSTR NVARCHAR NVARCHAR2 NVL

	OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTIMIZATION OPTION OPTIONALLY OPTIONS OR
	ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER OUTFILE

	PACKAGE PACKAGES PARALLEL_ENABLE PARSER PARTIAL PARTITION PARTITIONS PASSING PASSWORD PCTFREE PER_P PERCENT PERFORMANCE PERM PLACING PLAN PLANS POLICY POSITION
	PIPELINED
/* PGXC_BEGIN */
	POOL PRECEDING PRECISION
/* PGXC_END */
	PREDICT  // DB4AI
/* PGXC_BEGIN */
	PREFERRED PREFIX PRESERVE PREPARE PREPARED PRIMARY
/* PGXC_END */
	PRECEDES_P PRIVATE PRIOR PRIORER PRIVILEGES PRIVILEGE PROCEDURAL PROCEDURE PROFILE PUBLICATION PUBLISH PURGE

	QUERY QUOTE

	RANDOMIZED RANGE RATIO RAW READ REAL REASSIGN REBUILD RECHECK RECURSIVE RECYCLEBIN REDISANYVALUE REF REFERENCES REFRESH REINDEX REJECT_P
	RELATIVE_P RELEASE RELOPTIONS REMOTE_P REMOVE RENAME REPEAT REPEATABLE REPLACE REPLICA
	RESET RESIZE RESOURCE RESPECT_P RESTART RESTRICT RETURN RETURNED_SQLSTATE RETURNING RETURNS REUSE REVOKE RIGHT ROLE ROLES ROLLBACK ROLLUP ROTATE
	ROTATION ROW ROW_COUNT ROWNUM ROWS ROWTYPE_P RULE

	SAMPLE SAVEPOINT SCHEDULE SCHEMA SCHEMA_NAME SCROLL SEARCH SECOND_P SECURITY SELECT SEPARATOR_P SEQUENCE SEQUENCES
	SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHIPPABLE SHOW SHUTDOWN SIBLINGS
	SIMILAR SIMPLE SIZE SKIP SLAVE SLICE SMALLDATETIME SMALLDATETIME_FORMAT_P SMALLINT SNAPSHOT SOME SOURCE_P SPACE SPECIFICATION SPILL SPLIT STABLE STACKED_P STANDALONE_P START STARTS STARTWITH
	STATEMENT STATEMENT_ID STATISTICS STDIN STDOUT STORAGE STORE_P STORED STRATIFY STREAM STRICT_P STRIP_P SUBCLASS_ORIGIN SUBPARTITION SUBPARTITIONS SUBSCRIPTION SUBSTRING
	SYMMETRIC SYNONYM SYSDATE SYSID SYSTEM_P SYS_REFCURSOR STARTING SQL_P

	TABLE TABLE_NAME TABLES TABLESAMPLE TABLESPACE TARGET TEMP TEMPLATE TEMPORARY TERMINATED TEXT_P THAN THEN TIME TIME_FORMAT_P TIES TIMECAPSULE TIMESTAMP TIMESTAMP_FORMAT_P TIMESTAMPDIFF TIMEZONE_HOUR_P TIMEZONE_MINUTE_P TINYINT
	TO TRAILING TRANSACTION TRANSFORM TREAT TRIGGER TRIM TRUE_P
	TRUNCATE TRUSTED TSFIELD TSTAG TSTIME TYPE_P TYPES_P

	UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLIMITED UNLISTEN UNLOCK UNLOGGED UNIMCSTORED
	UNTIL UNUSABLE UPDATE USEEOF USER USING

	VACUUM VALID VALIDATE VALIDATION VALIDATOR VALUE_P VALUES VARCHAR VARCHAR2 VARIABLES VARIADIC VARRAY VARYING VCGROUP
	VERBOSE VERIFY VERSION_P VIEW VISIBLE VOLATILE

	WAIT WARNINGS WEAK WHEN WHERE WHILE_P WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WORKLOAD WRAPPER WRITE

	XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLPARSE
	XMLPI XMLROOT XMLSERIALIZE

	YEAR_P YEAR_MONTH_P YES_P

	ZONE

/*
 * The grammar thinks these are keywords, but they are not in the kwlist.h
 * list and so can never be entered directly.  The filter in parser.c
 * creates these tokens when required.
 */
%token		NULLS_FIRST NULLS_LAST WITH_TIME INCLUDING_ALL
			RENAME_PARTITION
			PARTITION_FOR
			SUBPARTITION_FOR
			ADD_PARTITION
			DROP_PARTITION
			REBUILD_PARTITION
			MODIFY_PARTITION
			ADD_SUBPARTITION
			DROP_SUBPARTITION
			NOT_ENFORCED
			VALID_BEGIN
			DECLARE_CURSOR ON_UPDATE_TIME
			START_WITH CONNECT_BY SHOW_ERRORS
			END_OF_INPUT
			END_OF_INPUT_COLON
			END_OF_PROC
			EVENT_TRIGGER
			NOT_IN NOT_BETWEEN NOT_LIKE NOT_ILIKE NOT_SIMILAR
			FORCE_INDEX USE_INDEX IGNORE_INDEX
			CURSOR_EXPR
			LATERAL_EXPR
			FALSE_ON_ERROR TRUE_ON_ERROR ERROR_ON_ERROR

/* Precedence: lowest to highest */
%nonassoc   COMMENT
%nonassoc   FIRST_P AFTER
%nonassoc   PARTIAL_EMPTY_PREC
%nonassoc   CLUSTER
%nonassoc	SET				/* see relation_expr_opt_alias */
%nonassoc	AUTO_INCREMENT
%right      PRIOR SEPARATOR_P
%right      FEATURES TARGET // DB4AI
%left		UNION EXCEPT MINUS_P
%left		INTERSECT
%left		OR
%left		AND
%right		NOT
%right		'=' CmpNullOp COLON_EQUALS
%nonassoc	'<' '>' CmpOp
%nonassoc	LIKE ILIKE SIMILAR NOT_LIKE NOT_ILIKE NOT_SIMILAR
%nonassoc	ESCAPE
%nonassoc	OVERLAPS
%nonassoc	BETWEEN NOT_BETWEEN
%nonassoc	IN_P NOT_IN
%left		POSTFIXOP		/* dummy for postfix Op rules */
%nonassoc   lower_than_index
%nonassoc   INDEX
%nonassoc   lower_than_under
%nonassoc   UNDER
%nonassoc   ROTATE
%nonassoc   higher_than_rotate
%nonassoc   LATERAL_P
%left       ','
/*
 * 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;
 * and for NULL so that it can follow b_expr in ColQualList without creating
 * postfix-operator problems.
 *
 * To support CUBE and ROLLUP in GROUP BY without reserving them, we give them
 * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
 * rather than reducing a conflicting rule that takes CUBE as a function name.
 * Using the same precedence as IDENT seems right for the reasons given above.
 *
 * The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
 * are even messier: since UNBOUNDED is an unreserved keyword (per spec!),
 * there is no principled way to distinguish these from the productions
 * a_expr PRECEDING/FOLLOWING.  We hack this up by giving UNBOUNDED slightly
 * lower precedence than PRECEDING and FOLLOWING.  At present this doesn't
 * appear to cause UNBOUNDED to be treated differently from other unreserved
 * keywords anywhere else in the grammar, but it's definitely risky.  We can
 * blame any funny behavior of UNBOUNDED on the SQL standard, though.
 */
%nonassoc	UNBOUNDED		/* ideally should have same precedence as IDENT */
%nonassoc	IDENT GENERATED NULL_P PARTITION SUBPARTITION RANGE ROWS PRECEDING FOLLOWING CUBE ROLLUP
/* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */
/*$$include "gram-tsql-nonassoc-ident-tokens"*/
%left		Op OPERATOR '@'		/* multi-character ops and user-defined operators */
%nonassoc	NOTNULL
%nonassoc	ISNULL
%nonassoc	IS				/* sets precedence for IS NULL, etc */
%left		'+' '-'
%left		'*' '/' '%'
%left		'^'
/* Unary Operators */
%left		AT				/* sets precedence for AT TIME ZONE */
%left		COLLATE
%right		UMINUS BY NAME_P PASSING ROW TYPE_P VALUE_P
%left		'[' ']'
%left		'(' ')'
%left		EMPTY_FROM_CLAUSE
%right		INTO
%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 ASOF_P INNER_P NATURAL ENCRYPTED APPLY OUTER_P
/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
%right		PRESERVE STRIP_P
%token <keyword> CONSTRUCTOR FINAL MAP MEMBER RESULT SELF STATIC_P UNDER
%token		SELF_INOUT
			STATIC_FUNCTION
			MEMBER_FUNCTION
			STATIC_PROCEDURE
			MEMBER_PROCEDURE
			CONSTRUCTOR_FUNCTION
			MAP_MEMBER

/* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */
/*$$include "gram-tsql-decl.y"*/

%%

/*
 *	The target production for the whole parse.
 */
stmtblock:	stmtmulti
			{
				pg_yyget_extra(yyscanner)->parsetree = $1;
			}
		;

/* the thrashing around here is to discard "empty" statements... */
stmtmulti:	stmtmulti ';' stmt
				{
					if ($3 != NULL)
					{
						if (IsA($3, List))
						{
							$$ = list_concat($1, (List*)$3);
						}
						else
						{
						$$ = lappend($1, $3);
						}
					}
					else
						$$ = $1;
				}
			| stmtmulti ';' END_OF_INPUT stmt
				{
					if ($4 != NULL)
					{
						if (IsA($4, List))
						{
							$$ = list_concat($1, (List*)$4);
						}
						else
						{
						$$ = lappend($1, $4);
						}
					}
					else
						$$ = $1;
				}
			| stmtmulti END_OF_INPUT_COLON stmt
				{
					if ($3 != NULL)
					{
						if (IsA($3, List))
						{
							$$ = list_concat($1, (List*)$3);
						}
						else
						{
						$$ = lappend($1, $3);
						}
					}
					else
						$$ = $1;
				}
			|
			{
                #ifndef ENABLE_MULTIPLE_NODES
                	if (u_sess->attr.attr_common.plsql_show_all_error &&
						CompileWhich() != PLPGSQL_COMPILE_NULL) {
                        errstate = NOTICE;
                    } else {
                        errstate = ERROR;
                    }
                #else
                    errstate = ERROR;
                #endif 
			}
			stmt
				{
					if ($2 != NULL)
					{
						if (IsA($2, List))
						{
							$$ = (List*)$2;
						}
						else
						{
						$$ = list_make1($2);
						}
					}
					else
						$$ = NIL;
				}
		;
stmt :
			AlterAppWorkloadGroupMappingStmt
			| AlterCoordinatorStmt
			| AlterDatabaseStmt
			| AlterDatabaseSetStmt
			| AlterDataSourceStmt
			| AlterDefaultPrivilegesStmt
			| AlterDomainStmt
			| AlterEnumStmt
			| AlterEventTrigStmt
			| AlterExtensionStmt
			| AlterExtensionContentsStmt
			| AlterFdwStmt
			| AlterForeignServerStmt
			| AlterForeignTableStmt
			| AlterFunctionStmt
			| AlterProcedureStmt
			| AlterPublicationStmt
			| AlterGroupStmt
			| AlterNodeGroupStmt
			| AlterNodeStmt
			| AlterObjectSchemaStmt
			| AlterOwnerStmt
			| AlterRlsPolicyStmt
			| AlterResourcePoolStmt
			| AlterGlobalConfigStmt
			| AlterSeqStmt
			| AlterSchemaStmt
			| AlterSubscriptionStmt
			| AlterTableStmt
			| AlterSystemStmt
			| AlterTriggerStmt
			| AlterCompositeTypeStmt
			| AlterRoleSetStmt
			| AlterRoleStmt
			| AlterSessionStmt
			| AlterTSConfigurationStmt
			| AlterTSDictionaryStmt
			| AlterUserMappingStmt
			| AlterUserSetStmt
			| AlterUserStmt
			| AlterWorkloadGroupStmt
			| AnalyzeStmt
			| AnonyBlockStmt
			| BarrierStmt
			| CreateAppWorkloadGroupMappingStmt
			| CallFuncStmt
			| CheckPointStmt
			| CleanConnStmt
			| ClosePortalStmt
			| ClusterStmt
			| CommentStmt
			| CompileStmt
			| ConstraintsSetStmt
			| CopyStmt
			| CreateAmStmt
			| CreateAsStmt
			| CreateAssertStmt
			| CreateCastStmt
                        | CreateContQueryStmt
                        | CreateStreamStmt
			| CreateConversionStmt
			| CreateDomainStmt
			| CreateDirectoryStmt
			| CreateEventTrigStmt
			| CreateExtensionStmt
			| CreateFdwStmt
			| CreateForeignServerStmt
			| CreateForeignTableStmt
			| CreateDataSourceStmt
			| CreateFunctionStmt
			| CreateEventStmt
			| AlterEventStmt
			| DropEventStmt
			| ShowEventStmt
			| CreatePackageStmt
			| CreatePackageBodyStmt
			| CreateGroupStmt
			| CreateMatViewStmt
			| CreateMatViewLogStmt
			| DropMatViewLogStmt
			| CreateModelStmt  // DB4AI
			| CreateNodeGroupStmt
			| CreateNodeStmt
			| CreateOpClassStmt
			| CreateOpFamilyStmt
			| AlterOpFamilyStmt
			| CreateRlsPolicyStmt
			| CreatePLangStmt
			| CreateProcedureStmt
			| CreatePublicationStmt
            | CreateKeyStmt
			| CreatePolicyLabelStmt
			| CreateWeakPasswordDictionaryStmt
			| DropWeakPasswordDictionaryStmt
			| AlterPolicyLabelStmt
			| DropPolicyLabelStmt
            | CreateAuditPolicyStmt
            | AlterAuditPolicyStmt
            | DropAuditPolicyStmt
			| CreateMaskingPolicyStmt
			| AlterMaskingPolicyStmt
			| DropMaskingPolicyStmt
			| CreateResourcePoolStmt
			| CreateSchemaStmt
			| CreateSeqStmt
			| CreateStmt
			| CreateSubscriptionStmt
			| CreateSynonymStmt
			| CreateTableSpaceStmt
			| CreateTrigStmt
			| CreateRoleStmt
			| CreateUserStmt
			| CreateUserMappingStmt
			| CreateWorkloadGroupStmt
			| CreatedbStmt
			| DeallocateStmt
			| DeclareCursorStmt
			| DefineStmt
			| DeleteStmt
			| DiscardStmt
			| DoStmt
			| DropAppWorkloadGroupMappingStmt
			| DropAssertStmt
			| DropCastStmt
			| DropDataSourceStmt
			| DropDirectoryStmt
			| DropFdwStmt
			| DropForeignServerStmt
			| DropGroupStmt
			| DropModelStmt // DB4AI
			| DropNodeGroupStmt
			| DropNodeStmt
			| DropOpClassStmt
			| DropOpFamilyStmt
			| DropOwnedStmt
			| DropRlsPolicyStmt
			| DropPLangStmt
			| DropResourcePoolStmt
			| DropGlobalConfigStmt
			| DropRuleStmt
			| DropStmt
			| DropSubscriptionStmt
			| DropSynonymStmt
			| DropTableSpaceStmt
			| DropTrigStmt
			| DropRoleStmt
			| DropUserStmt
			| DropUserMappingStmt
			| DropWorkloadGroupStmt
			| DropdbStmt
			| ExecuteStmt
			| ExecDirectStmt
			| ExplainStmt
			| FetchStmt
			| GetDiagStmt
			| GrantStmt
			| GrantRoleStmt
			| GrantDbStmt
			| IndexStmt
			| InsertStmt
			| ListenStmt
			| RefreshMatViewStmt
			| LoadStmt
			| LockStmt
			| MergeStmt
			| NotifyStmt
			| PrepareStmt
			| PurgeStmt
			| ReassignOwnedStmt
			| ReindexStmt
			| RemoveAggrStmt
			| RemoveFuncStmt
			| RemovePackageStmt
			| RemoveOperStmt
			| RenameStmt
			| RevokeStmt
			| RevokeRoleStmt
			| RevokeDbStmt
			| RuleStmt
			| SecLabelStmt
			| SelectStmt
			| ShutdownStmt
			| TimeCapsuleStmt
			| SnapshotStmt
			| TransactionStmt
			| TruncateStmt
			| UnlistenStmt
			| UpdateStmt
			| VacuumStmt
			| VariableResetStmt
			| VariableSetStmt
			| VariableMultiSetStmt
			| VariableShowStmt
			| VerifyStmt
			| ViewStmt
			| ShrinkStmt
			| /*EMPTY*/
				{ $$ = NULL; }
			| DelimiterStmt
		;

/*****************************************************************************
 *
 * Create a new Postgres DBMS role
 *
 *****************************************************************************/

CreateRoleStmt:
			CREATE ROLE RoleId opt_with {u_sess->parser_cxt.isForbidTruncate = true;} OptRoleList
				{
					CreateRoleStmt *n = makeNode(CreateRoleStmt);
					n->stmt_type = ROLESTMT_ROLE;
					if (!isRestoreMode)
						IsValidIdentUsername($3);
					n->role = $3;
					n->options = $6;
					$$ = (Node *)n;
					u_sess->parser_cxt.isForbidTruncate = false;
				}
		;

ShrinkStmt:
            SHRINK TABLE relation_expr_list opt_nowait
                {
                    ShrinkStmt *n = makeNode(ShrinkStmt);
                    n->relations = $3;
                    n->nowait = $4;
                    $$ = (Node*)n;
                }
            |   SHRINK INDEX relation_expr_list opt_nowait
                    {
                        ShrinkStmt *n = makeNode(ShrinkStmt);
                        n->relations = $3;
                        n->nowait = $4;
                        $$ = (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 CreateOptRoleElem			{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

AlterOptRoleList:
			AlterOptRoleList AlterOptRoleElem		{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

password_string:
			Sconst
				{
					t_thrd.postgres_cxt.clear_key_memory = true;
					$$ = $1;
				}
			| IDENT
				{
					t_thrd.postgres_cxt.clear_key_memory = true;
					core_yy_extra_type yyextra = pg_yyget_extra(yyscanner)->core_yy_extra;
					if (yyextra.ident_quoted)
						$$ = $1;
					else {
            			const char* message = "Password must be quoted";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
							 errmsg("Password must be quoted")));
					}
				}
namedata_string:
            Sconst
                {
                    $$ = pg_strtolower($1);
                }
            | IDENT
                {
                    core_yy_extra_type yyextra = pg_yyget_extra(yyscanner)->core_yy_extra;
                    if (yyextra.ident_quoted)
                        $$ = $1;
                    else {
            			const char* message = "name data must be quoted";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        ereport(errstate,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("name data must be quoted")));
					}
                }
		;
AlterOptRoleElem:
			PASSWORD password_string
				{
					$$ = makeDefElem("password",
									 (Node *)list_make1(makeStringConst($2, @2)));
				}
			| IDENTIFIED BY password_string
				{
					$$ = makeDefElem("password",
						(Node *)list_make1(makeStringConst($3, @3)));
				}
			| ENCRYPTED IDENTIFIED BY password_string
				{
					$$ = makeDefElem("encryptedPassword",
						(Node *)list_make1(makeStringConst($4, @4)));
				}
			| UNENCRYPTED IDENTIFIED BY password_string
				{
					$$ = makeDefElem("unencryptedPassword",
						(Node *)list_make1(makeStringConst($4, @4)));
				}
			| IDENTIFIED BY password_string REPLACE password_string
				{
					$$ = makeDefElem("password",
						(Node *)list_make2(makeStringConst($3, @3), makeStringConst($5, @5)));
				}
			| ENCRYPTED IDENTIFIED BY password_string REPLACE password_string
				{
					$$ = makeDefElem("encryptedPassword",
						(Node *)list_make2(makeStringConst($4, @4), makeStringConst($6, @6)));
				}
			| UNENCRYPTED IDENTIFIED BY password_string REPLACE password_string
				{
					$$ = makeDefElem("unencryptedPassword",
						(Node *)list_make2(makeStringConst($4, @4), makeStringConst($6, @6)));
				}
			| IDENTIFIED BY DISABLE_P
				{
					$$ = makeDefElem("password", NULL);
				}
			| PASSWORD DISABLE_P
				{
					$$ = makeDefElem("password", NULL);
				}
			| PASSWORD EXPIRED_P
				{
					$$ = makeDefElem("expired", (Node *)makeInteger(TRUE));
				}
			| PASSWORD password_string EXPIRED_P
				{
					$$ = makeDefElem("expiredPassword", (Node *)list_make1(makeStringConst($2, @2)));
				}
			| IDENTIFIED BY password_string EXPIRED_P
				{
					$$ = makeDefElem("expiredPassword", (Node *)list_make1(makeStringConst($3, @3)));
				}
			| ENCRYPTED PASSWORD password_string
				{
					$$ = makeDefElem("encryptedPassword",
									 (Node *)list_make1(makeStringConst($3, @3)));
				}
			| UNENCRYPTED PASSWORD password_string
				{
					$$ = makeDefElem("unencryptedPassword",
									 (Node *)list_make1(makeStringConst($3, @3)));
				}
			| DEFAULT TABLESPACE name
				{
					$$ = makeDefElem("tablespace", (Node *)makeString($3));
				}
			| PROFILE DEFAULT
				{
					$$ = makeDefElem("profile", NULL);
				}
			| PROFILE name
				{
					$$ = makeDefElem("profile",
									 (Node *)list_make1(makeStringConst($2, @2)));
				}
			| INHERIT
				{
					$$ = makeDefElem("inherit", (Node *)makeInteger(TRUE));
				}
			| CONNECTION LIMIT SignedIconst
				{
					$$ = makeDefElem("connectionlimit", (Node *)makeInteger($3));
				}
			| RESOURCE POOL namedata_string
				{
					$$ = makeDefElem("respool", (Node *)makeString($3));
				}
			| NODE GROUP_P pgxcgroup_name
			    {
			        $$ = makeDefElem("node_group", (Node *)makeString($3));
			    }
			| USER GROUP_P namedata_string
				{
					$$ = makeDefElem("parent", (Node *)makeString($3));
				}
			| USER GROUP_P DEFAULT	
				{
					$$ = makeDefElem("parent_default", NULL);
				}
			| PERM SPACE Sconst
				{
					$$ = makeDefElem("space_limit", (Node *)makeString($3));
				}
			| TEMP SPACE Sconst
				{
					$$ = makeDefElem("temp_space_limit", (Node *)makeString($3));
				}
			| SPILL SPACE Sconst
				{
					$$ = makeDefElem("spill_space_limit", (Node *)makeString($3));
				}
			/* VALID and BEGIN is treated as a token to avoid confilict with BEGIN TRANSACTIOn and BEGIN ANONYMOUD BLOCK */
			| VALID_BEGIN Sconst
				{
					$$ = makeDefElem("validBegin", (Node *)makeString($2));
				}
			| VALID UNTIL Sconst
				{
					$$ = makeDefElem("validUntil", (Node *)makeString($3));
				}
		/*	Supported but not documented for roles, for use by ALTER GROUP. */
			| USER name_list
				{
					$$ = makeDefElem("rolemembers", (Node *)$2);
				}
			| IDENT
				{
					/*
					 * We handle identifiers that aren't parser keywords with
					 * the following special-case codes, to avoid bloating the
					 * size of the main parser.
					 */
					if (strcmp($1, "createrole") == 0)
						$$ = makeDefElem("createrole", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nocreaterole") == 0)
						$$ = makeDefElem("createrole", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "replication") == 0)
						$$ = makeDefElem("isreplication", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "noreplication") == 0)
						$$ = makeDefElem("isreplication", (Node *)makeInteger(FALSE));
					/* add audit admin privilege */
					else if (strcmp($1, "auditadmin") == 0)
						$$ = makeDefElem("isauditadmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "noauditadmin") == 0)
						$$ = makeDefElem("isauditadmin", (Node *)makeInteger(FALSE));
					/* END <audit> */
					else if (strcmp($1, "sysadmin") == 0)
						$$ = makeDefElem("issystemadmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nosysadmin") == 0)
						$$ = makeDefElem("issystemadmin", (Node *)makeInteger(FALSE));
					/* Add system monitor privilege, operator privilege. */
					else if (strcmp($1, "monadmin") == 0)
						$$ = makeDefElem("ismonitoradmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nomonadmin") == 0)
						$$ = makeDefElem("ismonitoradmin", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "opradmin") == 0)
						$$ = makeDefElem("isoperatoradmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "noopradmin") == 0)
						$$ = makeDefElem("isoperatoradmin", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "poladmin") == 0)
						$$ = makeDefElem("ispolicyadmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nopoladmin") == 0)
						$$ = makeDefElem("ispolicyadmin", (Node *)makeInteger(FALSE));
					/* End */
					else if (strcmp($1, "vcadmin") == 0)
						$$ = makeDefElem("isvcadmin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "novcadmin") == 0)
						$$ = makeDefElem("isvcadmin", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "createdb") == 0)
						$$ = makeDefElem("createdb", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nocreatedb") == 0)
						$$ = makeDefElem("createdb", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "useft") == 0)
						$$ = makeDefElem("useft", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nouseft") == 0)
						$$ = makeDefElem("useft", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "login") == 0)
						$$ = makeDefElem("canlogin", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nologin") == 0)
						$$ = makeDefElem("canlogin", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "independent") == 0)
						$$ = makeDefElem("independent", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "noindependent") == 0)
						$$ = makeDefElem("independent", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "persistence") == 0)
						$$ = makeDefElem("persistence", (Node *)makeInteger(TRUE));
					else if (strcmp($1, "nopersistence") == 0)
						$$ = makeDefElem("persistence", (Node *)makeInteger(FALSE));
					else if (strcmp($1, "noinherit") == 0)
					{
						/*
						 * Note that INHERIT is a keyword, so it's handled by main parser, but
						 * NOINHERIT is handled here.
						 */
						$$ = makeDefElem("inherit", (Node *)makeInteger(FALSE));
					}
					else if (strcmp($1, "pguser") == 0)
					{
						$$ = makeDefElem("pguser", (Node *)makeInteger(TRUE));
					}
					else {
            			const char* message = "unrecognized role option";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("unrecognized role option \"%s\"", $1),
									 parser_errposition(@1)));
					}
				}
		;

CreateOptRoleElem:
			AlterOptRoleElem			{ $$ = $1; }
			/* The following are not supported by ALTER ROLE/USER/GROUP */
			| SYSID Iconst
				{
					$$ = makeDefElem("sysid", (Node *)makeInteger($2));
				}
			| 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);
				}
		;


/*****************************************************************************
 *
 * Create a new Postgres DBMS user (role with implied login ability)
 *
 *****************************************************************************/

UserId:
			SCONST SET_USER_IDENT
					{
						$$ = GetValidUserHostId($1, $2);
					}
			| SCONST '@' SCONST
					{
						$$ = GetValidUserHostId($1, $3);
					}
			| SCONST
					{
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT || !u_sess->attr.attr_common.b_compatibility_user_host_auth)
							ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error at or near \"'%s'\"", $1), parser_errposition(@1)));
						if (strchr($1,'@'))
							ereport(ERROR,(errcode(ERRCODE_INVALID_NAME),errmsg("@ can't be allowed in username")));
						if (strlen($1) >= NAMEDATALEN) {
							ereport(ERROR,(errcode(ERRCODE_INVALID_NAME),errmsg("String %s is too long for user name (should be no longer than 64)", $1)));
						}
						$$ = $1;
					}
			| RoleId SET_USER_IDENT
					{
						$$ = GetValidUserHostId($1, $2);
					}
			| RoleId
					{
						IsValidIdentUsername($1);
						$$ = $1;
					}
		;

UserIdList:	UserId
					{ $$ = list_make1(makeString($1)); }
			| UserIdList ',' UserId
					{ $$ = lappend($1, makeString($3)); }
		;

CreateUserStmt:
			CREATE USER UserId opt_with {u_sess->parser_cxt.isForbidTruncate = true;} OptRoleList
				{
					CreateRoleStmt *n = makeNode(CreateRoleStmt);
					n->stmt_type = ROLESTMT_USER;
					n->role = $3;
					n->options = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
					u_sess->parser_cxt.isForbidTruncate = false;
				}
			| CREATE USER IF_P NOT EXISTS UserId opt_with {u_sess->parser_cxt.isForbidTruncate = true;} OptRoleList
				{
					CreateRoleStmt *n = makeNode(CreateRoleStmt);
					n->stmt_type = ROLESTMT_USER;
					n->role = $6;
					n->options = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
					u_sess->parser_cxt.isForbidTruncate = false;
				}
		;


/*****************************************************************************
 *
 * Alter a postgresql DBMS role
 *
 *****************************************************************************/

AlterRoleStmt:
			ALTER ROLE RoleId opt_with {u_sess->parser_cxt.isForbidTruncate = true;} AlterOptRoleList
				 {
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = $6;
					n->lockstatus = DO_NOTHING;
					$$ = (Node *)n;
					u_sess->parser_cxt.isForbidTruncate = false;
				 }
			| ALTER ROLE RoleId opt_with ACCOUNT LOCK_P
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = NIL;
					n->lockstatus = LOCK_ROLE;
					$$ = (Node *)n;
				}
			| ALTER ROLE RoleId opt_with ACCOUNT UNLOCK
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = NIL;
					n->lockstatus = UNLOCK_ROLE;
					$$ = (Node *)n;
				}
		;

opt_in_database:
			   /* EMPTY */					{ $$ = NULL; }
			| IN_P DATABASE database_name	{ $$ = $3; }
		;

AlterRoleSetStmt:
			ALTER ROLE RoleId opt_in_database SetResetClause
				{
					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
					n->role = $3;
					n->database = $4;
					n->setstmt = $5;
					$$ = (Node *)n;
				}
		;


/*****************************************************************************
 *
 * Alter a postgresql DBMS user
 *
 *****************************************************************************/

AlterUserStmt:
			ALTER USER UserId opt_with {u_sess->parser_cxt.isForbidTruncate = true;} AlterOptRoleList
				 {
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->missing_ok = FALSE;
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = $6;
					n->lockstatus = DO_NOTHING;
					$$ = (Node *)n;
					u_sess->parser_cxt.isForbidTruncate = false;
				 }
			| ALTER USER IF_P EXISTS UserId opt_with AlterOptRoleList
				 {
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->missing_ok = TRUE;
					n->role = $5;
					n->action = +1;	/* add, if there are members */
					n->options = $7;
					n->lockstatus = DO_NOTHING;
					$$ = (Node *)n;
				 }     
			| ALTER USER UserId opt_with ACCOUNT LOCK_P
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = NIL;
					n->lockstatus = LOCK_ROLE;
					$$ = (Node *)n;
				}
			| ALTER USER UserId opt_with ACCOUNT UNLOCK
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $3;
					n->action = +1;	/* add, if there are members */
					n->options = NIL;
					n->lockstatus = UNLOCK_ROLE;
					$$ = (Node *)n;
				}
		;


AlterUserSetStmt:
			ALTER USER UserId opt_in_database SetResetClause
				{
					AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
					n->role = $3;
					n->database = $4;
					n->setstmt = $5;
					$$ = (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 UserIdList opt_drop_behavior
				{
					DropRoleStmt *n = makeNode(DropRoleStmt);
					n->missing_ok = FALSE;
					n->is_user = TRUE;
					n->roles = $3;
					n->behavior = $4;
					$$ = (Node *)n;
				}
			| DROP USER IF_P EXISTS UserIdList opt_drop_behavior
				{
					DropRoleStmt *n = makeNode(DropRoleStmt);
					n->roles = $5;
					n->missing_ok = true;
					n->is_user = TRUE;
					n->behavior = $6;
					n->is_user = TRUE;
					n->behavior = $6;
					$$ = (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->missing_ok = false;
					$$ = (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; }
		;

/*****************************************************************************
 *
 * Alter SESSION
 *
 *****************************************************************************/

AlterSessionStmt:
			ALTER SESSION SET set_rest
				{
					VariableSetStmt *n = $4;
					n->is_local = false;
					$$ = (Node *) n;
				}
			;

/* "alter system" */
/*****************************************************************************
 *
 * Alter SYSTEM 
 * (1. kill a session by "select pg_terminate_session(pid, sessionId)", so it only needs a SelectStmt node.)
 * (2. disconnect a session. unsupported currently.)
 * (3. set system parameter to, this is used to change configuration parameters persistently.)
 *
 *****************************************************************************/

AlterSystemStmt:
			ALTER SYSTEM_P KILL SESSION Sconst altersys_option
				{
					SelectStmt *n = NULL;
					List *pid = NULL;

					pid = get_func_args($5);

					n = makeNode(SelectStmt);
					n->distinctClause = NIL;
					n->targetList = make_action_func(pid);
					n->intoClause = NULL;
					n->fromClause = NIL;
					n->whereClause = NULL;
					n->groupClause = NIL;
					n->havingClause = NULL;
					n->windowClause = NIL;
					$$ = (Node *)n;
				}

			| ALTER SYSTEM_P DISCONNECT SESSION Sconst altersys_option
				{
            		const char* message = "unsupported action \"DISCONNECT\" for statement \" alter system ";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
					    (errcode(ERRCODE_UNDEFINED_OBJECT),
					     errmsg("unsupported action \"DISCONNECT\" for statement \" alter system \"")));
				}

			| ALTER SYSTEM_P SET generic_set
				{
#if defined(ENABLE_MULTIPLE_NODES) || defined (ENABLE_PRIVATEGAUSS)
            		const char* message = "ALTER SYSTEM SET is not supported";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
					    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					     errmsg("ALTER SYSTEM SET is not supported.")));
#else
					AlterSystemStmt *n = makeNode(AlterSystemStmt);
					n->setstmt = $4;
					$$ = (Node *)n;
#endif
				}
			;

altersys_option:
			IMMEDIATE			{/* empty */}
			|				{/* empty */}
			;

AlterTriggerStmt:
			ALTER TRIGGER name enable_trigger
				{
					if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT )
						ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ALTER TRIGGER ... ENABLE/DISABLE is supported only in A_FORMAT database.")));
					AlterTriggerStmt *n = makeNode(AlterTriggerStmt);
					n->trigname = $3;
					n->tgenabled = $4;
					$$ = (Node *)n;
				}
			;
/*****************************************************************************
 *
 * 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 OptBlockchainWith 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->hasBlockChain = $6;
					n->schemaElts = $7;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
			| CREATE SCHEMA ColId OptBlockchainWith OptSchemaEltList
				{
					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
					n->missing_ok = FALSE;
					/* ...but not both */
					n->schemaname = $3;
					n->authid = NULL;
					n->hasBlockChain = $4;
					n->schemaElts = $5;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
			| CREATE SCHEMA IF_P NOT EXISTS ColId OptBlockchainWith OptSchemaEltList
				{
					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
					n->missing_ok = TRUE;
					/* ...but not both */
					n->schemaname = $6;
					n->authid = NULL;
					n->hasBlockChain = $7;
					n->schemaElts = $8;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
			| CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptBlockchainWith OptSchemaEltList
				{
					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
					n->missing_ok = TRUE;
					/* One can omit the schema name or the authorization id. */
					if ($6 != NULL)
						n->schemaname = $6;
					else
						n->schemaname = $8;
					n->authid = $8;
					n->hasBlockChain = $9;
					n->schemaElts = $10;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
			| CREATE SCHEMA ColId CharsetCollate
				{
					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
					n->schemaname = $3;
					n->authid = NULL;
					n->hasBlockChain = false;
					n->schemaElts = NULL;
					n->charset = $4->charset;
					n->collate = $4->collate;
					$$ = (Node *)n;
				}
			| CREATE SCHEMA IF_P NOT EXISTS ColId CharsetCollate
				{
					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
					n->schemaname = $6;
					n->authid = NULL;
					n->hasBlockChain = false;
					n->schemaElts = NULL;
					n->charset = $7->charset;
					n->collate = $7->collate;
					$$ = (Node *)n;
				}
		;

OptSchemaName:
			ColId									{ $$ = $1; }
			| /* EMPTY */							{ $$ = NULL; }
		;

OptSchemaEltList:
			OptSchemaEltList schema_stmt			{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

OptBlockchainWith:
			WITH BLOCKCHAIN
			    {
                    if (ENABLE_DMS) {
			            const char* message = "BLOCKCHAIN is not supported while DMS and DSS enabled";
			            InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			            ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 
				                errmsg("BLOCKCHAIN is not supported while DMS and DSS enabled")));
					}

                    $$ = true;
			    }
			| /* EMPTY */							{ $$ = false; }
		;

/*****************************************************************************
 *
 * ALTER SCHEMA WITH BLOCKCHAIN
 * alter blockchain property of a schema.
 *
 *****************************************************************************/
AlterSchemaStmt:
			ALTER SCHEMA ColId OptAlterToBlockchain
				{
					AlterSchemaStmt *n = makeNode(AlterSchemaStmt);
					n->schemaname = $3;
					n->authid = NULL;
					n->hasBlockChain = $4;
					n->charset = PG_INVALID_ENCODING;
					n->collate = NULL;
					$$ = (Node *)n;
				}
			| ALTER SCHEMA ColId CharsetCollate
				{
					AlterSchemaStmt *n = makeNode(AlterSchemaStmt);
					n->schemaname = $3;
					n->authid = NULL;
					n->hasBlockChain = false;
					n->charset = $4->charset;
					n->collate = $4->collate;
					$$ = (Node *)n;
				}
			;

OptAlterToBlockchain:
			WITH BLOCKCHAIN
			    {
                    if (ENABLE_DMS) {
			            const char* message = "BLOCKCHAIN is not supported while DMS and DSS enabled";
			            InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			            ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 
				                errmsg("BLOCKCHAIN is not supported while DMS and DSS enabled")));
					}

                    $$ = true;
			    }
			| WITHOUT BLOCKCHAIN					{ $$ = false; }
		;

/*
 *	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 GLOBAL TRANSACTION transaction_mode_list
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SET GLOBAL TRANSACTION is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SET GLOBAL TRANSACTION is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("SET GLOBAL TRANSACTION is only supported in B_FORMAT.")));
					}
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_MULTI;
					n->name = "GLOBAL TRANSACTION";
					n->args = $4;
					$$ = (Node *)n;
				}
			| SET generic_set_extension
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "SET config_parameter = expr is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SET config_parameter = expr is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						VariableSetStmt *n = $2;
						n->is_local = false;
						$$ = (Node *) n;
					} else {
						const char* message = "SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on.")));
					}
				}
			| SET SESSION generic_set_extension
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "SET config_parameter = expr is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SET config_parameter = expr is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						VariableSetStmt *n = $3;
						n->is_local = false;
						$$ = (Node *) n;
					} else {
						const char* message = "SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on.")));
					}
				}
		;

set_rest:
			TRANSACTION transaction_mode_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_MULTI;
					n->name = "TRANSACTION";
					n->args = $2;
					$$ = n;
				}
			| SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_MULTI;
					n->name = "SESSION CHARACTERISTICS";
					n->args = $5;
					$$ = n;
				}
			| set_rest_more
				{
					$$ = $1;
				}
			;

generic_set:
			var_name TO var_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = $1;
					n->args = $3;
					/* if we are setting role, we switch to the new syntax which check the password of role */
					if(!pg_strcasecmp("role", n->name) || !pg_strcasecmp("session_authorization", n->name))
					{
            			const char* message = "SET TO rolename\" not yet supported";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
							 	errmsg("\"SET %s TO rolename\" not yet supported", n->name),
								 	errhint("Use \"SET %s rolename\" clauses.", n->name)));
					}
					else
					{
						n->kind = VAR_SET_VALUE;
					}
					$$ = n;
				}
			| var_name '=' var_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = $1;
					n->args = $3;
					/* if we are setting role, we switch to the new syntax which check the password of role */
					if(!pg_strcasecmp("role", n->name) || !pg_strcasecmp("session_authorization", n->name))
					{
            			const char* message = "SET TO rolename\" not yet supported";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("\"SET %s = rolename\" not yet supported", n->name),
									 errhint("Use \"SET %s rolename\" clauses.", n->name)));
					}
					else
					{
						n->kind = VAR_SET_VALUE;
					}
					$$ = n;
				}
			| var_name TO DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = $1;
					$$ = n;
				}
			| var_name '=' DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = $1;
					$$ = n;
				}
			| CURRENT_SCHEMA TO var_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "current_schema";
					n->args = $3;
					$$ = n;
				}
			| CURRENT_SCHEMA '=' var_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "current_schema";
					n->args = $3;
					$$ = n;
				}
			| CURRENT_SCHEMA TO DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = "current_schema";
					$$ = n;
				}
			| CURRENT_SCHEMA '=' DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = "current_schema";
					$$ = n;
				}
                ;

set_rest_more:  /* Generic SET syntaxes: */
            generic_set
	            {
	                $$ = $1;
	            }
			| var_name FROM CURRENT_P
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_CURRENT;
					n->name = $1;
					$$ = n;
				}
			/* Special syntaxes mandated by SQL standard: */
			| TIME ZONE zone_value
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "timezone";
					if ($3 != NULL)
						n->args = list_make1($3);
					else
						n->kind = VAR_SET_DEFAULT;
					$$ = n;
				}
			| CATALOG_P Sconst
				{
            		const char* message = "current database cannot be changed";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("current database cannot be changed"),
							 parser_errposition(@2)));
					$$ = NULL; /*not reached*/
				}
			| SCHEMA Sconst
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "search_path";
					n->args = list_make1(makeStringConst($2, @2));
					$$ = n;
				}
			| NAMES opt_encoding set_names_collate
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					if ($3 != NULL) {
						if ($2 == NULL) {
							ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("cannot specify collation without character set"),
								parser_errposition(@3)));
						}
						n->args = list_make2(makeStringConst($2, @2), makeStringConst($3, @3));
						n->name = "set_names";
					} else {
						if ($2 != NULL) {
							n->args = list_make1(makeStringConst($2, @2));
						} else {
							n->kind = VAR_SET_DEFAULT;
						}
						if (ENABLE_MULTI_CHARSET) {
							n->name = "set_names";
						} else {
							n->name = "client_encoding";
						}
					}
					$$ = n;
				}
			| ROLE ColId_or_Sconst
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_ROLEPWD;
					n->name = "role";
					n->args = list_make1(makeStringConst($2, @2));
					$$ = n;
				}
			| ROLE ColId_or_Sconst PASSWORD {u_sess->parser_cxt.isForbidTruncate = true;} password_string
				{
					u_sess->parser_cxt.isForbidTruncate = false;
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_ROLEPWD;
					n->name = "role";
					n->args = list_make2(makeStringConst($2, @2), makeStringConst($5, @5));
					$$ = n;
				}
			| SESSION AUTHORIZATION ColId_or_Sconst PASSWORD {u_sess->parser_cxt.isForbidTruncate = true;} password_string
				{
					u_sess->parser_cxt.isForbidTruncate = false;
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_ROLEPWD;
					n->name = "session_authorization";
					n->args = list_make2(makeStringConst($3, @3), makeStringConst($6,@6));
					$$ = n;
				}
			| SESSION AUTHORIZATION DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = "session_authorization";
					$$ = n;
				}
			| XML_P OPTION document_or_content
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "xmloption";
					n->args = list_make1(makeStringConst(const_cast<char *>($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT"), @3));
					$$ = n;
				}
			/* Special syntaxes invented by PostgreSQL: */
			| TRANSACTION SNAPSHOT Sconst
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_MULTI;
					n->name = "TRANSACTION SNAPSHOT";
					n->args = list_make1(makeStringConst($3, @3));
					$$ = n;
				}
		;

/*****************************************************************************
 *
 * VariableMultiSetStmt only used for:
 * 1. set [session|global] configure_param = expr 
 * 2. set @usr_var := expr
 *
 *****************************************************************************/

VariableMultiSetStmt:	SET VariableSetElemsList
						{
#ifdef			ENABLE_MULTIPLE_NODES
							const char* message = "set multiple variables is not yet supported in distributed database.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
							ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("set multiple variables is not yet supported in distributed database.")));
#endif
							if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES))
							{
								VariableMultiSetStmt* n = makeNode(VariableMultiSetStmt);
								n->args = $2;
								$$ = (Node*)n;
							} else {
								const char* message = "SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on.";
								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
									(errmodule(MOD_PARSER),
										errcode(ERRCODE_SYNTAX_ERROR),
										errmsg("SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on."),
										parser_errposition(@1)));
								$$ = NULL;/* not reached */	
							}
						}
					;

VariableSetElemsList:
						 VariableSetElem 	{ $$ = list_make1($1); }
						| VariableSetElemsList ',' VariableSetElem 	{ $$ = lappend($1, $3); }
				;

VariableSetElem:
					set_session_extension
						{
							VariableSetStmt *n = $1;
							n->is_local = false;
							n->is_multiset = true;
							$$ = (Node *)n;
						}
					| set_global
						{
							$$ = $1;
						}
					| user_defined_single
						{
							VariableSetStmt *n = makeNode(VariableSetStmt);
							n->kind = VAR_SET_DEFINED;
							n->name = "USER DEFINED VARIABLE";
							n->defined_args = list_make1($1);
							n->is_local = false;
							n->is_multiset = true;
							$$ = (Node *)n;
						}
				;

user_defined_single:
			uservar_name COLON_EQUALS a_expr
				{
					UserSetElem *n = makeNode(UserSetElem);
					n->name = list_make1($1);
					n->val = (Expr *)$3;
					$$ = (Node *)n;
				}
			| uservar_name '=' a_expr
				{
					UserSetElem *n = makeNode(UserSetElem);
					n->name = list_make1($1);
					n->val = (Expr *)$3;
					$$ = (Node *)n;
				}
			;

set_global:	 set_global_extension
 				{
#if defined(ENABLE_MULTIPLE_NODES) || defined (ENABLE_PRIVATEGAUSS)
					const char* message = "SET GLOBAL is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SET GLOBAL is not supported.")));
#else
						AlterSystemStmt *n = makeNode(AlterSystemStmt);
						n->setstmt = $1;
						$$ = (Node *) n;
#endif
 				}

generic_set_extension:
			 var_name '=' guc_value_extension_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = $1;
					n->args = $3;
					/* if we are setting role, we switch to the new syntax which check the password of role */
					if(!pg_strcasecmp("role", n->name) || !pg_strcasecmp("session_authorization", n->name))
					{
						const char* message = "SET TO rolename\" not yet supported";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("\"SET %s = rolename\" not yet supported", n->name),
									 errhint("Use \"SET %s rolename\" clauses.", n->name)));
					}
					else
					{
						n->kind = VAR_SET_VALUE;
					}
					$$ = n;
				}
			| CURRENT_SCHEMA '=' guc_value_extension_list
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "current_schema";
					n->args = $3;
					$$ = n;
				}
		;

set_session_extension:
			 SET_IDENT_SESSION '.' guc_variable_set
				{
					VariableSetStmt *n = $3;
					n->is_local = false;
					$$ = n;
				}
			| SET_IDENT '=' set_expr
				{
					int len = strlen($1);
					errno_t rc = EOK;
 
					char *name = (char *)palloc(len - 1);
					rc = strncpy_s(name, len - 1, $1 + 2, len-2);
					securec_check(rc, "\0", "\0");

					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = pstrdup(name);
					n->args = list_make1($3);
					pfree(name);
					$$ = n;
				}
			| SET_IDENT '=' DEFAULT
				{
					int len = strlen($1);
					errno_t rc = EOK;
 
					char *name = (char *)palloc(len - 1);
					rc = strncpy_s(name, len - 1, $1 + 2, len-2);
					securec_check(rc, "\0", "\0");
	
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = pstrdup(name);
					pfree(name);
					$$ = n;
				}
			;
 
set_global_extension:
			GLOBAL guc_variable_set
				{
					VariableSetStmt *n = $2;
					$$ = n;
				}
			| SET_IDENT_GLOBAL '.' guc_variable_set
				{
					VariableSetStmt *n = $3;
					$$ = n;
 				}
 		;
 
guc_variable_set:
			var_name '=' set_expr
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = $1;
					n->args = list_make1($3);
					n->is_multiset = true;
					/* if we are setting role, we switch to the new syntax which check the password of role */
					if(!pg_strcasecmp("role", n->name) || !pg_strcasecmp("session_authorization", n->name))
					{
						const char* message = "SET TO rolename\" not yet supported";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("\"SET %s = rolename\" not yet supported", n->name),
									 errhint("Use \"SET %s rolename\" clauses.", n->name)));
					}
					else
					{
						n->kind = VAR_SET_VALUE;
					}
					$$ = n;
				}
			| var_name '=' DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = $1;
					n->is_multiset = true;
					$$ = n;
				}
			| CURRENT_SCHEMA '=' set_expr
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_VALUE;
					n->name = "current_schema";
					n->args = list_make1($3);
					$$ = n;
				}
			| CURRENT_SCHEMA '=' DEFAULT
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_SET_DEFAULT;
					n->name = "current_schema";
					$$ = n;
				}
			;

guc_value_extension_list: set_expr_extension		{ $$ = list_make1($1); }
				| guc_value_extension_list ',' set_expr_extension 	{ $$ = lappend($1, $3); }
		;

set_ident_expr:
			SET_IDENT
				{
					int len = strlen($1);
					errno_t rc = EOK;
 
					if (len > 2 && strncmp($1, "@@", 2) == 0) {
						char *name	= (char *)palloc(len - 1);
						rc = strncpy_s(name, len - 1, $1 + 2, len-2);
						securec_check(rc, "\0", "\0");
 
						SetVariableExpr *n = makeNode(SetVariableExpr);
						n->name = pstrdup(name);
						n->is_session = true;
						n->is_global = false;
						$$ = (Node *) n;
					} else {
 
					}
				}
			| SET_IDENT_SESSION '.' IDENT
				{
					SetVariableExpr *n = makeNode(SetVariableExpr);
					n->name = $3;
					n->is_session = true;
					n->is_global = false;
					$$ = (Node *) n;
				}
			| SET_IDENT_GLOBAL '.' IDENT
				{
					SetVariableExpr *n = makeNode(SetVariableExpr);
					n->name = $3;
					n->is_session = false;
					n->is_global = true;
					$$ = (Node *) n;
				}
		;

set_expr:	
			 var_value
				{ $$ = $1; }
			| set_expr_extension
				{ $$ = $1; }
		;

set_expr_extension:
			 set_ident_expr
				{ $$ = $1; }
			| '(' a_expr ')' opt_indirection
				{
					if ($4)
					{
						A_Indirection *n = makeNode(A_Indirection);
						n->arg = $2;
						n->indirection = check_indirection($4, yyscanner);
						$$ = (Node *)n;
					}
					else
						$$ = $2;
				}
			| case_expr
				{ $$ = $1; }
			| func_expr
				{ $$ = $1; }
			| select_with_parens			%prec UMINUS
				{
					SubLink *n = makeNode(SubLink);
					n->subLinkType = EXPR_SUBLINK;
					n->testexpr = NULL;
					n->operName = NIL;
					n->subselect = $1;
					n->location = @1;
					$$ = (Node *)n;
				}
			| select_with_parens indirection
				{
					/*
					 * Because the select_with_parens nonterminal is designed
					 * to "eat" as many levels of parens as possible, the
					 * '(' a_expr ')' opt_indirection production above will
					 * fail to match a sub-SELECT with indirection decoration;
					 * the sub-SELECT won't be regarded as an a_expr as long
					 * as there are parens around it.  To support applying
					 * subscripting or field selection to a sub-SELECT result,
					 * we need this redundant-looking production.
					 */
					SubLink *n = makeNode(SubLink);
					A_Indirection *a = makeNode(A_Indirection);
					n->subLinkType = EXPR_SUBLINK;
					n->testexpr = NULL;
					n->operName = NIL;
					n->subselect = $1;
					n->location = @1;
					a->arg = (Node *)n;
					a->indirection = check_indirection($2, yyscanner);
					$$ = (Node *)a;
				}
			| uservar_name           %prec UMINUS
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "@var_name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("@var_name is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						$$ = $1;
					} else {
						const char* message = "@var_name is supported only in B-format database, and enable_set_variable_b_format = on.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("@var_name is supported only in B-format database, and enable_set_variable_b_format = on."),
								parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
				}
			| b_expr TYPECAST Typename
				{ $$ = makeTypeCast($1, $3, NULL, NULL, NULL, @2); }
			| '@' b_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", NULL, $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 '@' b_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", $1, $3, @2); }
			| b_expr CmpOp b_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, $2, $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);
				}
			| b_expr IS DOCUMENT_P					%prec IS
				{
					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2);
				}
			| b_expr IS NOT DOCUMENT_P				%prec IS
				{
					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2),@2);
				}
			;

uservar_name:
			SET_USER_IDENT						
			{ 
				int len = strlen($1);
				error_t errorno = EOK;

				if (len < 1) {
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Incorrect user_defined variable."),
							parser_errposition(@1)));
				}

				char *name = (char *)palloc(len + 1);
				errorno = memset_s(name, len + 1, 0, len + 1);
				securec_check(errorno, "\0", "\0");
				if ((len > 2) && (strncmp($1, "'", 1) == 0 || strncmp($1, "\"", 1) == 0 || strncmp($1, "`", 1) == 0)) {
					errorno = strncpy_s(name, len + 1, $1 + 1, len + 1);
					securec_check(errorno, "\0", "\0");
					name[len - 2] = '\0';
				} else {
					errorno = strncpy_s(name, len + 1, $1, len + 1);
					securec_check(errorno, "\0", "\0");
					name[len] = '\0';
				}

				UserVar *n = makeNode(UserVar);
				n->name = downcase_truncate_identifier(name, strlen(name), true);
				$$ = (Node *)n;
			}
			;

var_name:	ColId								{ $$ = $1; }
			| var_name '.' ColId
				{
					int rc = EOK;						  
					int len = strlen($1) + strlen($3) + 2;
					$$ = (char *)palloc(len);
					rc = sprintf_s($$, len, "%s.%s", $1, $3);
					securec_check_ss(rc, "\0", "\0");
				}
		;

var_list:	var_value								{ $$ = list_make1($1); }
			| var_list ',' var_value				{ $$ = lappend($1, $3); }
		;

var_value:	opt_boolean_or_string
				{ $$ = makeStringConst($1, @1); }
			| NumericOnly
				{ $$ = makeAConst($1, @1); }
		;

iso_level:	READ UNCOMMITTED						{ $$ = "read uncommitted"; }
			| READ COMMITTED						{ $$ = "read committed"; }
			| REPEATABLE READ						{ $$ = "repeatable read"; }
			| SERIALIZABLE							{ $$ = "serializable"; }
		;

opt_boolean_or_string:
			TRUE_P									{ $$ = "true"; }
			| FALSE_P								{ $$ = "false"; }
			| ON									{ $$ = "on"; }
			/*
			 * OFF is also accepted as a boolean value, but is handled
			 * by the ColId rule below. The action for booleans and strings
			 * is the same, so we don't need to distinguish them here.
			 */
			| ColId_or_Sconst						{ $$ = $1; }
			| BINARY								{ $$ = "binary";}
		;

/* Timezone values can be:
 * - a string such as 'pst8pdt'
 * - an identifier such as "pst8pdt"
 * - an integer or floating point number
 * - a time interval per SQL99
 * ColId gives reduce/reduce errors against ConstInterval and LOCAL,
 * so use IDENT (meaning we reject anything that is a key word).
 */
zone_value:
			Sconst
				{
					$$ = makeStringConst($1, @1);
				}
			| IDENT
				{
					$$ = makeStringConst($1, @1);
				}
			| ConstInterval Sconst opt_interval
				{
					TypeName *t = $1;
					if ($3 != NIL)
					{
						A_Const *n = (A_Const *) linitial($3);
						if ((n->val.val.ival & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0) {
            				const char* message = "time zone interval must be HOUR or HOUR TO MINUTE";
            				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
									 parser_errposition(@3)));
						}
					}
					t->typmods = $3;
					$$ = makeStringConstCast($2, @2, t);
				}
			| ConstInterval '(' Iconst ')' Sconst opt_interval
				{
					TypeName *t = $1;
					if ($6 != NIL)
					{
						A_Const *n = (A_Const *) linitial($6);
						if ((n->val.val.ival & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0) {
            				const char* message = "time zone interval must be HOUR or HOUR TO MINUTE";
            				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
									 parser_errposition(@6)));
						}
						if (list_length($6) != 1) {
            				const char* message = "interval precision specified twice";
            				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("interval precision specified twice"),
									 parser_errposition(@1)));
						}
						t->typmods = lappend($6, makeIntConst($3, @3));
					}
					else
						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
												makeIntConst($3, @3));
					$$ = makeStringConstCast($5, @5, t);
				}
			| NumericOnly							{ $$ = makeAConst($1, @1); }
			| DEFAULT								{ $$ = NULL; }
			| LOCAL									{ $$ = NULL; }
		;

opt_encoding:
			Sconst									{ $$ = $1; }
			| IDENT									{ $$ = $1; }
			| BINARY								{ $$ = (char*)$1; }
			| DEFAULT								{ $$ = NULL; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

ColId_or_Sconst:
			ColId									{ $$ = $1; }
			| Sconst								{ $$ = $1; }
		;

VariableResetStmt:
			RESET var_name
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET;
					n->name = $2;
					$$ = (Node *) n;
				}
			| RESET TIME ZONE
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET;
					n->name = "timezone";
					$$ = (Node *) n;
				}
			| RESET CURRENT_SCHEMA
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET;
					n->name = "current_schema";
					$$ = (Node *) n;
				}
			| RESET TRANSACTION ISOLATION LEVEL
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET;
					n->name = "transaction_isolation";
					$$ = (Node *) n;
				}
			| RESET SESSION AUTHORIZATION
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET;
					n->name = "session_authorization";
					$$ = (Node *) n;
				}
			| RESET ALL
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					n->kind = VAR_RESET_ALL;
					$$ = (Node *) n;
				}
		;

/* SetResetClause allows SET or RESET without LOCAL */
SetResetClause:
			SET set_rest					{ $$ = $2; }
			| VariableResetStmt				{ $$ = (VariableSetStmt *) $1; }
		;

/* SetResetClause allows SET or RESET without LOCAL */
FunctionSetResetClause:
			SET set_rest_more				{ $$ = $2; }
			| VariableResetStmt				{ $$ = (VariableSetStmt *) $1; }
		;


VariableShowStmt:
			SHOW WARNINGS LIMIT Iconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show warnings feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_warnings";
						n->offset = 0;
						n->count = $4;
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW WARNINGS LIMIT Iconst ',' Iconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show warnings feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_warnings";
						n->offset = $4;
						n->count = $6;
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW IDENT '(' '*' ')' WARNINGS
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show count(*) warnings feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						if (strcmp($2, "count") != 0) {
							const char* message = "Un-support feature";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Un-support function \"%s\" for show warnings", $2)));
						}
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_warnings_count";
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW_ERRORS
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show errors feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_errors";
						n->offset = 0;
						n->count = MAX_ERROR_COUNT;
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW_ERRORS LIMIT Iconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show errors feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_errors";
						n->offset = 0;
						n->count = $3;
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW_ERRORS LIMIT Iconst ',' Iconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show errors feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_errors";
						n->offset = $3;
						n->count = $5;
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW IDENT '(' '*' ')' ERRORS
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show count(*) errors feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						if (strcmp($2, "count") != 0) {
							const char* message = "Un-support feature";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Un-support function \"%s\" for show errors", $2)));
						}
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_errors_count";
						$$ = (Node *) n;
					}
#endif
				}
			| SHOW var_name
			{
				if(strcmp($2, "events") == 0) {
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SHOW EVENTS is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("SHOW EVENTS is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "show events statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("SHOW EVENTS is supported only in B-format database."),
								parser_errposition(@1)));
					$$ = NULL;
				}
				ShowEventStmt *n = makeNode(ShowEventStmt);
				n->from_clause = NULL;
				n->where_clause = NULL;
				$$ = (Node *)n;
				} else if (strcmp($2, "warnings") == 0) {
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Show warnings feature is unsupported on distributed mode.")));
#else
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						VariableShowStmt *n = makeNode(VariableShowStmt);
						n->name = "show_warnings";
						n->offset = 0;
						n->count = MAX_ERROR_COUNT;
						$$ = (Node *) n;
					}
#endif
				} else {
					VariableShowStmt *n = makeNode(VariableShowStmt);
					n->name = $2;
					$$ = (Node *) n;
				} 
			}
			| SHOW CURRENT_SCHEMA
				{
					VariableShowStmt *n = makeNode(VariableShowStmt);
					n->name = "current_schema";
					$$ = (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 VARIABLES LIKE var_name
				{
					VariableShowStmt *n = makeNode(VariableShowStmt);
					n->name = "all";
					n->likename = $4;
					$$ = (Node *) n;
				}
			| SHOW ALL
				{
					VariableShowStmt *n = makeNode(VariableShowStmt);
					n->name = "all";
					$$ = (Node *) n;
				}
		;


ConstraintsSetStmt:
			SET CONSTRAINTS constraints_set_list constraints_set_mode
				{
					ConstraintsSetStmt *n = makeNode(ConstraintsSetStmt);
					n->constraints = $3;
					n->deferred = $4;
					$$ = (Node *) n;
				}
		;

constraints_set_list:
			ALL										{ $$ = NIL; }
			| qualified_name_list					{ $$ = $1; }
		;

constraints_set_mode:
			DEFERRED								{ $$ = TRUE; }
			| IMMEDIATE								{ $$ = FALSE; }
		;

/*****************************************************************************
 *
 * GET DIAGNOSTICS STATEMENT
 *
 *****************************************************************************/

GetDiagStmt: 	GET getdiag_area_opt DIAGNOSTICS statement_information
					{
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							ereport(errstate, (errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Un-support feature"),
								errdetail("get diagitem syntax is supported only in B compatibility")));
						}
						GetDiagStmt *n = makeNode(GetDiagStmt);
						n->condInfo = $4;
						n->hasCondNum = false;
						n->condNum = NULL;

						$$ = (Node *)n;
					}
				| GET getdiag_area_opt DIAGNOSTICS CONDITION condition_number condition_information
					{
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							ereport(errstate, (errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Un-support feature"),
								errdetail("get diagitem syntax is supported only in B compatibility")));
						}
						GetDiagStmt *n = makeNode(GetDiagStmt);
						n->condInfo = $6;
						n->hasCondNum = true;
						n->condNum = list_make1($5);

						$$ = (Node *)n;
					}
				;

getdiag_area_opt:
				| CURRENT_P
				| STACKED_P
					{
						const char* message = "GET STACKED DIAGNOSTICS when handler not active.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR,
						(errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
							errmsg("GET STACKED DIAGNOSTICS when handler not active.")));
					}
				;

statement_information:
				statement_information_item
					{
						$$ = list_make1($1);
					}
				| statement_information ',' statement_information_item
					{
						$$ = lappend($1, $3);
					}
				;

statement_information_item:
				uservar_name '=' statement_information_item_name
					{
						CondInfo* n = (CondInfo *)palloc(sizeof(CondInfo));

						n->target = list_make1($1);
						n->kind = $3;

						$$ = n;
					}
				;

statement_information_item_name:
				NUMBER_P					{ $$ = COND_INFO_NUMBER; }
				| ROW_COUNT				{ $$ = COND_INFO_ROW_COUNT; }
				;

condition_number:
				ICONST						{ $$ = makeIntConst($1, @1); }
				| FCONST					{ $$ = makeIntConst((atof($1) + 0.5), @1); }
				| SCONST					{ $$ = makeIntConst((atof($1) + 0.5), @1); }
				| BCONST					
					{
						Datum val = DirectFunctionCall1(bittoint4, DirectFunctionCall3(bit_in, CStringGetDatum($1), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)));
						$$ = makeIntConst(DatumGetInt32(val), @1);
					}
				| TRUE_P					{ $$ = makeIntConst(TRUE, @1); }
				| FALSE_P					{ $$ = makeIntConst(FALSE, @1); }
				| NULL_P					{ $$ = makeIntConst(FALSE, @1); }
				| uservar_name				{ $$ = $1; }
				| IDENT						{ $$ = makeIntConst((atof($1) + 0.5), @1); }
				;

condition_information:
				condition_information_item
					{
						$$ = list_make1($1);
					}
				| condition_information ',' condition_information_item
					{
						$$ = lappend($1, $3);
					}
				;

condition_information_item:
				uservar_name '=' condition_information_item_name
					{
						CondInfo* n = (CondInfo *)palloc(sizeof(CondInfo));

						n->target = list_make1($1);
						n->kind = $3;

						$$ = n;
					}
				;

condition_information_item_name:
				CLASS_ORIGIN				{ $$ = COND_INFO_CLASS_ORIGIN; }
				| SUBCLASS_ORIGIN			{ $$ = COND_INFO_SUBCLASS_ORIGIN; }
				| CONSTRAINT_CATALOG		{ $$ = COND_INFO_CONSTRAINT_CATALOG; }
				| CONSTRAINT_SCHEMA			{ $$ = COND_INFO_CONSTRAINT_SCHEMA; }
				| CONSTRAINT_NAME			{ $$ = COND_INFO_CONSTRAINT_NAME; }
				| CATALOG_NAME				{ $$ = COND_INFO_CATALOG_NAME; }
				| SCHEMA_NAME				{ $$ = COND_INFO_SCHEMA_NAME; }
				| TABLE_NAME				{ $$ = COND_INFO_TABLE_NAME; }
				| COLUMN_NAME				{ $$ = COND_INFO_COLUMN_NAME; }
				| CURSOR_NAME				{ $$ = COND_INFO_CURSOR_NAME; }
				| MESSAGE_TEXT				{ $$ = COND_INFO_MESSAGE_TEXT; }
				| MYSQL_ERRNO				{ $$ = COND_INFO_MYSQL_ERRNO; }
				| RETURNED_SQLSTATE			{ $$ = COND_INFO_RETURNED_SQLSTATE; }
				;
/*****************************************************************************
 *
 * SHUTDOWN STATEMENT
 *
 *****************************************************************************/
ShutdownStmt:
                        SHUTDOWN
                                {
                                       ShutdownStmt *n = makeNode(ShutdownStmt);
                                       n->mode = NULL;
                                       $$ = (Node *) n;
                                }
                        | SHUTDOWN var_name
                                {
                                       ShutdownStmt *n = makeNode(ShutdownStmt);
                                       n->mode = $2;
                                       $$ = (Node *) n;
                                }
                ;

/*
 * Checkpoint statement
 */
CheckPointStmt:
			CHECKPOINT
				{
					CheckPointStmt *n = makeNode(CheckPointStmt);
					$$ = (Node *)n;
				}
		;


/*****************************************************************************
 *
 * DISCARD { ALL | TEMP | PLANS }
 *
 *****************************************************************************/

DiscardStmt:
			DISCARD ALL
				{
					DiscardStmt *n = makeNode(DiscardStmt);
					n->target = DISCARD_ALL;
					$$ = (Node *) n;
				}
			| DISCARD TEMP
				{
					DiscardStmt *n = makeNode(DiscardStmt);
					n->target = DISCARD_TEMP;
					$$ = (Node *) n;
				}
			| DISCARD TEMPORARY
				{
					DiscardStmt *n = makeNode(DiscardStmt);
					n->target = DISCARD_TEMP;
					$$ = (Node *) n;
				}
			| DISCARD PLANS
				{
					DiscardStmt *n = makeNode(DiscardStmt);
					n->target = DISCARD_PLANS;
					$$ = (Node *) n;
				}
		;


/*****************************************************************************
 *
 *	ALTER [ TABLE | INDEX | SEQUENCE | VIEW | MATERIALIZED VIEW| STREAM] variations
 *
 * Note: we accept all subcommands for each of the five variants, and sort
 * out what's really legal at execution time.
 *****************************************************************************/

AlterTableStmt:
		ALTER TABLE relation_expr MODIFY_P '(' modify_column_cmds ')'
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $3;
					n->cmds = $6;
					n->relkind = OBJECT_TABLE;
					n->missing_ok = false;
					n->need_rewrite_sql = false;
					$$ = (Node *)n;
				}
		|	ALTER TABLE relation_expr ADD_P '(' add_column_cmds ')'
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $3;
					n->cmds = $6;
					n->relkind = OBJECT_TABLE;
					n->missing_ok = false;
					n->need_rewrite_sql = false;
					$$ = (Node *)n;
				}
		/* REDISANYVALUE key value only used in tsdb redis command, it is used in OM code */
		|	ALTER TABLE relation_expr REDISANYVALUE
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $3;
					n->cmds = NIL;
					n->relkind = OBJECT_TABLE;
					n->missing_ok = false;
					n->need_rewrite_sql = false;
					$$ = (Node *)n;
				}
		/*
		 * ALTER TABLE IF_P EXISTS MODIFY_P '(' modify_column_cmds ')'
		 */
		|	ALTER TABLE IF_P EXISTS relation_expr MODIFY_P '(' modify_column_cmds ')'
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $5;
					n->cmds = $8;
					n->relkind = OBJECT_TABLE;
					n->missing_ok = true;
					n->need_rewrite_sql = false;
					$$ = (Node *)n;
				}
		/*
		 * ALTER TABLE IF_P EXISTS ADD_P '(' add_column_cmds ')'
		 */
		|	ALTER TABLE IF_P EXISTS relation_expr ADD_P '(' add_column_cmds ')'
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $5;
					n->cmds = $8;
					n->relkind = OBJECT_TABLE;
					n->missing_ok = true;
					n->need_rewrite_sql = false;
					$$ = (Node *)n;
				}
		|	ALTER TABLE relation_expr alter_table_or_partition
				{
					if ($4->length == 1 && ((AlterTableCmd*)lfirst($4->head))->subtype == AT_RebuildAllIndexOnPartition)
					{
						ReindexStmt *n = makeNode(ReindexStmt);
						n->kind = OBJECT_TABLE_PARTITION;
						n->relation = $3;
						n->name = ((AlterTableCmd*)lfirst($4->head))->name;
						$$ = (Node *)n;
					}
					else
					{
						AlterTableStmt *n = makeNode(AlterTableStmt);
						n->relation = $3;
						n->cmds = $4;
						n->relkind = OBJECT_TABLE;
						n->missing_ok = false;
						n->need_rewrite_sql = false;
						$$ = (Node *)n;
					}
				}
		|	ALTER TABLE IF_P EXISTS relation_expr alter_table_or_partition
				{
					if ($6->length == 1 && ((AlterTableCmd*)lfirst($6->head))->subtype == AT_RebuildAllIndexOnPartition)
					{
						ReindexStmt *n = makeNode(ReindexStmt);
						n->kind = OBJECT_TABLE_PARTITION;
						n->relation = $5;
						n->name = ((AlterTableCmd*)lfirst($6->head))->name;
						$$ = (Node *)n;
					}
					else
					{
						AlterTableStmt *n = makeNode(AlterTableStmt);
						n->relation = $5;
						n->cmds = $6;
						n->relkind = OBJECT_TABLE;
						n->missing_ok = true;
						n->need_rewrite_sql = false;
						$$ = (Node *)n;
					}
				}
		|	ALTER INDEX qualified_name alter_table_or_partition
				{
					if ($4->length == 1 && ((AlterTableCmd*)lfirst($4->head))->subtype == AT_RebuildIndex)
					{
						ReindexStmt *n = makeNode(ReindexStmt);
						n->kind = OBJECT_INDEX;
						n->relation = $3;
						n->name = NULL;
						$$ = (Node *)n;
					}
					else if ($4->length == 1 && ((AlterTableCmd*)lfirst($4->head))->subtype == AT_RebuildIndexPartition)
					{
						ReindexStmt *n = makeNode(ReindexStmt);
						n->kind = OBJECT_INDEX_PARTITION;
						n->relation = $3;
						n->name = ((AlterTableCmd*)lfirst($4->head))->name;
						$$ = (Node *)n;
					}
					else
					{
						ListCell   *cell;
						foreach(cell, $4)
						{
							AlterTableCmd* cmd = (AlterTableCmd*) lfirst(cell);
							if (cmd->subtype == AT_RebuildIndex
								|| cmd->subtype == AT_RebuildIndexPartition)
							{
            					const char* message = "REBUILD is not supported for multiple commands";
            					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("REBUILD is not supported for multiple commands")));
							}
						}

						AlterTableStmt *n = makeNode(AlterTableStmt);
						n->relation = $3;
						n->cmds = $4;
						n->relkind = OBJECT_INDEX;
						n->missing_ok = false;
						$$ = (Node *)n;
					}
				}
		|	ALTER INDEX IF_P EXISTS qualified_name alter_table_or_partition
				{
					ListCell   *cell;
					foreach(cell, $6)
					{
						AlterTableCmd* cmd = (AlterTableCmd*) lfirst(cell);
						if (cmd->subtype == AT_RebuildIndex
							|| cmd->subtype == AT_RebuildIndexPartition)
						{
            				const char* message = "IF EXISTS is not supported for REBUILD";
            				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("IF EXISTS is not supported for REBUILD")));
						}
					}

					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $5;
					n->cmds = $6;
					n->relkind = OBJECT_INDEX;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
		|	ALTER SEQUENCE qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $3;
					n->cmds = $4;
					n->relkind = OBJECT_SEQUENCE;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
		|	ALTER LARGE_P SEQUENCE qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $4;
					n->cmds = $5;
					n->relkind = OBJECT_LARGE_SEQUENCE;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
		|	ALTER SEQUENCE IF_P EXISTS qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $5;
					n->cmds = $6;
					n->relkind = OBJECT_SEQUENCE;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
		|	ALTER LARGE_P SEQUENCE IF_P EXISTS qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $6;
					n->cmds = $7;
					n->relkind = OBJECT_LARGE_SEQUENCE;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
		|	ALTER VIEW qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $3;
					n->cmds = $4;
					n->relkind = OBJECT_VIEW;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
		|	ALTER VIEW IF_P EXISTS qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $5;
					n->cmds = $6;
					n->relkind = OBJECT_VIEW;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
		|	ALTER MATERIALIZED VIEW qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $4;
					n->cmds = $5;
					n->relkind = OBJECT_MATVIEW;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
		|	ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $6;
					n->cmds = $7;
					n->relkind = OBJECT_MATVIEW;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
        |   ALTER STREAM  qualified_name alter_table_cmds
            {
                AlterTableStmt *n = makeNode(AlterTableStmt);
                n->relation = $3;
                n->cmds = $4;
                n->relkind = OBJECT_STREAM;
                n->missing_ok = false;
                $$ = (Node *)n;
            }
        ;

modify_column_cmds:
			modify_column_cmd							{ $$ = list_make1($1); }
			| modify_column_cmds ',' modify_column_cmd	{ $$ = lappend($$, $3); }
			;
modify_column_cmd:
			ColId Typename opt_charset ColQualList opt_column_options add_column_first_after
				{
					AlterTableCmd *n = (AlterTableCmd *)$6;
					if ($4 == NULL && $5 == NULL && n->is_first == false && n->after_name == NULL && !ENABLE_MODIFY_COLUMN) {
						ColumnDef *def = makeNode(ColumnDef);
						n->subtype = AT_AlterColumnType;
						n->name = $1;
						n->def = (Node *) def;
						/* We only use these three fields of the ColumnDef node */
						def->typname = $2;
						def->typname->charset = $3;
						def->collClause = NULL;
						def->raw_default = NULL;
						def->update_default = NULL;
						def->clientLogicColumnRef=NULL;
						$$ = (Node *)n;
					} else {
#ifdef ENABLE_MULTIPLE_NODES
						const char* message = "Un-support feature";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("Un-support feature"),
								errdetail("The distributed capability is not supported currently.")));
#endif
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							ereport(errstate, (errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Un-support feature"),
								parser_errposition(@4),
								errdetail("this modify syntax is supported only in B compatibility")));
						}
						ColumnDef *def = makeNode(ColumnDef);
						def->colname = $1;
						def->typname = $2;
						def->typname->charset = $3;
						def->columnOptions = $5;
						def->kvtype = ATT_KV_UNDEFINED;
						def->inhcount = 0;
						def->is_local = true;
						def->is_not_null = false;
						def->is_from_type = false;
						def->storage = 0;
						def->cmprs_mode = ATT_CMPR_UNDEFINED;
						def->raw_default = NULL;
						def->cooked_default = NULL;
						def->collOid = InvalidOid;
						def->fdwoptions = NULL;
						def->update_default = NULL;
						SplitColQualList($4, &def->constraints, &def->collClause, &def->clientLogicColumnRef, yyscanner);
						n->subtype = AT_ModifyColumn;
						n->name = $1;
						n->def = (Node *)def;
						$$ = (Node *)n;						
					}
				}
			| ColId NOT NULL_P opt_enable
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetNotNull;
					n->name = $1;
					$$ = (Node *)n;
				}
			| ColId NULL_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropNotNull;
					n->name = $1;
					$$ = (Node *)n;
				}
			| ColId CONSTRAINT name NOT NULL_P opt_enable
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					ColumnDef *def = makeNode(ColumnDef);
					Constraint *cons = makeNode(Constraint);
					n->subtype = AT_SetNotNull;
					n->name = $1;
					n->def = (Node *) def;
					def->constraints = list_make1(cons);
					cons->contype = CONSTR_NOTNULL;
					cons->conname = $3;
					cons->location = @2;
					$$ = (Node *)n;
				}
			| ColId CONSTRAINT name NULL_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					ColumnDef *def = makeNode(ColumnDef);
					Constraint *cons = makeNode(Constraint);
					n->subtype = AT_DropNotNull;
					n->name = $1;
					n->def = (Node *) def;
					def->constraints = list_make1(cons);
					cons->contype = CONSTR_NULL;
					cons->conname = $3;
					cons->location = @2;
					$$ = (Node *)n;
				}
			;
opt_enable:	ENABLE_P		{}
			| /* empty */	{}
			;
add_column_cmds:
			columnDef
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddColumn;
					n->def = $1;
					$$ = list_make1(n);
				}
			| add_column_cmds ',' columnDef
				{
				 	AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddColumn;
					n->def = $3;
					$$ = lappend($1, n);
				}
			;

/* ALTER TABLE sql clause both for PARTITION and ordinary table */
alter_table_or_partition:
			alter_table_cmds        { $$ = ($1); }
			| alter_partition_cmds  { $$ = ($1); }
		;

/* ALTER TABLE sql clauses for ordinary table */
alter_table_cmds:
			alter_table_cmd                         { $$ = list_make1($1); }
			| alter_table_cmds ',' alter_table_cmd  { $$ = lappend($1, $3); }
		;

/* ALTER TABLE PARTITION sql clauses */
alter_partition_cmds:
			alter_partition_cmd                            { $$ = list_make1($1); }
			| alter_partition_cmds ',' alter_partition_cmd { $$ = lappend($1, $3); }
			| move_partition_cmd                           { $$ = list_make1($1); }
			| exchange_partition_cmd                       { $$ = list_make1($1); }
			| reset_partition_cmd                          { $$ = list_make1($1); }
			| modify_partition_cmd                         { $$ = list_make1($1); }
		;

alter_partition_cmd:
		/* ALTER INDEX index_name MODIFY PARTITION partition_name UNUSABLE */
		MODIFY_PARTITION ColId UNUSABLE
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_UnusableIndexPartition;
				n->name = $2;
				$$ = (Node *)n;
			}
		/* ALTER TABLE table_name MODIFY PARTITION partition_name UNUSABLE ALL INDEX */
		| MODIFY_PARTITION ColId UNUSABLE LOCAL INDEXES
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_UnusableAllIndexOnPartition;
				n->name = $2;
				$$ = (Node *)n;
			}
		/* ALTER INDEX index_name REBUILD PARTITION partition_name */
		| REBUILD_PARTITION ColId
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_RebuildIndexPartition;
				n->name = $2;
				$$ = (Node *)n;
			}
		/* ALTER TABLE table_name MODIFY PARTITION partition_name REBUILD ALL INDEX */
		| MODIFY_PARTITION ColId REBUILD UNUSABLE LOCAL INDEXES
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_RebuildAllIndexOnPartition;
				n->name = $2;
				$$ = (Node *)n;
			}
		/* ALTER TABLE ADD PARTITION: use less/than */
		| ADD_PARTITION name VALUES LESS THAN
		'(' maxValueList ')' opt_part_options
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->boundary = $7;
				p->tablespacename = $9;
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		/* ALTER TABLE ADD PARTITION: use START/END */
		| ADD_PARTITION name START '(' maxValueList ')'  END_P '(' maxValueList ')' opt_range_every_list opt_part_options
			{
				RangePartitionStartEndDefState *p = makeNode(RangePartitionStartEndDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->startValue = $5;
				p->endValue = $9;
				p->everyValue = $11;
				p->tableSpaceName = $12;
				s->partitionList = list_make1(p);
				s->isStartEnd = true;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name END_P '(' maxValueList ')' opt_part_options
			{
				RangePartitionStartEndDefState *p = makeNode(RangePartitionStartEndDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->startValue = NIL;
				p->endValue = $5;
				p->everyValue = NIL;
				p->tableSpaceName = $7;
				s->partitionList = list_make1(p);
				s->isStartEnd = true;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name START '(' maxValueList ')' opt_part_options
			{
				RangePartitionStartEndDefState *p = makeNode(RangePartitionStartEndDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->startValue = $5;
				p->endValue = NIL;
				p->everyValue = NIL;
				p->tableSpaceName = $7;
				s->partitionList = list_make1(p);
				s->isStartEnd = true;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name VALUES '(' expr_list ')' opt_part_options
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->boundary = $5;
				p->tablespacename = $7;
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name VALUES '(' DEFAULT ')' opt_part_options
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				Const *n_default = makeNode(Const);
				n_default->ismaxvalue = true;
				n_default->location = -1;
				p->boundary = list_make1(n_default);
				p->tablespacename = $7;
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name VALUES LESS THAN
		'(' maxValueList ')' opt_part_options '(' subpartition_definition_list ')'
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->boundary = $7;
				p->tablespacename = $9;
				p->subPartitionDefState = $11;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = p->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name VALUES '(' expr_list ')' opt_part_options '(' subpartition_definition_list ')'
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				p->boundary = $5;
				p->tablespacename = $7;
				p->subPartitionDefState = $9;
			    int i = 0;
				ListCell *elem = NULL;
				List *parts = p->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| ADD_PARTITION name VALUES '(' DEFAULT ')' OptTableSpace '(' subpartition_definition_list ')'
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddPartitionState *s = makeNode(AddPartitionState);
				p->partitionName = $2;
				Const *n_default = makeNode(Const);
				n_default->ismaxvalue = true;
				n_default->location = -1;
				p->boundary = list_make1(n_default);
				p->tablespacename = $7;
				p->subPartitionDefState = $9;
			    int i = 0;
				ListCell *elem = NULL;
				List *parts = p->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				s->partitionList = list_make1(p);
				s->isStartEnd = false;
				n->subtype = AT_AddPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		/* ALTER TABLE MODIFY PARTITION ADD SUBPARTITION */
		| MODIFY_PARTITION name ADD_SUBPARTITION name VALUES LESS THAN '(' maxValueList ')' OptTableSpace
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddSubPartitionState *s = makeNode(AddSubPartitionState);
				p->partitionName = $4;
				p->boundary = $9;
				p->tablespacename = $11;
				s->subPartitionList = list_make1(p);
				s->partitionName = $2;
				n->subtype = AT_AddSubPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| MODIFY_PARTITION name ADD_SUBPARTITION name VALUES '(' expr_list ')' OptTableSpace
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddSubPartitionState *s = makeNode(AddSubPartitionState);
				p->partitionName = $4;
				p->boundary = $7;
				p->tablespacename = $9;
				s->subPartitionList = list_make1(p);
				s->partitionName = $2;
				n->subtype = AT_AddSubPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		| MODIFY_PARTITION name ADD_SUBPARTITION name VALUES '(' DEFAULT ')' OptTableSpace
			{
				ListPartitionDefState *p = makeNode(ListPartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);
				AddSubPartitionState *s = makeNode(AddSubPartitionState);
				p->partitionName = $4;
				Const *n_default = makeNode(Const);
				n_default->ismaxvalue = true;
				n_default->location = -1;
				p->boundary = list_make1(n_default);
				p->tablespacename = $9;
				s->subPartitionList = list_make1(p);
				s->partitionName = $2;
				n->subtype = AT_AddSubPartition;
				n->def = (Node*)s;
				$$ = (Node *)n;
			}
		/* ALTER TABLE DROP PARTITION */
		| DROP_PARTITION ColId OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_DropPartition;
				n->name = $2;
				n->behavior = DROP_CASCADE;
				n->missing_ok = FALSE;
				n->alterGPI = $3;
				$$ = (Node *)n;
			}
		/* ALTER TABLE DROP PARTITION */
		| DROP_PARTITION FOR '(' maxValueList ')' OptGPI
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);

				p->boundary = $4;
				n->subtype = AT_DropPartition;
				n->def = (Node*)p;
				n->behavior = DROP_CASCADE;
				n->missing_ok = FALSE;
				n->alterGPI = $6;
				$$ = (Node *)n;
			}
		/* ALTER TABLE DROP SUBPARTITION */
		| DROP_SUBPARTITION ColId OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_DropSubPartition;
				n->name = $2;
				n->behavior = DROP_CASCADE;
				n->missing_ok = FALSE;
				n->alterGPI = $3;
				$$ = (Node *)n;
			}
		| DROP_SUBPARTITION FOR '(' expr_list ')' OptGPI
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);

				p->boundary = $4;
				n->subtype = AT_DropSubPartition;
				n->def = (Node*)p;
				n->behavior = DROP_CASCADE;
				n->missing_ok = FALSE;
				n->alterGPI = $6;
				$$ = (Node *)n;
			}
		/* merge 2 or more partitions into 1 partition */
		| MERGE PARTITIONS name_list INTO PARTITION name OptTableSpace OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->def = (Node*)$3;
				n->name = $6;
				n->target_partition_tablespace = $7;
				n->subtype = AT_MergePartition;
				n->alterGPI = $8;
				$$ = (Node*)n;
			}
		/* split one partition into two partition */
		| SPLIT PARTITION name AT '(' maxValueList ')' INTO
		  '(' split_dest_partition_define_list ')' OptGPI
			{
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->src_partition_name = $3;
				s->split_point = $6;
				s->dest_partition_define_list = $10;
				s->partition_for_values = NULL;

				n->def = (Node*)s;
				n->subtype = AT_SplitPartition;
				n->alterGPI = $12;
				$$ = (Node*)n;
			}
		/* split one partition into two partition */
		| SPLIT PARTITION_FOR '(' maxValueList ')' AT '(' maxValueList ')' INTO
		  '(' split_dest_partition_define_list ')' OptGPI
			{
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->partition_for_values = $4;
				s->split_point = $8;
				s->dest_partition_define_list = $12;
				s->src_partition_name = NULL;

				n->def = (Node*)s;
				n->subtype = AT_SplitPartition;
				n->alterGPI = $14;
				$$ = (Node*)n;
			}
		/*split one partition into multiple partition*/
		| SPLIT PARTITION name INTO '(' range_partition_definition_list ')' OptGPI
			{
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->src_partition_name = $3;
				s->dest_partition_define_list = $6;
				s->split_point = NULL;
				s->partition_for_values = NULL;

				n->def = (Node*)s;
				n->subtype = AT_SplitPartition;
				n->alterGPI = $8;
				$$ = (Node*)n;
			}
		| SPLIT PARTITION_FOR '(' maxValueList ')' INTO '(' range_partition_definition_list ')' OptGPI
			{
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->partition_for_values = $4;
				s->dest_partition_define_list = $8;
				s->src_partition_name = NULL;
				s->split_point = NULL;

				n->def = (Node*)s;
				n->subtype = AT_SplitPartition;
				n->alterGPI = $10;
				$$ = (Node*)n;
			}
		/* split one list subpartition into two subpartition */
		| SPLIT SUBPARTITION name VALUES '(' maxValueList ')' INTO
		  '(' split_dest_listsubpartition_define_list ')' OptGPI
			{
				if (list_length($10) != 2)  {
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("List subpartition can be split into only two subpartitions.")));
				}
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->src_partition_name = $3;
				s->newListSubPartitionBoundry = $6;
				s->dest_partition_define_list = $10;
				s->partition_for_values = NULL;
				s->splitType = LISTSUBPARTITIION;

				n->def = (Node*)s;
				n->subtype = AT_SplitSubPartition;
				n->alterGPI = $12;
				$$ = (Node*)n;
			}
		/* split one range subpartition into two subpartition */
		| SPLIT SUBPARTITION name AT '(' maxValueList ')' INTO
		  '(' split_dest_rangesubpartition_define_list ')' OptGPI
			{
				if (list_length($10) != 2)  {
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("List subpartition can be split into only two subpartitions.")));
				}
				AlterTableCmd	*n = makeNode(AlterTableCmd);
				SplitPartitionState	*s = makeNode(SplitPartitionState);

				s->src_partition_name = $3;
				s->split_point = $6;
				s->dest_partition_define_list = $10;
				s->partition_for_values = NULL;
				s->splitType = RANGESUBPARTITIION;

				n->def = (Node*)s;
				n->subtype = AT_SplitSubPartition;
				n->alterGPI = $12;
				$$ = (Node*)n;
			}
		/* truncate partition */
		| TRUNCATE PARTITION ColId OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_TruncatePartition;
				n->missing_ok = FALSE;
				n->alterGPI = $4;
				$$ = (Node *)n;

				n->name = $3;

			}
		/* truncate partition */
		| TRUNCATE PARTITION_FOR '(' maxValueList ')' OptGPI
			{

				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);

				p->boundary = $4;
				n->subtype = AT_TruncatePartition;
				n->def = (Node*)p;
				n->missing_ok = FALSE;
				n->alterGPI = $6;
				$$ = (Node *)n;

			}
		/* truncate subpartition */
		| TRUNCATE SUBPARTITION ColId OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_TruncateSubPartition;
				n->missing_ok = FALSE;
				n->alterGPI = $4;
				$$ = (Node *)n;

				n->name = $3;

			}
		/* ENABLE ROW MOVEMENT */
		| ENABLE_P ROW MOVEMENT
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_EnableRowMoveMent;
				n->missing_ok = FALSE;
				$$ = (Node *) n;
			}
		/* DISABLE ROW MOVEMENT */
		| DISABLE_P ROW MOVEMENT
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_DisableRowMoveMent;
				n->missing_ok = FALSE;
				$$ = (Node *) n;

			}
		;

modify_partition_cmd:
		/* ALTER TABLE <name> MODIFY PARTITION <part_name> IMCSTORED */
		MODIFY_PARTITION imcs_partition_name IMCSTORED
		{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_ModifyPartitionImcstored;
				n->name = $2;
				$$ = (Node *)n;
			}
		| MODIFY_PARTITION imcs_partition_name IMCSTORED '(' name_list ')'
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_ModifyPartitionImcstored;
				n->name = $2;
				n->def = (Node *)$5;
				$$ = (Node *)n;
			}
		| MODIFY_PARTITION imcs_partition_name UNIMCSTORED
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_ModifyPartitionUnImcstored;
				n->name = $2;
				$$ = (Node *)n;
			}
		;

move_partition_cmd:
		/* ALTER TABLE <name> MOVE PARTITION <part_name> TABLESPACE <tablespacename> */
		MOVE PARTITION partition_name TABLESPACE name
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				n->subtype = AT_SetPartitionTableSpace;
				n->def = (Node*)$3;
				n->name = $5;
				$$ = (Node *)n;
			}
		/* ALTER TABLE <name> MOVE PARTITION FOR (...) TABLESPACE <tablespacename> */
		| MOVE PARTITION_FOR '(' maxValueList ')' TABLESPACE name
			{
				RangePartitionDefState *p = makeNode(RangePartitionDefState);
				AlterTableCmd *n = makeNode(AlterTableCmd);

				p->boundary = $4;

				n->subtype = AT_SetPartitionTableSpace;
				n->def = (Node*)p;
				n->name = $7;
				$$ = (Node *)n;
			}
		;

exchange_partition_cmd:
		/* exchange partition */
		EXCHANGE PARTITION '(' ColId ')'
		  WITH TABLE relation_expr opt_verbose OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_ExchangePartition;
				n->name = $4;
				n->exchange_with_rel = $8;
				n->check_validation = TRUE;
				n->exchange_verbose = $9;
				n->missing_ok = FALSE;
				n->alterGPI = $10;
				$$ = (Node *)n;
			}
		/* exchange partition */
		| EXCHANGE PARTITION '(' ColId ')'
		  WITH TABLE relation_expr WITH VALIDATION opt_verbose OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_ExchangePartition;
				n->name = $4;
				n->exchange_with_rel = $8;
				n->check_validation = TRUE;
				n->exchange_verbose = $11;
				n->missing_ok = FALSE;
				n->alterGPI = $12;
				$$ = (Node *)n;
			}
		/* exchange partition */
		| EXCHANGE PARTITION '(' ColId ')'
		  WITH TABLE relation_expr WITHOUT VALIDATION OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_ExchangePartition;
				n->name = $4;
				n->exchange_with_rel = $8;
				n->check_validation = FALSE;
				n->missing_ok = FALSE;
				n->alterGPI = $11;
				$$ = (Node *)n;
			}

		/* exchange partition */
		| EXCHANGE PARTITION_FOR '(' maxValueList ')'
		  WITH TABLE relation_expr opt_verbose OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				RangePartitionDefState *p = makeNode(RangePartitionDefState);

				p->boundary = $4;

				n->subtype = AT_ExchangePartition;
				n->exchange_with_rel = $8;
				n->check_validation = TRUE;
				n->exchange_verbose = $9;
				n->def = (Node*)p;
				n->missing_ok = FALSE;
				n->alterGPI = $10;
				$$ = (Node *)n;
			}

		| EXCHANGE PARTITION_FOR '(' maxValueList ')'
		  WITH TABLE relation_expr WITH VALIDATION opt_verbose OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				RangePartitionDefState *p = makeNode(RangePartitionDefState);

				p->boundary = $4;

				n->subtype = AT_ExchangePartition;
				n->exchange_with_rel = $8;
				n->check_validation = TRUE;
				n->exchange_verbose = $11;
				n->def = (Node*)p;
				n->missing_ok = FALSE;
				n->alterGPI = $12;
				$$ = (Node *)n;
			}

		| EXCHANGE PARTITION_FOR '(' maxValueList ')'
		  WITH TABLE relation_expr WITHOUT VALIDATION OptGPI
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);
				RangePartitionDefState *p = makeNode(RangePartitionDefState);

				p->boundary = $4;

				n->subtype = AT_ExchangePartition;
				n->exchange_with_rel = $8;
				n->check_validation = FALSE;
				n->def = (Node*)p;
				n->missing_ok = FALSE;
				n->alterGPI = $11;
				$$ = (Node *)n;
			}
		;

reset_partition_cmd:
		RESET PARTITION
			{
				AlterTableCmd *n = makeNode(AlterTableCmd);

				n->subtype = AT_ResetPartitionno;
				n->missing_ok = FALSE;
				$$ = (Node *) n;

			}
		;

alter_table_cmd:
			/*ALTER INDEX index_name UNUSABLE*/
			UNUSABLE
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_UnusableIndex;
					$$ = (Node *)n;
				}
			|
			INVISIBLE
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_InvisibleIndexDirect;
					$$ = (Node *)n;
				}
			|
			VISIBLE
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_VisibleIndexDirect;
					$$ = (Node *)n;
				}
			|
			ALTER INDEX index_name INVISIBLE
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_InvisibleIndex;
					n->name = $3;
					$$ = (Node *)n;
				}
			|
			ALTER INDEX index_name VISIBLE
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_VisibleIndex;
					n->name = $3;
					$$ = (Node *)n;
				}
			|
			/*ALTER INDEX index_name REBUILD*/
			REBUILD
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_RebuildIndex;
					$$ = (Node *)n;
				}
			|
			/*ALTER INDEX index_name DISABLE*/
			DISABLE_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableIndex;
					$$ = (Node *)n;
				}
			|
			/*ALTER INDEX index_name ENABLE*/
			ENABLE_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableIndex;
					$$ = (Node *)n;
				}
			|
			/* ALTER TABLE <name> ADD <coldef> */
			ADD_P columnDef add_column_first_after
				{
					AlterTableCmd *n = (AlterTableCmd *)$3;
					n->subtype = AT_AddColumn;
					n->def = $2;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ADD COLUMN <coldef> */
			| ADD_P COLUMN columnDef add_column_first_after
				{
					AlterTableCmd *n = (AlterTableCmd *)$4;
					n->subtype = AT_AddColumn;
					n->def = $3;
					$$ = (Node *)n;
				}
			| ADD_P TABLE qualified_name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					AddTableIntoCBIState *s = makeNode(AddTableIntoCBIState);
					s->relation = $3;
					n->def = (Node *)s;
					n->subtype = AT_AddIntoCBI;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */
			| ALTER opt_column ColId alter_column_default
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ColumnDefault;
					n->name = $3;
					n->def = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP NOT NULL */
			| ALTER opt_column ColId DROP NOT NULL_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropNotNull;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET NOT NULL */
			| ALTER opt_column ColId SET NOT NULL_P
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetNotNull;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS <SignedIconst> */
			| ALTER opt_column ColId SET STATISTICS SignedIconst
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetStatistics;
					n->name = $3;
					n->def = (Node *) makeInteger($6);
					n->additional_property = AT_CMD_WithoutPercent;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS PERCENT <SignedIconst> */
			| ALTER opt_column ColId SET STATISTICS PERCENT SignedIconst
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetStatistics;
					n->name = $3;
					n->def = (Node *) makeInteger($7);
					n->additional_property = AT_CMD_WithPercent;
					$$ = (Node *)n;
				}
			| ADD_P STATISTICS '(' opt_multi_name_list ')'
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddStatistics;
					n->def = (Node *) $4;
					$$ = (Node *)n;
				}
			| DELETE_P STATISTICS '(' opt_multi_name_list ')'
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DeleteStatistics;
					n->def = (Node *) $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
			| ALTER opt_column ColId SET reloptions
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetOptions;
					n->name = $3;
					n->def = (Node *) $5;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET ( column_parameter = value [, ... ] ) */
			| ALTER opt_column ColId RESET reloptions
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ResetOptions;
					n->name = $3;
					n->def = (Node *) $5;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
			| ALTER opt_column ColId SET STORAGE ColId
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetStorage;
					n->name = $3;
					n->def = (Node *) makeString($6);
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DROP [COLUMN] IF EXISTS <colname> [RESTRICT|CASCADE] */
			| DROP opt_column IF_P EXISTS ColId opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropColumn;
					n->name = $5;
					n->behavior = $6;
					n->missing_ok = TRUE;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DROP [COLUMN] <colname> [RESTRICT|CASCADE] */
			| DROP opt_column ColId opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropColumn;
					n->name = $3;
					n->behavior = $4;
					n->missing_ok = FALSE;
					$$ = (Node *)n;
				}
			/*
			 * ALTER TABLE <name> ALTER [COLUMN] <colname> [SET DATA] TYPE <typename>
			 *		[ USING <expression> ]
			 */
			| ALTER opt_column ColId opt_set_data TYPE_P Typename opt_collate_clause alter_using
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					ColumnDef *def = makeNode(ColumnDef);
					n->subtype = AT_AlterColumnType;
					n->name = $3;
					n->def = (Node *) def;
					/* We only use these three fields of the ColumnDef node */
					def->typname = $6;
					def->collClause = (CollateClause *) $7;
					def->raw_default = $8;
					def->clientLogicColumnRef=NULL;
					$$ = (Node *)n;
				}
			/* ALTER FOREIGN TABLE <name> ALTER [COLUMN] <colname> OPTIONS */
			| ALTER opt_column ColId alter_generic_options
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AlterColumnGenericOptions;
					n->name = $3;
					n->def = (Node *) $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ADD CONSTRAINT ... */
			| ADD_P TableConstraint
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddConstraint;
					n->def = $2;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> VALIDATE CONSTRAINT ... */
			| VALIDATE CONSTRAINT name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ValidateConstraint;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE [VALIDATE | NOVALIDATE] CONSTRAINT ... */
			| ENABLE_P ConstraintAttr_isValidate CONSTRAINT name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					if ($2 == CAS_NO_VALIDATE)
						n->subtype = AT_NOValidateConstraint;
					else
						n->subtype = AT_ValidateConstraint; 
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE [VALIDATE | NOVALIDATE] CONSTRAINT ... */
			| DISABLE_P ConstraintAttr_isValidate CONSTRAINT name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					if ($2 == CAS_VALIDATE)
						n->subtype = AT_DISABLE_ValidateConstraint;
					else
						n->subtype = AT_DISABLE_NOValidateConstraint; 
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */
			| DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropConstraint;
					n->name = $5;
					n->behavior = $6;
					n->missing_ok = TRUE;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DROP CONSTRAINT <name> [RESTRICT|CASCADE] */
			| DROP CONSTRAINT name opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropConstraint;
					n->name = $3;
					n->behavior = $4;
					n->missing_ok = FALSE;
					$$ = (Node *)n;
				}
			| MODIFY_P modify_column_cmd
				{
					$$ = $2;
				}
			| MODIFY_P COLUMN ColId Typename opt_charset ColQualList opt_column_options add_column_first_after
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The distributed capability is not supported currently.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Un-support feature"),
							parser_errposition(@1),
							errdetail("ALTER TABLE MODIFY COLUMN syntax is supported only in B compatibility")));
					}
					ColumnDef *def = makeNode(ColumnDef);
					def->colname = $3;
					def->typname = $4;
					def->typname->charset = $5;
					def->columnOptions = $7;
					def->kvtype = ATT_KV_UNDEFINED;
					def->inhcount = 0;
					def->is_local = true;
					def->is_not_null = false;
					def->is_from_type = false;
					def->storage = 0;
					def->cmprs_mode = ATT_CMPR_UNDEFINED;
					def->raw_default = NULL;
					def->update_default = NULL;
					def->cooked_default = NULL;
					def->collOid = InvalidOid;
					def->fdwoptions = NULL;
					SplitColQualList($6, &def->constraints, &def->collClause, &def->clientLogicColumnRef, yyscanner);
					AlterTableCmd *n = (AlterTableCmd *)$8;
					n->subtype = AT_ModifyColumn;
					n->name = $3;
					n->def = (Node *)def;
					$$ = (Node *)n;
				}
			| CHANGE opt_column ColId ColId Typename opt_charset ColQualList opt_column_options add_column_first_after
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The distributed capability is not supported currently.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Un-support feature"),
							parser_errposition(@1),
							errdetail("ALTER TABLE CHANGE syntax is supported only in B compatibility")));
					}
					ColumnDef *def = makeNode(ColumnDef);
					def->colname = $4;
					def->typname = $5;
					def->typname->charset = $6;
					def->columnOptions = $8;
					def->kvtype = ATT_KV_UNDEFINED;
					def->inhcount = 0;
					def->is_local = true;
					def->is_not_null = false;
					def->is_from_type = false;
					def->storage = 0;
					def->cmprs_mode = ATT_CMPR_UNDEFINED;
					def->raw_default = NULL;
					def->update_default = NULL;
					def->cooked_default = NULL;
					def->collOid = InvalidOid;
					def->fdwoptions = NULL;
					SplitColQualList($7, &def->constraints, &def->collClause, &def->clientLogicColumnRef, yyscanner);
					AlterTableCmd *n = (AlterTableCmd *)$9;
					n->subtype = AT_ModifyColumn;
					n->name = $3;
					n->def = (Node *)def;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> SET WITH OIDS  */
			| SET WITH OIDS
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddOids;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> 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 ALWAYS TRIGGER <trig> */
			| ENABLE_P ALWAYS TRIGGER name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableAlwaysTrig;
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */
			| ENABLE_P REPLICA TRIGGER name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableReplicaTrig;
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE TRIGGER ALL */
			| ENABLE_P TRIGGER ALL
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableTrigAll;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE TRIGGER USER */
			| ENABLE_P TRIGGER USER
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableTrigUser;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE TRIGGER <trig> */
			| DISABLE_P TRIGGER name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableTrig;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE TRIGGER ALL */
			| DISABLE_P TRIGGER ALL
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableTrigAll;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE TRIGGER USER */
			| DISABLE_P TRIGGER USER
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableTrigUser;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE RULE <rule> */
			| ENABLE_P RULE name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableRule;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */
			| ENABLE_P ALWAYS RULE name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableAlwaysRule;
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */
			| ENABLE_P REPLICA RULE name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableReplicaRule;
					n->name = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE RULE <rule> */
			| DISABLE_P RULE name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableRule;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> INHERIT <parent> */
			| INHERIT qualified_name
				{
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						const char* message = "inherits is not support in B-format database, it conflicts with multi-relation update";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("%s", message)));
					}
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddInherit;
					n->def = (Node *) $2;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> NO INHERIT <parent> */
			| NO INHERIT qualified_name
				{
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						const char* message = "inherits is not support in B-format database, it conflicts with multi-relation update";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("%s", message)));
					}
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropInherit;
					n->def = (Node *) $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> OF <type_name> */
			| OF any_name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					TypeName *def = makeTypeNameFromNameList($2);
					def->location = @2;
					n->subtype = AT_AddOf;
					n->def = (Node *) def;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> NOT OF */
			| NOT OF
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropOf;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> OWNER TO RoleId */
			| OWNER TO UserId
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ChangeOwner;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
			| SET TABLESPACE name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetTableSpace;
					n->name = $3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> SET COMPRESS/NOCOMPRESS */
			| SET COMPRESS
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SET_COMPRESS;
					n->name = "COMPRESS";
					$$ = (Node *)n;
				}
			| SET NOCOMPRESS
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SET_COMPRESS;
					n->name = "NOCOMPRESS";
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> SET (...) */
			| SET reloptions
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetRelOptions;
					n->def = (Node *)$2;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> RESET (...) */
			| RESET reloptions
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ResetRelOptions;
					n->def = (Node *)$2;
					$$ = (Node *)n;
				}
				/* ALTER TABLE <name> REPLICA IDENTITY  */
				| REPLICA IDENTITY_P replica_identity
				    {
				        AlterTableCmd *n = makeNode(AlterTableCmd);
				        n->subtype = AT_ReplicaIdentity;
				        n->def = $3;
				        $$ = (Node *)n;
				    }
				| alter_generic_options
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_GenericOptions;
					n->def = (Node *)$1;
					$$ = (Node *) n;
				}
				| imcstored_clause
				{
					$$ = $1;
				}

/* PGXC_BEGIN */
			/* ALTER TABLE <name> DISTRIBUTE BY ... */
			| OptDistributeByInternal
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DistributeBy;
					n->def = (Node *)$1;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> TO [ NODE (nodelist) | GROUP groupname ] */
			| OptSubClusterInternal
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SubCluster;
					n->def = (Node *)$1;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ADD NODE (nodelist) */
			| ADD_P NODE pgxcnodes
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddNodeList;
					n->def = (Node *)$3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DELETE NODE (nodelist) */
			| DELETE_P NODE pgxcnodes
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DeleteNodeList;
					n->def = (Node *)$3;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> UPDATE SLICE LIKE (reftalbename), only used for redis range/list distribution table */
			| UPDATE SLICE LIKE qualified_name
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_UpdateSliceLike;
					n->exchange_with_rel = $4;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENABLE ROW LEVEL SECURITY */
			| ENABLE_P ROW LEVEL SECURITY
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EnableRls;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> DISABLE ROW LEVEL SECURITY */
			| DISABLE_P ROW LEVEL SECURITY
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DisableRls;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> FORCE ROW LEVEL SECURITY */
			| FORCE ROW LEVEL SECURITY
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ForceRls;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> NO FORCE ROW LEVEL SECURITY */
			| NO FORCE ROW LEVEL SECURITY
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_NoForceRls;
					$$ = (Node *)n;
				}
			/* ALTER TABLE <name> ENCRYPTION KEY ROTATION */
			| ENCRYPTION KEY ROTATION
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_EncryptionKeyRotation;
					$$ = (Node *)n;
				}
            | AutoIncrementValue
                {
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "auto_increment is not yet supported";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                            errmsg("auto_increment is not yet supported")));
#endif
                    if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
                        ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                        errmsg("auto_increment is supported only in B-format database")));
                    }
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_SetAutoIncrement;
                    n->def = $1;
					$$ = (Node *)n;
                }
			| CharsetCollate
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_SetCharsetCollate;
					n->def = (Node *)$1;
					$$ = (Node*)n;					
				}
			| CONVERT_P TO convert_charset opt_collate
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_ConvertCharset;
					CharsetCollateOptions *cc = makeNode(CharsetCollateOptions);
					cc->cctype = OPT_CHARSETCOLLATE;
					cc->charset = $3;
					cc->collate = $4;
					n->def = (Node *)cc;
					$$ = (Node*)n;
				}
/* PGXC_END */
/* table comments start */
            | COMMENT opt_equal Sconst
            {
                    BCompatibilityOptionSupportCheck($1);
                    AlterTableCmd *n = makeNode(AlterTableCmd);
                    n->subtype = AT_COMMENTS;
                    n->name = $3;
                    $$ = (Node *)n;
            }
/* table comments end */
		;

alter_column_default:
			SET DEFAULT a_expr			{ $$ = $3; }
			| DROP DEFAULT				{ $$ = NULL; }
		;

opt_drop_behavior:
			CASCADE						{ $$ = DROP_CASCADE; }
			| RESTRICT					{ $$ = DROP_RESTRICT; }
			| CASCADE CONSTRAINTS				{ $$ = DROP_CASCADE; }
			| /* EMPTY */				{ $$ = DROP_RESTRICT; /* default */ }
		;

opt_collate_clause:
			COLLATE collate_name
				{
					CollateClause *n = makeNode(CollateClause);
					n->arg = NULL;
					n->collname = $2;
					n->location = @1;
					$$ = (Node *) n;
				}
			| /* EMPTY */				{ $$ = NULL; }
		;

alter_using:
			USING a_expr				{ $$ = $2; }
			| /* EMPTY */				{ $$ = NULL; }
		;

reloptions:
			'(' reloption_list ')'					{ $$ = $2; }
		;

replica_identity:
           NOTHING
               {
                   ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt);
                   n->identity_type = REPLICA_IDENTITY_NOTHING;
                   n->name = NULL;
                   $$ = (Node *) n;
               }
           | FULL
               {
                   ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt);
                   n->identity_type = REPLICA_IDENTITY_FULL;
                   n->name = NULL;
                   $$ = (Node *) n;
               }
           | DEFAULT
               {
                   ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt);
                   n->identity_type = REPLICA_IDENTITY_DEFAULT;
                   n->name = NULL;
                   $$ = (Node *) n;
               }
           | USING INDEX name
               {
                   ReplicaIdentityStmt *n = makeNode(ReplicaIdentityStmt);
                   n->identity_type = REPLICA_IDENTITY_INDEX;
                   n->name = $3;
                   $$ = (Node *) n;
               }
       ;

opt_reloptions:		WITH reloptions					{ $$ = $2; }
			 |		/* EMPTY */						{ $$ = NIL; }
		;

opt_index_options:
			 /* EMPTY */						{ $$ = NIL; }
			 | index_options  { $$ = $1; }
			 ;
index_options:
			 index_option
			 {
					$$ = list_make1($1);
			 }
			 | index_options index_option
			 {
					$$ = lcons($2, $1);
			 }
			 ;
index_option:
			 COMMENT opt_equal Sconst
			 {
					BCompatibilityOptionSupportCheck($1);
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_INDEX;
					n->objname = NIL;
					n->objargs = NIL;
					n->comment = $3;
					$$ = (Node*)n;
			 }
			 ;

opt_table_index_options:
			 /* EMPTY */		{ $$ = NIL; }
			 | table_index_options	{ $$ = $1; }
			 ;
table_index_options:
			 table_index_option
			 {
					$$ = list_make1($1);
			 }
			 | table_index_options table_index_option
			 {
					$$ = lcons($2, $1);
			 }
			 ;
table_index_option:
			 COMMENT opt_equal Sconst
			 {
					BCompatibilityOptionSupportCheck($1);
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_INDEX;
					n->objname = NIL;
					n->objargs = NIL;
					n->comment = $3;
					$$ = (Node*)n;
			 }
			 | USING IDENT
			 {
					BCompatibilityOptionSupportCheck($1);
					$$ = makeStringConst($2, -1);
			 }
			 | INVISIBLE
			 {
					Value *n = makeString("invisible");
					$$ = (Node*)n;
			 }
			 | VISIBLE
			 {
					Value *n = makeString("visible");
					$$ = (Node*)n;
			 }
		;

opt_table_options:
			 /* EMPTY */						{ $$ = NIL; }
			 | table_options  { $$ = $1; }
			 ;
table_options:
			 table_option
			 {
					$$ = list_make1($1);
			 }
			 | table_options opt_comma table_option
			 {
					$$ = lcons($3, $1);
			 }
			 ;
table_option:
			 COMMENT opt_equal Sconst
			 {
					BCompatibilityOptionSupportCheck($1);
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TABLE;
					n->objname = NIL;
					n->objargs = NIL;
					n->comment = $3;
					$$ = (Node*)n;
			 }
			 ;

opt_comma:
          /* empty */
        | ','
        ;

opt_column_options:
			 /* EMPTY */						{ $$ = NIL; }
			 | column_options  { $$ = $1; }
			 ;
column_options:
			 column_option
			 {
					$$ = list_make1($1);
			 }
			 | column_options column_option
			 {
					$$ = lcons($2, $1);
			 }
			 ;
column_option:
			 COMMENT Sconst
			 {
					BCompatibilityOptionSupportCheck($1);
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_COLUMN;
					n->objname = NIL;
					n->objargs = NIL;
					n->comment = $2;
					$$ = (Node*)n;
			 }
			 ;

opt_part_options:
			 OptTableSpace part_options  { $$ = $1; }
			 | OptTableSpace               { $$ = $1; }
			 ;
/* set null return for grammer comparitibility */
part_options:
			 part_option
			 {
					$$ = NULL;
			 }
			 | part_options part_option
			 {
					$$ = NULL;
			 }
			 ;
part_option:
			 COMMENT opt_equal Sconst
			 {
					BCompatibilityOptionSupportCheck($1);
					u_sess->parser_cxt.hasPartitionComment = true;
					$$ = (Node*)NULL;
			 }
			 ;

reloption_list:
			reloption_elem							{ $$ = list_make1($1); }
			| reloption_list ',' reloption_elem		{ $$ = lappend($1, $3); }
		;

/* This should match def_elem and also allow qualified names */
reloption_elem:
			ColLabel '=' def_arg
				{
					$$ = makeDefElem($1, (Node *) $3);
				}
			| ColLabel '=' ROW
				{
					$$ = makeDefElem($1, (Node *) makeString(pstrdup($3)));
				}
			| ColLabel
				{
					$$ = makeDefElem($1, NULL);
				}
			| ColLabel '.' ColLabel '=' def_arg
				{
					$$ = makeDefElemExtended($1, $3, (Node *) $5,
											 DEFELEM_UNSPEC);
				}
			| ColLabel '.' ColLabel
				{
					$$ = makeDefElemExtended($1, $3, NULL, DEFELEM_UNSPEC);
				}
		;

split_dest_partition_define_list:
	PARTITION name OptTableSpace ',' PARTITION name OptTableSpace
		{
			List	*result = NULL;
			RangePartitionDefState *p1 = makeNode(RangePartitionDefState);
			RangePartitionDefState *p2 = makeNode(RangePartitionDefState);

			p1->partitionName = $2;
			p1->tablespacename = $3;
			p1->boundary = NULL;

			p2->partitionName = $6;
			p2->tablespacename = $7;
			p2->boundary = NULL;

			result = lappend(result, p1);
			result = lappend(result, p2);

			$$ = result;
		}
	;

split_dest_listsubpartition_define_list:
	SUBPARTITION name OptTableSpace ',' SUBPARTITION name OptTableSpace
		{
			List	*result = NULL;
			ListPartitionDefState *p1 = makeNode(ListPartitionDefState);
			ListPartitionDefState *p2 = makeNode(ListPartitionDefState);

			p1->partitionName = $2;
			p1->tablespacename = $3;
			p1->boundary = NULL;

			p2->partitionName = $6;
			p2->tablespacename = $7;
			p2->boundary = NULL;

			result = lappend(result, p1);
			result = lappend(result, p2);

			$$ = result;
		}
	;

split_dest_rangesubpartition_define_list:
	SUBPARTITION name OptTableSpace ',' SUBPARTITION name OptTableSpace
		{
			List	*result = NULL;
			RangePartitionDefState *p1 = makeNode(RangePartitionDefState);
			RangePartitionDefState *p2 = makeNode(RangePartitionDefState);

			p1->partitionName = $2;
			p1->tablespacename = $3;
			p1->boundary = NULL;

			p2->partitionName = $6;
			p2->tablespacename = $7;
			p2->boundary = NULL;

			result = lappend(result, p1);
			result = lappend(result, p2);

			$$ = result;
		}
	;

/*****************************************************************************
 *
 *	ALTER TYPE
 *
 * really variants of the ALTER TABLE subcommands with different spellings
 *****************************************************************************/

AlterCompositeTypeStmt:
			ALTER TYPE_P any_name alter_type_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);

					/* can't use qualified_name, sigh */
					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
					n->cmds = $4;
					n->relkind = OBJECT_TYPE;
					$$ = (Node *)n;
				}
			;

alter_type_cmds:
			alter_type_cmd							{ $$ = list_make1($1); }
			| alter_type_cmds ',' alter_type_cmd	{ $$ = lappend($1, $3); }
		;

alter_type_cmd:
			/* ALTER TYPE <name> ADD ATTRIBUTE <coldef> [RESTRICT|CASCADE] */
			ADD_P ATTRIBUTE TableFuncElement opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_AddColumn;
					n->def = $3;
					n->behavior = $4;
					$$ = (Node *)n;
				}
			/* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> [RESTRICT|CASCADE] */
			| DROP ATTRIBUTE IF_P EXISTS ColId opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropColumn;
					n->name = $5;
					n->behavior = $6;
					n->missing_ok = TRUE;
					$$ = (Node *)n;
				}
			/* ALTER TYPE <name> DROP ATTRIBUTE <attname> [RESTRICT|CASCADE] */
			| DROP ATTRIBUTE ColId opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_DropColumn;
					n->name = $3;
					n->behavior = $4;
					n->missing_ok = FALSE;
					$$ = (Node *)n;
				}
			/* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */
			| ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_collate_clause opt_drop_behavior
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					ColumnDef *def = makeNode(ColumnDef);
					n->subtype = AT_AlterColumnType;
					n->name = $3;
					n->def = (Node *) def;
					n->behavior = $8;
					/* We only use these three fields of the ColumnDef node */
					def->typname = $6;
					def->clientLogicColumnRef=NULL;
					def->collClause = (CollateClause *) $7;
					def->raw_default = NULL;
					def->update_default = NULL;
					$$ = (Node *)n;
				}
		;


/*****************************************************************************
 *
 *		QUERY :
 *				close <portalname>
 *
 *****************************************************************************/

ClosePortalStmt:
			CLOSE cursor_name
				{
					ClosePortalStmt *n = makeNode(ClosePortalStmt);
					n->portalname = $2;
					$$ = (Node *)n;
				}
			| CLOSE ALL
				{
					ClosePortalStmt *n = makeNode(ClosePortalStmt);
					n->portalname = NULL;
					$$ = (Node *)n;
				}
		;


/*****************************************************************************
 *
 *		QUERY :
 *				COPY relname [(columnList)] FROM/TO file [WITH] [(options)]
 *				COPY ( SELECT ... ) TO file [WITH] [(options)]
 *
 *				In the preferred syntax the options are comma-separated
 *				and use generic identifiers instead of keywords.  The pre-9.0
 *				syntax had a hard-wired, space-separated set of options.
 *
 *				Really old syntax, from versions 7.2 and prior:
 *				COPY [ BINARY ] table [ WITH OIDS ] FROM/TO file
 *					[ [ USING ] DELIMITERS 'delimiter' ] ]
 *					[ WITH NULL AS 'null string' ]
 *				This option placement is not supported with COPY (SELECT...).
 *
 *****************************************************************************/

CopyStmt:	COPY opt_binary qualified_name opt_column_list opt_oids
			copy_from copy_file_name opt_load opt_useeof copy_delimiter opt_noescaping OptCopyLogError OptCopyRejectLimit opt_with copy_options 
			opt_processed
				{
					CopyStmt *n = makeNode(CopyStmt);
					n->relation = $3;
					n->query = NULL;
					n->attlist = u_sess->parser_cxt.col_list;
					n->is_from = $6;
					n->filename = $7;
					if ($4)
						n->relation->length = @4;
					else if ($5)
						n->relation->length = @5;
					else
						n->relation->length = @6;
					n->options = 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 ($9)
						n->options = lappend(n->options, $9);
                                        if ($10)
                                                n->options = lappend(n->options, $10);
					if ($11)
						n->options = lappend(n->options, $11);
					if ($12)
						n->options = lappend(n->options, $12);
					if ($13)
						n->options = lappend(n->options, $13);
					if ($15)
						n->options = list_concat(n->options, $15);
					$$ = (Node *)n;

					u_sess->parser_cxt.is_load_copy = false;
					u_sess->parser_cxt.col_list = NULL;
				}
			| COPY select_with_parens TO copy_file_name opt_noescaping opt_with copy_options opt_processed
				{
					CopyStmt *n = makeNode(CopyStmt);
					n->relation = NULL;
					n->query = $2;
					n->attlist = NIL;
					n->is_from = false;
					n->filename = $4;
					n->options = $7;
					if ($5)
						n->options = lappend(n->options, $5);
					$$ = (Node *)n;
				}
		;

opt_processed:
                ENCRYPTED {$$=TRUE;}
				|  /*EMPTY*/						{ $$ = FALSE; }
		;

opt_load:
                LOAD								
				{
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "COPY ... LOAD FROM is not supported";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY ... LOAD FROM is not supported")));
#endif
					u_sess->parser_cxt.is_load_copy = true; 
					$$ = makeDefElem("loader", (Node *)makeInteger(TRUE)); 
				}
				|  /*EMPTY*/						{ $$ = NULL; }
		;

opt_useeof:
                USEEOF
                                {
                                        $$ = makeDefElem("useeof", (Node *)makeInteger(TRUE));
                                }
                                |  /*EMPTY*/                                            { $$ = NULL; }
		;

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; }
			| REDISANYVALUE                              { $$ = NULL; }
		;

copy_options: copy_opt_list							{ $$ = $1; }
			| '(' copy_generic_opt_list ')'			{ $$ = $2; }
		;

/* old COPY option syntax */
copy_opt_list:
			copy_opt_list copy_opt_item				{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

copy_opt_item:
			BINARY
				{
					$$ = makeDefElem("format", (Node *)makeString("binary"));
				}
			| OIDS
				{
					$$ = makeDefElem("oids", (Node *)makeInteger(TRUE));
				}
			| FREEZE
				{
					$$ = makeDefElem("freeze", (Node *)makeInteger(TRUE));
				}
			| DELIMITER opt_as Sconst
				{
					$$ = makeDefElem("delimiter", (Node *)makeString($3));
				}
			| NULL_P opt_as Sconst
				{
					$$ = makeDefElem("null", (Node *)makeString($3));
				}
			| CSV
				{
					$$ = makeDefElem("format", (Node *)makeString("csv"));
				}
			| FIXED_P
				{
					$$ = makeDefElem("format", (Node *)makeString("fixed"));
				}
			| 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 QUOTE '*'
				{
					$$ = makeDefElem("force_quote", (Node *)makeNode(A_Star));
				}
			| FORCE NOT NULL_P columnList
				{
					$$ = makeDefElem("force_not_null", (Node *)$4);
				}
			| ENCODING Sconst
				{
					$$ = makeDefElem("encoding", (Node *)makeString($2));
				}
			| EOL Sconst
				{
					$$ = makeDefElem("eol", (Node*)makeString($2));
				}
			| FILEHEADER_P Sconst
				{
					$$ = makeDefElem("fileheader", (Node*)makeString($2));
				}
			| FORMATTER '(' copy_foramtter_opt ')'
				{
					$$ = makeDefElem("formatter", (Node*)$3);
				}
			| IGNORE_EXTRA_DATA
				{
					$$ = makeDefElem("ignore_extra_data", (Node *)makeInteger(TRUE));
				}
			| DATE_FORMAT_P Sconst
				{
					$$ = makeDefElem("date_format", (Node *)makeString($2));
				}
			| TIME_FORMAT_P Sconst
				{
					$$ = makeDefElem("time_format", (Node *)makeString($2));
				}
			| TIMESTAMP_FORMAT_P Sconst
				{
					$$ = makeDefElem("timestamp_format", (Node *)makeString($2));
				}
			| SMALLDATETIME_FORMAT_P Sconst
				{
					$$ = makeDefElem("smalldatetime_format", (Node *)makeString($2));
				}
			| COMPATIBLE_ILLEGAL_CHARS
				{
					$$ = makeDefElem("compatible_illegal_chars", (Node *)makeInteger(TRUE));
				}
			| FILL_MISSING_FIELDS
				{
					$$ = makeDefElem("fill_missing_fields", (Node *)makeString("one"));
				}
			| FILL_MISSING_FIELDS Sconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "FILL_MISSING_FIELDS is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("FILL_MISSING_FIELDS is not supported")));
#endif
					$$ = makeDefElem("fill_missing_fields", (Node *)makeString($2));
				}
            | TRANSFORM '(' copy_column_expr_list ')'
			    {
                    $$ = MakeDefElemWithLoc("transform", (Node *)$3, @1, @4);
                }
			| load_when_option
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "WHEN is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("WHEN is not supported")));
#endif
					$$ = $1;
				}
			| SKIP Iconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SKIP is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SKIP is not supported")));
#endif
					$$ = makeDefElem("skip", (Node *)makeInteger($2));
				}
			| SEQUENCE '(' copy_column_sequence_list ')'
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SEQUENCE is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SEQUENCE is not supported")));
#endif
					$$ = makeDefElem("sequence", (Node *)$3);
				}
			| FILLER '(' copy_column_filler_list ')'
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "FILLER is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("FILLER is not supported")));
#endif
					RemoveFillerCol($3, u_sess->parser_cxt.col_list);
					$$ = makeDefElem("filler", (Node *)$3);
				}
			| CONSTANT '(' copy_column_constant_list ')'
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "CONSTANT is not supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("CONSTANT is not supported")));
#endif
					$$ = makeDefElem("constant", (Node *)$3);
				}
		;

/* The following exist for backward compatibility with very old versions */

opt_binary:
			BINARY
				{
					$$ = makeDefElem("format", (Node *)makeString("binary"));
				}
			| /*EMPTY*/								{ $$ = NULL; }
		;

opt_oids:
			WITH OIDS
				{
					$$ = makeDefElem("oids", (Node *)makeInteger(TRUE));
				}
			| /*EMPTY*/								{ $$ = NULL; }
		;

copy_delimiter:
			opt_using DELIMITERS Sconst
				{
					$$ = makeDefElem("delimiter", (Node *)makeString($3));
				}
			| /*EMPTY*/								{ $$ = NULL; }
		;

opt_using:
			USING									{}
			| /*EMPTY*/								{}
		;

opt_noescaping:
			WITHOUT ESCAPING
				{
					$$ = makeDefElem("noescaping", (Node *)makeInteger(TRUE));
				}
			| /*EMPTY*/ 							{$$ = NULL;}
		;

OptCopyLogError:
			LOG_P ERRORS DATA_P
				{
					$$ = makeDefElem("log_errors_data", (Node *)makeInteger(TRUE));
				}
			| LOG_P ERRORS
             	{
             		$$ = makeDefElem("log_errors", (Node *)makeInteger(TRUE));
             	}
             	| /*EMPTY*/	                        { $$ = NULL; }
		;

OptCopyRejectLimit:
			REJECT_P LIMIT Sconst
				{
					$$ = makeDefElem("reject_limit", (Node*)makeString($3));
				}
			| /*EMPTY*/								{ $$ = NULL; }
		;

/* new COPY option syntax */
copy_generic_opt_list:
			copy_generic_opt_elem
				{
					$$ = list_make1($1);
				}
			| copy_generic_opt_list ',' copy_generic_opt_elem
				{
					$$ = lappend($1, $3);
				}
		;

copy_generic_opt_elem:
			ColLabel copy_generic_opt_arg
				{
					/* Character "when_expr" may be injected as "COPY ... WHEN ... "*/
					if (pg_strcasecmp($1, "when_expr") == 0)
						ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("option \"%s\" not recognized", $1)));
					$$ = makeDefElem($1, $2);
				}
		;

copy_generic_opt_arg:
			opt_boolean_or_string			{ $$ = (Node *) makeString($1); }
			| NumericOnly					{ $$ = (Node *) $1; }
			| '*'							{ $$ = (Node *) makeNode(A_Star); }
			| '(' copy_generic_opt_arg_list ')'		{ $$ = (Node *) $2; }
			| /* EMPTY */					{ $$ = NULL; }
		;

copy_generic_opt_arg_list:
			  copy_generic_opt_arg_list_item
				{
					$$ = list_make1($1);
				}
			| copy_generic_opt_arg_list ',' copy_generic_opt_arg_list_item
				{
					$$ = lappend($1, $3);
				}
		;

/* beware of emitting non-string list elements here; see commands/define.c */
copy_generic_opt_arg_list_item:
			opt_boolean_or_string	{ $$ = (Node *) makeString($1); }
		;

copy_foramtter_opt:
			copy_col_format_def
				{
					$$ = list_make1($1);
				}
			| copy_foramtter_opt ',' copy_col_format_def
				{
					$$ = lappend($1, $3);
				}
		;

copy_col_format_def:
			ColId '(' Iconst ',' Iconst ')'
				{
					Position *arg = makeNode(Position);
					arg->colname = $1;
					arg->position = $3;
					arg->fixedlen = $5;
					$$ = (Node*)arg;
				}
		;

copy_column_expr_list:
			copy_column_expr_item
				{
					$$ = list_make1($1);
				}
			| copy_column_expr_list ',' copy_column_expr_item
				{
					$$ = lappend($1, $3);
				}
		;
copy_column_expr_item:
			ColId OptCopyColTypename OptCopyColExpr
				{
					CopyColExpr* n = makeNode(CopyColExpr);
					n->colname = $1;
					if ($2 != NULL)
						n->typname = $2;
					else
						n->typname = NULL;
					if ($3 != NULL)
						n->colexpr = $3;
					else
						n->colexpr = NULL;
					$$ = (Node*)n;
				}
		;

OptCopyColTypename:
				Typename			{ $$ = $1; }
				| /*EMPTY*/			{ $$ = NULL; }
		;
OptCopyColExpr:
				AS b_expr			{ $$ = $2; }
				| /*EMPTY*/			{ $$ = NULL; }
		;

copy_column_sequence_list:
			copy_column_sequence_item
				{
					$$ = list_make1($1);
				}
			| copy_column_sequence_list ',' copy_column_sequence_item
				{
					$$ = lappend($1, $3);
				}
		;
copy_column_sequence_item:
			ColId '(' column_sequence_item_sart column_sequence_item_step ')'
				{
					SqlLoadSequInfo* n = makeNode(SqlLoadSequInfo);
					n->colname = $1;
					n->start = $3;
					n->step = $4;
					$$ = (Node *)n;
				}
		;

column_sequence_item_step:
			',' Iconst			{ $$ = $2; }
			| ',' FCONST		{ $$ = SequenceStrGetInt64($2); }
			| /*EMPTY*/			{ $$ = 1; }
		;
column_sequence_item_sart:
			Iconst			{ $$ = $1; }
			| FCONST		{ $$ = SequenceStrGetInt64($1); }
		;
		
copy_column_filler_list:
			copy_column_filler_item
				{
					$$ = list_make1($1);
				}
			| copy_column_filler_list ',' copy_column_filler_item
				{
					$$ = lappend($1, $3);
				}
		;
copy_column_filler_item:
			ColId
				{
					SqlLoadFillerInfo* n = makeNode(SqlLoadFillerInfo);
					n->colname = $1;
					n->index = GetFillerColIndex($1, u_sess->parser_cxt.col_list);
					$$ = (Node *)n;
				}
		;

copy_column_constant_list:
			copy_column_constant_item
				{
					$$ = list_make1($1);
				}
			| copy_column_constant_list ',' copy_column_constant_item
				{
					$$ = lappend($1, $3);
				}
		;
copy_column_constant_item:
			ColId Sconst
				{
					SqlLoadConsInfo* n = makeNode(SqlLoadConsInfo);
					n->colname = $1;
					n->consVal = $2;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *       QUERY :
 *             CREATE STREAM relname
 *
 *     feature:
 *     1) create foreign table for streaming server
 *
 *
 *****************************************************************************/
 
CreateStreamStmt: 
        CREATE STREAM qualified_name '(' OptTableElementList ')'
            {
                CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
                n->servername = STREAMING_SERVER;
                n->base.if_not_exists = false;
                n->base.relation = $3;
                n->base.tableElts = $5;
                $$ = (Node *)n;
            }
        | CREATE STREAM IF_P NOT EXISTS qualified_name '(' OptTableElementList ')'
            {
                CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
                n->servername = STREAMING_SERVER;
                n->base.if_not_exists = true;
                n->base.relation = $6;
                n->base.tableElts = $8;
                $$ = (Node *)n;
            }
        ;

/*****************************************************************************
 *
 *		PURGE :
 *			PURGE TABLE [schema_name.]table_name
 *			PURGE INDEX [schema_name.]index_name
 *			PURGE TABLESPACE tablespace_name
 *			PURGE RECYCLEBIN
 *
 *****************************************************************************/
PurgeStmt:
	PURGE TABLE qualified_name 
		{
			TcapFeatureEnsure();
			PurgeStmt *n = makeNode(PurgeStmt);
			n->purtype = PURGE_TABLE;
			n->purobj = $3;
			$$ = (Node *)n;
		}

	| PURGE INDEX qualified_name
		{
			TcapFeatureEnsure();
			PurgeStmt *n = makeNode(PurgeStmt);
			n->purtype = PURGE_INDEX;
			n->purobj = $3;
			$$ = (Node *)n;
		}

	| PURGE TABLESPACE name
		{
            const char* message = "PURGE TABLESPACE is not yet supported.";
            InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("PURGE TABLESPACE is not yet supported.")));
			TcapFeatureEnsure();
			PurgeStmt *n = makeNode(PurgeStmt);
			n->purtype = PURGE_TABLESPACE;
			n->purobj = makeRangeVar(NULL, $3, @3);
			$$ = (Node *) n;
		}

	| PURGE RECYCLEBIN
		{
			TcapFeatureEnsure();
			PurgeStmt *n = makeNode(PurgeStmt);
			n->purtype = PURGE_RECYCLEBIN;
			n->purobj = makeRangeVar(NULL, NULL, @2);
			$$ = (Node *) n;
		}
		;

/*****************************************************************************
 *
 *      TIMECAPSULE :
 *          TIMECAPSULE TABLE { table_name } TO { TIMESTAMP | CSN } expression
 *          TIMECAPSULE TABLE { table_name } TO BEFORE DROP [RENAME TO new_tablename]
 *          TIMECAPSULE TABLE { table_name } TO BEFORE TRUNCATE [ FORCE ]
 *
 *****************************************************************************/
 
TimeCapsuleStmt:
	TIMECAPSULE TABLE qualified_name TO opt_timecapsule_clause 
		{
			TcapFeatureEnsure();
			TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt);

			n->relation = $3;
			n->tcaptype = TIMECAPSULE_VERSION;

			n->tvtype = ((RangeTimeCapsule *)$5)->tvtype;
			n->tvver = ((RangeTimeCapsule *)$5)->tvver;

			$$ = (Node *) n;
		}

	| TIMECAPSULE TABLE qualified_name TO BEFORE DROP opt_rename
		{
			TcapFeatureEnsure();
			TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt);
			n->relation = $3;
			n->tcaptype = TIMECAPSULE_DROP;
			n->new_relname = $7;
			$$ = (Node *) n;
		}

	| TIMECAPSULE TABLE qualified_name TO BEFORE TRUNCATE
		{
			TcapFeatureEnsure();
			TimeCapsuleStmt *n = makeNode(TimeCapsuleStmt);
			n->relation = $3;
			n->tcaptype = TIMECAPSULE_TRUNCATE;
			$$ = (Node *) n;
		}
		;

opt_rename:
	RENAME TO name					{ $$ = $3; }
	| /* EMPTY */					{ $$ = NULL; }
	;

/*****************************************************************************
 *
 *		QUERY :
 *				CREATE TABLE relname
 *
 *		PGXC-related extensions:
 *		1) Distribution type of a table:
 *			DISTRIBUTE BY ( HASH(column) | MODULO(column) |
 *							REPLICATION | ROUNDROBIN )
 *		2) Subcluster for table
 *			TO ( GROUP groupname | NODE nodename1,...,nodenameN )
 *
 *		3) Internal additional data from CN to CN and CN to DN; the clause must be the last clause.
 *			INTERNAL DATA xxxxxxxx
 *
 *****************************************************************************/

CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
			OptInherit OptAutoIncrement optCharsetCollate OptWith OnCommitOption OptCompress OptPartitionElement
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			opt_table_options
			opt_table_partitioning_clause
			opt_internal_data OptKind
				{
					CreateStmt *n = makeNode(CreateStmt);
					$4->relpersistence = $2;
					n->relkind = $20;
					n->relation = $4;
					n->tableElts = $6;
					n->inhRelations = $8;
					n->constraints = NIL;
					n->options = $11;
					n->oncommit = $12;
					n->row_compress = $13;
					n->tablespacename = $14;
					n->if_not_exists = false;
/* PGXC_BEGIN */
					n->distributeby = $15;
					n->subcluster = $16;
/* PGXC_END */
					n->tableOptions = $17;
					n->partTableState = (PartitionState *)$18;
					n->internalData = $19;
					n->autoIncStart = $9;
					if ($10 == NULL) {
						n->charset = PG_INVALID_ENCODING;
					} else {
						n->charset = $10->charset;
						n->collate = $10->collate;
					}
					$$ = (Node *)n;
				}
		| CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '('
			OptTableElementList ')' OptInherit OptAutoIncrement optCharsetCollate OptWith OnCommitOption
			OptCompress OptPartitionElement
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			opt_table_options
			opt_table_partitioning_clause
			opt_internal_data
				{
					CreateStmt *n = makeNode(CreateStmt);
					$7->relpersistence = $2;
					n->relation = $7;
					n->tableElts = $9;
					n->inhRelations = $11;
					n->constraints = NIL;
					n->options = $14;
					n->oncommit = $15;
					n->row_compress = $16;
					n->tablespacename = $17;
					n->if_not_exists = true;
/* PGXC_BEGIN */
					n->distributeby = $18;
					n->subcluster = $19;
/* PGXC_END */
					n->tableOptions = $20;
                    n->partTableState = (PartitionState *)$21;
					n->internalData = $22;
					n->autoIncStart = $12;
					if ($13 == NULL) {
						n->charset = PG_INVALID_ENCODING;
					} else {
						n->charset = $13->charset;
						n->collate = $13->collate;
					}
					$$ = (Node *)n;
				}
		| CREATE OptTemp TABLE qualified_name OF any_name
			OptTypedTableElementList OptWith OnCommitOption OptCompress OptPartitionElement
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			opt_table_options
				{
					CreateStmt *n = makeNode(CreateStmt);
					$4->relpersistence = $2;
					n->relation = $4;
					n->tableElts = $7;
					n->ofTypename = makeTypeNameFromNameList($6);
					n->ofTypename->location = @6;
					n->constraints = NIL;
					n->options = $8;
					n->oncommit = $9;
					n->row_compress = $10;
					n->tablespacename = $11;
					n->if_not_exists = false;
/* PGXC_BEGIN */
					n->distributeby = $12;
					n->subcluster = $13;
/* PGXC_END */
					n->tableOptions = $14;
					n->partTableState = NULL;
					n->internalData = NULL;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
		| CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name
			OptTypedTableElementList OptWith OnCommitOption OptCompress OptPartitionElement
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			opt_table_options
				{
					CreateStmt *n = makeNode(CreateStmt);
					$7->relpersistence = $2;
					n->relation = $7;
					n->tableElts = $10;
					n->ofTypename = makeTypeNameFromNameList($9);
					n->ofTypename->location = @9;
					n->constraints = NIL;
					n->options = $11;
					n->oncommit = $12;
					n->row_compress = $13;
					n->tablespacename = $14;
					n->if_not_exists = true;
/* PGXC_BEGIN */
					n->distributeby = $15;
					n->subcluster = $16;
/* PGXC_END */
					n->tableOptions = $17;
					n->partTableState = NULL;
					n->internalData = NULL;
					n->charset = PG_INVALID_ENCODING;
					$$ = (Node *)n;
				}
		;

OptKind:
	FOR MATERIALIZED VIEW
		{
			$$ = OBJECT_MATVIEW;
		}
	| /* empty */
		{
			$$ = OBJECT_TABLE;
		}
	;

opt_table_partitioning_clause:
		range_partitioning_clause
			{
				$$ = $1;
			}
		| hash_partitioning_clause
			{
				$$ = $1;
			}
		| list_partitioning_clause
			{
				$$ = $1;
			}
		| value_partitioning_clause
			{
				$$ = $1;
			}
		| /* empty */			{ $$ = NULL; }
		;

range_partitioning_clause:
		PARTITION BY RANGE opt_columns '(' column_item_list ')'
		opt_interval_partition_clause opt_partitions_num subpartitioning_clause '(' range_partition_definition_list ')' opt_row_movement_clause
			{
				PartitionState *n = makeNode(PartitionState);
				if ($10 != NULL && list_length($6) != 1) {
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				if ($10 != NULL && $8 != NULL) {
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("Subpartitions do not support interval partition."),
							errcause("System error."), erraction("Contact engineer to support.")));
				}
				if ($9 > 0 && u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@9),
						errdetail("range partition with partitions clause is supported only in B compatibility")));
				}
				n->partitionKey = $6;
				n->intervalPartDef = (IntervalPartitionDefState *)$8;
				n->partitionsNum = $9;
				n->partitionList = $12;

				if (n->intervalPartDef)
					n->partitionStrategy = 'i';
				else
					n->partitionStrategy = 'r';

				n->rowMovement = (RowMovementValue)$14;
				n->subPartitionState = (PartitionState *)$10;

				$$ = (Node *)n;
			}
		;

list_partitioning_clause:
		PARTITION BY LIST opt_columns '(' column_item_list ')' opt_partitions_num subpartitioning_clause
		'(' list_partition_definition_list ')' opt_row_movement_clause
			{
#ifdef ENABLE_MULTIPLE_NODES
            	const char* message = "Un-support feature";
            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($6) != 1 && $9 != NULL) {
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("Un-support feature"),
								errdetail("The partition key's length should be 1.")));
				}
				if ($8 > 0 && u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@8),
						errdetail("list partition with partitions clause is supported only in B compatibility")));
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $6;
				n->intervalPartDef = NULL;
				n->partitionList = $11;
				n->partitionStrategy = 'l';
				n->partitionsNum = $8;
				n->subPartitionState = (PartitionState *)$9;
				n->rowMovement = (RowMovementValue)$13;

				$$ = (Node *)n;

			}
		;

hash_partitioning_clause:
		PARTITION BY IDENT '(' column_item_list ')' opt_partitions_num subpartitioning_clause
		opt_hash_partition_definition_list opt_row_movement_clause
			{
#ifdef ENABLE_MULTIPLE_NODES
            	const char* message = "Un-support feature";
            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($5) != 1) {
            	const char* message = "Un-support feature";
            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				if (strcmp($3, "hash") != 0) {
            		const char* message = "Un-support feature";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("unrecognized option \"%s\"", $3)));	
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = $9;
				n->partitionStrategy = 'h';
				n->partitionsNum = $7;
				n->subPartitionState = (PartitionState *)$8;
				n->rowMovement = (RowMovementValue)$10;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = n->partitionList;
				foreach(elem, parts) {
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				$$ = (Node *)n;

			}
		| PARTITION BY KEY '(' column_item_list ')' opt_partitions_num subpartitioning_clause
		opt_hash_partition_definition_list opt_row_movement_clause
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@3),
						errdetail("PARTITION BY KEY is supported only in B compatibility")));
				}
#ifdef ENABLE_MULTIPLE_NODES
		            	const char* message = "Un-support feature";
		            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($5) != 1) {
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = $9;
				n->partitionStrategy = 'h';
				n->partitionsNum = $7;
				n->subPartitionState = (PartitionState *)$8;
				n->rowMovement = (RowMovementValue)$10;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = n->partitionList;
				foreach(elem, parts) {
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				$$ = (Node *)n;

			}
		;

opt_columns:
		COLUMNS
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@1),
						errdetail("COLUMNS is supported only in B compatibility")));
				}
				$$ = NULL;
			}
		| /* empty */			{ $$ = NULL; }
		;

opt_partitions_num:
		PARTITIONS Iconst
			{
				if ($2 <= 0) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Invalid number of partitions"),
						parser_errposition(@2),
						errdetail("partitions number must be a positive integer")));
				}
				$$ = $2;
			}
		| /* empty */			{ $$ = 0; }
		;

opt_subpartitions_num:
		SUBPARTITIONS Iconst
			{
				if ($2 <= 0) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Invalid number of partitions"),
						parser_errposition(@2),
						errdetail("subpartitions number must be a positive integer")));
				}
				$$ = $2;
			}
		| /* empty */			{ $$ = 0; }
		;

opt_hash_partition_definition_list:
		'(' hash_partition_definition_list ')' { $$ = $2; }
		| /* empty */			{ $$ = NIL; }
		;

value_partitioning_clause:
		PARTITION BY VALUES '(' column_item_list ')'
			{
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->partitionStrategy = 'v';

				$$ = (Node *)n;
			}
		;

subpartitioning_clause:
		range_subpartitioning_clause
			{
				$$ = $1;
			}
		| hash_subpartitioning_clause
			{
				$$ = $1;
			}
		| list_subpartitioning_clause
			{
				$$ = $1;
			}
		| /* empty */			{ $$ = NULL; }
		;

range_subpartitioning_clause:
		SUBPARTITION BY RANGE '(' column_item_list ')'
			{
#ifdef ENABLE_MULTIPLE_NODES
				ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				PartitionState *n = makeNode(PartitionState);
				if (list_length($5) != 1) {
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = NIL;
				n->partitionStrategy = 'r';

				n->rowMovement = ROWMOVEMENT_DEFAULT;
				n->subPartitionState = NULL;

				$$ = (Node *)n;
			}
		;

list_subpartitioning_clause:
		SUBPARTITION BY LIST '(' column_item_list ')'
			{
#ifdef ENABLE_MULTIPLE_NODES
            	const char* message = "Un-support feature";
            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($5) != 1) {
            		const char* message = "Un-support feature";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = NIL;
				n->partitionStrategy = 'l';
				n->subPartitionState = NULL;
				$$ = (Node *)n;
			}
		;

hash_subpartitioning_clause:
		SUBPARTITION BY IDENT '(' column_item_list ')' opt_subpartitions_num
			{
#ifdef ENABLE_MULTIPLE_NODES
            	const char* message = "Un-support feature";
            	InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($5) != 1) {
            		const char* message = "Un-support feature";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				if (strcmp($3, "hash") != 0) {
            		const char* message = "Un-support feature";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("unrecognized option \"%s\"", $3)));	
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = NIL;
				n->partitionStrategy = 'h';
				n->subPartitionState = NULL;
				n->partitionsNum = $7;
				$$ = (Node *)n;

			}
		| SUBPARTITION BY KEY '(' column_item_list ')' opt_subpartitions_num
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@3),
						errdetail("SUBPARTITION BY KEY is supported only in B compatibility")));
				}
#ifdef ENABLE_MULTIPLE_NODES
				const char* message = "Un-support feature";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));
#endif
				if (list_length($5) != 1) {
					const char* message = "Un-support feature";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The partition key's length should be 1.")));
				}
				PartitionState *n = makeNode(PartitionState);
				n->partitionKey = $5;
				n->intervalPartDef = NULL;
				n->partitionList = NIL;
				n->partitionStrategy = 'h';
				n->subPartitionState = NULL;
				n->partitionsNum = $7;
				$$ = (Node *)n;
			}
		;

subpartition_definition_list:
		subpartition_item
			{
				$$ = list_make1($1);
			}
		| subpartition_definition_list ',' subpartition_item
			{
				$$ = lappend($1, $3);
			}
		;

subpartition_item:
		SUBPARTITION name VALUES '(' listValueList ')' opt_part_options
			{
				ListPartitionDefState *n = makeNode(ListPartitionDefState);
				n->partitionName = $2;
				n->boundary = $5;
				n->tablespacename = $7;

				$$ = (Node *)n;
			}
		| SUBPARTITION name opt_part_options
			{
				HashPartitionDefState *n = makeNode(HashPartitionDefState);
				n->partitionName = $2;
				n->tablespacename = $3;

				$$ = (Node*)n;
			}
		| SUBPARTITION name VALUES LESS THAN
		'(' maxValueList ')' opt_part_options
			{
				RangePartitionDefState *n = makeNode(RangePartitionDefState);
				n->partitionName = $2;
				n->boundary = $7;
				n->tablespacename = $9;

				$$ = (Node *)n;
			}
		;

column_item_list:
		column_item
			{
				$$ = list_make1($1);
			}
		| column_item_list ',' column_item
			{
				$$ = lappend($1, $3);
			}
		;

column_item:
		a_expr
			{
				//$$ = makeColumnRef($1, NIL, @1, yyscanner);
				$$ = $1;
				int colCount = 0;
				CheckPartitionExpr($$, &colCount);
				if (colCount == 0)
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("No Column in the part expr")));
			}
		;

opt_interval_partition_clause:
		INTERVAL '(' interval_expr ')' opt_interval_tablespaceList
			{
				IntervalPartitionDefState* n = makeNode(IntervalPartitionDefState);
				n->partInterval = $3;
				n->intervalTablespaces = $5;

				$$ = (Node *)n;
			}
		| /* empty */
			{
				$$ = NULL;
			}
		;

opt_interval_tablespaceList:
		STORE_P IN_P  '(' tablespaceList ')'
			{
				$$= $4;
			}
		|
			{
				$$ = NIL;
			}
		;

interval_expr:
		a_expr
			{
				$$ = $1;
			}
		;

tablespaceList:
		name_list
			{
				$$ = $1;
			}
		;

range_partition_definition_list: /* general range partition syntax: start/end or less/than */
		range_less_than_list
			{
				$$ = $1;
			}
		| range_start_end_list
			{
				$$ = $1;
			}
		;

list_partition_definition_list:
		list_partition_item
			{
				$$ = list_make1($1);
			}
		| list_partition_definition_list ',' list_partition_item
			{
				$$ = lappend($1, $3);
			}
		;

hash_partition_definition_list:
		hash_partition_item
			{
				$$ = list_make1($1);
			}
		| hash_partition_definition_list ',' hash_partition_item
			{
				$$ = lappend($1, $3);
			}
		;

range_less_than_list:
		range_less_than_item
			{
				$$ = list_make1($1);
			}
		| range_less_than_list ',' range_less_than_item
			{
				$$ = lappend($1, $3);
			}
		;

list_partition_item:
		PARTITION name VALUES opt_in_p '(' listValueList ')' opt_part_options
			{
				ListPartitionDefState *n = makeNode(ListPartitionDefState);
				n->partitionName = $2;
				n->boundary = $6;
				n->tablespacename = $8;

				$$ = (Node *)n;
			}
		| PARTITION name VALUES opt_in_p '(' listValueList ')' opt_part_options '(' subpartition_definition_list ')'
			{
				ListPartitionDefState *n = makeNode(ListPartitionDefState);
				n->partitionName = $2;
				n->boundary = $6;
				n->tablespacename = $8;
				n->subPartitionDefState = $10;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = n->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				$$ = (Node *)n;
			}
		;

opt_in_p:
		IN_P
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support syntax in current compatibility"),
						parser_errposition(@1),
						errdetail("VALUES IN is supported only in B compatibility")));
				}
				$$ = NULL;
			}
		| /* empty */			{ $$ = NULL; }
		;

hash_partition_item:
		PARTITION name opt_part_options
			{
				HashPartitionDefState *n = makeNode(HashPartitionDefState);
				n->partitionName = $2;
				n->tablespacename = $3;

				$$ = (Node*)n;
			}
		| PARTITION name opt_part_options '(' subpartition_definition_list ')'
			{
				HashPartitionDefState *n = makeNode(HashPartitionDefState);
				n->partitionName = $2;
				n->tablespacename = $3;
				n->subPartitionDefState = $5;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = n->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}
				$$ = (Node *)n;
			}
		;

range_partition_boundary:
		MAXVALUE
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature in current compatibility"),
							parser_errposition(@1),
							errdetail("MAXVALUE without parentheses is supported only in B compatibility")));
				}
				Const *bound = makeNode(Const);
				bound->ismaxvalue = true;
				bound->location = @1;

				$$ = list_make1(bound);
			}
		| '(' maxValueList ')'
			{
				$$ = $2;
			}
		;

range_less_than_item:
		PARTITION name VALUES LESS THAN range_partition_boundary opt_part_options
			{
				RangePartitionDefState *n = makeNode(RangePartitionDefState);
				n->partitionName = $2;
				n->boundary = $6;
				n->tablespacename = $7;

				$$ = (Node *)n;
			}
		| PARTITION name VALUES LESS THAN range_partition_boundary opt_part_options '(' subpartition_definition_list ')'
			{
				RangePartitionDefState *n = makeNode(RangePartitionDefState);
				n->partitionName = $2;
				n->boundary = $6;
				n->tablespacename = $7;
				n->subPartitionDefState = $9;
				int i = 0;
				ListCell *elem = NULL;
				List *parts = n->subPartitionDefState;
				foreach(elem, parts) {
					if (!IsA((Node*)lfirst(elem), HashPartitionDefState)) {
						break;
					}
					HashPartitionDefState *hashPart = (HashPartitionDefState*)lfirst(elem);
					hashPart->boundary = list_make1(makeIntConst(i, -1));
					i++;
				}

				$$ = (Node *)n;
			}
		;
		
range_start_end_list:
		range_start_end_item
			{
				$$ = list_make1($1);
			}
		| range_start_end_list ',' range_start_end_item
			{
				$$ = lappend($1, $3);
			}
		;
	
range_start_end_item:
		PARTITION name START '(' maxValueList ')'  END_P '(' maxValueList ')' opt_range_every_list opt_part_options
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = $5;
				n->endValue = $9;
				n->everyValue = $11;
				n->tableSpaceName = $12;

				$$ = (Node *)n;
			}
		| PARTITION name END_P '(' maxValueList ')' opt_part_options
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = NIL;
				n->endValue = $5;
				n->everyValue = NIL;
				n->tableSpaceName = $7;

				$$ = (Node *)n;
			}
		| PARTITION name START '(' maxValueList ')' opt_part_options
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = $5;
				n->endValue = NIL;
				n->everyValue = NIL;
				n->tableSpaceName = $7;

				$$ = (Node *)n;
			}
		;

opt_range_every_list:
		EVERY '(' maxValueList ')' 
			{
				$$ = $3;
			}
		| /* empty */ { $$ = NIL; }
		;

partition_name:
		ColId
			{
				$$ = makeRangeVar(NULL, $1, @1);
			}
		;

maxValueList:
		maxValueItem
			{
				$$ = list_make1($1);
			}
		| maxValueList ',' maxValueItem
			{
				$$ = lappend($1, $3);
			}
		;

maxValueItem:
		a_expr
			{
				if IsA($1, ColumnRef) {
					ColumnRef* ref = (ColumnRef*)$1;
					List* l = (ref != NULL) ? ref->fields : NULL;
					Node* sn = list_length(l) == 1 ? linitial_node(Node, l) : NULL;
					if (sn != NULL && !IsA(sn, String)){
						$$ = $1;
					} else if (sn != NULL) {
						char* colname = strVal(sn);
						if (strcasecmp("maxvalue", colname) == 0) {
							Const *n = makeNode(Const);
							n->ismaxvalue = true;
							n->location = @1;	
							$$ = (Node*)n;	
						}
					} else {
						$$ = $1;
					}
				} else {
					$$ = $1;
				}
			}
		;

listValueList:
		expr_list
			{
				$$ = $1;
			}
		| DEFAULT
			{
				Const *n = makeNode(Const);
 
				n->ismaxvalue = true;
				n->location = @1;
 
				$$ = list_make1(n);
			}
		;

opt_row_movement_clause: ENABLE_P ROW MOVEMENT		{ $$ = ROWMOVEMENT_ENABLE; }
			| DISABLE_P ROW MOVEMENT					{ $$ = ROWMOVEMENT_DISABLE; }
			| /*EMPTY*/								{ $$ = ROWMOVEMENT_DEFAULT; }
		;

/*
 * Redundancy here is needed to avoid shift/reduce conflicts,
 * since TEMP is not a reserved word.  See also OptTempTableName.
 *
 * NOTE: we accept both GLOBAL and LOCAL options.  They currently do nothing,
 * but future versions might consider GLOBAL to request SQL-spec-compliant
 * temp table behavior, so warn about that.  Since we have no modules the
 * LOCAL keyword is really meaningless; furthermore, some other products
 * implement LOCAL as meaning the same as our default temp table behavior,
 * so we'll probably continue to treat LOCAL as a noise word.
 */
OptTemp:	TEMPORARY					{ $$ = RELPERSISTENCE_TEMP; }
			| TEMP						{ $$ = RELPERSISTENCE_TEMP; }
			| LOCAL TEMPORARY			{ $$ = RELPERSISTENCE_TEMP; }
			| LOCAL TEMP				{ $$ = RELPERSISTENCE_TEMP; }
			| GLOBAL TEMPORARY
				{
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "GLOBAL is deprecated in temporary table creation";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(WARNING,
							(errmsg("GLOBAL is deprecated in temporary table creation"),
							 parser_errposition(@1)));
					$$ = RELPERSISTENCE_TEMP;
#else
                                        $$ = RELPERSISTENCE_GLOBAL_TEMP;
#endif
				}
			| GLOBAL TEMP
				{
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "GLOBAL is deprecated in temporary table creation";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(WARNING,
							(errmsg("GLOBAL is deprecated in temporary table creation"),
							 parser_errposition(@1)));
					$$ = RELPERSISTENCE_TEMP;
#else
                                        $$ = RELPERSISTENCE_GLOBAL_TEMP;
#endif
				}
			| UNLOGGED					{ $$ = RELPERSISTENCE_UNLOGGED; }
			| /*EMPTY*/					{ $$ = RELPERSISTENCE_PERMANENT; }
		;

OptTableElementList:
			TableElementList					{ $$ = $1; }
			| /*EMPTY*/							{ $$ = NIL; }
		;

OptTypedTableElementList:
			'(' TypedTableElementList ')'		{ $$ = $2; }
			| /*EMPTY*/							{ $$ = NIL; }
		;

TableElementList:
			TableElement
				{
					$$ = list_make1($1);
				}
			| TableElementList ',' TableElement
				{
					$$ = lappend($1, $3);
				}
		;

TypedTableElementList:
			TypedTableElement
				{
					$$ = list_make1($1);
				}
			| TypedTableElementList ',' TypedTableElement
				{
					$$ = lappend($1, $3);
				}
		;

TableElement:
			columnDef							{ $$ = $1; }
			| TableLikeClause					{ $$ = $1; }
			| TableConstraint					{ $$ = $1; }
		;

TypedTableElement:
			columnOptions						{ $$ = $1; }
			| TableConstraint	 				{ $$ = $1; }
		;

columnDef:	ColId Typename opt_charset KVType ColCmprsMode create_generic_options ColQualList opt_column_options
				{
					ColumnDef *n = makeNode(ColumnDef);
					n->colname = $1;
					n->typname = $2;
					n->typname->charset = $3;
					n->kvtype = $4;
					n->inhcount = 0;
					n->is_local = true;
					n->is_not_null = false;
					n->is_from_type = false;
					n->storage = 0;
					n->cmprs_mode = $5;
					n->raw_default = NULL;
					n->update_default = NULL;
					n->cooked_default = NULL;
					n->collOid = InvalidOid;
					n->fdwoptions = $6;
					if ($4 == ATT_KV_UNDEFINED) {
						SplitColQualList($7, &n->constraints, &n->collClause, &n->clientLogicColumnRef,
									 yyscanner);
					} else {
						SplitColQualList($7, &n->constraints, &n->collClause,
										yyscanner);
					}
					n->columnOptions = $8;
					$$ = (Node *)n;
				}
		;

add_column_first_after:
				FIRST_P
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "ALTER TABLE ... ADD ... FIRST is not yet supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("ALTER TABLE ... ADD ... FIRST is not yet supported")));
#endif
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->is_first = true;
					n->after_name = NULL;
					$$ = (Node *)n;
				}
				| AFTER ColId
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "ALTER TABLE ... ADD ... AFTER column_name is not yet supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("ALTER TABLE ... ADD ... AFTER column_name is not yet supported")));
#endif
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->is_first = false;
					n->after_name = $2;
					$$ = (Node *)n;
				}
				| /* EMPTY */
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->is_first = false;
					n->after_name = NULL;
					$$ = (Node *)n;
				}
			;

KVType: TSTAG		{$$ = ATT_KV_TAG;}  /* tag for kv storage */
		| TSFIELD	{$$ = ATT_KV_FIELD;}  /* field for kv storage */
		| TSTIME	{$$ = ATT_KV_TIMETAG;}  /* field for kv storage */
		| /* EMPTY */	{$$ = ATT_KV_UNDEFINED;} /* not using kv storage */
;

ColCmprsMode:	DELTA		{$$ = ATT_CMPR_DELTA;}  /* delta compression */
		| PREFIX	{$$ = ATT_CMPR_PREFIX;}  /* prefix compression */
		| DICTIONARY		{$$ = ATT_CMPR_DICTIONARY;}  /* dictionary compression */
		| NUMSTR	{$$ = ATT_CMPR_NUMSTR;}  /* number-string compression */
		| NOCOMPRESS	{$$ = ATT_CMPR_NOCOMPRESS;}  /* don't compress */
		| /* EMPTY */	{$$ = ATT_CMPR_UNDEFINED;} /* not specified by user */
;

columnOptions:	ColId WithOptions ColQualList
				{
					ColumnDef *n = makeNode(ColumnDef);
					n->colname = $1;
					n->typname = NULL;
					n->inhcount = 0;
					n->is_local = true;
					n->is_not_null = false;
					n->is_from_type = false;
					n->storage = 0;
					n->raw_default = NULL;
					n->cooked_default = NULL;
					n->collOid = InvalidOid;
					SplitColQualList($3, &n->constraints, &n->collClause, &n->clientLogicColumnRef,
									 yyscanner);
					$$ = (Node *)n;
				}
		;

WithOptions:
			WITH OPTIONS							{$$ = NIL; }
			| /*EMPTY*/								{$$ = NIL; }
		;

ColQualList:
			ColQualList ColConstraint				{ $$ = lappend($1, $2); }
			| /*EMPTY*/								{ $$ = NIL; }
		;

ColConstraint:
			CONSTRAINT name ColConstraintElem
				{
					Constraint *n = (Constraint *) $3;
            		const char* message = "check node type inconsistant";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					AssertEreport(IsA(n, Constraint),
									MOD_OPT,
									"check node type inconsistant");
					n->conname = $2;
					n->location = @1;
					$$ = (Node *) n;
				}
			| ColConstraintElem						{ $$ = $1; }
			| ConstraintAttr						{ $$ = $1; }
			| COLLATE collate_name
				{
					/*
					 * Note: the CollateClause is momentarily included in
					 * the list built by ColQualList, but we split it out
					 * again in SplitColQualList.
					 */
					CollateClause *n = makeNode(CollateClause);
					n->arg = NULL;
					n->collname = $2;
					n->location = @1;
					$$ = (Node *) n;
				}
			| ENCRYPTED with_algorithm
				{
					$$=$2;
				}
			| AUTO_INCREMENT
				{
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "auto_increment is not yet supported";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                            errmsg("auto_increment is not yet supported")));
#endif
                    if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
                        ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                        errmsg("auto_increment is supported only in B-format database")));
                    }
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_AUTO_INCREMENT;
					n->location = @1;
					n->raw_expr = NULL;
					n->cooked_expr = NULL;
					$$ = (Node *)n;
				}
		;	
with_algorithm:
                       WITH '(' algorithm_desc ')'
                       {
                        $$=$3;
                       }
                       | /*EMPTY*/ {
                               ClientLogicColumnRef  *n = makeNode(ClientLogicColumnRef);
                               n->column_key_name=NULL;
                               n->columnEncryptionAlgorithmType = EncryptionType::DETERMINISTIC_TYPE;
                               n->orig_typname=NULL;
							   n->location=0;
                               $$ = (Node *) n;
                       }
               ;
algorithm_desc:
        datatypecl columnEncryptionKey ',' encryptionType
        {
            ClientLogicColumnRef  *n = makeNode(ClientLogicColumnRef);
            n->column_key_name=$2;
            n->columnEncryptionAlgorithmType = $4;
            n->orig_typname=NULL;
			n->dest_typname=$1;
            n->location=@2;
            $$ = (Node *) n;
        }
        | datatypecl encryptionType ',' columnEncryptionKey
        {
            ClientLogicColumnRef  *n = makeNode(ClientLogicColumnRef);
            n->column_key_name=$4;
            n->columnEncryptionAlgorithmType = $2;
            n->orig_typname=NULL;
			n->dest_typname=$1;
            n->location=@2;
            $$ = (Node *) n;
        }
		;
columnEncryptionKey:  COLUMN_ENCRYPTION_KEY '=' setting_name  {$$=$3; };
encryptionType:
                ENCRYPTION_TYPE '=' RANDOMIZED {$$ =EncryptionType::RANDOMIZED_TYPE;}
    |           ENCRYPTION_TYPE '=' DETERMINISTIC {$$ =EncryptionType::DETERMINISTIC_TYPE;     }
;
setting_name:
        ColId { $$ = check_setting_name(list_make1(makeString($1)), yyscanner); }
        | ColId indirection
            {
                $$ = check_setting_name(lcons(makeString($1), $2), yyscanner);
            }
        ;

CreateKeyStmt:
        CreateMasterKeyStmt             { $$ = $1; }
        | CreateColumnKeyStmt          { $$ = $1; }
        ;

CreateMasterKeyStmt: 
        CREATE CLIENT MASTER KEY setting_name WITH '(' master_key_params ')'
        {   
            CreateClientLogicGlobal *n = makeNode(CreateClientLogicGlobal);
            n->global_key_name = $5;
            
            ClientLogicGlobalParam *n1 = makeNode (ClientLogicGlobalParam);
            n1->key = ClientLogicGlobalProperty::CLIENT_GLOBAL_FUNCTION;
            n1->value = "encryption";
            // len is not filled on purpose ??

            n->global_setting_params = lappend($8, (Node*)n1);
            $$=(Node*) n;
        }
        ;

master_key_params:
        master_key_elem                         { $$ = list_make1($1); }
        | master_key_params ',' master_key_elem { $$ = lappend($1, $3); }
        ;

master_key_elem: 
        KEY_STORE '=' ColId
        {
            ClientLogicGlobalParam *n = makeNode (ClientLogicGlobalParam);
            n->key = ClientLogicGlobalProperty::CMK_KEY_STORE;
            n->value = $3;
            // len is not filled on purpose ??
            $$ = (Node*) n;
        }
        | KEY_PATH '=' ColId_or_Sconst
        {
            ClientLogicGlobalParam *n = makeNode (ClientLogicGlobalParam);
            n->key = ClientLogicGlobalProperty::CMK_KEY_PATH;
            n->value =$3;
            // len is not filled on purpose ??
            $$ = (Node*) n;
        }
        | ALGORITHM '=' ColId
        {
            ClientLogicGlobalParam *n = makeNode (ClientLogicGlobalParam);
            n->key = ClientLogicGlobalProperty::CMK_ALGORITHM;
            n->value=$3;
            // len is not filled on purpose ??
            $$ = (Node*) n;
        }
        ;

CreateColumnKeyStmt:
        CREATE COLUMN ENCRYPTION KEY setting_name WITH VALUES '(' column_key_params ')'
        {
            CreateClientLogicColumn *n = makeNode(CreateClientLogicColumn);
            n->column_key_name = $5;

            ClientLogicColumnParam *n1 = makeNode (ClientLogicColumnParam);
            n1->key = ClientLogicColumnProperty::COLUMN_COLUMN_FUNCTION;
            n1->value = "encryption";
            // len is not filled on purpose ??

            n->column_setting_params = lappend($9, (Node*)n1);;
            $$=(Node*)n;
        }
        ;

column_key_params:
        column_key_elem                         { $$ = list_make1($1); }
        | column_key_params ',' column_key_elem { $$ = lappend($1, $3); }
        ;

column_key_elem: 
        CLIENT_MASTER_KEY '=' setting_name  {   
            ClientLogicColumnParam *n = makeNode (ClientLogicColumnParam);
            n->key = ClientLogicColumnProperty::CLIENT_GLOBAL_SETTING;
            n->value = NULL;
            n->qualname = $3;
            $$ = (Node*) n;
        }  
        | ALGORITHM '=' ColId
        {
            ClientLogicColumnParam *n = makeNode (ClientLogicColumnParam);
            n->key = ClientLogicColumnProperty::CEK_ALGORITHM;
            n->value =$3;
            n->qualname = NIL;
            $$ = (Node*) n;
        }
        | ENCRYPTED_VALUE '=' Sconst
        {
            ClientLogicColumnParam *n = makeNode (ClientLogicColumnParam);
            n->key = ClientLogicColumnProperty::CEK_EXPECTED_VALUE;
            n->value=$3;
            n->qualname = NIL;
            $$ = (Node*) n;
        }
        ;

datatypecl:
	DATATYPE_CL  '=' client_logic_type','
	{   
    	    $$ = $3;
	}
	| {$$= NULL;}
	;

/*
 * @HDFS
 * InformationalConstraintElem is used for informational constraint.
 */
InformationalConstraintElem:
            NOT_ENFORCED
                {
                    InformationalConstraint *n = makeNode(InformationalConstraint);
                    n->nonforced = true;
                    n->enableOpt = true;
                    $$ = (Node *) n;
                }
            | NOT_ENFORCED  DISABLE_P QUERY OPTIMIZATION
                {
                    InformationalConstraint *n = makeNode(InformationalConstraint);
                    n->nonforced = true;
                    n->enableOpt = false;
                    $$ = (Node *) n;
                }
            | NOT_ENFORCED  ENABLE_P QUERY OPTIMIZATION
                {
                    InformationalConstraint *n = makeNode(InformationalConstraint);
                    n->nonforced = true;
                    n->enableOpt = true;
                    $$ = (Node *) n;
                }
            | ENFORCED
                {
                    InformationalConstraint *n = makeNode(InformationalConstraint);
                    n->nonforced = false;
                    n->enableOpt = false;
                    $$ = (Node *) n;
                }
            | /*EMPTY*/
                {
                    InformationalConstraint *n = makeNode(InformationalConstraint);
                    n->nonforced = false;
                    n->enableOpt = false;
                    $$ = (Node *) n;
                }
        ;

/* DEFAULT NULL is already the default for Postgres.
 * But define it here and carry it forward into the system
 * to make it explicit.
 * - thomas 1998-09-13
 *
 * WITH NULL and NULL are not 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->location = @1;
					$$ = (Node *)n;
				}
			| NOT NULL_P ENABLE_P
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_NOTNULL;
					n->location = @1;
					$$ = (Node *)n;
				}
			| NULL_P
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_NULL;
					n->location = @1;
					$$ = (Node *)n;
				}
			| opt_unique_key opt_definition OptConsTableSpaceWithEmpty InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = NULL;
					n->options = $2;
					n->indexname = NULL;
					n->indexspace = $3;
					n->inforConstraint = (InformationalConstraint *) $4;
					n->initially_valid = true;
					$$ = (Node *)n;
				}
			| opt_unique_key opt_definition OptConsTableSpaceWithEmpty ENABLE_P ConstraintAttr_isValidate InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = NULL;
					n->options = $2;
					n->indexname = NULL;
					n->indexspace = $3;

					int cas_type = 0;
					if ($5 == CAS_NO_VALIDATE)
						cas_type = CAS_NOT_VALID;
					processCASbits(cas_type, @5, "UNIQUE",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									NULL, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = false;
					n->inforConstraint = (InformationalConstraint *) $6;
					$$ = (Node *)n;
				}
			| opt_unique_key opt_definition OptConsTableSpaceWithEmpty DISABLE_P ConstraintAttr_isValidate InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = NULL;
					n->options = $2;
					n->indexname = NULL;
					n->indexspace = $3;
					
					int cas_type = 0;
					if ($5 == CAS_VALIDATE)
						cas_type = CAS_DISABLE_VALIDATE;
					else
						cas_type = CAS_DISABLE_NO_VALIDATE;
					processCASbits(cas_type, @5, "UNIQUE",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									NULL, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = true;
					n->inforConstraint = (InformationalConstraint *) $6;
					$$ = (Node *)n;
				}
			| PRIMARY KEY opt_definition OptConsTableSpaceWithEmpty InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = NULL;
					n->options = $3;
					n->indexname = NULL;
					n->indexspace = $4;
					n->inforConstraint = (InformationalConstraint *) $5;
					n->initially_valid = true;
					$$ = (Node *)n;
				}
			| PRIMARY KEY opt_definition OptConsTableSpaceWithEmpty ENABLE_P ConstraintAttr_isValidate InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = NULL;
					n->options = $3;
					n->indexname = NULL;
					n->indexspace = $4;
					
					int cas_type = 0;
					if ($6 == CAS_NO_VALIDATE)
						cas_type = CAS_NOT_VALID;
					processCASbits(cas_type, @6, "PRIMARY KEY",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									NULL, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = false;
					n->inforConstraint = (InformationalConstraint *) $7;
					$$ = (Node *)n;
				}
			| PRIMARY KEY opt_definition OptConsTableSpaceWithEmpty DISABLE_P ConstraintAttr_isValidate InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = NULL;
					n->options = $3;
					n->indexname = NULL;
					n->indexspace = $4;
					
					int cas_type = 0;
					if ($6 == CAS_VALIDATE)
						cas_type = CAS_DISABLE_VALIDATE;
					else
						cas_type = CAS_DISABLE_NO_VALIDATE;
					processCASbits(cas_type, @6, "PRIMARY KEY",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									NULL, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = true;
					n->inforConstraint = (InformationalConstraint *) $7;
					$$ = (Node *)n;
				}
			| CHECK '(' a_expr ')' opt_no_inherit
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_CHECK;
					n->location = @1;
					n->is_no_inherit = $5;
					n->raw_expr = $3;
					n->cooked_expr = NULL;
					$$ = (Node *)n;
				}
			| CHECK '(' a_expr ')' opt_no_inherit ENABLE_P ConstraintAttr_isValidate
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_CHECK;
					n->location = @1;
					n->is_no_inherit = $5;
					n->raw_expr = $3;
					n->cooked_expr = NULL;
					
					int cas_type = 0;
					if ($7 == CAS_NO_VALIDATE)
						cas_type = CAS_NOT_VALID;
					processCASbits(cas_type, @7, "CHECK",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									&n->is_no_inherit, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = false;
					$$ = (Node *)n;
				}
			| CHECK '(' a_expr ')' opt_no_inherit DISABLE_P ConstraintAttr_isValidate
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_CHECK;
					n->location = @1;
					n->is_no_inherit = $5;
					n->raw_expr = $3;
					n->cooked_expr = NULL;
					
					int cas_type = 0;
					if ($7 == CAS_VALIDATE)
						cas_type = CAS_DISABLE_VALIDATE;
					else
						cas_type = CAS_DISABLE_NO_VALIDATE;

					processCASbits(cas_type, @7, "CHECK",
									&n->deferrable, &n->initdeferred, &n->skip_validation,
									&n->is_no_inherit, yyscanner);
					n->initially_valid = !n->skip_validation;
					n->isdisable = true;
					$$ = (Node *)n;
				}
			| DEFAULT b_expr
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_DEFAULT;
					n->location = @1;
					n->raw_expr = $2;
					n->cooked_expr = NULL;
					$$ = (Node *)n;
				}
			| ON_UPDATE_TIME UPDATE b_expr
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_DEFAULT;
						n->location = @1;
						n->update_expr = $3;
						n->cooked_expr = NULL;
						$$ = (Node *)n;
					} else {
						const char* message = "on update syntax be supported dbcompatibility B.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
                                                                 errcode(ERRCODE_SYNTAX_ERROR),
                                                                 errmsg("on update syntax is supported in dbcompatibility B."),
                                                                 parser_errposition(@1)));
						$$ = NULL;
					}
#endif
				}
			| GENERATED ALWAYS AS '(' a_expr ')' generated_column_option
				{
#ifdef ENABLE_MULTIPLE_NODES
            		const char* message = "Generated column is not yet supported";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errmodule(MOD_GEN_COL), errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Generated column is not yet supported.")));
#endif
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_GENERATED;
					n->generated_when = ATTRIBUTE_IDENTITY_ALWAYS;
					n->raw_expr = $5;
					n->cooked_expr = NULL;
					n->location = @1;
					$$ = (Node *)n;
				}
			| REFERENCES qualified_name opt_column_list key_match key_actions
				{
#ifdef 			ENABLE_MULTIPLE_NODES
            		const char* message = "REFERENCES constraint is not yet supported.";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("REFERENCES constraint is not yet supported.")));
#endif						
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_FOREIGN;
					n->location = @1;
					n->pktable			= $2;
					n->fk_attrs			= NIL;
					n->pk_attrs			= $3;
					n->fk_matchtype		= $4;
					n->fk_upd_action	= (char) ($5 >> 8);
					n->fk_del_action	= (char) ($5 & 0xFF);
					n->skip_validation  = false;
					n->initially_valid  = true;
					$$ = (Node *)n;
				}
			| REFERENCES qualified_name opt_column_list key_match key_actions ENABLE_P
				{
            		const char* message = "REFERENCES constraint is not yet supported.";
            		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("REFERENCES constraint is not yet supported.")));
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_FOREIGN;
					n->location = @1;
					n->pktable = $2;
					n->fk_attrs = NIL;
					n->pk_attrs = $3;
					n->fk_matchtype = $4;
					n->fk_upd_action = (char) ($5 >> 8);
					n->fk_del_action = (char) ($5 & 0xFF);
					n->skip_validation  = false;
					n->initially_valid = true;
					$$ = (Node *)n;
				}
		;
 
opt_unique_key:
			UNIQUE { $$ = NULL; }
			| UNIQUE KEY
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					ereport(errstate, (errmodule(MOD_PARSER),
						errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Un-support feature"),
						parser_errposition(@1),
						errdetail("UNIQUE KEY is supported only in B compatibility")));
				}
				$$ = NULL;
			}
			;
 
generated_column_option:
			STORED { $$ = 's'; }
			| /* EMPTY */ { $$ = '\0'; }
			;

/*
 * ConstraintAttr represents constraint attributes, which we parse as if
 * they were independent constraint clauses, in order to avoid shift/reduce
 * conflicts (since NOT might start either an independent NOT NULL clause
 * or an attribute).  parse_utilcmd.c is responsible for attaching the
 * attribute information to the preceding "real" constraint node, and for
 * complaining if attribute clauses appear in the wrong place or wrong
 * combinations.
 *
 * See also ConstraintAttributeSpec, which can be used in places where
 * there is no parsing conflict.  (Note: currently, NOT VALID and NO INHERIT
 * are allowed clauses in ConstraintAttributeSpec, but not here.  Someday we
 * might need to allow them here too, but for the moment it doesn't seem
 * useful in the statements that use ConstraintAttr.)
 */
ConstraintAttr:
			DEFERRABLE
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_ATTR_DEFERRABLE;
					n->location = @1;
					$$ = (Node *)n;
				}
			| NOT DEFERRABLE
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
					n->location = @1;
					$$ = (Node *)n;
				}
			| INITIALLY DEFERRED
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_ATTR_DEFERRED;
					n->location = @1;
					$$ = (Node *)n;
				}
			| INITIALLY IMMEDIATE
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_ATTR_IMMEDIATE;
					n->location = @1;
					$$ = (Node *)n;
				}
		;


TableLikeClause:
			LIKE qualified_name TableLikeOptionList
				{
					TableLikeClause *n = makeNode(TableLikeClause);
					n->relation = $2;
					n->options = $3;
#ifndef ENABLE_MULTIPLE_NODES					
					if (IS_SINGLE_NODE && (n->options & CREATE_TABLE_LIKE_DISTRIBUTION))
					{
            			const char* message = "Un-support feature";
            			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("Un-support feature"),                                          
									errdetail("The distributed capability is not supported currently."))); 
					}
#endif					
					$$ = (Node *)n;
				}
			| LIKE qualified_name INCLUDING_ALL excluding_option_list
				{
					TableLikeClause *n = makeNode(TableLikeClause);
					n->relation = $2;
					n->options = CREATE_TABLE_LIKE_ALL & ~$4;
#ifndef ENABLE_MULTIPLE_NODES					
					if (IS_SINGLE_NODE) 
					{
						n->options = n->options & ~CREATE_TABLE_LIKE_DISTRIBUTION;
					}
#endif					
					$$ = (Node *)n;
				}
		;

excluding_option_list:
				excluding_option_list EXCLUDING TableLikeExcludingOption	{ $$ = $1 | $3; }
				| /* EMPTY */						{ $$ = 0; }
		;

TableLikeOptionList:
				TableLikeOptionList INCLUDING TableLikeIncludingOption	{ $$ = $1 | $3; }
				| TableLikeOptionList EXCLUDING TableLikeExcludingOption	{ $$ = $1 & ~$3; }
				| /* EMPTY */						{ $$ = CREATE_TABLE_LIKE_DEFAULTS_SERIAL; }
		;

TableLikeIncludingOption:
				DEFAULTS			{ $$ = CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_DEFAULTS_SERIAL; }
				| CONSTRAINTS		{ $$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
				| INDEXES			{ $$ = CREATE_TABLE_LIKE_INDEXES; }
				| STORAGE			{ $$ = CREATE_TABLE_LIKE_STORAGE; }
				| COMMENTS			{ $$ = CREATE_TABLE_LIKE_COMMENTS; }
				| PARTITION			{ $$ = CREATE_TABLE_LIKE_PARTITION; }
				| RELOPTIONS		{ $$ = CREATE_TABLE_LIKE_RELOPTIONS; }
				| DISTRIBUTION		{ $$ = CREATE_TABLE_LIKE_DISTRIBUTION; }
				| OIDS				{ $$ = CREATE_TABLE_LIKE_OIDS;}
				| GENERATED			{ $$ = CREATE_TABLE_LIKE_GENERATED; }
		;

TableLikeExcludingOption:
				DEFAULTS			{ $$ = CREATE_TABLE_LIKE_DEFAULTS | CREATE_TABLE_LIKE_DEFAULTS_SERIAL; }
				| CONSTRAINTS		{ $$ = CREATE_TABLE_LIKE_CONSTRAINTS; }
				| INDEXES			{ $$ = CREATE_TABLE_LIKE_INDEXES; }
				| STORAGE			{ $$ = CREATE_TABLE_LIKE_STORAGE; }
				| COMMENTS			{ $$ = CREATE_TABLE_LIKE_COMMENTS; }
				| PARTITION			{ $$ = CREATE_TABLE_LIKE_PARTITION; }
				| RELOPTIONS		{ $$ = CREATE_TABLE_LIKE_RELOPTIONS; }
				| DISTRIBUTION		{ $$ = CREATE_TABLE_LIKE_DISTRIBUTION; }
				| OIDS				{ $$ = CREATE_TABLE_LIKE_OIDS; }
				| GENERATED			{ $$ = CREATE_TABLE_LIKE_GENERATED; }
				| ALL				{ $$ = CREATE_TABLE_LIKE_ALL; }
		;

opt_internal_data: 
            INTERNAL DATA_P 	internal_data_body		{$$ = $3;}
			| /* EMPTY */      	{$$ = NULL;}
		;

internal_data_body: 	{
				int		begin 		= 0;
				int		end			= 0;
				char	*body 		= NULL;
				int		body_len 	= 0;

				int	tok = YYEMPTY;
				base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);

				if (yychar == YYEOF || yychar == YYEMPTY)
					tok = YYLEX;

				begin = yylloc;
				while(tok != YYEOF)
				{
					if (tok == ';')
					{
						end = yylloc;
					}
					tok = YYLEX;
				}

				if (end == 0)
					parser_yyerror("internal data of create statment is not ended correctly");

				body_len = end - begin + 1 ;

				body = (char *)palloc0(body_len + 1);
				strncpy(body,
					yyextra->core_yy_extra.scanbuf + begin - 1, body_len);

				body[body_len] = '\0';
				$$ = body;
			}
		;

/* ConstraintElem specifies constraint syntax which is not embedded into
 *	a column definition. ColConstraintElem specifies the embedded form.
 * - thomas 1997-12-03
 */
TableConstraint:
			CONSTRAINT name ConstraintElem
				{
					Constraint *n = (Constraint *) $3;
					Assert(IsA(n, Constraint));
					if ((n->conname == NULL) || (n->conname != NULL && n->contype == CONSTR_FOREIGN)) {
						n->conname = $2;
					}		
					n->location = @1;
					$$ = (Node *) n;
				}
			| CONSTRAINT ConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "CONSTRAINT without constraint_name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("CONSTRAINT without constraint_name is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = (Constraint *) $2;
						Assert(IsA(n, Constraint));
						n->location = @1;
						$$ = (Node *) n;
					} else {
						const char* message = "CONSTRAINT without constraint_name is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("CONSTRAINT without constraint_name is supported only in B-format database."),
									parser_errposition(@1)));
  						$$ = NULL;/* not reached */
					}
				}
			| ConstraintElem
			    {
					Constraint *n = (Constraint *) $1;
					$$ = (Node *) n;
                }
		;

ConstraintElem:
			CHECK '(' a_expr ')' ConstraintAttributeSpec opt_index_options
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_CHECK;
					n->location = @1;
					n->raw_expr = $3;
					n->cooked_expr = NULL;
					processCASbits($5, @5, "CHECK",
								   NULL, NULL, &n->skip_validation,
								   &n->is_no_inherit, yyscanner);
					n->constraintOptions = $6;
					n->initially_valid = !n->skip_validation;
					if ($5 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					$$ = (Node *)n;
				}
			| UNIQUE name access_method_clause_without_keyword '(' constraint_params ')' opt_c_include opt_definition OptConsTableSpace opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "UNIQUE name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("UNIQUE name is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						if (strcasecmp($2, "index") == 0 || strcasecmp($2, "key") == 0) {
							const char* message = "index/key cannot be used as unique name.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errmodule(MOD_PARSER),
										errcode(ERRCODE_SYNTAX_ERROR),
										errmsg("index/key cannot be used as unique name."),
										parser_errposition(@1)));
						}
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_UNIQUE;
						n->location = @1;
						n->conname = $2;
						n->access_method = $3;
						n->keys = $5;
						n->including = $7;
						n->options = $8;
						n->indexname = NULL;
						n->indexspace = $9;
						n->constraintOptions = $10;
						n->initially_valid = true;
						processCASbits($11, @11, "UNIQUE",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $12; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "UNIQUE name is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("UNIQUE name is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
					
				}
			| UNIQUE name access_method_clause_without_keyword '(' constraint_params ')' opt_c_include opt_definition opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "UNIQUE name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("UNIQUE name is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						if (strcasecmp($2, "index") == 0 || strcasecmp($2, "key") == 0) {
							const char* message = "index/key cannot be used as unique name.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errmodule(MOD_PARSER),
										errcode(ERRCODE_SYNTAX_ERROR),
										errmsg("index/key cannot be used as unique name."),
										parser_errposition(@1)));
						}
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_UNIQUE;
						n->location = @1;
						n->conname = $2;
						n->access_method = $3;
						n->keys = $5;
						n->including = $7;
						n->options = $8;
						n->indexname = NULL;
						n->indexspace = NULL;
						n->constraintOptions = $9;
						n->initially_valid = true;
						processCASbits($10, @10, "UNIQUE",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $11; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "UNIQUE name is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("UNIQUE name is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
					
				}
			| UNIQUE USING IDENT '(' constraint_params ')' opt_c_include opt_definition OptConsTableSpace opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "UNIQUE access_method_clause is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("UNIQUE access_method_clause is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_UNIQUE;
						n->location = @1;
						n->access_method = $3;
						n->keys = $5;
						n->including = $7;
						n->options = $8;
						n->indexname = NULL;
						n->indexspace = $9;
						n->constraintOptions = $10;
						n->initially_valid = true;
						processCASbits($11, @11, "UNIQUE",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $12; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "UNIQUE access_method_clause is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("UNIQUE access_method_clause is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */						
					}
				}
			| UNIQUE USING IDENT '(' constraint_params ')' opt_c_include opt_definition opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "UNIQUE access_method_clause is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("UNIQUE access_method_clause is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_UNIQUE;
						n->location = @1;
						n->access_method = $3;
						n->keys = $5;
						n->including = $7;
						n->options = $8;
						n->indexname = NULL;
						n->indexspace = NULL;
						n->constraintOptions = $9;
						n->initially_valid = true;
						processCASbits($10, @10, "UNIQUE",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $11; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "UNIQUE access_method_clause is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("UNIQUE access_method_clause is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */						
					}
				}
			| UNIQUE '(' constraint_params ')' opt_c_include opt_definition OptConsTableSpace opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = $3;
					n->including = $5;
					n->options = $6;
					n->indexname = NULL;
					n->indexspace = $7;
					n->constraintOptions = $8;
					processCASbits($9, @9, "UNIQUE",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint *) $10; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($9 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					setAccessMethod(n);
					$$ = (Node *)n;
				}
			| UNIQUE '(' constraint_params ')' opt_c_include opt_definition opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = $3;
					n->including = $5;
					n->options = $6;
					n->indexname = NULL;
					n->indexspace = NULL;
					n->constraintOptions = $7;
					processCASbits($8, @8, "UNIQUE",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint *) $9; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($8 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					setAccessMethod(n);
					$$ = (Node *)n;
				}
			| UNIQUE ExistingIndex ConstraintAttributeSpec InformationalConstraintElem opt_index_options
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_UNIQUE;
					n->location = @1;
					n->keys = NIL;
					n->including = NIL;
					n->options = NIL;
					n->indexname = $2;
					n->indexspace = NULL;
					processCASbits($3, @3, "UNIQUE",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint *) $4; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($3 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					n->constraintOptions = $5;
					$$ = (Node *)n;
				}
			| PRIMARY KEY USING IDENT '(' constraint_params ')' opt_c_include opt_definition OptConsTableSpace opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "PRIMARY KEY USING access_method is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("PRIMARY KEY USING access_method is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_PRIMARY;
						n->location = @1;
						n->access_method = $4;
						n->keys = $6;
						n->including = $8;
						n->options = $9;
						n->indexname = NULL;
						n->indexspace = $10;
						n->constraintOptions = $11;
						n->initially_valid = true;
						processCASbits($12, @12, "PRIMARY KEY",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $13; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "PRIMARY KEY USING access_method is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("PRIMARY KEY USING access_method is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */					
					}
				}
			| PRIMARY KEY USING IDENT '(' constraint_params ')' opt_c_include opt_definition opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "PRIMARY KEY USING access_method is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("PRIMARY KEY USING access_method is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_PRIMARY;
						n->location = @1;
						n->access_method = $4;
						n->keys = $6;
						n->including = $8;
						n->options = $9;
						n->indexname = NULL;
						n->indexspace = NULL;
						n->constraintOptions = $10;
						n->initially_valid = true;
						processCASbits($11, @11, "PRIMARY KEY",
									   &n->deferrable, &n->initdeferred, NULL,
									   NULL, yyscanner);
						n->inforConstraint = (InformationalConstraint *) $12; /* informational constraint info */
						setAccessMethod(n);
						$$ = (Node *)n;
					} else {
						const char* message = "PRIMARY KEY USING access_method is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("PRIMARY KEY USING access_method is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */					
					}
				}
			| PRIMARY KEY '(' constraint_params ')' opt_c_include opt_definition OptConsTableSpace opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = $4;
					n->including = $6;
					n->options = $7;
					n->indexname = NULL;
					n->indexspace = $8;
					n->constraintOptions = $9;
					processCASbits($10, @10, "PRIMARY KEY",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint *) $11; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($10 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					setAccessMethod(n);
					$$ = (Node *)n;
				}
			| PRIMARY KEY '(' constraint_params ')' opt_c_include opt_definition opt_table_index_options
				ConstraintAttributeSpec InformationalConstraintElem
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = $4;
					n->including = $6;
					n->options = $7;
					n->indexname = NULL;
					n->indexspace = NULL;
					n->constraintOptions = $8;
					processCASbits($9, @9, "PRIMARY KEY",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint *) $10; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($9 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					setAccessMethod(n);
					$$ = (Node *)n;
				}
			| PRIMARY KEY ExistingIndex ConstraintAttributeSpec InformationalConstraintElem opt_index_options
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_PRIMARY;
					n->location = @1;
					n->keys = NIL;
					n->including = NIL;
					n->options = NIL;
					n->indexname = $3;
					n->indexspace = NULL;
					processCASbits($4, @4, "PRIMARY KEY",
								   &n->deferrable, &n->initdeferred, &n->skip_validation,
								   NULL, yyscanner);
					n->inforConstraint = (InformationalConstraint*) $5; /* informational constraint info */
					n->initially_valid = !n->skip_validation;
					if ($4 & (CAS_DISABLE_VALIDATE | CAS_DISABLE_NO_VALIDATE))
						n->isdisable = true;
					n->constraintOptions = $6;
					$$ = (Node *)n;
				}
			| EXCLUDE access_method_clause '(' ExclusionConstraintList ')'
				opt_c_include opt_definition OptConsTableSpaceWithEmpty ExclusionWhereClause
				ConstraintAttributeSpec opt_index_options
				{
            		const char* message = "EXCLUDE constraint is not yet supported.";
        			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("EXCLUDE constraint is not yet supported.")));
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_EXCLUSION;
					n->location = @1;
					n->access_method	= $2;
					n->exclusions		= $4;
					n->including		= $6;
					n->options			= $7;
					n->indexname		= NULL;
					n->indexspace		= $8;
					n->where_clause		= $9;
					processCASbits($10, @10, "EXCLUDE",
								   &n->deferrable, &n->initdeferred, NULL,
								   NULL, yyscanner);
					n->constraintOptions = $11;
					n->initially_valid   = true;
					$$ = (Node *)n;
				}
			| FOREIGN KEY name '(' columnList ')' REFERENCES qualified_name
				opt_column_list key_match key_actions ConstraintAttributeSpec opt_index_options
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "FOREIGN KEY name ... REFERENCES constraint is not yet supported.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("FOREIGN KEY name ... REFERENCES constraint is not yet supported.")));
#endif						
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						Constraint *n = makeNode(Constraint);
						n->contype = CONSTR_FOREIGN;
						n->location = @1;
						n->conname = $3;
						n->pktable			= $8;
						n->fk_attrs			= $5;
						n->pk_attrs			= $9;
						n->fk_matchtype		= $10;
						n->fk_upd_action	= (char) ($11 >> 8);
						n->fk_del_action	= (char) ($11 & 0xFF);
						processCASbits($12, @12, "FOREIGN KEY",
									   &n->deferrable, &n->initdeferred,
									   &n->skip_validation, NULL,
									   yyscanner);
						n->initially_valid = !n->skip_validation;
						n->constraintOptions = $13;
						$$ = (Node *)n;
					} else {
						const char* message = "FOREIGN KEY name is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("FOREIGN KEY name is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */	
					}
				}
			| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
				opt_column_list key_match key_actions ConstraintAttributeSpec opt_index_options
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
            		const char* message = "FOREIGN KEY ... REFERENCES constraint is not yet supported.";
        			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("FOREIGN KEY ... REFERENCES constraint is not yet supported.")));
#endif						
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_FOREIGN;
					n->location = @1;
					n->pktable			= $7;
					n->fk_attrs			= $4;
					n->pk_attrs			= $8;
					n->fk_matchtype		= $9;
					n->fk_upd_action	= (char) ($10 >> 8);
					n->fk_del_action	= (char) ($10 & 0xFF);
					processCASbits($11, @11, "FOREIGN KEY",
								   &n->deferrable, &n->initdeferred,
								   &n->skip_validation, NULL,
								   yyscanner);
					n->initially_valid = !n->skip_validation;
					n->constraintOptions = $12;
					$$ = (Node *)n;
				}			
			| PARTIAL CLUSTER KEY '(' columnList ')' ConstraintAttributeSpec opt_index_options
				{
					Constraint *n = makeNode(Constraint);
					n->contype = CONSTR_CLUSTER;
					n->location = @1;
					n->keys = $5;
					processCASbits($7, @7, "PARTIAL CLUSTER KEY",
								   NULL, NULL, NULL, NULL,
								   yyscanner);
					n->constraintOptions = $8;
					n->initially_valid   = true;
					$$ = (Node *)n;
				}
		;

opt_no_inherit:	NO INHERIT							{  $$ = TRUE; }
			| /* EMPTY */							{  $$ = FALSE; }
		;

opt_column_list:
			'(' columnList ')'						{ u_sess->parser_cxt.col_list = $2; $$ = $2; }
			| /*EMPTY*/								{ u_sess->parser_cxt.col_list = NIL; $$ = NIL; }
		;

columnList:
			columnElem								{ $$ = list_make1($1); }
			| columnList ',' columnElem				{ $$ = lappend($1, $3); }
		;

columnElem: ColId
				{
					$$ = (Node *) makeString($1);
				}
		;

opt_c_include:	INCLUDE '(' columnList ')'			{ $$ = $3; }
			 |		/* EMPTY */						{ $$ = NIL; }
		;

key_match:  MATCH FULL
			{
				$$ = FKCONSTR_MATCH_FULL;
			}
		| MATCH PARTIAL
			{
        		const char* message = "MATCH PARTIAL not yet implemented";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						 errmsg("MATCH PARTIAL not yet implemented"),
						 parser_errposition(@1)));
				$$ = FKCONSTR_MATCH_PARTIAL;
			}
		| MATCH SIMPLE
			{
				$$ = FKCONSTR_MATCH_UNSPECIFIED;
			}
		| /*EMPTY*/
			{
				$$ = FKCONSTR_MATCH_UNSPECIFIED;
			}
		;

ExclusionConstraintList:
			ExclusionConstraintElem					{ $$ = list_make1($1); }
			| ExclusionConstraintList ',' ExclusionConstraintElem
													{ $$ = lappend($1, $3); }
		;

ExclusionConstraintElem: index_elem WITH any_operator
			{
				$$ = list_make2($1, $3);
			}
			/* allow OPERATOR() decoration for the benefit of ruleutils.c */
			| index_elem WITH OPERATOR '(' any_operator ')'
			{
				$$ = list_make2($1, $5);
			}
		;

ExclusionWhereClause:
			WHERE '(' a_expr ')'					{ $$ = $3; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

/*
 * We combine the update and delete actions into one value temporarily
 * for simplicity of parsing, and then break them down again in the
 * calling production.  update is in the left 8 bits, delete in the right.
 * Note that NOACTION is the default.
 */
key_actions:
			key_update
				{ $$ = ($1 << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); }
			| key_delete
				{ $$ = (FKCONSTR_ACTION_NOACTION << 8) | ($1 & 0xFF); }
			| key_update key_delete
				{ $$ = ($1 << 8) | ($2 & 0xFF); }
			| key_delete key_update
				{ $$ = ($2 << 8) | ($1 & 0xFF); }
			| /*EMPTY*/
				{ $$ = (FKCONSTR_ACTION_NOACTION << 8) | (FKCONSTR_ACTION_NOACTION & 0xFF); }
		;

key_update: ON UPDATE key_action		{ $$ = $3; }
		;

key_delete: ON DELETE_P key_action		{ $$ = $3; }
		;

key_action:
			NO ACTION					{ $$ = FKCONSTR_ACTION_NOACTION; }
			| RESTRICT					{ $$ = FKCONSTR_ACTION_RESTRICT; }
			| CASCADE					{ $$ = FKCONSTR_ACTION_CASCADE; }
			| SET NULL_P				{ $$ = FKCONSTR_ACTION_SETNULL; }
			| SET DEFAULT				{ $$ = FKCONSTR_ACTION_SETDEFAULT; }
		;

OptInherit: INHERITS '(' qualified_name_list ')'
			{
				if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
					const char* message = "inherits is not support in B-format database, it conflicts with multi-relation update";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("inherits is not support in B-format database, it conflicts with multi-relation update")));
				}
				$$ = $3;
			}
			| /*EMPTY*/								{ $$ = NIL; }
		;

/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
OptWith:
			WITH reloptions				{ $$ = $2; }
			| WITH OIDS
			{
				if (!u_sess->attr.attr_common.IsInplaceUpgrade) {
        			const char* message = "CREATE TABLE ... WITH OIDS is not yet supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("CREATE TABLE ... WITH OIDS is not yet supported.")));
				}
				$$ = 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; }
		;
AutoIncrementValue: AUTO_INCREMENT Iconst	{ $$ = (Node *)makeInteger($2); }
        | AUTO_INCREMENT '=' Iconst	{ $$ = (Node *)makeInteger($3); }
        | AUTO_INCREMENT FCONST	{ $$ = (Node *)makeFloat($2); }
		| AUTO_INCREMENT '=' FCONST	{ $$ = (Node *)makeFloat($3); }
		;

OptAutoIncrement: AutoIncrementValue
            {
#ifdef ENABLE_MULTIPLE_NODES
                const char* message = "auto_increment is not yet supported";
                InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                ereport(errstate,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("auto_increment is not yet supported")));
#endif
                if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
                    ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                    errmsg("auto_increment is supported only in B-format database")));
                }
                $$ = (Node*)makeDefElem("start", $1);
            }
            | /* EMPTY */ { $$ = NULL; }
		;

OptTableSpace:   TABLESPACE opt_equal name					{ $$ = $3; }
			| /*EMPTY*/								{ $$ = NULL; }
		;
OptGPI: 	UPDATE GLOBAL INDEX 	{ $$ = TRUE; }
			| /*EMPTY*/				{ if (UPDATE_GLOBAL_INDEX_ON_PARTITION_CHANGE) {$$ = TRUE;} else {$$ = false;}}
		;
OptCompress: COMPRESS	{ $$ = REL_CMPRS_FIELDS_EXTRACT; }
			| NOCOMPRESS { $$ = REL_CMPRS_PAGE_PLAIN; }
			| /* EMPTY */ { $$ = REL_CMPRS_PAGE_PLAIN; }
		;

/* PGXC_BEGIN */
OptDistributeBy: OptDistributeByInternal			{ $$ = $1; }
			| /* EMPTY */							{ $$ = NULL; }
		;
OptDatanodeName:    DATANODE name					{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

/*
 * For the distribution type, we use IDENT to limit the impact of keywords
 * related to distribution on other commands and to allow extensibility for
 * new distributions.
 */
OptDistributeType: IDENT							{ $$ = $1; }
		;

OptDistributeByInternal:  DISTRIBUTE BY OptDistributeType '(' name_list ')'
				{
					DistributeBy *n = makeNode(DistributeBy);
#ifndef ENABLE_MULTIPLE_NODES					
					if (IS_SINGLE_NODE)
					{
        				const char* message = "Un-support feature";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,          
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("Un-support feature"),
								errdetail("The distributed capability is not supported currently.")));			
					}
#endif					
					if (strcmp($3, "modulo") == 0)
						n->disttype = DISTTYPE_MODULO;
					else if (strcmp($3, "hash") == 0)
						n->disttype = DISTTYPE_HASH;
					else if (strcmp($3, "list") == 0 || strcmp($3, "range") == 0) {
        				const char* message = "distribution needs user-defined slice clause";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("%s distribution needs user-defined slice clause", $3)));
					} else {
        				const char* message = "unrecognized distribution option";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        			ereport(errstate,
                                			(errcode(ERRCODE_SYNTAX_ERROR),
                                 				errmsg("unrecognized distribution option \"%s\"", $3)));
					}
					n->colname = $5;
					if (list_length(n->colname) > 1 && strcmp($3, "hash") != 0)
					{
        				const char* message = "distribute key can not exceed 1";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        			ereport(errstate,
                                			(errcode(ERRCODE_SYNTAX_ERROR),
                                 				errmsg("The number of %s distribute key can not exceed 1", $3)));

					}
					$$ = n;
				}
			| DISTRIBUTE BY OptDistributeType
				{
					DistributeBy *n = makeNode(DistributeBy);
#ifndef ENABLE_MULTIPLE_NODES					
					if (IS_SINGLE_NODE)
					{
        				const char* message = "Un-support feature";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,          
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("Un-support feature"),
								errdetail("The distributed capability is not supported currently.")));			
					}
#endif					
					if (strcmp($3, "replication") == 0)
                        n->disttype = DISTTYPE_REPLICATION;
					else if (strcmp($3, "roundrobin") == 0)
						n->disttype = DISTTYPE_ROUNDROBIN;
                    else if (strcmp($3, "hidetag") == 0)
                        n->disttype = DISTTYPE_HIDETAG;
                    else {
        				const char* message = "unrecognized distribution option";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        ereport(errstate,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("unrecognized distribution option \"%s\"", $3)));
					}
					n->colname = NULL;
					$$ = n;
				}
			| distribute_by_range_clause
				{
					$$ = $1;
				}
			| distribute_by_list_clause
				{
					$$ = $1;
				}
		;


distribute_by_list_clause: /* distribute by list ..., or distribute by list ... slice reference base_table */
			DISTRIBUTE BY LIST '(' name_list ')' OptListDistribution
				{
#ifndef ENABLE_MULTIPLE_NODES					
        			const char* message = "unrecognized distribution option";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,          
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The distributed capability is not supported currently.")));			

#endif					

					DistributeBy *n = makeNode(DistributeBy);
					n->disttype = DISTTYPE_LIST;
					n->colname = $5;
					n->distState = (DistState *)$7; 

					if (list_length(n->colname) > 4)
					{
        				const char* message = "The number of LIST distribution keys can not exceed 4";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        			ereport(errstate,
                                			(errcode(ERRCODE_SYNTAX_ERROR),
                                 				errmsg("The number of LIST distribution keys can not exceed 4")));

					}
					$$ = n;
				}
		;

OptListDistribution: 
		'(' list_dist_state ')'
			{ 
				$$ = $2; 
			}
		| SliceReferenceClause
			{
				DistState *n = makeNode(DistState);
				n->strategy = 'l';
				n->refTableName = $1;
				$$ = (Node *)n;
			}
		;

list_dist_state: /* DistState Struct for LIST distribution syntax */
		list_distribution_rules_list
			{
				DistState *n = makeNode(DistState);
				n->strategy = 'l';
				n->sliceList = $1;
				$$ = (Node *)n;
			}
		;

list_distribution_rules_list: /* list of DistSliceValue Struct for LIST distribution syntax */
		list_dist_value
			{
				$$ = list_make1($1);
			}
		| list_distribution_rules_list ',' list_dist_value
			{
				$$ = lappend($1, $3);
			}
		;

list_dist_value:
		SLICE name VALUES '(' list_distribution_rule_row ')' OptDatanodeName
			{
				ListSliceDefState *n = makeNode(ListSliceDefState);
				n->name = $2;
				n->boundaries = $5;
				n->datanode_name = $7;
				$$ = (Node *)n;
			}
		| SLICE name VALUES '(' DEFAULT ')' OptDatanodeName
			{
				Const *m = makeNode(Const);
				m->ismaxvalue = true;
				m->location = @1;

				ListSliceDefState *n = makeNode(ListSliceDefState);
				List *boundary = list_make1((void *)m); 
				n->boundaries = list_make1((void *)boundary);
				n->name = $2;
				n->datanode_name = $7;
				$$ = (Node *)n;
			}
		;

list_distribution_rule_row:  /* ListSliceDefState Struct for LIST distribution syntax */
		list_distribution_rule_single
			{
				$$ = list_make1($1); 
			}
		| list_distribution_rule_row ',' list_distribution_rule_single
			{
				$$ = lappend($1, $3);
			}
		;

list_distribution_rule_single:
		'(' expr_list ')' 
			{
				$$ = $2;
			}
		| c_expr_noparen
			{
				$$ = list_make1($1);
			}
		;



distribute_by_range_clause:
		DISTRIBUTE BY RANGE '(' name_list ')'  '(' range_slice_definition_list ')'
			{
#ifndef ENABLE_MULTIPLE_NODES	
        			const char* message = "The number of LIST distribution keys can not exceed 4";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);				
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("Un-support feature"),
							errdetail("The distributed capability is not supported currently.")));			
#endif
				DistributeBy *n = makeNode(DistributeBy);
				n->disttype = DISTTYPE_RANGE;
				n->colname = $5;
				DistState *n1 = makeNode(DistState);
				n1->strategy = 'r';
				n1->sliceList = $8;
				n->distState = n1;

				if (list_length(n->colname) > 4) {
        			const char* message = "The number of LIST distribution keys can not exceed 4";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("The number of range distribution key can not exceed 4")));
				}

				$$ = n;
			}
		| DISTRIBUTE BY RANGE '(' name_list ')' SliceReferenceClause
			{
#ifndef ENABLE_MULTIPLE_NODES	
        		const char* message = "Un-support feature";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);				
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("Un-support feature"),
						errdetail("The distributed capability is not supported currently.")));			
#endif
				DistributeBy *n = makeNode(DistributeBy);
				n->disttype = DISTTYPE_RANGE;
				n->colname = $5;
				DistState *n1 = makeNode(DistState);
				n1->strategy = 'r';
				n1->refTableName = $7;
				n->distState = n1;
				$$ = n;
			}
		;

SliceReferenceClause:
		SLICE REFERENCES name
			{
				$$ = $3;
			}
		;

range_slice_definition_list: /* general range slice syntax: values less than or start .. end */
		range_slice_less_than_list
			{
				$$ = $1;
			}
		| range_slice_start_end_list
			{
				$$ = $1;
			}
		;

range_slice_less_than_list:
		range_slice_less_than_item
			{
				$$ = list_make1($1);
			}
		| range_slice_less_than_list ',' range_slice_less_than_item
			{
				$$ = lappend($1, $3);
			}
		;

range_slice_less_than_item:
		SLICE name VALUES LESS THAN '(' maxValueList ')' OptDatanodeName
			{
				RangePartitionDefState *n = makeNode(RangePartitionDefState);
				n->partitionName = $2;
				n->boundary = $7;
				n->tablespacename = $9;

				$$ = (Node *)n;
			}
		;

range_slice_start_end_list:
		range_slice_start_end_item
			{
				$$ = list_make1($1);
			}
		| range_slice_start_end_list ',' range_slice_start_end_item
			{
				$$ = lappend($1, $3);
			}
		;

range_slice_start_end_item:
		SLICE name START '(' maxValueList ')' END_P '(' maxValueList ')' opt_range_every_list
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = $5;
				n->endValue = $9;
				n->everyValue = $11;

				$$ = (Node *)n;
			}
		| SLICE name END_P '(' maxValueList ')'
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = NIL;
				n->endValue = $5;
				n->everyValue = NIL;

				$$ = (Node *)n;
			}
		| SLICE name START '(' maxValueList ')'
			{
				RangePartitionStartEndDefState *n = makeNode(RangePartitionStartEndDefState);
				n->partitionName = $2;
				n->startValue = $5;
				n->endValue = NIL;
				n->everyValue = NIL;

				$$ = (Node *)n;
			}
		;

OptSubCluster:
			OptSubClusterInternal
				{
					$$ = $1;
				}
			| /* EMPTY */							{ $$ = NULL; }
		;

OptSubClusterInternal:
			TO NODE pgxcnodes
				{
					PGXCSubCluster *n = makeNode(PGXCSubCluster);
					n->clustertype = SUBCLUSTER_NODE;
					n->members = $3;
					$$ = n;
				}
			| TO GROUP_P pgxcgroup_name
				{
					PGXCSubCluster *n = makeNode(PGXCSubCluster);
					n->clustertype = SUBCLUSTER_GROUP;
					n->members = list_make1(makeString($3));
					$$ = n;
				}
		;
/* PGXC_END */

OptConsTableSpace:   USING INDEX OptPartitionElement	{ $$ = $3; }
		;

OptConsTableSpaceWithEmpty:	USING INDEX OptPartitionElement		{ $$ = $3; }
				| /*EMPTY*/				{ $$ = NULL; }
		;

OptPartitionElement:
		OptTableSpace OptPctFree OptInitRans OptMaxTrans OptStorage
			{
				$$ = $1;
			}
		;

OptPctFree:
			PCTFREE Iconst
			| /* empty */
		;

OptInitRans:
			INITRANS Iconst
			| /* empty */
		;

OptMaxTrans:
			MAXTRANS Iconst
			| /* empty */
		;

OptStorage:
		STORAGE '(' OptInitial OptNext OptMinextents OptMaxextents ')'
		| /* empty */
		;
OptInitial:
		INITIAL_P Iconst IDENT
		| /* empty */
		;

OptNext:
		NEXT Iconst IDENT
		| /*empty*/
		;

OptMinextents:
		MINEXTENTS Iconst
		| /*empty*/
		;

OptMaxextents:
		MAXEXTENTS UNLIMITED
		| MAXEXTENTS Iconst
		| /*empty*/
		;

ExistingIndex:   USING INDEX index_name				{ $$ = $3; }
		;


/*****************************************************************************
 *
 *		QUERY :
 *				CREATE TABLE relname AS SelectStmt [ WITH [NO] DATA ]
 *
 *
 * Note: SELECT ... INTO is a now-deprecated alternative for this.
 *
 *****************************************************************************/

CreateAsStmt:
		CREATE OptTemp TABLE create_as_target AS SelectStmt opt_with_data
				{
					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
					ctas->query = $6;
					ctas->into = $4;
					ctas->relkind = OBJECT_TABLE;
					ctas->is_select_into = false;
					/* cram additional flags into the IntoClause */
					$4->rel->relpersistence = $2;
					$4->skipData = !($7);
					$$ = (Node *) ctas;
				}
		;

OptDuplicate:
			/* empty */	{ $$ = DUPLICATE_ERROR; }
			| IGNORE	{ $$ = DUPLICATE_IGNORE; }
			| REPLACE	{ $$ = DUPLICATE_REPLACE; }
		;

create_as_target:
			qualified_name opt_column_list OptWith OnCommitOption OptCompress OptTableSpace
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
				{
					$$ = makeNode(IntoClause);
					$$->rel = $1;
					$$->colNames = $2;
					$$->options = $3;
					$$->onCommit = $4;
					$$->row_compress = $5;
					$$->tableSpaceName = $6;
					$$->skipData = false;		/* might get changed later */
/* PGXC_BEGIN */
					$$->distributeby = $7;
					$$->subcluster = $8;
					$$->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
/* PGXC_END */
				}
			| qualified_name '(' OptTableElementList ')' OptInherit OptAutoIncrement optCharsetCollate OptWith OnCommitOption OptCompress OptPartitionElement
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			OptDuplicate
				{
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("define column_definition is supported only in B-format database")));
					}
					$$ = makeNode(IntoClause);
					$$->rel = $1;
					$$->tableElts = $3;
					if ($$->tableElts == NIL) {
						ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("syntax error at or near \"%s\"", ")"), parser_errposition(@4)));
					}
					$$->autoIncStart = $6;
					$$->options = $8;
					$$->onCommit = $9;
					$$->row_compress = $10;
					$$->tableSpaceName = $11;
					$$->skipData = false;           /* might get changed later */
/* PGXC_BEGIN */
					$$->distributeby = $12;
					$$->subcluster = $13;
					$$->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
/* PGXC_END */
					$$->onduplicate = $14;
				}
		;

opt_with_data:
			WITH DATA_P								{ $$ = TRUE; }
			| WITH NO DATA_P						{ $$ = FALSE; }
			| /*EMPTY*/								{ $$ = TRUE; }
		;

/*****************************************************************************
 *
 *              QUERY :
 *                              CREATE SNAPSHOT relname AS SelectStmt
 *                              CREATE SNAPSHOT relname FROM @ version USING (AlterAndDMLStmts)
 *                              SAMPLE SNAPSHOT relname AS postfix AT RATIO FCONST
 *                              PUBLISH SNAPSHOT relname @ version
 *                              ARCHIVE SNAPSHOT relname @ version
 *                              PURGE SNAPSHOT relname @ version
 *
 *****************************************************************************/

SnapshotStmt:
			CREATE OptTemp SNAPSHOT qualified_name OptSnapshotVersion
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			OptSnapshotComment
			AS SelectStmt
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "CREATE SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("CREATE SNAPSHOT is not yet supported.")));
#endif

				if ($2 != RELPERSISTENCE_PERMANENT)
				{
        			const char* message = "Temporary snapshots are not supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Temporary snapshots are not supported.")));
				}

				if ($7 != NULL)
				{
        			const char* message = "Clustered snapshots are not supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Clustered snapshots are not supported.")));
				}

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("create_snapshot")),
					lcons(checkNullNode(makeStringConst($4->schemaname, @4)),
					list_make4(checkNullNode(makeStringConst($4->relname, @4)),
					makeAArrayExpr(list_make1(make_node_from_scanbuf(@10, yylloc , yyscanner)), @10),
					checkNullNode(makeStringConst($5, @5)), checkNullNode(makeStringConst($8, @8)))));
			}
			| CREATE OptTemp SNAPSHOT qualified_name OptSnapshotVersion
/* PGXC_BEGIN */
			OptDistributeBy OptSubCluster
/* PGXC_END */
			FROM SnapshotVersion
			OptSnapshotComment
			USING '(' AlterSnapshotCmdList ')'
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "CREATE SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("CREATE SNAPSHOT is not yet supported.")));
#endif

				if ($2 != RELPERSISTENCE_PERMANENT)
				{
        			const char* message = "Temporary snapshots are not supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Temporary snapshots are not supported.")));
				}

				if ($6 != NULL)
				{
        			const char* message = "illegal DISTRIBUTE BY clause in CREATE SNAPSHOT ... FROM";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("illegal DISTRIBUTE BY clause in CREATE SNAPSHOT ... FROM"),
						errhint("DISTRIBUTE BY is inherited from parent snapshot."),
						parser_errposition(@6)));
				}

				if ($7 != NULL)
				{
        			const char* message = "Clustered snapshots are not supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("Clustered snapshots are not supported."),
						parser_errposition(@7)));
				}

				if ($13 == NIL)
				{
        			const char* message = "List of snapshot modifications is empty.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("List of snapshot modifications is empty."),
						parser_errposition(@13)));
				}

				char *snapshot_name = (char *)palloc0(strlen($4->relname) + 1 + strlen($9) + 1);
				sprintf(snapshot_name, "%s%c%s", $4->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $9);
				$4->relname = snapshot_name;

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("prepare_snapshot")),
					lcons(checkNullNode(makeStringConst($4->schemaname, @4)),
					list_make4(checkNullNode(makeStringConst($4->relname, @4)),
					makeAArrayExpr($13, @13),
					checkNullNode(makeStringConst($5, @5)),
					checkNullNode(makeStringConst($10, @10)))));
			}
			| SAMPLE SNAPSHOT qualified_name SnapshotVersion OptSnapshotStratify SnapshotSampleList
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "SAMPLE SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("SAMPLE SNAPSHOT is not yet supported.")));
#endif

				char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1);
				sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4);
				$3->relname = snapshot_name;

				List *stratify = NIL;
				foreach_cell (c, $5) {
					ColumnRef *r = (ColumnRef*)lfirst(c);
					stratify = lappend(stratify,
					checkNullNode(makeStringConst(((Value *)llast(r->fields))->val.str, @5)));
				}

				List *names = NIL, *ratios = NIL, *comments = NIL;
				foreach_cell (c, $6) {
					names = lappend(names, lfirst(c));
					c = lnext(c);
					ratios = lappend(ratios, lfirst(c));
					c = lnext(c);
					comments = lappend(comments, lfirst(c));
				}

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("sample_snapshot")),
					lcons(checkNullNode(makeStringConst($3->schemaname, @3)),
					lcons(checkNullNode(makeStringConst($3->relname, @3)),
					list_make4(makeAArrayExpr(names, -1), makeAArrayExpr(ratios, -1),
						(stratify == NIL) ? makeNullAConst(-1) : makeAArrayExpr(stratify, @5),
						makeAArrayExpr(comments, -1)))));
			}
			| ARCHIVE SNAPSHOT qualified_name SnapshotVersion
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "ARCHIVE SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("ARCHIVE SNAPSHOT is not yet supported.")));
#endif

				char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1);
				sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4);
				$3->relname = snapshot_name;

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("archive_snapshot")),
					list_make2(checkNullNode(makeStringConst($3->schemaname, @3)),
					checkNullNode(makeStringConst($3->relname, @3))));
			}
			| PUBLISH SNAPSHOT qualified_name SnapshotVersion
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "PUBLISH SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("PUBLISH SNAPSHOT is not yet supported.")));
#endif

				char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1);
				sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4);
				$3->relname = snapshot_name;

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("publish_snapshot")),
					list_make2(checkNullNode(makeStringConst($3->schemaname, @3)),
					checkNullNode(makeStringConst($3->relname, @3))));
			}
			| PURGE SNAPSHOT qualified_name SnapshotVersion {}
			{
#ifdef ENABLE_MULTIPLE_NODES
        		const char* message = "PURGE SNAPSHOT is not yet supported.";
    			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("PURGE SNAPSHOT is not yet supported.")));
#endif

				char *snapshot_name = (char *)palloc0(strlen($3->relname) + 1 + strlen($4) + 1);
				sprintf(snapshot_name, "%s%c%s", $3->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $4);
				$3->relname = snapshot_name;

				$$ = makeCallFuncStmt(
					list_make2(makeString("db4ai"), makeString("purge_snapshot")),
					list_make2(checkNullNode(makeStringConst($3->schemaname, @3)),
					checkNullNode(makeStringConst($3->relname, @3))));
			}
		;

SnapshotVersion:
			'@' Iconst
				{
					char buf[64];
					snprintf(buf, sizeof(buf), "%d", $2);
					$$ = pstrdup(buf);
				}
			| '@' FCONST
				{	for (int i = strlen($2) - 1; i >= 0; i--)
					{
						if ($2[i] == '.')
						{
							$2[i] = DB4AI_SNAPSHOT_VERSION_SEPARATOR;
						}
					}
					$$ = $2;
				}
			| '@' VCONST			{ $$ = $2; }
			| '@' ColId_or_Sconst	{ $$ = $2; }
		;

OptSnapshotVersion:
			SnapshotVersion
				{
#ifdef ENABLE_MULTIPLE_NODES
        			const char* message = "SNAPSHOT VERSION syntax is not yet supported.";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("SNAPSHOT VERSION syntax is not yet supported.")));
#endif
					$$ = $1;
				}
			| /*EMPTY*/				{ $$ = NULL; }
		;

OptSnapshotComment:
			COMMENT IS comment_text	{ $$ = $3; }
			| /*EMPTY*/				{ $$ = NULL; }
		;

AlterSnapshotCmdList: AlterSnapshotCmdListNoParens
			| AlterSnapshotCmdListWithParens
		;

AlterSnapshotCmdListWithParens:
			'(' AlterSnapshotCmdListNoParens ')'		{ $$ = $2; }
			| '(' AlterSnapshotCmdListWithParens ')'	{ $$ = $2; }
		;

AlterSnapshotCmdListNoParens:
			AlterSnapshotCmdOrEmpty { $$ = $1; }
			| AlterSnapshotCmdListNoParens ';' AlterSnapshotCmdOrEmpty { $$ = list_concat($1, $3); }
		;

AlterSnapshotCmdOrEmpty:
			INSERT OptInsertIntoSnapshot insert_rest
				{
					$$ = list_make2(make_node_from_scanbuf(@1, ($2) ? @2 : @3, yyscanner),
									make_node_from_scanbuf(@3, yylloc, yyscanner));
				}
			| UPDATE OptAlterUpdateSnapshot OptSnapshotAlias SET set_clause_list from_clause where_clause
				{
					$$ = list_make1(make_node_from_scanbuf(@1, ($2) ? @2 : ($3) ? @3 : @4, yyscanner));
					if ($3)
						$$ = lappend($$, make_node_from_scanbuf(@3, @4, yyscanner));
					$$ = lappend($$, make_node_from_scanbuf(@4, (@5 == @6) ? ((@5 == @7) ? yylloc : @7) : @6, yyscanner));
					if ($6 != NIL)
						$$ = lappend($$, make_node_from_scanbuf(@6, (@6 == @7) ? yylloc : @7, yyscanner));
					if ($7 != NULL)
						$$ = lappend($$, make_node_from_scanbuf(@7, yylloc, yyscanner));
				}
			| DELETE_P OptDeleteFromSnapshot OptSnapshotAlias using_clause where_clause
				{
					$$ = list_make1(make_node_from_scanbuf(@1, ($2) ? @2 : ($3) ? @3 : (@1 == @4) ? ((@1 == @5) ? yylloc : @5) : @4, yyscanner));
					if ($3)
						$$ = lappend($$, make_node_from_scanbuf(@3, (@3 == @4) ? ((@3 == @5) ? yylloc : @5) : @4, yyscanner));
					if ($4 != NIL)
						$$ = lappend($$, make_node_from_scanbuf(@4, (@4 == @5) ? yylloc : @5, yyscanner));
					if ($5 != NULL)
						$$ = lappend($$, make_node_from_scanbuf(@5, yylloc, yyscanner));
				}
			| ALTER OptAlterUpdateSnapshot AlterSnapshotDdlList
				{
					$$ = list_make2(make_node_from_scanbuf(@1, ($2) ? @2 : @3, yyscanner),
									make_node_from_scanbuf(@3, yylloc, yyscanner));
				}
			| /*EMPTY*/		{ $$ = NIL; }
		;

OptAlterUpdateSnapshot:
			SNAPSHOT		{ $$ = TRUE; }
			| /*EMPTY*/		{ $$ = FALSE; }
		;

OptInsertIntoSnapshot:
			INTO SNAPSHOT	{ $$ = TRUE; }
			| /*EMPTY*/		{ $$ = FALSE; }
		;

OptDeleteFromSnapshot:
			FROM SNAPSHOT	{ $$ = TRUE; }
			| /*EMPTY*/		{ $$ = FALSE; }
		;

OptSnapshotAlias:
			AS ColId		{ $$ = TRUE; }
			| /*EMPTY*/		{ $$ = FALSE; }
		;

AlterSnapshotDdlList:		// parse and ignore
			AlterSnapshotDdl							{ $$ = FALSE; }
			| AlterSnapshotDdlList ',' AlterSnapshotDdl	{ $$ = FALSE; }
		;

AlterSnapshotDdl:			// parse and ignore
			ADD_P opt_column columnDef			{ $$ = FALSE; }
			| DROP opt_column IF_P EXISTS ColId	{ $$ = FALSE; }
			| DROP opt_column ColId				{ $$ = FALSE; }
		;

SnapshotSample:
			AS ColLabel AT RATIO FCONST OptSnapshotComment
			{
				$$ = list_make3(makeStringConst($2, @2), makeStringConst($5, @5), makeStringConst($6, @6));
			}
		;

SnapshotSampleList:
			SnapshotSample { $$ = $1; }
			| SnapshotSampleList ',' SnapshotSample { $$ = list_concat($1, $3); }
		;

OptSnapshotStratify:
			STRATIFY BY column_item_list	{ $$ = $3; }
			| /*EMPTY*/						{ $$ = NIL; }
		;

 /*****************************************************************************
 *
 *        QUERY :
 *                        CREATE MATERIALIZED VIEW relname AS SelectStmt
 *
 *****************************************************************************/

CreateMatViewStmt:
	   CREATE OptNoLog INCREMENTAL MATERIALIZED VIEW create_mv_target AS SelectStmt opt_with_data
			   {
				   CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
				   ctas->query = $8;
				   ctas->into = $6;
				   ctas->relkind = OBJECT_MATVIEW;
				   ctas->is_select_into = false;
				   /* cram additional flags into the IntoClause */
				   $6->rel->relpersistence = $2;
				   $6->skipData = !($9);
				   $6->ivm = true;
                   if ($6->options) {
        				const char* message = "options for incremental materialized views not yet supported";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        ereport(errstate,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                errmsg("options for incremental materialized views not yet supported")));
                   }
#ifndef ENABLE_MULTIPLE_NODES
                   if ($6->distributeby) {
        				const char* message = "It's not supported to specify distribute key on incremental materialized views";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        ereport(errstate,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                errmsg("It's not supported to specify distribute key on incremental materialized views")));
                   }
#endif
				   $$ = (Node *) ctas;
			   }
		| CREATE MATERIALIZED VIEW create_mv_target build_deferred AS SelectStmt
				{
					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
					ctas->query = $7;
					ctas->into = $4;
					ctas->relkind = OBJECT_MATVIEW;
					ctas->is_select_into = false;
					/* cram additional flags into the IntoClause */
					$4->rel->relpersistence = RELPERSISTENCE_PERMANENT;
					$4->skipData = $5;
					$4->ivm = false;
					$$ = (Node *) ctas;
				}
		| CREATE MATERIALIZED VIEW create_mv_target AS SelectStmt opt_with_data
				{
					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
					ctas->query = $6;
					ctas->into = $4;
					ctas->relkind = OBJECT_MATVIEW;
					ctas->is_select_into = false;
					/* cram additional flags into the IntoClause */
					$4->rel->relpersistence = RELPERSISTENCE_PERMANENT;
					$4->skipData = !($7);
					$4->ivm = false;
					$$ = (Node *) ctas;
				}
	   ;

create_mv_target:
		   qualified_name opt_column_list
/* PGXC_BEGIN */
           OptDistributeBy
/* PGXC_END */
		   opt_reloptions OptTableSpace
			   {
				   $$ = makeNode(IntoClause);
				   $$->rel = $1;
				   $$->colNames = $2;
				   $$->options = $4;
				   $$->onCommit = ONCOMMIT_NOOP;
				   $$->tableSpaceName = $5;
				   $$->skipData = false;	   /* might get changed later */
				   $$->ivm = false;
/* PGXC_BEGIN */
                   $$->distributeby = $3;
/* PGXC_END */
				   $$->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
			   }
	   ;

OptNoLog:  UNLOGGED 				   { $$ = RELPERSISTENCE_UNLOGGED; }
		   | /*EMPTY*/				   { $$ = RELPERSISTENCE_PERMANENT; }
	   ;

opt_incremental:
			INCREMENTAL							{ $$ = TRUE; }
			| /*EMPTY*/							{ $$ = FALSE; }
		;

build_deferred:
			BUILD DEFERRED						{ $$ = TRUE; }
			| BUILD IMMEDIATE					{ $$ = FALSE; }
		;

/*****************************************************************************
 *
 *     QUERY :
 *             REFRESH MATERIALIZED VIEW qualified_name
 *
 *****************************************************************************/

RefreshMatViewStmt:
           REFRESH opt_incremental MATERIALIZED VIEW qualified_name opt_with_data
               {
                   RefreshMatViewStmt *n = makeNode(RefreshMatViewStmt);
                   n->relation = $5;
                   n->incremental = $2;
                   n->skipData = !($6);
                   if (n->skipData) {
        				const char* message = "WITH NO DATA for materialized views not yet supported";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                       ereport(errstate,
                           (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						    errmsg("WITH NO DATA for materialized views not yet supported")));
                   }
                   $$ = (Node *) n;
               }
       ;

CreateMatViewLogStmt:
			CREATE MATERIALIZED VIEW LOG_P ON qualified_name
				{
					CreateMatViewLogStmt* stmt = makeNode(CreateMatViewLogStmt);
					stmt->relation = $6;
					$$ = (Node*)stmt;
				}
		;

DropMatViewLogStmt:
			DROP MATERIALIZED VIEW LOG_P ON qualified_name
				{
					DropMatViewLogStmt* stmt = makeNode(DropMatViewLogStmt);
					stmt->relation = $6;
					$$ = (Node*)stmt;
				}
		;

/*****************************************************************************
 *
 *		QUERY :
 *				CREATE SEQUENCE seqname
 *				ALTER SEQUENCE seqname
 *
 *****************************************************************************/

CreateSeqStmt:
			CREATE OptTemp opt_large_seq SEQUENCE qualified_name OptSeqOptList
				{
					CreateSeqStmt *n = makeNode(CreateSeqStmt);
					$5->relpersistence = $2;
					n->is_large = $3;
#ifdef ENABLE_MULTIPLE_NODES
					if (n->is_large) {
        				const char* message = "large sequence is not supported.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("large sequence is not supported.")));
					}
#endif

					n->sequence = $5;
					n->options = $6;
					n->missing_ok = false;
					n->ownerId = InvalidOid;
/* PGXC_BEGIN */
					n->is_serial = false;
/* PGXC_END */
					n->uuid = 0;
					n->canCreateTempSeq = false;
					$$ = (Node *)n;
				}
			| CREATE OptTemp opt_large_seq SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList
				{
					CreateSeqStmt *n = makeNode(CreateSeqStmt);
					$8->relpersistence = $2;
					n->is_large = $3;
#ifdef ENABLE_MULTIPLE_NODES
					if (n->is_large) {
        				const char* message = "large sequence is not supported.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("large sequence is not supported.")));
					}
#endif

					n->sequence = $8;
					n->options = $9;
					n->missing_ok = true;
					n->ownerId = InvalidOid;
/* PGXC_BEGIN */
					n->is_serial = false;
/* PGXC_END */
					n->uuid = 0;
					n->canCreateTempSeq = false;
					$$ = (Node *)n;
				}
		;

AlterSeqStmt:
			ALTER SEQUENCE qualified_name SeqOptList
				{
					AlterSeqStmt *n = makeNode(AlterSeqStmt);
					n->sequence = $3;
					n->options = $4;
					n->missing_ok = false;
/* PGXC_BEGIN */
					n->is_serial = false;
/* PGXC_END */
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE qualified_name SeqOptList
				{
					AlterSeqStmt *n = makeNode(AlterSeqStmt);
					n->is_large = true;
					n->sequence = $4;
					n->options = $5;
					n->missing_ok = false;
/* PGXC_BEGIN */
					n->is_serial = false;
/* PGXC_END */
					$$ = (Node *)n;
				}
			| ALTER SEQUENCE IF_P EXISTS qualified_name SeqOptList
				{
					AlterSeqStmt *n = makeNode(AlterSeqStmt);
					n->sequence = $5;
					n->options = $6;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE IF_P EXISTS qualified_name SeqOptList
				{
					AlterSeqStmt *n = makeNode(AlterSeqStmt);
					n->is_large = true;
					n->sequence = $6;
					n->options = $7;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
		;

opt_large_seq: LARGE_P								{$$ = true; }
			| /*EMPTY*/								{$$ = false; }
		;

OptSeqOptList: SeqOptList							{ $$ = $1; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

SeqOptList: SeqOptElem								{ $$ = list_make1($1); }
			| SeqOptList SeqOptElem					{ $$ = lappend($1, $2); }
		;

SeqOptElem: 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_WITH NumericOnly
				{
					$$ = makeDefElem("start", (Node *)$2);
				}

			| START NumericOnly
				{
					$$ = makeDefElem("start", (Node *)$2);
				}
			| RESTART
				{
					$$ = makeDefElem("restart", NULL);
				}
			| RESTART opt_with NumericOnly
				{
					$$ = makeDefElem("restart", (Node *)$3);
				}
			| NOCYCLE
				{
					$$ = makeDefElem("cycle", (Node *)makeInteger(FALSE));
				}
			| NOMAXVALUE
				{
					$$ = makeDefElem("maxvalue", NULL);
				}
			| NOMINVALUE
				{
					$$ = makeDefElem("minvalue", NULL);
				}
		;

opt_by:		BY				{}
			| /* empty */	{}
	  ;

NumericOnly:
			FCONST								{ $$ = makeFloat($1); }
			| '+' FCONST						{ $$ = makeFloat($2); }
			| '-' FCONST
				{
					$$ = makeFloat($2);
					doNegateFloat($$);
				}
			| SignedIconst						{ $$ = makeInteger($1); }
		;

NumericOnly_list:	NumericOnly						{ $$ = list_make1($1); }
				| NumericOnly_list ',' NumericOnly	{ $$ = lappend($1, $3); }
		;

/*****************************************************************************
 *
 *		QUERIES :
 *				CREATE [OR REPLACE] [TRUSTED] [PROCEDURAL] LANGUAGE ...
 *				DROP [PROCEDURAL] LANGUAGE ...
 *
 *****************************************************************************/

CreatePLangStmt:
			CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
			{
				CreatePLangStmt *n = makeNode(CreatePLangStmt);
				n->replace = $2;
				n->plname = $6;
				/* parameters are all to be supplied by system */
				n->plhandler = NIL;
				n->plinline = NIL;
				n->plvalidator = NIL;
				n->pltrusted = false;
				$$ = (Node *)n;
			}
			| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
			  HANDLER handler_name opt_inline_handler opt_validator
			{
				CreatePLangStmt *n = makeNode(CreatePLangStmt);
				n->replace = $2;
				n->plname = $6;
				n->plhandler = $8;
				n->plinline = $9;
				n->plvalidator = $10;
				n->pltrusted = $3;
				$$ = (Node *)n;
			}
		;

opt_trusted:
			TRUSTED									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

/* This ought to be just func_name, but that causes reduce/reduce conflicts
 * (CREATE LANGUAGE is the only place where func_name isn't followed by '(').
 * Work around by using simple names, instead.
 */
handler_name:
			name						{ $$ = list_make1(makeString($1)); }
			| name attrs				{ $$ = lcons(makeString($1), $2); }
		;

opt_inline_handler:
			INLINE_P handler_name					{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

validator_clause:
			VALIDATOR handler_name					{ $$ = $2; }
			| NO VALIDATOR							{ $$ = NIL; }
		;

opt_validator:
			validator_clause						{ $$ = $1; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

DropPLangStmt:
			DROP opt_procedural LANGUAGE ColId_or_Sconst opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_LANGUAGE;
					n->objects = list_make1(list_make1(makeString($4)));
					n->arguments = NIL;
					n->behavior = $5;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *)n;
				}
			| DROP opt_procedural LANGUAGE IF_P EXISTS ColId_or_Sconst opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_LANGUAGE;
					n->objects = list_make1(list_make1(makeString($6)));
					n->behavior = $7;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *)n;
				}
		;

opt_procedural:
			PROCEDURAL								{}
			| /*EMPTY*/								{}
		;

tblspc_options:
			'(' tblspc_option_list ')'					{ $$ = $2; }
		;
opt_tblspc_options:		WITH tblspc_options					{ $$ = $2; }
			 |	/* EMPTY */						{ $$ = NIL; }
		;

tblspc_option_list:
			tblspc_option_elem						{ $$ = list_make1($1); }
			| tblspc_option_list ',' tblspc_option_elem			{ $$ = lappend($1, $3); }
		;

tblspc_option_elem:
			ColLabel '=' Sconst
			{
				$$ = makeDefElem($1, (Node *) makeString($3));
			}
			| ColLabel '=' func_type
			{
				if(0 != pg_strcasecmp($1, "filesystem"))
				{
        			const char* message = "Must use single quoted string for option";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("Must use single quoted string for \"%s\" option.", $1)));
				}
				$$ = makeDefElem($1, (Node *) $3);
			}
			| ColLabel '=' NumericOnly
			{
				$$ = makeDefElem($1, (Node *) $3);
			}
		;
/*****************************************************************************
 *
 *		QUERY:
 *             CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
 *
 *****************************************************************************/

CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner OptRelative LOCATION Sconst OptMaxSize opt_tblspc_options
				{
					CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
					n->tablespacename = $3;
					n->owner = $4;
					n->location = $7;
					n->maxsize = $8;
					n->options = $9;
					n->relative = $5;
					$$ = (Node *) n;
				}
				| CREATE TABLESPACE name LoggingStr DATAFILE Sconst OptDatafileSize OptReuse OptAuto
				{
					CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
					n->tablespacename = $3;
					n->owner = NULL;
					n->location = $6;
					n->maxsize = $7;
					$$ = (Node *) n;
				}
				| CREATE TABLESPACE name DATAFILE Sconst OptDatafileSize OptReuse OptAuto LoggingStr
				{
					CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
					n->tablespacename = $3;
					n->owner = NULL;
					n->location = $5;
					n->maxsize = $6;
					$$ = (Node *) n;
				}
				| CREATE TABLESPACE name DATAFILE Sconst OptDatafileSize OptReuse OptAuto
				{
					CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
					n->tablespacename = $3;
					n->owner = NULL;
					n->location = $5;
					n->maxsize = $6;
					$$ = (Node *) n;
				}
		;

LoggingStr:
			LOGGING									{ $$ = NULL ;}
			| NOLOGGING								{ $$ = NULL ;}
		;

OptDatafileSize:
			SIZE Iconst IDENT 							{ $$ = NULL; }
			| /*EMPTY */								{ $$ = NULL; }
		;

OptReuse:
			REUSE									{ $$ = NULL; }
			| /*EMPTY */								{ $$ = NULL; }
		;

OptAuto:
			AUTOEXTEND ON OptNextStr OptMaxSize					{ $$ = NULL; }
			| AUTOEXTEND OFF							{ $$ = NULL; }
			| /*EMPTY */								{ $$ = NULL; }
		;

OptNextStr:
			NEXT Iconst IDENT							{ $$ = NULL; }
			| /*EMPTY */								{ $$ = NULL; }
		;

OptMaxSize:
			MAXSIZE Sconst								{ $$ = $2; }
 			| /*EMPTY */								{  $$ = NULL;}
		;
size_clause:
			Sconst						        		{ $$ = $1; }
			| UNLIMITED                                 { $$ = "unlimited"; }
			;

OptRelative:
			RELATIVE_P									{ $$ = true; }
			| /*EMPTY */	 							{ $$ = false; }
		;

OptTableSpaceOwner: OWNER name			{ $$ = $2; }
			| /*EMPTY */				{ $$ = NULL; }
		;

/*****************************************************************************
 *
 *		QUERY :
 *				DROP TABLESPACE <tablespace>
 *
 *		No need for drop behaviour as we cannot implement dependencies for
 *		objects in other databases; we can only support RESTRICT.
 *
 ****************************************************************************/

DropTableSpaceStmt: DROP TABLESPACE name
				{
					DropTableSpaceStmt *n = makeNode(DropTableSpaceStmt);
					n->tablespacename = $3;
					n->missing_ok = false;
					$$ = (Node *) n;
				}
				|  DROP TABLESPACE IF_P EXISTS name
				{
					DropTableSpaceStmt *n = makeNode(DropTableSpaceStmt);
					n->tablespacename = $5;
					n->missing_ok = true;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *             CREATE EXTENSION extension
 *             [ WITH ] [ SCHEMA schema ] [ VERSION version ] [ FROM oldversion ]
 *
 *****************************************************************************/

CreateExtensionStmt: CREATE EXTENSION name opt_with create_extension_opt_list
				{
					CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
					n->extname = $3;
					n->if_not_exists = false;
					n->options = $5;
					$$ = (Node *) n;
				}
				| CREATE EXTENSION IF_P NOT EXISTS name opt_with create_extension_opt_list
				{
					CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
					n->extname = $6;
					n->if_not_exists = true;
					n->options = $8;
					$$ = (Node *) n;
				}
		;

create_extension_opt_list:
			create_extension_opt_list create_extension_opt_item
				{ $$ = lappend($1, $2); }
			| /* EMPTY */
				{ $$ = NIL; }
		;

create_extension_opt_item:
			SCHEMA name
				{
					$$ = makeDefElem("schema", (Node *)makeString($2));
				}
			| VERSION_P ColId_or_Sconst
				{
					$$ = makeDefElem("new_version", (Node *)makeString($2));
				}
			| FROM ColId_or_Sconst
				{
					$$ = makeDefElem("old_version", (Node *)makeString($2));
				}
		;
/*****************************************************************************
 *
 *		QUERY:
 *             CREATE OR REPLACE DIRECTORY directory AS '/path/to/directory/'
 *
 *****************************************************************************/

CreateDirectoryStmt:  CREATE opt_or_replace DIRECTORY name AS Sconst
				{
					CreateDirectoryStmt *n = makeNode(CreateDirectoryStmt);
					n->replace = $2;
					n->directoryname = $4;
					n->location = $6;
					n->owner = NULL;
					$$ = (Node *)n;
				}
	       	;

/*****************************************************************************
 *
 *		QUERY :
 *				DROP DIRECTORY [IF EXISTS] directory
 *
 ****************************************************************************/

DropDirectoryStmt: DROP DIRECTORY name
				{
					DropDirectoryStmt *n = makeNode(DropDirectoryStmt);
					n->directoryname = $3;
					n->missing_ok = false;
					$$ = (Node *) n;
				}
		 | DROP DIRECTORY IF_P EXISTS name
                                { 
					DropDirectoryStmt *n = makeNode(DropDirectoryStmt);
					n->directoryname = $5;
					n->missing_ok = true;
					$$ = (Node *) n;
                                }
		;

/*****************************************************************************
 *
 * ALTER EXTENSION name UPDATE [ TO version ]
 *
 *****************************************************************************/

AlterExtensionStmt: ALTER EXTENSION name UPDATE alter_extension_opt_list
				{
					AlterExtensionStmt *n = makeNode(AlterExtensionStmt);
					n->extname = $3;
					n->options = $5;
					$$ = (Node *) n;
				}
		;

alter_extension_opt_list:
			alter_extension_opt_list alter_extension_opt_item
				{ $$ = lappend($1, $2); }
			| /* EMPTY */
				{ $$ = NIL; }
		;

alter_extension_opt_item:
			TO ColId_or_Sconst
				{
					$$ = makeDefElem("new_version", (Node *)makeString($2));
				}
		;

/*****************************************************************************
 *
 * ALTER EXTENSION name ADD/DROP object-identifier
 *
 *****************************************************************************/

AlterExtensionContentsStmt:
			ALTER EXTENSION name add_drop AGGREGATE func_name aggr_args
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_AGGREGATE;
					n->objname = $6;
					n->objargs = $7;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop EVENT_TRIGGER name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_EVENT_TRIGGER;
					n->objname = list_make1(makeString($6));
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')'
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_CAST;
					n->objname = list_make1($7);
					n->objargs = list_make1($9);
					$$ = (Node *) n;
				}
			| ALTER EXTENSION name add_drop COLLATION any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_COLLATION;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop CONVERSION_P any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_CONVERSION;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop DOMAIN_P any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_DOMAIN;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop FUNCTION function_with_argtypes
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_FUNCTION;
					n->objname = $6->funcname;
					n->objargs = $6->funcargs;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop opt_procedural LANGUAGE name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_LANGUAGE;
					n->objname = list_make1(makeString($7));
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop OPERATOR any_operator oper_argtypes
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_OPERATOR;
					n->objname = $6;
					n->objargs = $7;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING access_method
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_OPCLASS;
					n->objname = lcons(makeString($9), $7);
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_OPFAMILY;
					n->objname = lcons(makeString($9), $7);
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop SCHEMA name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_SCHEMA;
					n->objname = list_make1(makeString($6));
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TABLE any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TABLE;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TEXT_P SEARCH PARSER any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TSPARSER;
					n->objname = $8;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TEXT_P SEARCH DICTIONARY any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TSDICTIONARY;
					n->objname = $8;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TEXT_P SEARCH TEMPLATE any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TSTEMPLATE;
					n->objname = $8;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TEXT_P SEARCH CONFIGURATION any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TSCONFIGURATION;
					n->objname = $8;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop SEQUENCE any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_SEQUENCE;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop VIEW any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_VIEW;
					n->objname = $6;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop MATERIALIZED VIEW any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_MATVIEW;
					n->objname = $7;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop FOREIGN TABLE any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_FOREIGN_TABLE;
					n->objname = $7;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop FOREIGN DATA_P WRAPPER name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_FDW;
					n->objname = list_make1(makeString($8));
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop SERVER name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_FOREIGN_SERVER;
					n->objname = list_make1(makeString($6));
					$$ = (Node *)n;
				}
			| ALTER EXTENSION name add_drop TYPE_P any_name
				{
					AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
					n->extname = $3;
					n->action = $4;
					n->objtype = OBJECT_TYPE;
					n->objname = $6;
					$$ = (Node *)n;
				}
		;
/*****************************************************************************
 *
 *             QUERY:
 *             CREATE WEAK PASSWORD DICTIONARY
 *
 *****************************************************************************/

CreateWeakPasswordDictionaryStmt:
        CREATE WEAK PASSWORD DICTIONARY opt_vals {u_sess->parser_cxt.isForbidTruncate = true;} weak_password_string_list
               {
                       u_sess->parser_cxt.isForbidTruncate = false;
                       CreateWeakPasswordDictionaryStmt *n = makeNode(CreateWeakPasswordDictionaryStmt);
                       n->weak_password_string_list = $7;
                       $$ = (Node*)n;
               }
			   ;

opt_vals:               WITH VALUES                                            {}
                       | /*EMPTY*/                                             {}
			   ;

weak_password_string_list:  '(' password_string ')'                                 { $$ = list_make1(makeString($2)); }
                       | weak_password_string_list ',' '(' password_string ')'      { $$ = lappend($1, makeString($4)); } 
               ;

/*****************************************************************************
 *
 *		QUERY:
 *				DROP WEAK PASSWORD DICTIONARY
 *
 *****************************************************************************/

DropWeakPasswordDictionaryStmt:
			DROP WEAK PASSWORD DICTIONARY 
				{
					DropWeakPasswordDictionaryStmt *n = makeNode(DropWeakPasswordDictionaryStmt);
					$$ = (Node *)n;
				}
		;
					
/*****************************************************************************
 *
 *		QUERY:
 *             CREATE FOREIGN DATA WRAPPER name options
 *
 *****************************************************************************/

CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name opt_fdw_options create_generic_options
				{
					CreateFdwStmt *n = makeNode(CreateFdwStmt);
					n->fdwname = $5;
					n->func_options = $6;
					n->options = $7;
					$$ = (Node *) n;
				}
		;

fdw_option:
			HANDLER handler_name				{ $$ = makeDefElem("handler", (Node *)$2); }
			| NO HANDLER						{ $$ = makeDefElem("handler", NULL); }
			| VALIDATOR handler_name			{ $$ = makeDefElem("validator", (Node *)$2); }
			| NO VALIDATOR						{ $$ = makeDefElem("validator", NULL); }
		;

fdw_options:
			fdw_option							{ $$ = list_make1($1); }
			| fdw_options fdw_option			{ $$ = lappend($1, $2); }
		;

opt_fdw_options:
			fdw_options							{ $$ = $1; }
			| /*EMPTY*/							{ $$ = NIL; }
		;

/*****************************************************************************
 *
 *		QUERY :
 *				DROP FOREIGN DATA WRAPPER name
 *
 ****************************************************************************/

DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FDW;
					n->objects = list_make1(list_make1(makeString($5)));
					n->arguments = NIL;
					n->missing_ok = false;
					n->behavior = $6;
					n->concurrent = false;
					$$ = (Node *) n;
				}
				|  DROP FOREIGN DATA_P WRAPPER IF_P EXISTS name opt_drop_behavior
                {
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FDW;
					n->objects = list_make1(list_make1(makeString($7)));
					n->arguments = NIL;
					n->missing_ok = true;
					n->behavior = $8;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY :
 *				ALTER FOREIGN DATA WRAPPER name options
 *
 ****************************************************************************/

AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name opt_fdw_options alter_generic_options
				{
					AlterFdwStmt *n = makeNode(AlterFdwStmt);
					n->fdwname = $5;
					n->func_options = $6;
					n->options = $7;
					$$ = (Node *) n;
				}
			| ALTER FOREIGN DATA_P WRAPPER name fdw_options
				{
					AlterFdwStmt *n = makeNode(AlterFdwStmt);
					n->fdwname = $5;
					n->func_options = $6;
					n->options = NIL;
					$$ = (Node *) n;
				}
		;

/* Options definition for CREATE FDW, SERVER and USER MAPPING */
create_generic_options:
			OPTIONS '(' generic_option_list ')'			{ $$ = $3; }
			| /*EMPTY*/									{ $$ = NIL; }
		;

generic_option_list:
			generic_option_elem
				{
					$$ = list_make1($1);
				}
			| generic_option_list ',' generic_option_elem
				{
					$$ = lappend($1, $3);
				}
		;

/* Options definition for ALTER FDW, SERVER and USER MAPPING */
alter_generic_options:
			OPTIONS	'(' alter_generic_option_list ')'		{ $$ = $3; }
		;

alter_generic_option_list:
			alter_generic_option_elem
				{
					$$ = list_make1($1);
				}
			| alter_generic_option_list ',' alter_generic_option_elem
				{
					$$ = lappend($1, $3);
				}
		;

alter_generic_option_elem:
			generic_option_elem
				{
					$$ = $1;
				}
			| SET generic_option_elem
				{
					$$ = $2;
					$$->defaction = DEFELEM_SET;
				}
			| ADD_P generic_option_elem
				{
					$$ = $2;
					$$->defaction = DEFELEM_ADD;
				}
			| DROP generic_option_name
				{
					$$ = makeDefElemExtended(NULL, $2, NULL, DEFELEM_DROP);
				}
		;

generic_option_elem:
			generic_option_name generic_option_arg
				{
                    if (strcmp($1, "error_table") == 0) {
        				const char* message = "Invalid option";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                        ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("Invalid option %s", $1)));
					}

					$$ = 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]
 *
 *****************************************************************************/
fdwName:    IDENT           {$$ = $1;};

CreateForeignServerStmt: CREATE SERVER name opt_type opt_foreign_server_version
						 FOREIGN DATA_P WRAPPER fdwName create_generic_options
				{
					CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt);
					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
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FOREIGN_SERVER;
					n->objects = list_make1(list_make1(makeString($3)));
					n->arguments = NIL;
					n->missing_ok = false;
					n->behavior = $4;
					n->concurrent = false;
					$$ = (Node *) n;
				}
				|  DROP SERVER IF_P EXISTS name opt_drop_behavior
                {
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FOREIGN_SERVER;
					n->objects = list_make1(list_make1(makeString($5)));
					n->arguments = NIL;
					n->missing_ok = true;
					n->behavior = $6;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY :
 *				ALTER SERVER name [VERSION] [OPTIONS]
 *
 ****************************************************************************/

AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_options
				{
					AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
					n->servername = $3;
					n->version = $4;
					n->options = $5;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER SERVER name foreign_server_version
				{
					AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
					n->servername = $3;
					n->version = $4;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER SERVER name alter_generic_options
				{
					AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
					n->servername = $3;
					n->options = $4;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *             CREATE FOREIGN TABLE relname (...) SERVER name (...)
 *
 *****************************************************************************/

CreateForeignTableStmt:
		CREATE FOREIGN TABLE qualified_name
			OptForeignTableElementList
			SERVER name create_generic_options ForeignTblWritable
			OptForeignTableLogError OptForeignTableLogRemote OptPerNodeRejectLimit OptDistributeBy
/* PGXC_BEGIN */
			OptSubCluster
/* PGXC_END */
			OptForeignPartBy
				{
					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
					$4->relpersistence = RELPERSISTENCE_PERMANENT;
					n->base.relation = $4;
					n->base.tableElts = $5;
					n->base.inhRelations = NIL;
					n->base.if_not_exists = false;
					/* FDW-specific data */
					n->servername = $7;
					n->options = $8;

					n->write_only = $9;
					n->error_relation = (Node*)$10;
					if ($11 != NULL)
						n->extOptions = lappend(n->extOptions, $11);
					if ($12 != NULL)
						n->extOptions = lappend(n->extOptions, $12);
					n->base.distributeby = $13;
/* PGXC_BEGIN */
					n->base.subcluster = $14;
/* PGXC_END */
					if ($15 != NULL)
						n->part_state = $15;

					$$ = (Node *) n;
				}
		| CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name
			OptForeignTableElementList
			SERVER name create_generic_options ForeignTblWritable
			OptForeignTableLogError OptForeignTableLogRemote OptPerNodeRejectLimit OptDistributeBy
/* PGXC_BEGIN */
			OptSubCluster
/* PGXC_END */
			OptForeignPartBy
				{
					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
					$7->relpersistence = RELPERSISTENCE_PERMANENT;
					n->base.relation = $7;
					n->base.tableElts = $8;
					n->base.inhRelations = NIL;
					n->base.if_not_exists = true;
					/* FDW-specific data */
					n->servername = $10;
					n->options = $11;

					n->write_only = $12;
					n->error_relation = (Node*)$13;
					if ($14 != NULL)
						n->extOptions = lappend(n->extOptions, $14);
					if ($15 != NULL)
						n->extOptions = lappend(n->extOptions, $15);
					n->base.distributeby = $16;
/* PGXC_BEGIN */
					n->base.subcluster = $17;
/* PGXC_END */
					if ($18 != NULL)
						n->part_state = $18;

					$$ = (Node *) n;
				}
/* ENABLE_MOT BEGIN */
                | CREATE FOREIGN TABLE qualified_name
			OptForeignTableElementList
			create_generic_options ForeignTblWritable
			OptForeignTableLogError OptForeignTableLogRemote OptPerNodeRejectLimit OptDistributeBy
/* PGXC_BEGIN */
			OptSubCluster
/* PGXC_END */
			OptForeignPartBy
				{
					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
					$4->relpersistence = RELPERSISTENCE_PERMANENT;
					n->base.relation = $4;
					n->base.tableElts = $5;
					n->base.inhRelations = NIL;
					n->base.if_not_exists = false;
					/* FDW-specific data */
#ifdef ENABLE_MOT
					n->servername = pstrdup("mot_server");
#else
        			const char* message = "Foreign server is not specified";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                    ereport(errstate,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("Foreign server is not specified")));
#endif
					n->options = $6;

					n->write_only = $7;
					n->error_relation = (Node*)$8;
					if ($9 != NULL)
						n->extOptions = lappend(n->extOptions, $9);
					if ($10 != NULL)
						n->extOptions = lappend(n->extOptions, $10);
					n->base.distributeby = $11;
/* PGXC_BEGIN */
					n->base.subcluster = $12;
/* PGXC_END */
					if ($13 != NULL)
						n->part_state = $13;

					$$ = (Node *) n;
				}
               | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name
			OptForeignTableElementList
			create_generic_options ForeignTblWritable
			OptForeignTableLogError OptForeignTableLogRemote OptPerNodeRejectLimit OptDistributeBy
/* PGXC_BEGIN */
			OptSubCluster
/* PGXC_END */
			OptForeignPartBy
				{
					CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt);
					$7->relpersistence = RELPERSISTENCE_PERMANENT;
					n->base.relation = $7;
					n->base.tableElts = $8;
					n->base.inhRelations = NIL;
					n->base.if_not_exists = true;
					/* FDW-specific data */
#ifdef ENABLE_MOT
					n->servername = pstrdup("mot_server");
#else
        			const char* message = "Foreign server is not specified";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                    ereport(errstate,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("Foreign server is not specified")));
#endif
					n->options = $9;

					n->write_only = $10;
					n->error_relation = (Node*)$11;
					if ($12 != NULL)
						n->extOptions = lappend(n->extOptions, $12);
					if ($13 != NULL)
						n->extOptions = lappend(n->extOptions, $13);
					n->base.distributeby = $14;
/* PGXC_BEGIN */
					n->base.subcluster = $15;
/* PGXC_END */
					if ($16 != NULL)
						n->part_state = $16;

					$$ = (Node *) n;
				}
/* ENABLE_MOT END */
		;

ForeignTblWritable : WRITE ONLY  { $$ = true; }
					| READ ONLY   { $$ = false; }
					| /* EMPTY */ { $$ = false; }
				;

OptForeignTableElementList:
					'(' ForeignTableElementList ')'			{ $$ = $2; }
					| '(' ')'								{ $$ = NIL; }
				;

ForeignTableElementList:
				ForeignTableElement
					{
						$$ = list_make1($1);
					}
				| ForeignTableElementList ',' ForeignTableElement
					{
						$$ = lappend($1, $3);
					}
			;

ForeignTableElement:
			ForeignColDef				    { $$ = $1; }
			| ForeignTableLikeClause			{ $$ = $1; }
			| TableConstraint			    { $$ = $1; } /* @hdfs Add informational constraint syntax on the HDFS foreign table. */
		;
ForeignColDef: ColId Typename ForeignPosition create_generic_options  ColQualList
				{
					ColumnDef *n = makeNode(ColumnDef);
					n->colname = $1;
					n->typname = $2;
					n->inhcount = 0;
					n->is_local = true;
					n->is_not_null = false;
					n->is_from_type = false;
					n->storage = 0;
					n->raw_default = NULL;
					n->cooked_default = NULL;
					n->collOid = InvalidOid;
					n->fdwoptions = $4;
					n->clientLogicColumnRef=NULL;
					SplitColQualList($5, &n->constraints, &n->collClause,
										yyscanner);
					if ($3)
					{
						((Position*)$3)->colname = pstrdup($1);
						n->position = (Position*)$3;
					}
					$$ = (Node*)n;
				}
		;

ForeignPosition:
			POSITION '(' Iconst ',' Iconst ')'
				{
					Position *n = makeNode(Position);
					n->position = $3;
					n->fixedlen = $5;
					$$ = (Node*)n;
				}
			| /*EMPTY*/ 								{ $$ = NULL; }
		;

ForeignTableLikeClause:
			LIKE qualified_name				
				{					
					TableLikeClause *n = makeNode(TableLikeClause);
					n->relation = $2;
					$$ = (Node *)n;
				}
		;	

OptForeignTableLogError:
			LOG_P INTO qualified_name 	{ $$ = (Node*)$3; }
			| WITH  qualified_name 		{ $$ = (Node*)$2; }
			| /*EMPTY*/ 				{ $$ = NULL;}
		;

OptForeignTableLogRemote:
			REMOTE_P LOG_P Sconst
				{
					$$ = (Node*)makeDefElem("log_remote", (Node *)makeString($3));
				}
			| REMOTE_P LOG_P
				{
					$$ = (Node*)makeDefElem("log_remote", (Node*)makeString(""));
				}
			| /* EMPTY */				{ $$ = NULL; }
		;

OptPerNodeRejectLimit:
			PER_P NODE REJECT_P LIMIT Sconst
				{
					$$ = (Node*)makeDefElem("reject_limit", (Node*)makeString($5));
				}
			| /*EMPTY*/ 					{ $$ = NULL; }
		;

OptForeignPartBy:
			OptForeignPartAuto          { $$ = $1; }
			| /*EMPTY*/                 { $$ = NULL; }
		;

OptForeignPartAuto: PARTITION BY '(' partition_item_list ')' AUTOMAPPED
			{
				ForeignPartState *n = makeNode(ForeignPartState);
				n->partitionKey = $4;
				$$ = n;
			}
		| PARTITION BY '(' partition_item_list ')'
			{
				ForeignPartState *n = makeNode(ForeignPartState);
				n->partitionKey = $4;
				$$ = n;
			}
		;

partition_item_list:
		partition_item
			{
				$$ = list_make1($1);
			}
		| partition_item_list ',' partition_item
			{
				$$ = lappend($1, $3);
			}
		;

partition_item:
		ColId
			{
				$$ = makeColumnRef($1, NIL, @1, yyscanner);
			}
		;

/*****************************************************************************
 *
 *		QUERY:
 *             ALTER FOREIGN TABLE relname [...]
 *
 *****************************************************************************/

AlterForeignTableStmt:
			ALTER FOREIGN TABLE relation_expr alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $4;
					n->cmds = $5;
					n->relkind = OBJECT_FOREIGN_TABLE;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN TABLE IF_P EXISTS relation_expr alter_table_cmds
				{
					AlterTableStmt *n = makeNode(AlterTableStmt);
					n->relation = $6;
					n->cmds = $7;
					n->relkind = OBJECT_FOREIGN_TABLE;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
            | ALTER FOREIGN TABLE relation_expr MODIFY_P '(' modify_column_cmds ')'
                {
                    AlterTableStmt *n = makeNode(AlterTableStmt);
                    n->relation = $4;
                    n->cmds = $7;
                    n->relkind = OBJECT_FOREIGN_TABLE;
                    n->missing_ok = false;
                    $$ = (Node *)n;
                }
            | ALTER FOREIGN TABLE IF_P EXISTS relation_expr MODIFY_P '(' modify_column_cmds ')'
                {
                    AlterTableStmt *n = makeNode(AlterTableStmt);
                    n->relation = $6;
                    n->cmds = $9;
                    n->relkind = OBJECT_FOREIGN_TABLE;
                    n->missing_ok = true;
                    $$ = (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;
				}
		;


/*****************************************************************************
 *
 *		QUERY:
 *				CREATE MODEL <model_name>
 *
 *
 *****************************************************************************/


CreateModelStmt:
		CREATE MODEL ColId
		USING ColId
		features_clause
		target_clause
		from_clause
		with_hyperparameters_clause
	{
		CreateModelStmt *n = makeNode(CreateModelStmt);
		n->model 			= pstrdup($3);
		n->architecture 	= pstrdup($5);
		n->model_features 	= $6;
		n->model_target   	= $7;

		// The clause will be constructed in tranform
		SelectStmt *s = makeNode(SelectStmt);
		s->fromClause = $8;	

		n->select_query = (Node*) s;
		n->hyperparameters  = $9;

		$$ = (Node*) n;
	}
	;

features_clause:
	FEATURES target_list{
		List* result = $2;

		// Verify that target clause is not '*'
		foreach_cell(it, result){
			ResTarget* n = (ResTarget*) lfirst(it);
			ColumnRef* cr = (n->val != NULL && IsA(n->val, ColumnRef)) ? (ColumnRef*)(n->val) : NULL;
			List* l = (cr != NULL) ? cr->fields : NULL;
			Node* node = list_length(l) > 0 ? linitial_node(Node, l) : NULL;
			if (node != NULL && IsA(node, A_Star)){
				elog(errstate, "FEATURES clause cannot be *");
			}		
		}

		$$ = result;
	}
	| {
		List* result = NULL;
		$$ = result;
	}
	;

target_clause:
	TARGET target_list{
		List* result = $2;

		// Verify that target clause is not '*'
		foreach_cell(it, result){
			ResTarget* n = (ResTarget*) lfirst(it);
			ColumnRef* cr = (n->val != NULL && IsA(n->val, ColumnRef)) ? (ColumnRef*)(n->val) : NULL;
			List* l = (cr != NULL) ? cr->fields : NULL;
			Node* node = list_length(l) > 0 ? linitial_node(Node, l) : NULL;
			if (node != NULL && IsA(node, A_Star)){
				elog(errstate, "TARGET clause cannot be *");
			}
		}

		$$ = result;
	}
	| {
		List* result = NULL;
		$$ = result;
	}
	;

with_hyperparameters_clause:
	WITH hyperparameter_name_value_list { $$ = $2; }
	| { $$ = NULL; }
	;

hyperparameter_name_value_list:
	hyperparameter_name_value		{ $$ = list_make1($1); }
	| hyperparameter_name_value_list ',' hyperparameter_name_value
	{
		$$ = lappend($1,$3);
	}
	;

hyperparameter_name_value:
	ColLabel '=' var_value
	{
		VariableSetStmt *n = makeNode(VariableSetStmt);
		n->kind = VAR_SET_VALUE;
		n->name = $1;
		n->args = list_make1($3);
		$$ = (Node*) n;
	}
	| ColLabel '=' DEFAULT
	{
		VariableSetStmt *n = makeNode(VariableSetStmt);
		n->kind = VAR_SET_DEFAULT;
		n->name = $1;
		n->args = NULL;
		$$ = (Node*) n;
	}
	;

DropModelStmt:
	DROP MODEL ColId opt_drop_behavior
	{
		DropStmt *n = makeNode(DropStmt);
		n->removeType = OBJECT_DB4AI_MODEL;
		n->objects = list_make1(list_make1(makeString($3)));
		n->arguments = NULL;
		n->behavior = $4;
		n->missing_ok = false;
		n->concurrent = false;
		n->isProcedure = false;
		$$ = (Node *)n;
	};

/*****************************************************************************
 *
 *      QUERIES For ROW LEVEL SECURITY:
 *              CREATE [ROW LEVEL SECURITY] POLICY name ON table
 *                  [AS { PERMISSIVE | RESTRICTIVE }]
 *                  [FOR { ALL | SELECT | INSERT | UPDATE | DELETE }]
 *                  [TO role, ...]
 *                  [USING (qual)]
 *
 *              ALTER [ROW LEVEL SECURITY] POLICY name ON table
 *                  [TO role, ...]
 *                  [USING (qual)]
 *
 *              DROP [ROW LEVEL SECURITY] POLIICY [IF EXISTS] name ON table [CASCADE | RESTRICT]
 *
 *****************************************************************************/

CreateRlsPolicyStmt:
			CREATE RowLevelSecurityPolicyName ON qualified_name RLSDefaultPermissive
				RLSDefaultForCmd RLSDefaultToRole
				RLSOptionalUsingExpr
				{
					/* Did not support INSERT, MERGE yet */
					if (strcmp($6, "insert") == 0 ||
						strcmp($6, "merge") == 0)
					{
        				const char* message = "Row Level Security is not yet supported for INSERT and MERGE";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("Row Level Security is not yet supported for INSERT and MERGE")));
					}
					CreateRlsPolicyStmt *n = makeNode(CreateRlsPolicyStmt);
					n->fromExternal = true;
					n->policyName = $2;
					n->relation = $4;
					n->isPermissive = $5;
					n->cmdName = $6;
					n->roleList = $7;
					n->usingQual = $8;
					$$ = (Node *) n;
				}
		;

AlterRlsPolicyStmt:
			ALTER RowLevelSecurityPolicyName ON qualified_name RLSOptionalToRole
				RLSOptionalUsingExpr
				{
					AlterRlsPolicyStmt *n = makeNode(AlterRlsPolicyStmt);
					n->policyName = $2;
					n->relation = $4;
					n->roleList = $5;
					n->usingQual = $6;
					$$ = (Node *) n;
				}
		;

DropRlsPolicyStmt:
			DROP RowLevelSecurityPolicyName ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_RLSPOLICY;
					n->objects = list_make1(lappend($4, makeString($2)));
					n->arguments = NIL;
					n->behavior = $5;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP POLICY IF_P EXISTS name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_RLSPOLICY;
					n->objects = list_make1(lappend($7, makeString($5)));
					n->arguments = NIL;
					n->behavior = $8;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP ROW LEVEL SECURITY POLICY IF_P EXISTS name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_RLSPOLICY;
					n->objects = list_make1(lappend($10, makeString($8)));
					n->arguments = NIL;
					n->behavior = $11;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;

RowLevelSecurityPolicyName:
			ROW LEVEL SECURITY POLICY name	{ $$ = $5; }
			| POLICY name						{ $$ = $2; }
		;

RLSOptionalUsingExpr:
			USING '(' a_expr ')'	{ $$ = $3; }
			| /* EMPTY */			{ $$ = NULL; }
		;

RLSDefaultToRole:
			TO row_level_security_role_list			{ $$ = $2; }
			| /* EMPTY */			{ $$ = list_make1(makeString("public")); }
		;

RLSOptionalToRole:
			TO row_level_security_role_list			{ $$ = $2; }
			| /* EMPTY */			{ $$ = NULL; }
		;

row_level_security_role_list: row_level_security_role
							{ $$ = list_make1(makeString($1)); }
					|	row_level_security_role_list ',' row_level_security_role
							{ $$ = lappend($1, makeString($3)); }
					;

row_level_security_role:
			RoleId			{ $$ = $1; }
		|	CURRENT_USER	{ $$ = pstrdup($1); }
		|	SESSION_USER	{ $$ = pstrdup($1); }
		;

RLSDefaultPermissive:
			AS IDENT
				{
					if (strcmp($2, "permissive") == 0)
						$$ = true;
					else if (strcmp($2, "restrictive") == 0)
						$$ = false;
					else {
        				const char* message = "unrecognized row security option";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
							 errmsg("unrecognized row security option \"%s\"", $2),
								 errhint("Only PERMISSIVE or RESTRICTIVE policies are supported currently."),
									 parser_errposition(@2)));
					}
				}
			| /* EMPTY */			{ $$ = true; }
		;

RLSDefaultForCmd:
			FOR row_level_security_cmd	{ $$ = $2; }
			| /* EMPTY */			{ $$ = "all"; }
		;

row_level_security_cmd:
			ALL				{ $$ = "all"; }
		|	SELECT			{ $$ = "select"; }
		|	UPDATE			{ $$ = "update"; }
		|	DELETE_P		{ $$ = "delete"; }
		|	INSERT			{ $$ = "insert"; }
		|	MERGE			{ $$ = "merge"; }
		;

/*****************************************************************************
 *
 *		QUERIES:
 *				CREATE OR REPLACE SYNONYM STATEMENTS
 *
 *****************************************************************************/

CreateSynonymStmt:
			CREATE opt_or_replace opt_public SYNONYM any_name FOR any_name
				{
					bool isPublic = $3;
					if (isPublic && list_length($5) != 1) {
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("missing or invalid synonym identifier")));
					}
					CreateSynonymStmt *n = makeNode(CreateSynonymStmt);
					List *anyname = $5;
					n->replace = $2;
					n->isPublic = isPublic;
					n->synName = $5;
					n->objName = $7;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERIES:
 *				DROP SYNONYM STATEMENTS
 *
 *****************************************************************************/

DropSynonymStmt:
			DROP opt_public SYNONYM any_name  opt_drop_behavior
				{
					bool isPublic = $2;
					List *synName = $4;
					if (isPublic && list_length(synName) != 1) {
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("missing or invalid synonym identifier")));
					}
					DropSynonymStmt *n = makeNode(DropSynonymStmt);
					n->isPublic = $2;
					n->synName = synName;
					n->behavior = $5;
					n->missing = false;
					$$ = (Node *) n;
				}
			| DROP opt_public SYNONYM IF_P EXISTS any_name  opt_drop_behavior
				{
					bool isPublic = $2;
					List *synName = $6;
					if (isPublic && list_length(synName) != 1) {
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("missing or invalid synonym identifier")));
					}
					
					DropSynonymStmt *n = makeNode(DropSynonymStmt);
					n->isPublic = isPublic;
					n->synName = synName;
					n->behavior = $7;
					n->missing = true;
					$$ = (Node *) n;
				}
		;


opt_public:
		IDENT
		{ 
			if (strcasecmp($1, "public") == 0) {
				$$ = true;
			} else {
				yychar = IDENT;
				$$ = false;
			}
		}
		| /*EMPTY*/								{ $$ = false; }
	;


/*****************************************************************************
 *
 *		QUERY:
 *             CREATE DATA SOURCE name [TYPE] [VERSION] [OPTIONS]
 *
 *****************************************************************************/

CreateDataSourceStmt: CREATE DATA_P SOURCE_P name opt_data_source_type 
				opt_data_source_version create_generic_options
				{
					CreateDataSourceStmt *n = makeNode(CreateDataSourceStmt);
					n->srcname = $4;
					n->srctype = $5;
					n->version = $6;
					n->options = $7;
					$$ = (Node *) n;
				}
		;

data_source_type:
			TYPE_P Sconst			{ $$ = $2; }
		;

opt_data_source_type:
			data_source_type			{ $$ = $1; }
			| /*EMPTY*/				{ $$ = NULL; }
		;

data_source_version:
			VERSION_P Sconst		{ $$ = $2; }
			| VERSION_P NULL_P		{ $$ = NULL; }
		;

opt_data_source_version:
			data_source_version	{ $$ = $1; }
			| /*EMPTY*/				{ $$ = NULL; }
		;

/*****************************************************************************
 *
 *		QUERY :
 *				ALTER DATA SOURCE name [TYPE] [VERSION] [OPTIONS]
 *
 ****************************************************************************/

AlterDataSourceStmt: ALTER DATA_P SOURCE_P name data_source_type data_source_version alter_generic_options
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->srctype = $5;
					n->version = $6;
					n->options = $7;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name data_source_type data_source_version
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->srctype = $5;
					n->version = $6;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name data_source_type alter_generic_options
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->srctype = $5;
					n->options = $6;
					n->has_version = false;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name data_source_version alter_generic_options
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->version = $5;
					n->options = $6;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name data_source_type
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->srctype = $5;
					n->has_version = false;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name data_source_version
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->version = $5;
					n->has_version = true;
					$$ = (Node *) n;
				}
			| ALTER DATA_P SOURCE_P name alter_generic_options
				{
					AlterDataSourceStmt *n = makeNode(AlterDataSourceStmt);
					n->srcname = $4;
					n->options = $5;
					n->has_version = false;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY :
 *				DROP DATA SOURCE name
 *
 ****************************************************************************/

DropDataSourceStmt: DROP DATA_P SOURCE_P name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_DATA_SOURCE;
					n->objects = list_make1(list_make1(makeString($4)));
					n->arguments = NIL;
					n->missing_ok = false;
					n->behavior = $5;
					n->concurrent = false;
					$$ = (Node *) n;
				}
				|  DROP DATA_P SOURCE_P IF_P EXISTS name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_DATA_SOURCE;
					n->objects = list_make1(list_make1(makeString($6)));
					n->arguments = NIL;
					n->missing_ok = true;
					n->behavior = $7;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *             CREATE ACCESS METHOD name HANDLER handler_name
 *
 *****************************************************************************/

CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name
				{
					CreateAmStmt *n = makeNode(CreateAmStmt);
					n->amname = $4;
					n->handler_name = $8;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *		QUERIES :
 *				CREATE TRIGGER ...
 *				DROP TRIGGER ...
 *
 *****************************************************************************/

CreateTrigStmt:
			CREATE opt_or_replace definer_user TRIGGER qualified_trigger_name TriggerActionTime TriggerEvents ON
			qualified_name TriggerForSpec TriggerWhen
			EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')'
				{
					if ($2 != false)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
							 	errmsg("or replace is not supported here."), parser_errposition(@2)));
					}
					if ($3 != NULL && !u_sess->attr.attr_common.enable_dump_trigger_definer)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("only support definer in B compatibility database and B syntax")));
					}
					CreateTrigStmt *n = makeNode(CreateTrigStmt);
					n->definer = $3;
					n->if_not_exists = false;
					n->schemaname = $5->schemaname;
					n->trigname = $5->relname;					
					n->relation = $9;
					n->funcname = $14;
					n->args = $16;
					n->row = $10;
					n->timing = $6;
					n->events = intVal(linitial($7));
					n->columns = (List *) lsecond($7);
					n->whenClause = $11;
					n->isconstraint  = FALSE;
					n->deferrable	 = FALSE;
					n->initdeferred  = FALSE;
					n->constrrel = NULL;
					n->funcSource = NULL;
					n->trgordername = NULL;
					n->is_follows = NULL;
					$$ = (Node *)n;
				}
			| CREATE CONSTRAINT TRIGGER qualified_trigger_name AFTER TriggerEvents ON
			qualified_name OptConstrFromTable ConstraintAttributeSpec
			FOR EACH ROW TriggerWhen
			EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')'
				{
					CreateTrigStmt *n = makeNode(CreateTrigStmt);
					n->schemaname = $4->schemaname;
					n->trigname = $4->relname;
					n->definer = NULL;
					n->if_not_exists  = false;
					n->relation = $8;
					n->funcname = $17;
					n->args = $19;
					n->row = TRUE;
					n->timing = TRIGGER_TYPE_AFTER;
					n->events = intVal(linitial($6));
					n->columns = (List *) lsecond($6);
					n->whenClause = $14;
					n->isconstraint  = TRUE;
					processCASbits($10, @10, "TRIGGER",
								   &n->deferrable, &n->initdeferred, NULL,
								   NULL, yyscanner);
					n->constrrel = $9;
					n->funcSource = NULL;
					n->trgordername = NULL;
					n->is_follows = NULL;
					$$ = (Node *)n;
				}
			| CREATE opt_or_replace definer_user TRIGGER qualified_trigger_name TriggerActionTime TriggerEvents ON
			qualified_name TriggerForSpec TriggerWhen
			trigger_order
			{
				u_sess->parser_cxt.eaten_declare = false;
				u_sess->parser_cxt.eaten_begin = false;
				pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
				u_sess->parser_cxt.isCreateFuncOrProc = true;
			} subprogram_body
				{
					if ($2 != false)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
							 	errmsg("or replace is not supported here."), parser_errposition(@2)));					}
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Current syntax is supported only in B compatibility database")));
					}
					CreateTrigStmt *n = makeNode(CreateTrigStmt);
					
					n->definer = $3;
					n->if_not_exists = false;
					n->schemaname = $5->schemaname;
					n->trigname = $5->relname;
					n->timing = $6;
					n->events = intVal(linitial($7));
					n->columns = (List *) lsecond($7);
					n->relation = $9;
					n->row = $10;
					n->whenClause = $11;
					n->trgordername = $12->trigger_name;
					n->is_follows = $12->is_follows;
					FunctionSources *funcSource = (FunctionSources *)$14;
					n->funcSource = funcSource;
					n->isconstraint  = FALSE;
					n->deferrable	 = FALSE;
					n->initdeferred  = FALSE;
					n->constrrel = NULL;
					$$ = (Node *)n;
				}
			| CREATE opt_or_replace definer_user TRIGGER IF_P NOT EXISTS qualified_trigger_name TriggerActionTime TriggerEvents ON
			qualified_name TriggerForSpec TriggerWhen
			trigger_order
			{
				u_sess->parser_cxt.eaten_declare = false;
				u_sess->parser_cxt.eaten_begin = false;
				pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
				u_sess->parser_cxt.isCreateFuncOrProc = true;
			} subprogram_body
				{
					if ($2 != false)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
							 	errmsg("or replace is not supported here."), parser_errposition(@2)));
					}
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
					{
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("Current syntax is supported only in B compatibility database")));
					}
					CreateTrigStmt *n = makeNode(CreateTrigStmt);
					
					n->definer = $3;
					n->if_not_exists = true;
					n->schemaname = $8->schemaname;
					n->trigname = $8->relname;
					n->timing = $9;
					n->events = intVal(linitial($10));
					n->columns = (List *) lsecond($10);
					n->relation = $12;
					n->row = $13;
					n->whenClause = $14;
					n->trgordername = $15->trigger_name;
					n->is_follows = $15->is_follows;
					FunctionSources *funcSource = (FunctionSources *)$17;
					n->funcSource = funcSource;
					n->isconstraint  = FALSE;
					n->deferrable	 = FALSE;
					n->initdeferred  = FALSE;
					n->constrrel = NULL;
					$$ = (Node *)n;
				}
			;

TriggerActionTime:
			BEFORE								{ $$ = TRIGGER_TYPE_BEFORE; }
			| AFTER								{ $$ = TRIGGER_TYPE_AFTER; }
			| INSTEAD OF						{ $$ = TRIGGER_TYPE_INSTEAD; }
		;

TriggerEvents:
			TriggerOneEvent
				{ $$ = $1; }
			| TriggerEvents OR TriggerOneEvent
				{
					int		events1 = intVal(linitial($1));
					int		events2 = intVal(linitial($3));
					List   *columns1 = (List *) lsecond($1);
					List   *columns2 = (List *) lsecond($3);

					if (events1 & events2)
						parser_yyerror("duplicate trigger events specified");
					/*
					 * concat'ing the columns lists loses information about
					 * which columns went with which event, but so long as
					 * only UPDATE carries columns and we disallow multiple
					 * UPDATE items, it doesn't matter.  Command execution
					 * should just ignore the columns for non-UPDATE events.
					 */
					$$ = list_make2(makeInteger(events1 | events2),
									list_concat(columns1, columns2));
				}
		;

TriggerOneEvent:
			INSERT
				{ $$ = list_make2(makeInteger(TRIGGER_TYPE_INSERT), NIL); }
			| DELETE_P
				{ $$ = list_make2(makeInteger(TRIGGER_TYPE_DELETE), NIL); }
			| UPDATE
				{ $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), NIL); }
			| UPDATE OF columnList
				{ $$ = list_make2(makeInteger(TRIGGER_TYPE_UPDATE), $3); }
			| TRUNCATE
				{ $$ = list_make2(makeInteger(TRIGGER_TYPE_TRUNCATE), NIL); }
		;

TriggerForSpec:
			FOR TriggerForOptEach TriggerForType
				{
					$$ = $3;
				}
			| /* EMPTY */
				{
					/*
					 * If ROW/STATEMENT not specified, default to
					 * STATEMENT, per SQL
					 */
					$$ = FALSE;
				}
		;

TriggerForOptEach:
			EACH									{}
			| /*EMPTY*/								{}
		;

TriggerForType:
			ROW										{ $$ = TRUE; }
			| STATEMENT								{ $$ = FALSE; }
		;

TriggerWhen:
			WHEN '(' a_expr ')'						{ $$ = $3; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

FUNCTION_or_PROCEDURE:
			FUNCTION
		|	PROCEDURE
		;

TriggerFuncArgs:
			TriggerFuncArg							{ $$ = list_make1($1); }
			| TriggerFuncArgs ',' TriggerFuncArg	{ $$ = lappend($1, $3); }
			| /*EMPTY*/								{ $$ = NIL; }
		;

TriggerFuncArg:
			Iconst
				{
					char buf[64];
					snprintf(buf, sizeof(buf), "%d", $1);
					$$ = makeString(pstrdup(buf));
				}
			| FCONST								{ $$ = makeString($1); }
			| FCONST_F								{ $$ = makeString($1); }
			| FCONST_D								{ $$ = makeString($1); }
			| Sconst								{ $$ = makeString($1); }
			| ColLabel								{ $$ = makeString($1); }
		;

trigger_order:
			/* NULL */
			{
				TrgCharacter *n = (TrgCharacter *)palloc(sizeof(TrgCharacter));
				n->is_follows = false;
				n->trigger_name = NULL;
				$$ = n;
			}
			| FOLLOWS_P ColId
			{
				TrgCharacter *n = (TrgCharacter *)palloc(sizeof(TrgCharacter));
				n->is_follows = true;
				n->trigger_name = $2;
				$$ = n;
			}
			| PRECEDES_P ColId
			{
				TrgCharacter *n = (TrgCharacter *)palloc(sizeof(TrgCharacter));
				n->is_follows = false;
				n->trigger_name = $2;
				$$ = n;
			}
		;

OptConstrFromTable:
			FROM qualified_name						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

ConstraintAttributeSpec:
			/*EMPTY*/
				{ $$ = 0; }
			| ENABLE_P ConstraintAttr_isValidate
				{
					if($2 == CAS_VALIDATE)
						$$ = 0;
					else if ($2 == CAS_NO_VALIDATE)
						$$ = CAS_NOT_VALID;
					else
						$$ = 0;
				}
			| DISABLE_P ConstraintAttr_isValidate
				{
					if($2 == CAS_VALIDATE)
						$$ = CAS_DISABLE_VALIDATE;
					else
						$$ = CAS_DISABLE_NO_VALIDATE;
				}
			| ConstraintAttributeSpec ConstraintAttributeElem
				{
					/*
					 * We must complain about conflicting options.
					 * We could, but choose not to, complain about redundant
					 * options (ie, where $2's bit is already set in $1).
					 */
					int		newspec = $1 | $2;

					/* special message for this case */
					if ((newspec & (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) == (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) {
        				const char* message = "constraint declared INITIALLY DEFERRED must be DEFERRABLE";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
								 parser_errposition(@2)));
					}
					/* generic message for other conflicts */
					if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) ||
						(newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) {
        				const char* message = "conflicting constraint properties";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("conflicting constraint properties"),
								 parser_errposition(@2)));
					}
					$$ = newspec;
				}
		;

ConstraintAttributeElem:
			NOT DEFERRABLE					{ $$ = CAS_NOT_DEFERRABLE; }
			| DEFERRABLE					{ $$ = CAS_DEFERRABLE; }
			| INITIALLY IMMEDIATE			{ $$ = CAS_INITIALLY_IMMEDIATE; }
			| INITIALLY DEFERRED			{ $$ = CAS_INITIALLY_DEFERRED; }
			| NOT VALID						{ $$ = CAS_NOT_VALID; }
			| NO INHERIT					{ $$ = CAS_NO_INHERIT; }
		;

ConstraintAttr_isValidate:
			VALIDATE					{ $$ = CAS_VALIDATE; }
			| NOVALIDATE				{ $$ = CAS_NO_VALIDATE; }
			| /*EMPTY*/					{ $$ = CAS_VALIDATE_EMPTY; }
		;

CreateEventTrigStmt:
			CREATE EVENT_TRIGGER name ON ColLabel
			EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')'
				{
					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
					n->trigname = $3;
					n->eventname = $5;
					n->whenclause = NULL;
					n->funcname = $8;
					$$ = (Node *)n;
				}
			| CREATE EVENT_TRIGGER name ON ColLabel
			WHEN event_trigger_when_list
			EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')'
				{
					CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
					n->trigname = $3;
					n->eventname = $5;
					n->whenclause = $7;
					n->funcname = $10;
					$$ = (Node *)n;
				}
		;
 
event_trigger_when_list:
			event_trigger_when_item
			{ $$ = list_make1($1); }
			| event_trigger_when_list AND event_trigger_when_item
			{ $$ = lappend($1, $3); }
		;
 
event_trigger_when_item:
		ColId IN_P '(' event_trigger_value_list ')'
			{ $$ = makeDefElem($1, (Node *) $4); }
		;
 
event_trigger_value_list:
		SCONST
			{ $$ = list_make1(makeString($1)); }
		| event_trigger_value_list ',' SCONST
			{ $$ = lappend($1, makeString($3)); }
		;
 
AlterEventTrigStmt:
			ALTER EVENT_TRIGGER name enable_trigger
				{
					AlterEventTrigStmt *n = makeNode(AlterEventTrigStmt);
					n->trigname = $3;
					n->tgenabled = $4;
					$$ = (Node *) n;
				}
		;
 
enable_trigger:
			ENABLE_P                    { $$ = TRIGGER_FIRES_ON_ORIGIN; }
			| ENABLE_P REPLICA          { $$ = TRIGGER_FIRES_ON_REPLICA; }
			| ENABLE_P ALWAYS           { $$ = TRIGGER_FIRES_ALWAYS; }
			| DISABLE_P                 { $$ = TRIGGER_DISABLED; }
		;

qualified_trigger_name:
			name
				{
					$$ = makeRangeVar(NULL, $1, @1);
				}
			| ColId indirection
				{
					check_qualified_name($2, yyscanner);
					$$ = makeRangeVar(NULL, NULL, @1);
					const char* message = "improper qualified name (too many dotted names): %s";
					switch (list_length($2))
					{
						case 1:
							if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
							{
								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
										(errcode(ERRCODE_SYNTAX_ERROR),
										 errmsg("only support trigger in schema in B compatibility database"),
									 	 parser_errposition(@1)));
							}
							$$->schemaname = $1;
							$$->relname = strVal(linitial($2));
							break;
						default:
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("improper qualified name (too many dotted names): %s",
											NameListToString(lcons(makeString($1), $2))),
									 parser_errposition(@1)));
							break;
					}
				}
		;

DropTrigStmt:
			DROP TRIGGER qualified_trigger_name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TRIGGER;
					n->objects = list_make1(lappend($5, list_make2(makeString($3->schemaname), makeString($3->relname))));
					n->arguments = NIL;
					n->behavior = $6;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP TRIGGER IF_P EXISTS qualified_trigger_name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TRIGGER;
					n->objects = list_make1(lappend($7, list_make2(makeString($5->schemaname), makeString($5->relname))));
					n->arguments = NIL;
					n->behavior = $8;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP TRIGGER qualified_trigger_name opt_drop_behavior
				{
#ifdef	ENABLE_MULTIPLE_NODES
					const char* message = "drop trigger name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("drop trigger name is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("drop trigger without table name only support in B-format database")));
					}
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TRIGGER;
					n->objects = list_make1(list_make1(list_make2(makeString($3->schemaname), makeString($3->relname))));
					n->arguments = NIL;
					n->behavior = $4;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP TRIGGER IF_P EXISTS qualified_trigger_name opt_drop_behavior
				{
#ifdef	ENABLE_MULTIPLE_NODES
					const char* message = "drop trigger if exists name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("drop trigger if exists name is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("drop trigger without table name only support in B-format database")));
					}
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TRIGGER;
					n->objects = list_make1(list_make1(list_make2(makeString($5->schemaname), makeString($5->relname))));
					n->arguments = NIL;
					n->behavior = $6;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (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;
					processCASbits($8, @8, "ASSERTION",
								   &n->deferrable, &n->initdeferred, NULL,
								   NULL, yyscanner);
        			const char* message = "CREATE ASSERTION is not yet implemented";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("CREATE ASSERTION is not yet implemented")));

					$$ = (Node *)n;
				}
		;

DropAssertStmt:
			DROP ASSERTION name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->objects = NIL;
					n->arguments = NIL;
					n->behavior = $4;
					n->removeType = OBJECT_TRIGGER; /* XXX */
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("DROP ASSERTION is not yet implemented")));
					$$ = (Node *) n;
				}
		;


/*****************************************************************************
 *
 *		QUERY :
 *				define (aggregate,operator,type)
 *
 *****************************************************************************/

DefineStmt:
			CREATE AGGREGATE func_name aggr_args definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_AGGREGATE;
					n->oldstyle = false;
					n->defnames = $3;
					n->args = $4;
					n->definition = $5;
					$$ = (Node *)n;
				}
			| CREATE 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 = $3;
					n->args = NIL;
					n->definition = $4;
					$$ = (Node *)n;
				}
			| CREATE OPERATOR any_operator definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_OPERATOR;
					n->oldstyle = false;
					n->defnames = $3;
					n->args = NIL;
					n->definition = $4;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TYPE;
					n->oldstyle = false;
					n->defnames = $3;
					n->args = NIL;
					n->definition = $4;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name
				{
					/* Shell type (identified by lack of definition) */
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TYPE;
					n->oldstyle = false;
					n->defnames = $3;
					n->args = NIL;
					n->definition = NIL;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is '(' OptTableFuncElementList ')'
				{
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);

					/* can't use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
					n->replace = false;
					n->coldeflist = $6;
					n->final = true;
					n->typekind = TYPE_COMPOSITE_DEFAULT;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = NULL;
					$$ = (Node *)n;
				}
			| CREATE OR REPLACE TYPE_P any_name as_is '(' OptTableFuncElementList ')'
				{
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);

					/* can't use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($5, @5, yyscanner);
					n->replace = true;
					n->coldeflist = $8;
					n->final = true;
					n->typekind = TYPE_COMPOSITE_DEFAULT;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = NULL;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is OBJECT_P '(' OptTableFuncElementList ')' final_clause
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}
					if ($7 == NIL) {
						ereport(errstate, 
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("no attributes found in object type \"%s\"",strVal(linitial($3)))));						
					}
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typespec;
					initStringInfo(&typespec);
					/* Cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
					n->replace = false;
					n->coldeflist = $7;
					n->final = $9;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = NULL;

					appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @6, @8-@6+1);
					n->typespec = typespec.data;
					n->typebody = NULL;
					$$ = (Node *)n;					
				}
			| CREATE OR REPLACE TYPE_P any_name as_is OBJECT_P '(' OptTableFuncElementList ')' final_clause
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}
					if ($9 == NIL) {
						ereport(errstate, 
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("no attributes found in object type \"%s\"",strVal(linitial($5)))));						
					}
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typespec;
					initStringInfo(&typespec);
					/* Cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($5, @5, yyscanner);
					n->replace = true;
					n->coldeflist = $9;
					n->final = $11;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = NULL;

					appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @8, @10-@8+1);
					n->typespec = typespec.data;
					n->typebody = NULL;
					$$ = (Node *)n;					
				}
			| CREATE TYPE_P any_name as_is OBJECT_P '(' TableFuncElementList ',' Method_specList ')' final_clause
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typespec;
					initStringInfo(&typespec);
					/* Cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
					n->replace = false;
					n->coldeflist = $7;
					n->final = $11;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = $9;

					appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @6, @10-@6+1);
					n->typespec = typespec.data;
					n->typebody = NULL;
					$$ = (Node *)n;						
				}
			| CREATE OR REPLACE TYPE_P any_name as_is OBJECT_P '(' TableFuncElementList ',' Method_specList ')' final_clause
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}
					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typespec;
					initStringInfo(&typespec);
					/* Cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($5, @5, yyscanner);
					n->replace = true;
					n->coldeflist = $9;
					n->final = $13;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
					n->issubtype = false;
					n->supertype = NULL;
					n->methodlist = $11;

					appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @8, @12-@8+1);
					n->typespec = typespec.data;
					n->typebody = NULL;
					$$ = (Node *)n;						
				}
			| CREATE TYPE_P any_name UNDER any_name '(' TableFuncElementList ')' final_clause
				{
						if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
							ereport(errstate, 
									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
						}
						CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
						base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
						StringInfoData typespec;
						initStringInfo(&typespec);

						/* cannot use qualified_name, sigh */
						n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
						n->supertype = makeRangeVarFromAnyName($5, @5, yyscanner);
						n->coldeflist = $7;
						n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
						n->replace = false;
						n->final = $9;
						n->issubtype = true;
						n->methodlist = NULL;

						appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @6, @8-@6+1);
						n->typespec = typespec.data;
						n->typebody = NULL;
						$$ = (Node *)n;	
				}
			| CREATE OR REPLACE TYPE_P any_name UNDER any_name '(' TableFuncElementList ')' final_clause
				{
						if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
							ereport(errstate, 
									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
						}
						CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
						base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
						StringInfoData typespec;
						initStringInfo(&typespec);

						/* cannot use qualified_name, sigh */
						n->typevar = makeRangeVarFromAnyName($5, @5, yyscanner);
						n->supertype = makeRangeVarFromAnyName($7, @7, yyscanner);
						n->coldeflist = $9;
						n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
						n->replace = true;
						n->final = $11;
						n->issubtype = true;
						n->methodlist = NULL;
						
						appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @8, @10-@8+1);
						n->typespec = typespec.data;
						n->typebody = NULL;
						$$ = (Node *)n;	
				}
			| CREATE TYPE_P any_name UNDER any_name '(' TableFuncElementList ',' Method_specList ')' final_clause
				{
						if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
							ereport(errstate, 
									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
						}
						CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
						base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
						StringInfoData typespec;
						initStringInfo(&typespec);

						/* cannot use qualified_name, sigh */
						n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
						n->supertype = makeRangeVarFromAnyName($5, @5, yyscanner);
						n->coldeflist = $7;
						n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
						n->replace = false;
						n->final = $11;
						n->issubtype = true;
						n->methodlist = $9;

						appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @6, @10-@6+1);
						n->typespec = typespec.data;
						n->typebody = NULL;
						$$ = (Node *)n;		
				}
			| CREATE OR REPLACE TYPE_P any_name UNDER any_name '(' TableFuncElementList ',' Method_specList ')' final_clause
				{
						if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
							ereport(errstate, 
									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
						}
						CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
						base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
						StringInfoData typespec;
						initStringInfo(&typespec);

						/* cannot use qualified_name, sigh */
						n->typevar = makeRangeVarFromAnyName($5, @5, yyscanner);
						n->supertype = makeRangeVarFromAnyName($7, @7, yyscanner);
						n->coldeflist = $9;
						n->typekind = TYPE_COMPOSITE_OBJECT_TYPE;
						n->replace = true;
						n->final = $13;
						n->issubtype = true;
						n->methodlist = $11;

						appendBinaryStringInfo(&typespec, yyextra->core_yy_extra.scanbuf + @8, @12-@8+1);
						n->typespec = typespec.data;
						n->typebody = NULL;
						$$ = (Node *)n;
				}
			| CREATE TYPE_P BODY_P any_name as_is type_body_subprogram
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}

					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typebody;
					initStringInfo(&typebody);

					/* cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($4, @4, yyscanner);
					n->replace = false;
					n->methodlist = $6;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE_BODY;
					appendBinaryStringInfo(&typebody, yyextra->core_yy_extra.scanbuf + @5, yylloc - @5 +1);
					n->typebody = typebody.data;
					$$ = (Node *)n;
				}
			| CREATE OR REPLACE TYPE_P BODY_P any_name as_is type_body_subprogram
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT && !IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade) {
						ereport(errstate, 
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("CREATE TYPE AS OBJECT is only support in A-format database")));
					}

					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					StringInfoData typebody;
					initStringInfo(&typebody);

					/* cannot use qualified_name, sigh */
					n->typevar = makeRangeVarFromAnyName($6, @6, yyscanner);
					n->replace = true;
					n->methodlist = $8;
					n->typekind = TYPE_COMPOSITE_OBJECT_TYPE_BODY;
					appendBinaryStringInfo(&typebody, yyextra->core_yy_extra.scanbuf + @7, yylloc - @7 +1);
					n->typebody = typebody.data;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is VARRAY '(' ICONST ')' OF func_type
				{
					TableOfTypeStmt *n = makeNode(TableOfTypeStmt);
					n->typname = $3;
					n->reftypname = $10;
					n->replace = false;
					n->typtype = TYPTYPE_VARRAY;
					n->typecategory = TYPCATEGORY_VARRAY;
					$$ = (Node *)n;
				}
			| CREATE OR REPLACE TYPE_P any_name as_is VARRAY '(' ICONST ')' OF func_type
				{
					TableOfTypeStmt *n = makeNode(TableOfTypeStmt);
					n->typname = $5;
					n->reftypname = $12;
					n->replace = true;
					n->typtype = TYPTYPE_VARRAY;
					n->typecategory = TYPCATEGORY_VARRAY;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is TABLE OF func_type
				{
					TableOfTypeStmt *n = makeNode(TableOfTypeStmt);
					n->replace = false;
					n->typname = $3;
					n->reftypname = $7;
					n->typtype = TYPTYPE_TABLEOF;
					n->typecategory = TYPCATEGORY_TABLEOF;
					$$ = (Node *)n;
				}
			| CREATE OR REPLACE TYPE_P any_name as_is TABLE OF func_type
				{
					TableOfTypeStmt *n = makeNode(TableOfTypeStmt);
					n->replace = true;
					n->typname = $5;
					n->reftypname = $9;
					n->typtype = TYPTYPE_TABLEOF;
					n->typecategory = TYPCATEGORY_TABLEOF;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is ENUM_P '(' opt_enum_val_list ')'
				{
					CreateEnumStmt *n = makeNode(CreateEnumStmt);
					n->typname = $3;
					n->vals = $7;
					$$ = (Node *)n;
				}
			| CREATE TYPE_P any_name as_is RANGE definition
				{
					CreateRangeStmt *n = makeNode(CreateRangeStmt);
					n->typname = $3;
					n->params	= $6;
					$$ = (Node *)n;
				}
			| CREATE TEXT_P SEARCH PARSER any_name definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TSPARSER;
					n->args = NIL;
					n->defnames = $5;
					n->definition = $6;
					$$ = (Node *)n;
				}
			| CREATE TEXT_P SEARCH DICTIONARY any_name definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TSDICTIONARY;
					n->args = NIL;
					n->defnames = $5;
					n->definition = $6;
					$$ = (Node *)n;
				}
			| CREATE TEXT_P SEARCH TEMPLATE any_name definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TSTEMPLATE;
					n->args = NIL;
					n->defnames = $5;
					n->definition = $6;
					$$ = (Node *)n;
				}
			| CREATE TEXT_P SEARCH CONFIGURATION any_name tsconf_definition opt_cfoptions
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_TSCONFIGURATION;
					n->args = $7; /* record configuration options */
					n->defnames = $5;
					n->definition = $6;
					$$ = (Node *)n;
				}
			| CREATE COLLATION any_name definition
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_COLLATION;
					n->args = NIL;
					n->defnames = $3;
					n->definition = $4;
					$$ = (Node *)n;
				}
			| CREATE COLLATION any_name FROM any_name
				{
					DefineStmt *n = makeNode(DefineStmt);
					n->kind = OBJECT_COLLATION;
					n->args = NIL;
					n->defnames = $3;
					n->definition = list_make1(makeDefElem("from", (Node *) $5));
					$$ = (Node *)n;
				}
		;
type_body_subprogram: method_decl_in_type_list  ';' END_P ';'
				| method_decl_in_type_list  ';' END_P END_OF_INPUT_COLON
				{ $$ = $1;};

Method_specList: element_spec
				{
					$$ = list_make1($1);
				}
		| Method_specList ',' element_spec
				{
					$$ = lappend($1, $3);
				}
		;

element_spec : inheritance_clause MEMBER_FUNCTION func_name_opt_arg object_proc_args RETURN func_return
				{
					if ($4 != NIL && NULL != (FunctionParameter*)linitial($4))
					{
						FunctionParameter* firstparam = (FunctionParameter*)linitial($4);
						if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
							ereport(errstate, 
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
					}
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = false;
					n->definer = NULL;
					n->funcname = $3;
					n->parameters = $4;
					n->returnType = $6;
					n->typfunckind = OBJECTTYPE_MEMBER_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = false;
					$$ = (Node*)n;
				}
				| inheritance_clause STATIC_FUNCTION func_name_opt_arg object_proc_args RETURN func_return
				{
					if ($4 != NIL && NULL != (FunctionParameter*)linitial($4))
					{
						FunctionParameter* firstparam = (FunctionParameter*)linitial($4);
						if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
							ereport(errstate, 
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
					}
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = false;
					n->definer = NULL;
					n->funcname = $3;
					n->parameters = $4;
					n->returnType = $6;
					n->typfunckind = OBJECTTYPE_STATIC_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = false;
					$$ = (Node*)n;					
				}
				| inheritance_clause MEMBER_PROCEDURE func_name_opt_arg object_proc_args
				{
					if ($4 != NIL && NULL != (FunctionParameter*)linitial($4))
					{
						FunctionParameter* firstparam = (FunctionParameter*)linitial($4);
						if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
							ereport(errstate, 
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
					}
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					int count = get_outarg_num($4);
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = false;
					n->definer = NULL;
					n->funcname = $3;
					n->parameters = $4;
					n->returnType = NULL;
					if (count == 0)
					{
						n->returnType = makeTypeName("void");
						n->returnType->typmods = NULL;
						n->returnType->arrayBounds = NULL;
					}
					n->typfunckind = OBJECTTYPE_MEMBER_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = true;
					$$ = (Node*)n;					
				}
				| inheritance_clause STATIC_PROCEDURE func_name_opt_arg proc_args
				{
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					int count = get_outarg_num($4);
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = false;
					n->definer = NULL;
					n->funcname = $3;
					n->parameters = $4;
					n->returnType = NULL;
					if (count == 0)
					{
						n->returnType = makeTypeName("void");
						n->returnType->typmods = NULL;
						n->returnType->arrayBounds = NULL;
					}
					n->typfunckind = OBJECTTYPE_STATIC_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = true;
					$$ = (Node*)n;
				}
				| inheritance_clause CONSTRUCTOR_FUNCTION func_name_opt_arg object_proc_args RETURN SELF AS RESULT
				{
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = true;
					n->definer = NULL;
					n->funcname = $3;
					n->parameters = $4;
					n->returnType = NULL;
					n->typfunckind = OBJECTTYPE_CONSTRUCTOR_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = false;
					$$ = (Node*)n;
				}
				| inheritance_clause MAP_MEMBER FUNCTION func_name_opt_arg object_proc_args RETURN func_return
				{
					if ($5 != NIL && NULL != (FunctionParameter*)linitial($5))
					{
						FunctionParameter* firstparam = (FunctionParameter*)linitial($5);
						if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
							ereport(errstate, 
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
					}
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = true;
					n->definer = NULL;
					n->funcname = $4;
					n->parameters = $5;
					n->returnType = $7;
					n->typfunckind = OBJECTTYPE_MAP_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = false;
					$$ = (Node*)n;					
				}
				| inheritance_clause MAP_MEMBER PROCEDURE func_name_opt_arg object_proc_args
				{
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Only a function can be a MAP,ORDER or CONSTRUCTOR method")));					
				}
				| inheritance_clause ORDER MEMBER_PROCEDURE func_name_opt_arg object_proc_args
				{
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("Only a function can be a MAP,ORDER or CONSTRUCTOR method")));
				}
				| inheritance_clause ORDER MEMBER_FUNCTION func_name_opt_arg object_proc_args RETURN func_return
				{
					if ($5 != NIL && NULL != (FunctionParameter*)linitial($5))
					{
						FunctionParameter* firstparam = (FunctionParameter*)linitial($5);
						if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
							ereport(errstate, 
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
					}
					CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
					List *list = list_make1(makeDefElem("as", (Node *)list_make1(makeString("begin\nend"))));
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = true;
					n->definer = NULL;
					n->funcname = $4;
					n->parameters = $5;
					n->returnType = $7;
					n->typfunckind = OBJECTTYPE_ORDER_PROC;
					n->isfinal = $1;
					list = lappend(list, makeDefElem("language", (Node*) makeString("plpgsql")));
					n->options = list;
					n->withClause = NULL;
					n->isProcedure = false;
					$$ = (Node*)n;
				}

final_clause: FINAL										{ $$ = true;}
			| NOT FINAL									{ $$ = false;}
			| /* EMPTY */								{ $$ = true; } /*FINAL for default, allow to create subtype*/
		;

inheritance_clause: FINAL										{ $$ = true;}
			| NOT FINAL									{ $$ = false;}
			| /* EMPTY */								{ $$ = false; }/*NOT FINAL for default, allow subtype to override method*/
		;

object_func_args_with_defaults: '(' SELF_INOUT func_type ',' func_args_with_defaults_list ')'
		{
			FunctionParameter *self = makeNode(FunctionParameter);
			self->name = pstrdup("self");
			self->argType = $3;
			self->mode = FUNC_PARAM_INOUT;
			self->defexpr = NULL;
			$$ = list_concat(list_make1(self), $5);
		}
		| '(' func_args_with_defaults_list ')'			{ $$ = $2; }
		| '(' ')'										{ $$ = NIL; }
		;

object_proc_args:	object_func_args_with_defaults		{ $$ = $1; }
			| /* EMPTY */								{ $$ = NIL; }
		;

method_decl_in_type_list:
		element_decl_in_type								{ $$ = list_make1($1); }
		| method_decl_in_type_list ';' element_decl_in_type { $$ = lappend($1, $3); }
		;

element_decl_in_type: subprogram_decl_in_type
		| constructor_decl_in_type
		| map_order_decl_in_type
		{$$ = $1;}
		;

subprogram_decl_in_type : inheritance_clause MEMBER_FUNCTION func_name_opt_arg object_proc_args RETURN func_return opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			if ($4 != NIL && NULL != (FunctionParameter*)linitial($4))
			{
				FunctionParameter* firstparam = (FunctionParameter*)linitial($4);
				if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
			}
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @8);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$10;
			n->isOraStyle = true;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = $6;
			n->options = $7;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;
			n->funcname = $3;
			n->parameters = $4;
			n->typfunckind = OBJECTTYPE_MEMBER_PROC;
			n->isfinal = $1;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			n->withClause = NULL;
			n->isProcedure = false;
			$$ = (Node*)n;
		}
		| inheritance_clause STATIC_FUNCTION func_name_opt_arg object_proc_args RETURN func_return opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @8);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$10;
			n->isOraStyle = true;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = $6;
			n->options = $7;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;
			n->funcname = $3;
			n->parameters = $4;
			n->typfunckind = OBJECTTYPE_STATIC_PROC;
			n->isfinal = $1;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			n->withClause = NULL;
			n->isProcedure = false;
			$$ = (Node*)n;
		}
		| inheritance_clause MEMBER_PROCEDURE func_name_opt_arg object_proc_args opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			if ($4 != NIL && NULL != (FunctionParameter*)linitial($4))
			{
				FunctionParameter* firstparam = (FunctionParameter*)linitial($4);
				if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
			}
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @6);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$8;
			int count = get_outarg_num($4);
			n->isOraStyle = true;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;

			n->funcname = $3;
			n->parameters = $4;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = NULL;
			n->isProcedure = true;
			if (0 == count)
			{
				n->returnType = makeTypeName("void");
				n->returnType->typmods = NULL;
				n->returnType->arrayBounds = NULL;
			}
			n->options = $5;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			
			n->withClause = NIL;
			u_sess->parser_cxt.isCreateFuncOrProc = false;
			n->typfunckind = OBJECTTYPE_MEMBER_PROC;
			n->isfinal = $1;
			$$ = (Node*)n;
		}
		| inheritance_clause STATIC_PROCEDURE func_name_opt_arg object_proc_args opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			int rc = 0;
			rc = CompileWhich();
			if ((rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) && u_sess->cmd_cxt.CurrentExtensionObject == InvalidOid) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @6);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$8;
			int count = get_outarg_num($4);
			n->isOraStyle = true;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;

			n->funcname = $3;
			n->parameters = $4;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = NULL;
			n->isProcedure = true;
			if (0 == count)
			{
				n->returnType = makeTypeName("void");
				n->returnType->typmods = NULL;
				n->returnType->arrayBounds = NULL;
			}
			n->options = $5;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			
			n->withClause = NIL;
			u_sess->parser_cxt.isCreateFuncOrProc = false;
			n->typfunckind = OBJECTTYPE_STATIC_PROC;
			n->isfinal = $1;
			$$ = (Node*)n;
		}
		;

constructor_decl_in_type: inheritance_clause CONSTRUCTOR_FUNCTION func_name_opt_arg object_proc_args RETURN SELF AS RESULT opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @6);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$12;
			n->isOraStyle = true;

			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = NULL;
			n->options = $9;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;
			n->funcname = $3;
			n->parameters = $4;
			n->typfunckind = OBJECTTYPE_CONSTRUCTOR_PROC;
			n->isfinal = $1;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			n->withClause = NULL;
			n->isProcedure = false;
			$$ = (Node *)n;
		}
		;

map_order_decl_in_type : inheritance_clause MAP_MEMBER FUNCTION func_name_opt_arg object_proc_args RETURN func_return opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			if ($5 != NIL && NULL != (FunctionParameter*)linitial($5))
			{
				FunctionParameter* firstparam = (FunctionParameter*)linitial($5);
				if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
			}
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @6);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$11;
			n->isOraStyle = true;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = $7;
			n->options = $8;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;
			n->funcname = $4;
			n->parameters = $5;
			n->typfunckind = OBJECTTYPE_MAP_PROC;
			n->isfinal = $1;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			n->withClause = NULL;
			n->isProcedure = false;
			$$ = (Node*)n;
		}
		| inheritance_clause MAP_MEMBER PROCEDURE func_name_opt_arg object_proc_args opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			ereport(errstate, 
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("Only a function can be a MAP,ORDER or CONSTRUCTOR method")));
		}
		| inheritance_clause ORDER MEMBER_FUNCTION func_name_opt_arg object_proc_args RETURN func_return opt_createproc_opt_list as_is{
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			if ($5 != NIL && NULL != (FunctionParameter*)linitial($5))
			{
				FunctionParameter* firstparam = (FunctionParameter*)linitial($5);
				if ((NULL != firstparam->name) && (strcmp(firstparam->name,"self") == 0) && !(firstparam->mode == FUNC_PARAM_IN || firstparam->mode == FUNC_PARAM_INOUT))
					ereport(errstate, 
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("the SELF parameter can be declared only as IN or as IN OUT")));
			}
			int rc = 0;
			rc = CompileWhich();
			if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
				u_sess->plsql_cxt.procedure_first_line = GetLineNumber(pg_yyget_extra(yyscanner)->core_yy_extra.scanbuf, @6);
			}
			CreateFunctionStmt* n = makeNode(CreateFunctionStmt);
			FunctionSources *funcSource = (FunctionSources *)$11;
			n->isOraStyle = true;
			n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
			n->returnType = $7;
			n->options = $8;
			n->isPrivate = false;
			n->replace = true;
			n->definer = NULL;
			n->funcname = $4;
			n->parameters = $5;
			n->typfunckind = OBJECTTYPE_ORDER_PROC;
			n->isfinal = $1;
			n->options = lappend(n->options, makeDefElem("as",
							(Node*)list_make1(makeString(funcSource->bodySrc))));
			n->options = lappend(n->options, makeDefElem("language",
							(Node*)makeString("plpgsql")));
			n->withClause = NULL;
			n->isProcedure = false;
			$$ = (Node*)n;			
		}
		| inheritance_clause ORDER MEMBER_PROCEDURE func_name_opt_arg object_proc_args opt_createproc_opt_list as_is {
			u_sess->parser_cxt.eaten_declare = false;
			u_sess->parser_cxt.eaten_begin = false;
			pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->parser_cxt.isCreateFuncOrProc = true;
		} subprogram_body
		{
			ereport(errstate, 
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("Only a function can be a MAP,ORDER or CONSTRUCTOR method")));			
		}
		;

opt_cfoptions: WITH cfoptions							{ $$ = $2; }
			| /* EMPTY */								{ $$ = NIL; }
		;

cfoptions:'(' cfoption_list ')'							{ $$ = $2; }
		;

cfoption_list: cfoption_elem							{ $$ = list_make1($1); }
			| cfoption_list ',' cfoption_elem			{ $$ = lappend($1, $3); }
		;

cfoption_elem: ColLabel '=' def_arg						{ $$ = makeDefElem($1, (Node *) $3); }
			| ColLabel									{ $$ = makeDefElem($1, NULL); }
		;

tsconf_definition: '(' tsconf_def_list ')'				{ $$ = $2; }
		;

tsconf_def_list: tsconf_def_elem						{ $$ = list_make1($1); }
			| tsconf_def_list ',' tsconf_def_elem		{ $$ = lappend($1, $3); }
		;

tsconf_def_elem: PARSER '=' any_name					{ $$ = makeDefElem("parser", (Node *) $3); }
			| PARSER '=' DEFAULT						{ $$ = makeDefElem("parser", (Node *) list_make1(makeString("default"))); }
			| COPY '=' any_name							{ $$ = makeDefElem("copy", (Node *) $3); }
		;

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; }
			| reserved_keyword				{ $$ = (Node *)makeString(pstrdup($1)); }
			| qual_all_Op					{ $$ = (Node *)$1; }
			| NumericOnly					{ $$ = (Node *)$1; }
			| Sconst						{ $$ = (Node *)makeString($1); }
		;

/*
 * aggregate function args.
 * (*)									- normal agg with no args
 * (aggr_arg,...)						- normal agg with args
 * (ORDER BY type_list,...)				- ordered-set agg with no direct args

 */
aggr_args:	'(' type_list ')'						{ $$ = list_make2($2, makeInteger(-1)); }
			| '(' '*' ')'							{ $$ = list_make2(NIL, makeInteger(-1)); }
			| '(' ORDER BY type_list ')'
				{
					$$ = list_make2($4, makeInteger(0));
				}
		;

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);
				}
		;

opt_enum_val_list:
		enum_val_list							{ $$ = $1; }
		| /*EMPTY*/								{ $$ = NIL; }
		;

enum_val_list:	Sconst
				{ $$ = list_make1(makeString($1)); }
			| enum_val_list ',' Sconst
				{ $$ = lappend($1, makeString($3)); }
		;

/*****************************************************************************
 *
 *	ALTER TYPE enumtype ADD ...
 *
 *****************************************************************************/

AlterEnumStmt:
		ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst
			{
				AlterEnumStmt *n = makeNode(AlterEnumStmt);
				n->typname = $3;
				n->oldVal = NULL;
				n->newVal = $7;
				n->newValNeighbor = NULL;
				n->newValIsAfter = true;
				n->skipIfNewValExists = $6;
				$$ = (Node *) n;
			}
		 | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst BEFORE Sconst
			{
				AlterEnumStmt *n = makeNode(AlterEnumStmt);
				n->typname = $3;
				n->oldVal = NULL;
				n->newVal = $7;
				n->newValNeighbor = $9;
				n->newValIsAfter = false;
				n->skipIfNewValExists = $6;
				$$ = (Node *) n;
			}
		 | ALTER TYPE_P any_name ADD_P VALUE_P opt_if_not_exists Sconst AFTER Sconst
			{
				AlterEnumStmt *n = makeNode(AlterEnumStmt);
				n->typname = $3;
				n->oldVal = NULL;
				n->newVal = $7;
				n->newValNeighbor = $9;
				n->newValIsAfter = true;
				n->skipIfNewValExists = $6;
				$$ = (Node *) n;
			}
		 | ALTER TYPE_P any_name RENAME VALUE_P Sconst TO Sconst
			{
				AlterEnumStmt *n = makeNode(AlterEnumStmt);
				n->typname = $3;
				n->oldVal = $6;
				n->newVal = $8;
				n->newValNeighbor = NULL;
				n->newValIsAfter = false;
				n->skipIfNewValExists = false;
				$$ = (Node *) n;
			}
		 ;

opt_if_not_exists: IF_P NOT EXISTS 			{ $$ = true; }
		| /* empty */						{ $$ = false; }
		;

/*****************************************************************************
 *
 *		QUERIES :
 *				CREATE OPERATOR CLASS ...
 *				CREATE OPERATOR FAMILY ...
 *				ALTER OPERATOR FAMILY ...
 *				DROP OPERATOR CLASS ...
 *				DROP OPERATOR FAMILY ...
 *
 *****************************************************************************/

CreateOpClassStmt:
			CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
			USING access_method opt_opfamily AS opclass_item_list
				{
					CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
					n->opclassname = $4;
					n->isDefault = $5;
					n->datatype = $8;
					n->amname = $10;
					n->opfamilyname = $11;
					n->items = $13;
					$$ = (Node *) n;
				}
		;

opclass_item_list:
			opclass_item							{ $$ = list_make1($1); }
			| opclass_item_list ',' opclass_item	{ $$ = lappend($1, $3); }
		;

opclass_item:
			OPERATOR Iconst any_operator opclass_purpose opt_recheck
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_OPERATOR;
					n->name = $3;
					n->args = NIL;
					n->number = $2;
					n->order_family = $4;
					$$ = (Node *) n;
				}
			| OPERATOR Iconst any_operator oper_argtypes opclass_purpose
			  opt_recheck
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_OPERATOR;
					n->name = $3;
					n->args = $4;
					n->number = $2;
					n->order_family = $5;
					$$ = (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;
				}
			| FUNCTION Iconst '(' type_list ')' func_name func_args
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_FUNCTION;
					n->name = $6;
					n->args = extractArgTypes($7);
					n->number = $2;
					n->class_args = $4;
					$$ = (Node *) n;
				}
			| STORAGE Typename
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_STORAGETYPE;
					n->storedtype = $2;
					$$ = (Node *) n;
				}
		;

opt_default:	DEFAULT						{ $$ = TRUE; }
			| /*EMPTY*/						{ $$ = FALSE; }
		;

opt_opfamily:	FAMILY any_name				{ $$ = $2; }
			| /*EMPTY*/						{ $$ = NIL; }
		;

opclass_purpose: FOR SEARCH					{ $$ = NIL; }
			| FOR ORDER BY any_name			{ $$ = $4; }
			| /*EMPTY*/						{ $$ = NIL; }
		;

opt_recheck:	RECHECK
				{
					/*
					 * RECHECK no longer does anything in opclass definitions,
					 * but we still accept it to ease porting of old database
					 * dumps.
					 */
					ereport(NOTICE,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("RECHECK is no longer required"),
							 errhint("Update your data type."),
							 parser_errposition(@1)));
					$$ = TRUE;
				}
			| /*EMPTY*/						{ $$ = FALSE; }
		;


CreateOpFamilyStmt:
			CREATE OPERATOR FAMILY any_name USING access_method
				{
					CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt);
					n->opfamilyname = $4;
					n->amname = $6;
					$$ = (Node *) n;
				}
		;

AlterOpFamilyStmt:
			ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list
				{
					AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
					n->opfamilyname = $4;
					n->amname = $6;
					n->isDrop = false;
					n->items = $8;
					$$ = (Node *) n;
				}
			| ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list
				{
					AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
					n->opfamilyname = $4;
					n->amname = $6;
					n->isDrop = true;
					n->items = $8;
					$$ = (Node *) n;
				}
		;

opclass_drop_list:
			opclass_drop							{ $$ = list_make1($1); }
			| opclass_drop_list ',' opclass_drop	{ $$ = lappend($1, $3); }
		;

opclass_drop:
			OPERATOR Iconst '(' type_list ')'
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_OPERATOR;
					n->number = $2;
					n->args = $4;
					$$ = (Node *) n;
				}
			| FUNCTION Iconst '(' type_list ')'
				{
					CreateOpClassItem *n = makeNode(CreateOpClassItem);
					n->itemtype = OPCLASS_ITEM_FUNCTION;
					n->number = $2;
					n->args = $4;
					$$ = (Node *) n;
				}
		;


DropOpClassStmt:
			DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->objects = list_make1(lcons(makeString($6), $4));
					n->removeType = OBJECT_OPCLASS;
					n->behavior = $7;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->objects = list_make1(lcons(makeString($8), $6));
					n->removeType = OBJECT_OPCLASS;
					n->behavior = $9;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;

DropOpFamilyStmt:
			DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->objects = list_make1(lcons(makeString($6), $4));
					n->removeType = OBJECT_OPFAMILY;
					n->behavior = $7;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->objects = list_make1($6);
					n->objects = list_make1(lcons(makeString($8), $6));
					n->removeType = OBJECT_OPFAMILY;
					n->behavior = $9;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;


/*****************************************************************************
 *
 *		QUERY:
 *
 *		DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ]
 *		REASSIGN OWNED BY username [, username ...] TO username
 *
 *****************************************************************************/
DropOwnedStmt:
			DROP OWNED BY 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 opt_purge
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = $2;
					n->missing_ok = TRUE;
					n->objects = $5;
					n->arguments = NIL;
					n->behavior = $6;
					n->concurrent = false;
					n->purge = $7;				
					if (n->removeType != OBJECT_TABLE && n->purge) {
        				const char* message = "PURGE clause only allowed in \"DROP TABLE\" statement";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
							 errmsg("PURGE clause only allowed in \"DROP TABLE\" statement"),
							 parser_errposition(@7)));
					}

					$$ = (Node *)n;
				}
			| DROP drop_type any_name_list opt_drop_behavior opt_purge
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = $2;
					n->missing_ok = FALSE;
					n->objects = $3;
					n->arguments = NIL;
					n->behavior = $4;
					n->concurrent = false;
					n->purge = $5;
					if (n->removeType != OBJECT_TABLE && n->purge) {
        				const char* message = "PURGE clause only allowed in \"DROP TABLE\" statement";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
							 errmsg("PURGE clause only allowed in \"DROP TABLE\" statement"),
							 parser_errposition(@5)));
					}
					$$ = (Node *)n;
				}
			| DROP MATERIALIZED VIEW IF_P EXISTS any_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_MATVIEW;
					n->missing_ok = TRUE;
					n->objects = $6;
					n->behavior = $7;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP MATERIALIZED VIEW any_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_MATVIEW;
					n->missing_ok = FALSE;
					n->objects = $4;
					n->behavior = $5;
					n->concurrent = false;
					$$ = (Node *)n;
				}
			| DROP TYPE_P type_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TYPE;
					n->missing_ok = FALSE;
					n->objects = $3;
					n->behavior = $4;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP TYPE_P IF_P EXISTS type_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_TYPE;
					n->missing_ok = TRUE;
					n->objects = $5;
					n->behavior = $6;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP DOMAIN_P type_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_DOMAIN;
					n->missing_ok = FALSE;
					n->objects = $3;
					n->behavior = $4;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP DOMAIN_P IF_P EXISTS type_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_DOMAIN;
					n->missing_ok = TRUE;
					n->objects = $5;
					n->behavior = $6;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_INDEX;
					n->missing_ok = FALSE;
					n->objects = $4;
					n->arguments = NIL;
					n->behavior = $5;
					n->concurrent = true;
					$$ = (Node *)n;
				}
			| DROP INDEX CONCURRENTLY IF_P EXISTS any_name_list opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_INDEX;
					n->missing_ok = TRUE;
					n->objects = $6;
					n->arguments = NIL;
					n->behavior = $7;
					n->concurrent = true;
					$$ = (Node *)n;
				}
		;

opt_purge:
			PURGE								{ $$ = true; }
			| /* EMPTY */							{ $$ = false; }
		;


drop_type:	TABLE									{ $$ = OBJECT_TABLE; }
            | CONTVIEW                              { $$ = OBJECT_CONTQUERY; }
            | STREAM                                { $$ = OBJECT_STREAM; }
			| SEQUENCE								{ $$ = OBJECT_SEQUENCE; }
			| LARGE_P SEQUENCE						{ $$ = OBJECT_LARGE_SEQUENCE; }
			| VIEW									{ $$ = OBJECT_VIEW; }
			| INDEX									{ $$ = OBJECT_INDEX; }
			| FOREIGN TABLE							{ $$ = OBJECT_FOREIGN_TABLE; }
			| COLLATION								{ $$ = OBJECT_COLLATION; }
			| CONVERSION_P							{ $$ = OBJECT_CONVERSION; }
			| SCHEMA								{ $$ = OBJECT_SCHEMA; }
			| ACCESS METHOD                         { $$ = OBJECT_ACCESS_METHOD; }
			| EVENT_TRIGGER                         { $$ = OBJECT_EVENT_TRIGGER; }
			| EXTENSION								{ $$ = OBJECT_EXTENSION; }
			| TEXT_P SEARCH PARSER					{ $$ = OBJECT_TSPARSER; }
			| TEXT_P SEARCH DICTIONARY				{ $$ = OBJECT_TSDICTIONARY; }
			| TEXT_P SEARCH TEMPLATE				{ $$ = OBJECT_TSTEMPLATE; }
			| TEXT_P SEARCH CONFIGURATION			{ $$ = OBJECT_TSCONFIGURATION; }
            | CLIENT MASTER KEY                     { $$ = OBJECT_GLOBAL_SETTING; }
            | COLUMN ENCRYPTION KEY                 { $$ = OBJECT_COLUMN_SETTING; }
            | PUBLICATION                           { $$ = OBJECT_PUBLICATION; }
		;

collate_name:	any_name					{ $$ = $1; }
				| BINARY					{ $$ = list_make1(makeString("binary")); }
				| Sconst					{ $$ = list_make1(makeString($1)); }
		;

type_name_list:
			Typename                                { $$ = list_make1(list_make1($1)); }
			| type_name_list ',' Typename           { $$ = lappend($1, list_make1($3)); }
			
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 relation_expr_list opt_restart_seqs opt_drop_behavior opt_purge
				{
					TruncateStmt *n = makeNode(TruncateStmt);
					n->relations = $3;
					n->restart_seqs = $4;
					n->behavior = $5;
					n->purge = $6;
					$$ = (Node *)n;
				}
		;

opt_restart_seqs:
			CONTINUE_P IDENTITY_P		{ $$ = false; }
			| RESTART IDENTITY_P		{ $$ = true; }
			| /* EMPTY */				{ $$ = false; }
		;

/*****************************************************************************
 *
 *	The COMMENT ON statement can take different forms based upon the type of
 *	the object associated with the comment. The form of the statement is:
 *
 *	COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
 *				   COLLATION | CONVERSION | LANGUAGE | OPERATOR CLASS |
 *				   LARGE OBJECT | CAST | COLUMN | SCHEMA | TABLESPACE |
 *				   EXTENSION | ROLE | TEXT SEARCH PARSER |
 *				   TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE |
 *				   TEXT SEARCH CONFIGURATION | FOREIGN TABLE |
 *				   FOREIGN DATA WRAPPER | SERVER | EVENT_TRIGGER |
 *				   MATERIALIZED VIEW | SNAPSHOT] <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 = $5;
					n->comment = $7;
					$$ = (Node *) n;
				}
			| COMMENT ON CONSTRAINT name ON any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TABCONSTRAINT;
					n->objname = lappend($6, makeString($4));
					n->objargs = NIL;
					n->comment = $8;
					$$ = (Node *) n;
				}
			| COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_DOMCONSTRAINT;
					/*
					 * should use Typename not any_name in the production, but
					 * there's a shift/reduce conflict if we do that, so fix it
					 * up here.
					*/
					n->objname = list_make1(makeTypeNameFromNameList($7));
					n->objargs = list_make1(makeString($4));
					n->comment = $9;
					$$ = (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 OPERATOR FAMILY any_name USING access_method IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_OPFAMILY;
					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 ON TEXT_P SEARCH PARSER any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TSPARSER;
					n->objname = $6;
					n->comment = $8;
					$$ = (Node *) n;
				}
			| COMMENT ON TEXT_P SEARCH DICTIONARY any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TSDICTIONARY;
					n->objname = $6;
					n->comment = $8;
					$$ = (Node *) n;
				}
			| COMMENT ON TEXT_P SEARCH TEMPLATE any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TSTEMPLATE;
					n->objname = $6;
					n->comment = $8;
					$$ = (Node *) n;
				}
			| COMMENT ON TEXT_P SEARCH CONFIGURATION any_name IS comment_text
				{
					CommentStmt *n = makeNode(CommentStmt);
					n->objtype = OBJECT_TSCONFIGURATION;
					n->objname = $6;
					n->comment = $8;
					$$ = (Node *) n;
				}
		;

comment_type:
			COLUMN								{ $$ = OBJECT_COLUMN; }
			| DATABASE							{ $$ = OBJECT_DATABASE; }
			| SCHEMA							{ $$ = OBJECT_SCHEMA; }
			| INDEX								{ $$ = OBJECT_INDEX; }
			| SEQUENCE							{ $$ = OBJECT_SEQUENCE; }
			| LARGE_P SEQUENCE					{ $$ = OBJECT_LARGE_SEQUENCE; }
			| TABLE								{ $$ = OBJECT_TABLE; }
			| DOMAIN_P							{ $$ = OBJECT_DOMAIN; }
			| TYPE_P							{ $$ = OBJECT_TYPE; }
			| VIEW								{ $$ = OBJECT_VIEW; }
			| MATERIALIZED VIEW 				{ $$ = OBJECT_MATVIEW; }
			| SNAPSHOT							{ $$ = OBJECT_VIEW; }
			| COLLATION							{ $$ = OBJECT_COLLATION; }
			| CONVERSION_P						{ $$ = OBJECT_CONVERSION; }
			| TABLESPACE						{ $$ = OBJECT_TABLESPACE; }
			| EVENT_TRIGGER                     { $$ = OBJECT_EVENT_TRIGGER; }
			| EXTENSION							{ $$ = OBJECT_EXTENSION; }
			| ROLE								{ $$ = OBJECT_ROLE; }
			| USER								{ $$ = OBJECT_USER; }
			| FOREIGN TABLE						{ $$ = OBJECT_FOREIGN_TABLE; }
			| SERVER							{ $$ = OBJECT_FOREIGN_SERVER; }
			| FOREIGN DATA_P WRAPPER			{ $$ = OBJECT_FDW; }
		;

comment_text:
			Sconst								{ $$ = $1; }
			| NULL_P							{ $$ = NULL; }
		;


/*****************************************************************************
 *
 *  SECURITY LABEL [FOR <provider>] ON <object> IS <label>
 *
 *  As with COMMENT ON, <object> can refer to various types of database
 *  objects (e.g. TABLE, COLUMN, etc.).
 *
 *****************************************************************************/

SecLabelStmt:
			SECURITY LABEL opt_provider ON security_label_type any_name
			IS security_label
				{					
					SecLabelStmt *n = makeNode(SecLabelStmt);
					n->provider = $3;
					n->objtype = $5;
					n->objname = $6;
					n->objargs = NIL;
					n->label = $8;
					$$ = (Node *) n;
				}
			| SECURITY LABEL opt_provider ON AGGREGATE func_name aggr_args
			  IS security_label
				{
					SecLabelStmt *n = makeNode(SecLabelStmt);
					n->provider = $3;
					n->objtype = OBJECT_AGGREGATE;
					n->objname = $6;
					n->objargs = $7;
					n->label = $9;
					$$ = (Node *) n;
				}
			| SECURITY LABEL opt_provider ON FUNCTION func_name func_args
			  IS security_label
				{
					SecLabelStmt *n = makeNode(SecLabelStmt);
					n->provider = $3;
					n->objtype = OBJECT_FUNCTION;
					n->objname = $6;
					n->objargs = extractArgTypes($7);
					n->label = $9;
					$$ = (Node *) n;
				}
			| SECURITY LABEL opt_provider ON LARGE_P OBJECT_P NumericOnly
			  IS security_label
				{
					SecLabelStmt *n = makeNode(SecLabelStmt);
					n->provider = $3;
					n->objtype = OBJECT_LARGEOBJECT;
					n->objname = list_make1($7);
					n->objargs = NIL;
					n->label = $9;
					$$ = (Node *) n;
				}
			| SECURITY LABEL opt_provider ON opt_procedural LANGUAGE any_name
			  IS security_label
				{
					SecLabelStmt *n = makeNode(SecLabelStmt);
					n->provider = $3;
					n->objtype = OBJECT_LANGUAGE;
					n->objname = $7;
					n->objargs = NIL;
					n->label = $9;
					$$ = (Node *) n;
				}
		;

opt_provider:	FOR ColId_or_Sconst	{ $$ = $2; }
				| /* empty */		{ $$ = NULL; }
		;

security_label_type:
			COLUMN								{ $$ = OBJECT_COLUMN; }
			| DATABASE							{ $$ = OBJECT_DATABASE; }
			| EVENT_TRIGGER                     { $$ = OBJECT_EVENT_TRIGGER; }
			| FOREIGN TABLE						{ $$ = OBJECT_FOREIGN_TABLE; }
			| SCHEMA							{ $$ = OBJECT_SCHEMA; }
			| SEQUENCE							{ $$ = OBJECT_SEQUENCE; }
			| TABLE								{ $$ = OBJECT_TABLE; }
			| DOMAIN_P							{ $$ = OBJECT_TYPE; }
			| ROLE								{ $$ = OBJECT_ROLE; }
			| USER								{ $$ = OBJECT_USER; }
			| TABLESPACE						{ $$ = OBJECT_TABLESPACE; }
			| TYPE_P							{ $$ = OBJECT_TYPE; }
			| VIEW								{ $$ = OBJECT_VIEW; }
			| MATERIALIZED VIEW 				{ $$ = OBJECT_MATVIEW; }
		;

security_label:	Sconst				{ $$ = $1; }
				| NULL_P			{ $$ = NULL; }
		;

/*****************************************************************************
 *
 *		QUERY:
 *			fetch/move
 *
 *****************************************************************************/

FetchStmt:	FETCH fetch_args
				{
					FetchStmt *n = (FetchStmt *) $2;
					n->ismove = FALSE;
					$$ = (Node *)n;
				}
			| MOVE fetch_args
				{
					FetchStmt *n = (FetchStmt *) $2;
					n->ismove = TRUE;
					$$ = (Node *)n;
				}
		;

fetch_args:	cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $1;
					n->direction = FETCH_FORWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $2;
					n->direction = FETCH_FORWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| NEXT opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_FORWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| PRIOR opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_BACKWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| FIRST_P opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_ABSOLUTE;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| LAST_P opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_ABSOLUTE;
					n->howMany = -1;
					$$ = (Node *)n;
				}
			| ABSOLUTE_P SignedIconst opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_ABSOLUTE;
					n->howMany = $2;
					$$ = (Node *)n;
				}
			| RELATIVE_P SignedIconst opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_RELATIVE;
					n->howMany = $2;
					$$ = (Node *)n;
				}
			| SignedIconst opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_FORWARD;
					n->howMany = $1;
					$$ = (Node *)n;
				}
			| ALL opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_FORWARD;
					n->howMany = FETCH_ALL;
					$$ = (Node *)n;
				}
			| FORWARD opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_FORWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| FORWARD SignedIconst opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_FORWARD;
					n->howMany = $2;
					$$ = (Node *)n;
				}
			| FORWARD ALL opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_FORWARD;
					n->howMany = FETCH_ALL;
					$$ = (Node *)n;
				}
			| BACKWARD opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $3;
					n->direction = FETCH_BACKWARD;
					n->howMany = 1;
					$$ = (Node *)n;
				}
			| BACKWARD SignedIconst opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_BACKWARD;
					n->howMany = $2;
					$$ = (Node *)n;
				}
			| BACKWARD ALL opt_from_in cursor_name
				{
					FetchStmt *n = makeNode(FetchStmt);
					n->portalname = $4;
					n->direction = FETCH_BACKWARD;
					n->howMany = FETCH_ALL;
					$$ = (Node *)n;
				}
		;

from_in:	FROM									{}
			| IN_P									{}
		;

opt_from_in:	from_in								{}
			| /* EMPTY */							{}
		;


/*****************************************************************************
 *
 * GRANT and REVOKE statements
 *
 *****************************************************************************/

GrantStmt:	GRANT privileges ON privilege_target TO grantee_list
			opt_grant_grant_option
				{
					GrantStmt *n = makeNode(GrantStmt);
					n->is_grant = true;
					n->privileges = $2;
					n->targtype = ($4)->targtype;
					n->objtype = ($4)->objtype;
					n->objects = ($4)->objs;
					n->grantees = $6;
					n->grant_option = $7;
					$$ = (Node*)n;
				}
			| GRANT ALL privilege_str TO UserId
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $5;
					n->action = +1;	/* add, if there are members */
					n->options =  lappend(NULL,makeDefElem("issystemadmin", (Node *)makeInteger(TRUE)));
					$$ = (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->targtype = ($4)->targtype;
					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->targtype = ($7)->targtype;
					n->objtype = ($7)->objtype;
					n->objects = ($7)->objs;
					n->grantees = $9;
					n->behavior = $10;
					$$ = (Node *)n;
				}
			| REVOKE ALL privilege_str FROM UserId
				{
					AlterRoleStmt *n = makeNode(AlterRoleStmt);
					n->role = $5;
					n->action = +1;	/* add, if there are members */
					n->options =  lappend(NULL,makeDefElem("issystemadmin", (Node *)makeInteger(FALSE)));
					$$ = (Node *)n;
				}
		;
privilege_str: PRIVILEGES { $$ = NULL;}
	| PRIVILEGE { $$ = NULL;}
		;


/*
 * Privilege names are represented as strings; the validity of the privilege
 * names gets checked at execution.  This is a bit annoying but we have little
 * choice because of the syntactic conflict with lists of role names in
 * GRANT/REVOKE.  What's more, we have to call out in the "privilege"
 * production any reserved keywords that need to be usable as privilege names.
 */

/* either ALL [PRIVILEGES] or a list of individual privileges */
privileges: privilege_list
				{ $$ = $1; }
			| ALL
				{ $$ = NIL; }
			| ALL PRIVILEGES
				{ $$ = NIL; }
			| ALL '(' columnList ')'
				{
					AccessPriv *n = makeNode(AccessPriv);
					n->priv_name = NULL;
					n->cols = $3;
					$$ = list_make1(n);
				}
			| ALL PRIVILEGES '(' columnList ')'
				{
					AccessPriv *n = makeNode(AccessPriv);
					n->priv_name = NULL;
					n->cols = $4;
					$$ = list_make1(n);
				}
		;

privilege_list:	privilege							{ $$ = list_make1($1); }
			| privilege_list ',' privilege			{ $$ = lappend($1, $3); }
		;

privilege:	SELECT opt_column_list
			{
				AccessPriv *n = makeNode(AccessPriv);
				n->priv_name = pstrdup($1);
				n->cols = $2;
				$$ = n;
			}
		| REFERENCES opt_column_list
			{
				AccessPriv *n = makeNode(AccessPriv);
				n->priv_name = pstrdup($1);
				n->cols = $2;
				$$ = n;
			}
		| CREATE opt_column_list
			{
				AccessPriv *n = makeNode(AccessPriv);
				n->priv_name = pstrdup($1);
				n->cols = $2;
				$$ = n;
			}
		| ColId opt_column_list
			{
				AccessPriv *n = makeNode(AccessPriv);
				n->priv_name = $1;
				n->cols = $2;
				$$ = n;
			}
		;


/* Don't bother trying to fold the first two rules into one using
 * opt_table.  You're going to get conflicts.
 */
privilege_target:
			qualified_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_RELATION;
					n->objs = $1;
					$$ = n;
				}
			| TABLE qualified_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_RELATION;
					n->objs = $2;
					$$ = n;
				}
			| SEQUENCE qualified_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_SEQUENCE;
					n->objs = $2;
					$$ = n;
				}
			| LARGE_P SEQUENCE qualified_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_SEQUENCE;
					n->objs = $3;
					$$ = n;
				}
			| FOREIGN DATA_P WRAPPER name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_FDW;
					n->objs = $4;
					$$ = n;
				}
			| FOREIGN SERVER name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_FOREIGN_SERVER;
					n->objs = $3;
					$$ = n;
				}
			| FUNCTION function_with_argtypes_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_FUNCTION;
					n->objs = $2;
					$$ = n;
				}
			| PACKAGE any_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_PACKAGE;
					n->objs = $2;
					$$ = n;
				}
			| PROCEDURE function_with_argtypes_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_FUNCTION;
					n->objs = $2;
					$$ = n;
				}
			| DATABASE name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_DATABASE;
					n->objs = $2;
					$$ = n;
				}
			| DOMAIN_P any_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_DOMAIN;
					n->objs = $2;
					$$ = n;
				}
			| LANGUAGE name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_LANGUAGE;
					n->objs = $2;
					$$ = n;
				}
			| LARGE_P OBJECT_P NumericOnly_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_LARGEOBJECT;
					n->objs = $3;
					$$ = n;
				}
			| NODE GROUP_P name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_NODEGROUP;
					n->objs = $3;
					$$ = n;
				}
			| SCHEMA name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_NAMESPACE;
					n->objs = $2;
					$$ = n;
				}
			| TABLESPACE name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_TABLESPACE;
					n->objs = $2;
					$$ = n;
				}
			| DIRECTORY name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_DIRECTORY;
					n->objs = $2;
					$$ = n;
				}
			| TYPE_P any_name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_TYPE;
					n->objs = $2;
					$$ = n;
				}
			| ALL TABLES IN_P SCHEMA name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
					n->objtype = ACL_OBJECT_RELATION;
					n->objs = $5;
					$$ = n;
				}
			| ALL SEQUENCES IN_P SCHEMA name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
					n->objtype = ACL_OBJECT_SEQUENCE;
					n->objs = $5;
					$$ = n;
				}
			| ALL FUNCTIONS IN_P SCHEMA name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
					n->objtype = ACL_OBJECT_FUNCTION;
					n->objs = $5;
					$$ = n;
				}
			| ALL PACKAGES IN_P SCHEMA name_list
                {
                    PrivTarget *n = (PrivTarget *)palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
					n->objtype = ACL_OBJECT_PACKAGE;
					n->objs = $5;
					$$ = n;
                }
			| DATA_P SOURCE_P name_list
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_DATA_SOURCE;
					n->objs = $3;
					$$ = n;
				}
			| CLIENT_MASTER_KEY setting_name
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_GLOBAL_SETTING;
					n->objs = $2;
					$$ = n;
				}
			| COLUMN_ENCRYPTION_KEY setting_name
				{
					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
					n->targtype = ACL_TARGET_OBJECT;
					n->objtype = ACL_OBJECT_COLUMN_SETTING;
					n->objs = $2;
					$$ = n;
				}
		;


grantee_list:
			grantee									{ $$ = list_make1($1); }
			| grantee_list ',' grantee				{ $$ = lappend($1, $3); }
		;

grantee:	UserId
				{
					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 
				{ 
					if (isSecurityMode)
					{
						/* Do not support this grammar in security mode.*/
        				const char* message = "WITH GRANT OPTION is not supported in security mode.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("WITH GRANT OPTION is not supported in security mode.")));
					}
					$$ = 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 UserId						{ $$ = $3; }
			| /*EMPTY*/									{ $$ = NULL; }
		;

/*****************************************************************************
 *
 * GRANT and REVOKE DATABASE PRIVILEGE statements
 *
 *****************************************************************************/

GrantDbStmt:
            GRANT db_privileges TO grantee_list opt_grant_admin_option
                {
                    GrantDbStmt *n = makeNode(GrantDbStmt);
                    n->is_grant = true;
                    n->privileges = $2;
                    n->grantees = $4;
                    n->admin_opt = $5;
                    $$ = (Node*)n;
                }
            ;

RevokeDbStmt:
            REVOKE db_privileges FROM grantee_list
                {
                    GrantDbStmt *n = makeNode(GrantDbStmt);
                    n->is_grant = false;
                    n->privileges = $2;
                    n->grantees = $4;
                    n->admin_opt = false;
                    $$ = (Node*)n;
                }
            | REVOKE ADMIN OPTION FOR db_privileges FROM grantee_list
                {
                    GrantDbStmt *n = makeNode(GrantDbStmt);
                    n->is_grant = false;
                    n->privileges = $5;
                    n->grantees = $7;
                    n->admin_opt = true;
                    $$ = (Node*)n;
                }
        ;

db_privileges: db_privilege_list                       { $$ = $1; }
        ;

db_privilege_list: db_privilege                        { $$ = list_make1($1); }
            | db_privilege_list ',' db_privilege       { $$ = lappend($1, $3); }
        ;

db_privilege: CREATE ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any table");
                $$ = n;
            }
            | ALTER ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("alter any table");
                $$ = n;
            }
            | DROP ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any table");
                $$ = n;
            }
            | SELECT ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("select any table");
                $$ = n;
            }
            | INSERT ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("insert any table");
                $$ = n;
            }
            | UPDATE ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("update any table");
                $$ = n;
            }
            | DELETE_P ANY TABLE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("delete any table");
                $$ = n;
            }
            | CREATE ANY SEQUENCE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any sequence");
                $$ = n;
            }
            | CREATE ANY INDEX
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any index");
                $$ = n;
            }
            | CREATE ANY FUNCTION
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any function");
                $$ = n;
            }
            | EXECUTE ANY FUNCTION
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("execute any function");
                $$ = n;
            }
            | CREATE ANY PACKAGE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any package");
                $$ = n;
            }
            | EXECUTE ANY PACKAGE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("execute any package");
                $$ = n;
            }
            | CREATE ANY TYPE_P
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any type");
                $$ = n;
            }
            | ALTER ANY TYPE_P
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("alter any type");
                $$ = n;
            }
            | DROP ANY TYPE_P
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any type");
                $$ = n;
            }
            | ALTER ANY SEQUENCE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("alter any sequence");
                $$ = n;
            }
            | DROP ANY SEQUENCE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any sequence");
                $$ = n;
            }
            | SELECT ANY SEQUENCE
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("select any sequence");
                $$ = n;
            }
            | ALTER ANY INDEX
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("alter any index");
                $$ = n;
            }
            | DROP ANY INDEX
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any index");
                $$ = n;
            }
            | CREATE ANY SYNONYM
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any synonym");
                $$ = n;
            }
            | DROP ANY SYNONYM
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any synonym");
                $$ = n;
            }
            | CREATE IDENT SYNONYM
            {
                if (strcasecmp($2, "public") == 0) {
                    DbPriv *n = makeNode(DbPriv);
                    n->db_priv_name = pstrdup("create public synonym");
                    $$ = n;
                } else {
                    ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("Syntax error at or near \"%s\"", $2), parser_errposition(@2)));
                }
            }
            | DROP IDENT SYNONYM
            {
                if (strcasecmp($2, "public") == 0) {
                    DbPriv *n = makeNode(DbPriv);
                    n->db_priv_name = pstrdup("drop public synonym");
                    $$ = n;
                } else {
                    ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("Syntax error at or near \"%s\"", $2), parser_errposition(@2)));
                }
                }
            | CREATE ANY TRIGGER
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("create any trigger");
                $$ = n;
            }
            | ALTER ANY TRIGGER
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("alter any trigger");
                $$ = n;
            }
            | DROP ANY TRIGGER
            {
                DbPriv *n = makeNode(DbPriv);
                n->db_priv_name = pstrdup("drop any trigger");
                $$ = n;
            }
        ;

/*****************************************************************************
 *
 * ALTER DEFAULT PRIVILEGES statement
 *
 *****************************************************************************/

AlterDefaultPrivilegesStmt:
			ALTER DEFAULT PRIVILEGES DefACLOptionList DefACLAction
				{
					AlterDefaultPrivilegesStmt *n = makeNode(AlterDefaultPrivilegesStmt);
					n->options = $4;
					n->action = (GrantStmt *) $5;
					$$ = (Node*)n;
				}
		;

DefACLOptionList:
			DefACLOptionList DefACLOption			{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

DefACLOption:
			IN_P SCHEMA name_list
				{
					$$ = makeDefElem("schemas", (Node *)$3);
				}
			| FOR ROLE name_list
				{
					$$ = makeDefElem("roles", (Node *)$3);
				}
			| FOR USER name_list
				{
					$$ = makeDefElem("roles", (Node *)$3);
				}
		;

/*
 * This should match GRANT/REVOKE, except that individual target objects
 * are not mentioned and we only allow a subset of object types.
 */
DefACLAction:
			GRANT privileges ON defacl_privilege_target TO grantee_list
			opt_grant_grant_option
				{
					GrantStmt *n = makeNode(GrantStmt);
					n->is_grant = true;
					n->privileges = $2;
					n->targtype = ACL_TARGET_DEFAULTS;
					n->objtype = (GrantObjectType)$4;
					n->objects = NIL;
					n->grantees = $6;
					n->grant_option = $7;
					$$ = (Node*)n;
				}
			| REVOKE privileges ON defacl_privilege_target
			FROM grantee_list opt_drop_behavior
				{
					GrantStmt *n = makeNode(GrantStmt);
					n->is_grant = false;
					n->grant_option = false;
					n->privileges = $2;
					n->targtype = ACL_TARGET_DEFAULTS;
					n->objtype = (GrantObjectType)$4;
					n->objects = NIL;
					n->grantees = $6;
					n->behavior = $7;
					$$ = (Node *)n;
				}
			| REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target
			FROM grantee_list opt_drop_behavior
				{
					GrantStmt *n = makeNode(GrantStmt);
					n->is_grant = false;
					n->grant_option = true;
					n->privileges = $5;
					n->targtype = ACL_TARGET_DEFAULTS;
					n->objtype = (GrantObjectType)$7;
					n->objects = NIL;
					n->grantees = $9;
					n->behavior = $10;
					$$ = (Node *)n;
				}
		;

defacl_privilege_target:
			TABLES			{ $$ = ACL_OBJECT_RELATION; }
			| FUNCTIONS		{ $$ = ACL_OBJECT_FUNCTION; }
			| SEQUENCES		{ $$ = ACL_OBJECT_SEQUENCE; }
			| TYPES_P		{ $$ = ACL_OBJECT_TYPE; }
			| CLIENT_MASTER_KEYS			{ $$ = ACL_OBJECT_GLOBAL_SETTING; }
			| COLUMN_ENCRYPTION_KEYS		{ $$ = ACL_OBJECT_COLUMN_SETTING; }
			| PACKAGES      { $$ = ACL_OBJECT_PACKAGE; }
		;


/*****************************************************************************
 *
 *		QUERY: CREATE INDEX
 *
 * Note: we cannot put TABLESPACE clause after WHERE clause unless we are
 * willing to make TABLESPACE a fully reserved word.
 *****************************************************************************/

IndexStmt:	CREATE opt_unique INDEX opt_concurrently opt_index_name
			ON qualified_name access_method_clause '(' index_params ')'
			opt_include opt_reloptions OptPartitionElement opt_table_index_options where_clause
				{
					IndexStmt *n = makeNode(IndexStmt);
					n->unique = $2;
					n->concurrent = $4;
					n->missing_ok = false;
					n->schemaname = $5->schemaname;
					n->idxname = $5->relname;
					n->relation = $7;
					n->accessMethod = $8;
					n->indexParams = $10;
					n->indexIncludingParams = $12;
					n->options = $13;
					n->tableSpace = $14;
					n->indexOptions = $15;
					n->whereClause = $16;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->partClause = NULL;
					n->isPartitioned = false;
					n->isGlobal = false;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;
				}
				| CREATE opt_unique INDEX opt_concurrently opt_index_name
					ON qualified_name access_method_clause '(' index_params ')'
					LOCAL opt_partition_index_def opt_include opt_reloptions OptTableSpace opt_table_index_options
				{

					IndexStmt *n = makeNode(IndexStmt);
					n->unique = $2;
					n->concurrent = $4;
					n->missing_ok = false;
					n->schemaname = $5->schemaname;
					n->idxname = $5->relname;
					n->relation = $7;
					n->accessMethod = $8;
					n->indexParams = $10;
					n->partClause  = $13;
					n->indexIncludingParams = $14;
					n->options = $15;
					n->tableSpace = $16;
					n->indexOptions = $17;
					n->isPartitioned = true;
					n->isGlobal = false;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;

				}
				| CREATE opt_unique INDEX opt_concurrently opt_index_name
					ON qualified_name access_method_clause '(' index_params ')'
					GLOBAL opt_include opt_reloptions OptTableSpace opt_table_index_options
				{

					IndexStmt *n = makeNode(IndexStmt);
					n->unique = $2;
					n->concurrent = $4;
					n->missing_ok = false;
					n->schemaname = $5->schemaname;
					n->idxname = $5->relname;
					n->relation = $7;
					n->accessMethod = $8;
					n->indexParams = $10;
					n->partClause  = NULL;
					n->indexIncludingParams = $13;
					n->options = $14;
					n->tableSpace = $15;
					n->indexOptions = $16;
					n->isPartitioned = true;
					n->isGlobal = true;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;

				}
				| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS opt_index_name
					ON qualified_name access_method_clause '(' index_params ')'
					opt_include opt_reloptions OptPartitionElement opt_index_options where_clause
				{
					IndexStmt *n = makeNode(IndexStmt);
					n->unique = $2;
					n->concurrent = $4;
					n->missing_ok = true;
					n->schemaname = $8->schemaname;
					n->idxname = $8->relname;
					n->relation = $10;
					n->accessMethod = $11;
					n->indexParams = $13;
					n->indexIncludingParams = $15;
					n->options = $16;
					n->tableSpace = $17;
					n->indexOptions = $18;
					n->whereClause = $19;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->partClause = NULL;
					n->isPartitioned = false;
					n->isGlobal = false;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;
				}
				| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS opt_index_name
					ON qualified_name access_method_clause '(' index_params ')'
					LOCAL opt_partition_index_def opt_include opt_reloptions OptTableSpace opt_index_options
				{
					IndexStmt *n = makeNode(IndexStmt);
					n->unique = $2;
					n->concurrent = $4;
					n->missing_ok = true;
					n->schemaname = $8->schemaname;
					n->idxname = $8->relname;
					n->relation = $10;
					n->accessMethod = $11;
					n->indexParams = $13;
					n->partClause  = $16;
					n->indexIncludingParams = $17;
					n->options = $18;
					n->tableSpace = $19;
					n->indexOptions = $20;
					n->isPartitioned = true;
					n->isGlobal = false;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;
				}
				| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS opt_index_name
					ON qualified_name access_method_clause '(' index_params ')'
					GLOBAL opt_include opt_reloptions OptTableSpace opt_index_options
				{
					IndexStmt *n = makeNode(IndexStmt);
					n->missing_ok = true;
					n->unique = $2;
					n->concurrent = $4;
					n->schemaname = $8->schemaname;
					n->idxname = $8->relname;
					n->relation = $10;
					n->accessMethod = $11;
					n->indexParams = $13;
					n->partClause  = NULL;
					n->indexIncludingParams = $16;
					n->options = $17;
					n->tableSpace = $18;
					n->indexOptions = $19;
					n->isPartitioned = true;
					n->isGlobal = true;
					n->excludeOpNames = NIL;
					n->idxcomment = NULL;
					n->indexOid = InvalidOid;
					n->oldNode = InvalidOid;
					n->primary = false;
					n->isconstraint = false;
					n->deferrable = false;
					n->initdeferred = false;
					$$ = (Node *)n;
				}
		;

opt_unique:
			UNIQUE									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_concurrently:
			CONCURRENTLY							{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_index_name:
			index_name
				{
					$$ = makeRangeVar(NULL, $1, @1);
				}
			| ColId indirection
				{
					check_qualified_name($2, yyscanner);
					$$ = makeRangeVar(NULL, NULL, @1);
					const char* message = "improper qualified name (too many dotted names): %s";
					switch (list_length($2))
					{
						case 1:
							$$->catalogname = NULL;
							$$->schemaname = $1;
							$$->relname = strVal(linitial($2));
							break;
						default:
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("improper qualified name (too many dotted names): %s",
											NameListToString(lcons(makeString($1), $2))),
									 parser_errposition(@1)));
							break;
					}
				}
			| /*EMPTY*/								{ $$ = makeRangeVar(NULL, NULL, -1); }
		;

/* b compatibility index hint part */
key_usage_list:
			index_name
			{
				$$ = list_make1(makeString($1));
			}
			| key_usage_list ',' index_name
			{
				$$ = lappend($1,makeString($3));
			}
		;

index_hint_definition:
			USE_INDEX '(' key_usage_list ')'
			{
				IndexHintDefinition* n = makeNode(IndexHintDefinition);
				n->index_type = INDEX_HINT_USE;
				n->indexnames = $3;
				$$ = (Node*)n;
			}
			| USE_INDEX '(' ')'
			{
				IndexHintDefinition* n = makeNode(IndexHintDefinition);
				n->index_type = INDEX_HINT_USE;
				n->indexnames = NIL;
				$$ = (Node*)n;
			}
			| FORCE_INDEX '(' key_usage_list ')'
			{
				IndexHintDefinition* n = makeNode(IndexHintDefinition);
				n->index_type = INDEX_HINT_FORCE;
				n->indexnames = $3;
				$$ = (Node*)n;
			}
			| IGNORE_INDEX '(' key_usage_list ')'
			{
				IndexHintDefinition* n = makeNode(IndexHintDefinition);
				n->index_type = INDEX_HINT_IGNORE;
				n->indexnames = $3;
				$$ = (Node*)n;
			}
		;

index_hint_list:
			index_hint_definition
			{
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT)
				{
					const char* message = "index_hint is supported only in B-format database";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("index_hint is supported only in B-format database"),
							parser_errposition(@1)));
				}
				$$ = list_make1($1);
			}
			| index_hint_list index_hint_definition
			{
				$$ = lappend($1,$2);
			}
		;

opt_index_hint_list:
			index_hint_list {$$ = $1;}
			| /*Empty*/ {$$ = NIL;}
		;
/* b compatibility index hint part end*/


access_method_clause:
			USING access_method						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

access_method_clause_without_keyword:
			USING IDENT								{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

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_collation opt_class opt_asc_desc opt_nulls_order
				{
					$$ = makeNode(IndexElem);
					$$->name = $1;
					$$->expr = NULL;
					$$->indexcolname = NULL;
					$$->collation = $2;
					$$->opclass = $3;
					$$->ordering = (SortByDir)$4;
					$$->nulls_ordering = (SortByNulls)$5;
				}
			| index_functional_expr_key opt_collation opt_class opt_asc_desc opt_nulls_order
				{
					$$ = makeNode(IndexElem);
					$$->name = NULL;
					$$->expr = $1;
					$$->indexcolname = NULL;
					$$->collation = $2;
					$$->opclass = $3;
					$$->ordering = (SortByDir)$4;
					$$->nulls_ordering = (SortByNulls)$5;
				}
			| '(' a_expr ')' opt_collation opt_class opt_asc_desc opt_nulls_order
				{
					$$ = makeNode(IndexElem);
					$$->name = NULL;
					$$->expr = $2;
					$$->indexcolname = NULL;
					$$->collation = $4;
					$$->opclass = $5;
					$$->ordering = (SortByDir)$6;
					$$->nulls_ordering = (SortByNulls)$7;
				}
		;

constraint_params:	constraint_elem							{ $$ = list_make1($1); }
			| constraint_params ',' constraint_elem			{ $$ = lappend($1, $3); }
		;

con_asc_desc: ASC							{ $$ = SORTBY_ASC; }
			| DESC							{ $$ = SORTBY_DESC; }
		;

constraint_elem: ColId con_asc_desc
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "ASC/DESC is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ASC/DESC is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						$$ = makeNode(IndexElem);
						$$->name = $1;
						$$->expr = NULL;
						$$->indexcolname = NULL;
						$$->collation = NIL;
						$$->opclass = NIL;
						$$->ordering = (SortByDir)$2;
						$$->nulls_ordering = SORTBY_NULLS_DEFAULT;
					} else {
						const char* message = "ASC/DESC is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("ASC/DESC is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
				}
			| ColId
				{
					$$ = makeNode(IndexElem);
					$$->name = $1;
					$$->expr = NULL;
					$$->indexcolname = NULL;
					$$->collation = NIL;
					$$->opclass = NIL;
					$$->ordering = SORTBY_DEFAULT;
					$$->nulls_ordering = SORTBY_NULLS_DEFAULT;
				}
			| ColId '(' Iconst ')' opt_asc_desc
				{
					PrefixKey* pk = makeNode(PrefixKey);
					pk->arg = (Expr*)makeColumnRef(pstrdup($1), NIL, @1, yyscanner);
					pk->length = $3;

					$$ = makeNode(IndexElem);
					$$->name = NULL;
					$$->expr = (Node*)pk;
					$$->indexcolname = NULL;
					$$->collation = NIL;
					$$->opclass = NIL;
					$$->ordering = (SortByDir)$5;
					$$->nulls_ordering = SORTBY_NULLS_DEFAULT;
				}
			| '(' a_expr ')' opt_asc_desc
				{
#ifdef 			ENABLE_MULTIPLE_NODES	
					const char* message = "expression is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("expression is not yet supported in distributed database.")));
#endif	
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						$$ = makeNode(IndexElem);
						$$->name = NULL;
						$$->expr = $2;
						$$->indexcolname = NULL;
						$$->collation = NIL;
						$$->opclass = NIL;
						$$->ordering = (SortByDir)$4;
						$$->nulls_ordering = SORTBY_NULLS_DEFAULT;
					} else {
						const char* message = "expression is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("expression is supported only in B-format database."),
									parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
					
				}
		;

index_functional_expr_key:	col_name_keyword_nonambiguous '(' Iconst ')'
					{
						PrefixKey* pk = makeNode(PrefixKey);
						pk->arg = (Expr*)makeColumnRef(pstrdup($1), NIL, @1, yyscanner);
						pk->length = $3;
						$$ = (Node*)pk;
					}
				| func_name '(' func_arg_list opt_sort_clause ')'
					{
						List* elist = (List*)$3;
						List* nlist = (List*)$1;
						
						/*
						 * This syntax branch can be parsed either as a column prefix or as a function.
						 * In B-compatible mode, it is preferentially treated as a column prefix.
						 */
						if ($4 == NIL && list_length(elist) == 1 && list_length(nlist) == 1) {
							Node* arg = (Node*)linitial(elist);
							if (IsA(arg, A_Const) && ((A_Const*)arg)->val.type == T_Integer) {
								PrefixKey* pk = makeNode(PrefixKey);
								pk->arg = (Expr*)makeColumnRef(strVal(linitial(nlist)), NIL, @1, yyscanner);
								pk->length = intVal(&((A_Const*)arg)->val);
								$$ = (Node*)pk;
								break;
							}
						}
						
						FuncCall *n = makeNode(FuncCall);
						n->funcname = $1;
						n->args = $3;
						n->agg_order = $4;
						n->agg_star = FALSE;
						n->agg_distinct = FALSE;
						n->func_variadic = FALSE;
						n->over = NULL;
						n->location = @1;
						n->call_func = false;
						$$ = (Node *)n;
					}
				| func_application_special  { $$ = $1; }
				| func_expr_common_subexpr  { $$ = $1; }
				| CURRENT_SCHEMA
					{
						$$ = MakeNoArgFunctionCall(SystemFuncName("current_schema"), @1);
					}
		;

opt_include:		INCLUDE '(' index_including_params ')'			{ $$ = $3; }
			 |		/* EMPTY */						{ $$ = NIL; }
		;

index_including_params:	index_elem						{ $$ = list_make1($1); }
			| index_including_params ',' index_elem		{ $$ = lappend($1, $3); }
		;

collate:
			COLLATE opt_equal charset_collate_name
			{
#ifdef ENABLE_MULTIPLE_NODES
				const char* message = "specifying character sets and collations is not yet supported";
				InsertErrorMessage(message, u_sess->plsql_cxt.gsplsql_yylloc);
				ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("Un-support feature"),
					errdetail(specifying character sets and collations is not yet supported)));
#endif
				if (!DB_IS_CMPT_BD) {
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("specifying character sets and collations is supported only in B-format or D-format database")));
				}
				$$ = $3;
			}
		;

set_names_collate:    COLLATE charset_collate_name		{ $$ = $2; }
					| COLLATE DEFAULT					{ $$ = NULL; }
					| /*EMPTY*/							{ $$ = NULL; }
			;

opt_collate:
				collate								{ $$ = $1; }
				| /*EMPTY*/							{ $$ = NULL; }
			;

default_collate:
				collate								{ $$ = $1; }
				| DEFAULT collate					{ $$ = $2; }
			;

opt_collation: 
				COLLATE collate_name				{ $$ = $2; }
				| /*EMPTY*/							{ $$ = NIL; }
			;

opt_class:	any_name								{ $$ = $1; }
			| USING any_name						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

opt_asc_desc: ASC							{ $$ = SORTBY_ASC; }
			| DESC							{ $$ = SORTBY_DESC; }
			| /*EMPTY*/						{ $$ = SORTBY_DEFAULT; }
		;

opt_nulls_order: NULLS_FIRST				{ $$ = SORTBY_NULLS_FIRST; }
			| NULLS_LAST					{ $$ = SORTBY_NULLS_LAST; }
			| /*EMPTY*/						{ $$ = SORTBY_NULLS_DEFAULT; }
		;


opt_partition_index_def:	'(' range_partition_index_list  ')'
							{
								$$ = (Node *)$2;
							}
							| 	{$$ = NULL;}
							;

range_partition_index_list:
							range_partition_index_item
							{
								$$ = (Node*)list_make1($1);
							}
							| range_partition_index_list ',' range_partition_index_item
							{
								$$ = (Node*)lappend((List*)$1, $3);
							}
							;


range_partition_index_item:
                        PARTITION index_name opt_part_options
                        {
                            RangePartitionindexDefState* def = makeNode(RangePartitionindexDefState);
                            def->name = $2;
                            def->tablespace = $3;
                            $$ = (Node*)def;

                        }
                        | PARTITION index_name opt_part_options opt_subpartition_index_def
                        {
                            RangePartitionindexDefState* def = makeNode(RangePartitionindexDefState);
                            def->name = $2;
                            def->tablespace = $3;
                            def->sublist = (List *)$4;
                            $$ = (Node*)def;
                        }
						;

opt_subpartition_index_def:
                        '(' range_subpartition_index_list  ')'
                        {
                            $$ = (Node *)$2;
                        }
                        ;

range_subpartition_index_list:
                        range_subpartition_index_item
                        {
                            $$ = (Node*)list_make1($1);
                        }
                        | range_subpartition_index_list ',' range_subpartition_index_item
                        {
                            $$ = (Node*)lappend((List*)$1, $3);
                        }
                        ;

range_subpartition_index_item:
                       SUBPARTITION index_name opt_part_options
                        {
                            RangePartitionindexDefState* def = makeNode(RangePartitionindexDefState);
                            def->name = $2;
                            def->tablespace = $3;
                            $$ = (Node*)def;
                        }
                        ;
/*****************************************************************************
 *
 *		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 definer_user FUNCTION func_name_opt_arg proc_args
			RETURNS func_return createfunc_opt_list opt_definition
				{
					set_function_style_pg();
					CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
					n->isOraStyle = false;
					n->isPrivate = false;
					n->replace = $2;
					n->definer = $3;
					if (n->replace && NULL != n->definer) {
						parser_yyerror("not support DEFINER function");
					}			
					n->funcname = $5;
					n->parameters = $6;
					n->returnType = $8;
					n->options = $9;
					n->withClause = $10;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
			| CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args
			  RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
				{
					set_function_style_pg();
					CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
					n->isOraStyle = false;
					n->isPrivate = false;
					n->replace = $2;
					n->definer = $3;
					if (n->replace && NULL != n->definer) {
						parser_yyerror("not support DEFINER function");
					}
					n->funcname = $5;
					n->parameters = mergeTableFuncParameters($6, $10);
					n->returnType = TableFuncTypeName($10);
					n->returnType->location = @8;
					n->options = $12;
					n->withClause = $13;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
			| CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args
			  createfunc_opt_list opt_definition
				{
					set_function_style_pg();
					CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
					n->isOraStyle = false;
					n->isPrivate = false;
					n->replace = $2;
					n->definer = $3;
					if (n->replace && NULL != n->definer) {
						parser_yyerror("not support DEFINER function");
					}
					n->funcname = $5;
					n->parameters = $6;
					n->returnType = NULL;
					n->options = $7;
					n->withClause = $8;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
			| CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args
			  RETURN func_return opt_createproc_opt_list as_is {
				  u_sess->parser_cxt.eaten_declare = false;
				  u_sess->parser_cxt.eaten_begin = false;
				  pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
                  u_sess->parser_cxt.isCreateFuncOrProc = true;
				  if (set_is_create_plsql_type()) {
					set_create_plsql_type_start();
					set_function_style_a();
				  }
			  } subprogram_body
				{
					int rc = 0;
					rc = CompileWhich();
                                        if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) {
                                            u_sess->plsql_cxt.procedure_first_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @10);
                                        }
					CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
					FunctionSources *funcSource = (FunctionSources *)$12;
					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = $2;
					n->definer = $3;
					if (n->replace && NULL != n->definer) {
						parser_yyerror("not support DEFINER function");
					}
					n->funcname = $5;
					n->parameters = $6;
					n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
					if (enable_plpgsql_gsdependency_guc()) {
						n->funcHeadSrc = ParseFuncHeadSrc(yyscanner);
					}
					n->returnType = $8;
					n->options = $9;
					n->options = lappend(n->options, makeDefElem("as",
										(Node *)list_make1(makeString(funcSource->bodySrc))));
					n->options = lappend(n->options, makeDefElem("language",
										(Node *)makeString("plpgsql")));

					n->withClause = NIL;
					n->withClause = NIL;
					n->isProcedure = false;
                    u_sess->parser_cxt.isCreateFuncOrProc = false;
					$$ = (Node *)n;
				}
		;
CallFuncStmt:    CALL func_name '(' ')'
					{
#ifndef ENABLE_MULTIPLE_NODES
						$$ = makeCallFuncStmt($2, NULL, enable_out_param_override());
#else
						$$ = makeCallFuncStmt($2, NULL, false);
#endif
					}
				|	CALL func_name '(' callfunc_args ')'
					{
						ListCell* l = list_head($2);
						Node* name = (Node*)lfirst(l);
						if (IsA(name, String) && (strcmp(strVal(name), "gms_lob") == 0)) {
							ListCell* lc = list_head($4);
							Node* n1  = (Node*)lfirst(lc);
							if (IsA(n1, ColumnRef)) {
								char* lobname = strVal(linitial(((ColumnRef*)n1)->fields));
								Node* funcname = (Node*)lfirst(list_tail($2));
								if (strcmp(strVal(funcname), "createtemporary") == 0) {
									if (list_length($4) == 2) {
										$4 = lappend($4, makeIntConst(10, -1));
									}
								}
								if (strcmp(strVal(funcname), "getlength") != 0) {
									$4 = lappend($4, makeStringConst(lobname, -1));
								}
							} else if (IsA(n1, NamedArgExpr)) {
								Node* n2 = ((Node*)((NamedArgExpr*)n1)->arg);
								if (IsA(n2, ColumnRef)) {
									char* lobname = strVal(linitial(((ColumnRef*)n2)->fields));
									Node* funcname = (Node*)lfirst(list_tail($2));
									if (strcmp(strVal(funcname), "createtemporary") == 0) {
										if (list_length($4) == 2) {
											$4 = lappend($4, makeIntConst(10, -1));
										}
									}
									NamedArgExpr *na = makeNode(NamedArgExpr);
									na->name = pstrdup("lobname");
									na->arg = (Expr *)makeStringConst(lobname, -1);
									na->argnumber = -1;		/* until determined */
									na->location = @1;
									if (strcmp(strVal(funcname), "getlength") != 0) {
										$4 = lappend($4, (Node *) na);
									}
								}
							}
						}
#ifndef ENABLE_MULTIPLE_NODES
						$$ = makeCallFuncStmt($2, $4, enable_out_param_override());
#else
						$$ = makeCallFuncStmt($2, $4, false);
#endif
					}
				;
callfunc_args:   func_arg_expr
				{
					$$ = list_make1($1);
				}
			| callfunc_args ',' func_arg_expr
				{
					$$ = lappend($1, $3);
				}
			;
			
/*****************************************************************************
 *
 *             QUERY:
 *                             create [definer_name] event [IF NOT EXIST] <ename>
 *                                             on schedule schedule_time
 *                                             [ON COMPLETION [NOT] PRESERVE]
 *                                             [ENABLE | DISABLE | DISABLE ON SLAVE]
 *                                             [COMMENT 'string']
 *                                             do event_body
 *
 *****************************************************************************/
 
 CreateEventStmt:
                CREATE opt_or_replace definer_opt EVENT qualified_name ON SCHEDULE start_expr opt_ev_on_completion
                opt_ev_status comment_opt DO ev_body
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "create event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("CREATE EVENT is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						const char* message = "create event statement is only supported in B format.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate, (errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("CREATE EVENT is supported only in B-format database"),
								parser_errposition(@1)));
						$$ = NULL;
					} 
					if($2) {
						parser_yyerror("EVENT not support REPLACE function");
					}
					CreateEventStmt *n = makeNode(CreateEventStmt);
					n->def_name = $3;
					n->if_not_exists = false;
					n->event_name = $5;
					n->start_time_expr = $8;
					n->end_time_expr = NULL;
					n->interval_time = NULL;
					n->complete_preserve = $9;
					n->event_status = (EventStatus)$10;
					n->event_comment_str = $11;
					n->event_query_str = $13;
					$$ = (Node *)n;
				}
				| CREATE opt_or_replace definer_opt EVENT IF_P NOT EXISTS qualified_name ON SCHEDULE start_expr opt_ev_on_completion
                opt_ev_status comment_opt DO ev_body
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "create event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("CREATE EVENT is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						const char* message = "create event statement is only supported in B format.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("CREATE EVENT is supported only in B-format database."),
								parser_errposition(@1)));
						$$ = NULL;
					} 
					if($2) {
						parser_yyerror("EVENT not support REPLACE function");
					}
					CreateEventStmt *n = makeNode(CreateEventStmt);
					n->def_name = $3;
					n->if_not_exists = true;
					n->event_name = $8;
					n->start_time_expr = $11;
					n->end_time_expr = NULL;
					n->interval_time = NULL;
					n->complete_preserve = $12;
					n->event_status = (EventStatus)$13;
					n->event_comment_str = $14;
					n->event_query_str = $16;
					$$ = (Node *)n;
				}
				| CREATE opt_or_replace definer_opt EVENT qualified_name ON SCHEDULE EVERY every_interval start_expr end_expr opt_ev_on_completion
				opt_ev_status comment_opt DO ev_body
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "create event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("CREATE EVENT is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						const char* message = "create event statement is only supported in B format.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("CREATE EVENT is supported only in B-format database."),
								parser_errposition(@1)));
						$$ = NULL;
					}
					if($2) {
						parser_yyerror("EVENT not support REPLACE function");
					}
					CreateEventStmt *n = makeNode(CreateEventStmt);
					n->def_name = $3;
					n->if_not_exists = false;
					n->event_name = $5;
					n->start_time_expr = $10;
					n->end_time_expr = $11;
					n->interval_time = $9;
					n->complete_preserve = $12;
					n->event_status = (EventStatus)$13;
					n->event_comment_str = $14;
					n->event_query_str = $16;
					$$ = (Node *)n;
				}
				| CREATE opt_or_replace definer_opt EVENT IF_P NOT EXISTS qualified_name ON SCHEDULE EVERY every_interval start_expr end_expr opt_ev_on_completion
				opt_ev_status comment_opt DO ev_body
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "create event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); 
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("CREATE EVENT is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						const char* message = "create event statement is only supported in B format.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("CREATE EVENT is supported only in B-format database."),
								parser_errposition(@1)));
						$$ = NULL;
					}
					if($2) {
						parser_yyerror("EVENT not support REPLACE function");
					}
					CreateEventStmt *n = makeNode(CreateEventStmt);
					n->def_name = $3;
					n->if_not_exists = true;
					n->event_name = $8;
					n->start_time_expr = $13;
					n->end_time_expr = $14;
					n->interval_time = $12;
					n->complete_preserve = $15;
					n->event_status = (EventStatus)$16;
					n->event_comment_str = $17;
					n->event_query_str = $19;
					$$ = (Node *)n;
				}
			;


definer_opt:
			DEFINER '=' user                        { $$ = $3; }
			| /* EMPTY */                           { $$ = NULL; }
		;

user:
		ColId                                                                   { $$ = $1; }
	;

event_interval_unit: opt_interval			{$$ = $1;}
					| opt_evtime_unit		{$$ = $1;}
				;

every_interval:
                Iconst event_interval_unit			
				{
					TypeName *t;
					t = SystemTypeName("interval");
					t->typmods = $2;
					Node *num = makeIntConst($1, @1);
		            $$ = makeTypeCast(num, t, NULL, NULL, NULL, -1);
				}
				| Sconst event_interval_unit
				{
					TypeName *t;
					t = SystemTypeName("interval");
					t->typmods = $2;
					Node *num = makeStringConst($1, @1);
					$$ = makeTypeCast(num, t, NULL, NULL, NULL, -1);
				}
				| FCONST event_interval_unit
				{
					TypeName *t;
					t = SystemTypeName("interval");
					t->typmods = $2;
					Node *num = makeStringConst($1, @1);
					$$ = makeTypeCast(num, t, NULL, NULL, NULL, -1);
				}
			;

start_expr:		STARTS ev_timeexpr
			{ $$ = $2; }
				| AT ev_timeexpr  		
			{ $$ = $2; }
				| /* EMPTY */               { $$ = NULL; }
			;

end_expr:		ENDS ev_timeexpr		
			{ $$ = $2; }
				| /* EMPTY */ 				{ $$ = NULL; }
			;

ev_timeexpr:		initime	{ $$ = $1; }
			| initime '+' interval_list
			{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2);}
			| initime '-' interval_list
			{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2);}
		;

interval_list: interval_cell						{ $$ = $1; }
			| interval_list '+' interval_list
            	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
            | interval_list '-' interval_list
            	{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
	;

interval_cell:  ConstInterval ICONST opt_interval
				{
					char* a = NULL;
					a = (char*)palloc(8);
					pg_itoa($2, a);
					TypeName *t = $1;
					t->typmods = $3;
					$$ = makeStringConstCast(a, @2, t);
				}
				| ConstInterval Sconst opt_interval
				{
					TypeName *t = $1;
					t->typmods = $3;
					$$ = makeStringConstCast($2, @2, t);
				}
				| ConstInterval FCONST opt_interval
				{
					$$  = makeFloatConst($2, @2);
				}
				| /* EMPTY */ 				{ $$ = NULL; }
			;

initime: 		interval_intexpr			{$$ = $1; }
				| functime_expr				{$$ = $1; }
				| functime_app				{$$ = $1; }
			;

functime_app:			IDENT '(' ')'
				{
					FuncCall *n = makeNode(FuncCall);
					
					n->funcname = list_make1(makeString($1));
					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;
					n->call_func = false;
					$$ = (Node *)n;
				}
				| IDENT '(' func_arg_list ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = list_make1(makeString($1));
					n->args = $3;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			;

functime_expr: 
			CURRENT_TIMESTAMP
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("pg_systimestamp");
					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;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| CURRENT_TIMESTAMP '(' Iconst ')'
				{
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("timestamptz");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast(n, d, NULL, NULL, NULL, @1);
				}
			| LOCALTIMESTAMP
				{
					Node *n;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					$$ = makeTypeCast(n, SystemTypeName("timestamp"), NULL, NULL, NULL, @1);
				}
			| LOCALTIMESTAMP '(' Iconst ')'
				{
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("timestamp");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast(n, d, NULL, NULL, NULL, @1);
				}
			| SYSDATE
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("sysdate");
					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;
					n->call_func = false;
					$$ = (Node *)n;
				}
			;

interval_intexpr:
		 Sconst
		{
			$$ = makeStringConstCast($1, @1, SystemTypeName("timestamp"));
		}
	;

opt_ev_on_completion:
                       ON COMPLETION PRESERVE                  { $$ = FALSE; }
                       | ON COMPLETION NOT PRESERVE            { $$ = TRUE; }
                       | /*EMPTY*/                             	   { $$ = TRUE; }
               	;

opt_ev_status:
                       ENABLE_P                        				{ $$ = EVENT_ENABLE; }
                       | DISABLE_P                            		{ $$ = EVENT_DISABLE; }
                       | DISABLE_P ON SLAVE         				{ $$ = EVENT_DISABLE_ON_SLAVE; }
                       | /*EMPTY*/                                	{ $$ = EVENT_ENABLE; }
               ;



comment_opt:    COMMENT SCONST                                  { $$ = $2; }
                | /*EMPTY*/                                     { $$ = NULL; }
	;

ev_body:    {
				char    *ev_body_str = NULL;
				int     ev_body_len = 0;
				int     tok = YYEMPTY;
				int     proc_b = 0;
				int     proc_e = 0;
				int     rc = 0;
				int     pre_tok = 0;
				int    	ploc = 0;
				int     pre_loc = 0;
				int     next_tok = 0;
				int  	flag = 0;
				rc = CompileWhich();
				base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
				if (yychar == YYEOF || yychar == YYEMPTY) {
					tok = YYLEX;
				}
				else {
					tok = yychar;
					yychar = YYEMPTY;
				}
				proc_b = yylloc;
				/* start event body scan */
				while (true) {
					if(tok == ';') {
						++flag;
					}

					if(tok == YYEOF ) {
						tok = YYLEX;
						if(flag) {
							proc_e = pre_loc;
						} else {
							proc_e = yylloc;
						}	
						break;
					}
					ploc = yylloc;
					if(tok != 0) {
						pre_loc = ploc;
					}
					pre_tok = tok;
					tok = YYLEX;
				}
				if (proc_e == 0) {
					ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("event body is not ended correctly.")));
				}
				ev_body_len = proc_e - proc_b + 1;
				ev_body_str = (char*)palloc0(ev_body_len + 1);
				rc = strncpy_s(ev_body_str, ev_body_len + 1, yyextra->core_yy_extra.scanbuf + proc_b - 1, ev_body_len);
				securec_check(rc, "\0", "\0");
				ev_body_str[ev_body_len] = '\0';
				/* Reset the flag which mark whether we are in slash proc. */
				yyextra->core_yy_extra.in_slash_proc_body = false;
				yyextra->core_yy_extra.dolqstart = NULL;
				$$ = ev_body_str;
		}
	;


/*****************************************************************************
 *
 *             QUERY:
 *                  ALTER
 *						[DEFINER = user]
 *						EVENT event_name
 *						[ON SCHEDULE schedule]
 *						[ON COMPLETION [NOT] PRESERVE]
 *						[RENAME TO new_event_name]
 *						[ENABLE | DISABLE | DISABLE ON SLAVE]
 *						[COMMENT 'string']
 *						[DO event_body]
 *
 *****************************************************************************/
AlterEventStmt:
					ALTER definer_name_opt EVENT qualified_name  preserve_opt rename_opt status_opt comments_opt action_opt
					{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "alter event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ALTER EVENT is not yet supported in distributed database.")));
#endif
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							const char* message = "alter event statement is only supported in B format.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("ALTER EVENT is supported only in B-format database."),
									parser_errposition(@1)));
							$$ = NULL;
						}
						AlterEventStmt *n = makeNode(AlterEventStmt);
						n->def_name = $2;
						n->event_name = $4;
						n->start_time_expr = NULL;
						n->end_time_expr = NULL;
						n->interval_time = NULL;
						n->complete_preserve = $5;
						n->new_name = $6;
						n->event_status = $7;
						n->event_comment_str = $8;
						n->event_query_str = $9;
						$$ = (Node*)n;
					}
					| ALTER definer_name_opt EVENT qualified_name ON SCHEDULE AT ev_timeexpr preserve_opt 
					rename_opt status_opt comments_opt action_opt
					{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "alter event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ALTER EVENT is not yet supported in distributed database.")));
#endif
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							const char* message = "alter event statement is only supported in B format.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("ALTER EVENT is supported only in B-format database."),
								parser_errposition(@1)));
							$$ = NULL;
						}
						AlterEventStmt *n = makeNode(AlterEventStmt);
						n->def_name = $2;
						n->event_name = $4;
						n->start_time_expr = makeDefElem("start_date", (Node *)$8);
						n->end_time_expr = NULL;
						n->interval_time = makeDefElem("repeat_interval", NULL);
						n->complete_preserve = $9;
						n->new_name = $10;
						n->event_status = $11;
						n->event_comment_str = $12;
						n->event_query_str = $13;
						$$ = (Node*)n;
					}
					| ALTER definer_name_opt EVENT qualified_name ON SCHEDULE EVERY every_interval start_opt
					end_opt preserve_opt rename_opt status_opt comments_opt action_opt
					{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "alter event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ALTER EVENT is not yet supported in distributed database.")));
#endif
						if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
							const char* message = "alter event statement is only supported in B format.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errmodule(MOD_PARSER),
									errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("ALTER EVENT is supported only in B-format database."),
									parser_errposition(@1)));
							$$ = NULL;
							
						}
						AlterEventStmt *n = makeNode(AlterEventStmt);
						n->def_name = $2;
						n->event_name = $4;
						n->start_time_expr = $9;
						n->end_time_expr = $10;
						n->interval_time = makeDefElem("repeat_interval", (Node *)$8);
						n->complete_preserve = $11;
						n->new_name = $12;
						n->event_status = $13;
						n->event_comment_str = $14;
						n->event_query_str = $15;
						$$ = (Node*)n;
					}
                        ;

definer_name_opt:	DEFINER '=' user
			{ 
				$$ = makeDefElem("owner", (Node *)makeString($3));
			} 
                        | /* EMPTY */                           { $$ = NULL; }
                ;


end_opt:                ENDS ev_timeexpr 
                                {
                                        $$ = makeDefElem("end_date", (Node *)$2);
                                }
                                |/*EMPTY*/                      { $$ = NULL; }
                        ;

start_opt:
                                STARTS  ev_timeexpr
                                {
                                        $$ = makeDefElem("start_date", (Node *)$2);
                                }
                                | /*EMPTY*/                     { $$ = NULL; }
                        ;
preserve_opt:   ON COMPLETION PRESERVE
                                {
                                        $$ = makeDefElem("auto_drop", (Node *)makeInteger(0));
                                }
                                | ON COMPLETION NOT PRESERVE
                                {
                                        $$ = makeDefElem("auto_drop", (Node *)makeInteger(1));
                                }
                                | /*EMPTY*/                     { $$ = NULL; }
                        ;

rename_opt:		RENAME TO name
				{
					$$ = makeDefElem("rename", (Node *)makeString($3));
				}
				| /*EMPTY*/			{ $$ = NULL; }
			;
status_opt:		ENABLE_P			{$$ = makeDefElem("enabled", (Node *)makeInteger(0));}
				| DISABLE_P			{$$ = makeDefElem("enabled", (Node *)makeInteger(1));}
				| DISABLE_P ON SLAVE{$$ = makeDefElem("enabled", (Node *)makeInteger(2));}
				| /*EMPTY*/			{ $$ = NULL; }
			;

comments_opt:	COMMENT Sconst					{$$ = makeDefElem("comments", (Node *)makeString($2));}
				| /*EMPTY*/			{ $$ = NULL; }
			;

action_opt:		DO ev_body				{$$ = makeDefElem("program_action", (Node *)makeString($2));}
				| /*EMPTY*/			{ $$ = NULL; }
			;


/*****************************************************************************
 *
 *             QUERY:
 *                             DROP EVENT [IF EXISTS] event_name
 *
 *****************************************************************************/
DropEventStmt:
			DROP EVENT IF_P EXISTS qualified_name
			{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "drop event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("DROP EVENT is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "drop event statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("DROP EVENT is supported only in B-format database."),
							parser_errposition(@1)));
					$$ = NULL;
				}
				DropEventStmt *n = makeNode(DropEventStmt);
				n->missing_ok = true;
				n->event_name = $5;
				$$ = (Node*)n; 
			}
			| DROP EVENT qualified_name
			{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "drop event statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("DROP EVENT is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "drop event statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("DROP EVENT is supported only in B-format database"),
								parser_errposition(@1)));
					$$ = NULL;
				}
				DropEventStmt *n = makeNode(DropEventStmt);
				n->missing_ok = false;
				n->event_name = $3;
				$$ = (Node*)n; 
			}
		;

/*****************************************************************************
 *
 *             QUERY:
 *                             SHOW EVENTS
 *   							[{FROM | IN} schema_name]
 *  							[LIKE 'pattern' | WHERE expr]
 *
 *****************************************************************************/

ShowEventStmt:
			 SHOW EVENTS event_from_clause event_where_clause
			{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "show events statement is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SHOW EVENTS is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "show events statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("SHOW EVENTS is supported only in B-format database."),
							parser_errposition(@1)));
					$$ = NULL;
				}
				ShowEventStmt *n = makeNode(ShowEventStmt);
				n->from_clause = $3;
				n->where_clause = $4;
				$$ = (Node*)n;
            }
			| SHOW EVENTS event_from_clause
			{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "show events is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SHOW EVENTS is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "show events statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("SHOW EVENTS is supported only in B-format database."),
							parser_errposition(@1)));
					$$ = NULL;
				}
				ShowEventStmt *n = makeNode(ShowEventStmt);
					n->from_clause = $3;
					n->where_clause = NULL;	
					$$ = (Node*)n;
			}
			| SHOW EVENTS event_where_clause
			{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "show events is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SHOW EVENTS is not yet supported in distributed database.")));
#endif
				if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
					const char* message = "show events statement is only supported in B format.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate, (errmodule(MOD_PARSER),
							errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("SHOW EVENTS is supported only in B-format database."),
							parser_errposition(@1)));
					$$ = NULL;
				}
				ShowEventStmt *n = makeNode(ShowEventStmt);
				n->from_clause = NULL;
				n->where_clause = $3;
				$$ = (Node*)n;
			}
		;


event_from_clause:
			FROM ColId
			{
				$$ = makeStringConst($2, @2);
			}
			| IN_P ColId
			{
				$$ = makeStringConst($2, @2);
			}
        ;

event_where_clause:
			WHERE ev_where_body 
			{
				$$ = $2;
			}
			| LIKE Sconst
			{
				errno_t	rc = EOK;
				char* event_where_str;
				event_where_str = (char *)palloc(1024 + strlen($2));
				rc = strcpy_s(event_where_str, 1024 + strlen($2), "job_name like '");
				securec_check(rc, "\0", "\0");
				rc = strcat_s(event_where_str, 1024 + strlen($2), $2);
				securec_check(rc, "\0", "\0");
				rc = strcat_s(event_where_str, 1024 + strlen($2), "\'");
				securec_check(rc, "\0", "\0");
				$$ = event_where_str;
			}
        ;

ev_where_body:	{
				char    *ev_body_str = NULL;
				int     ev_body_len = 0;
				int     tok = YYEMPTY;
				int     proc_b = 0;
				int     proc_e = 0;
				int     rc = 0;
				int     pre_tok = 0;
				int    	ploc = 0;
				int     pre_loc = 0;
				int     next_tok = 0;
				int  	flag = 0;
				rc = CompileWhich();
				base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
				if (yychar == YYEOF || yychar == YYEMPTY) {
					tok = YYLEX;
				}
				else {
					tok = yychar;
					yychar = YYEMPTY;
				}
				proc_b = yylloc;
				/* start event body scan */
				while (true) {
					if(tok == ';') {
						++flag;
					}

					if(tok == YYEOF ) {
						tok = YYLEX;
						if(flag) {
							proc_e = pre_loc;
						} else {
							proc_e = yylloc;
						}
						break;
					}
					ploc = yylloc;
					if(tok != 0) {
						pre_loc = ploc;
					}
					pre_tok = tok;
					tok = YYLEX;
				}
				if (proc_e == 0) {
					ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("where body is not ended correctly.")));
				}
				ev_body_len = proc_e - proc_b + 1;
				ev_body_str = (char*)palloc0(ev_body_len + 1);
				rc = strncpy_s(ev_body_str, ev_body_len + 1, yyextra->core_yy_extra.scanbuf + proc_b - 1, ev_body_len);
				securec_check(rc, "\0", "\0");
				ev_body_str[ev_body_len] = '\0';
				/* Reset the flag which mark whether we are in slash proc. */
				yyextra->core_yy_extra.in_slash_proc_body = false;
				yyextra->core_yy_extra.dolqstart = NULL;
				$$ = ev_body_str;
			}
		;

CreateProcedureStmt:
			CREATE opt_or_replace definer_user PROCEDURE func_name_opt_arg proc_args
			opt_createproc_opt_list as_is {
				u_sess->parser_cxt.eaten_declare = false;
				u_sess->parser_cxt.eaten_begin = false;
				pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
                u_sess->parser_cxt.isCreateFuncOrProc = true;
				if (set_is_create_plsql_type()) {
					set_create_plsql_type_start();
					set_function_style_a();
				}
			} subprogram_body
				{
                                        int rc = 0;
                                        rc = CompileWhich();
                                        if ((rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) && u_sess->cmd_cxt.CurrentExtensionObject == InvalidOid) {
                                            u_sess->plsql_cxt.procedure_first_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @8);
                                        }
					rc = CompileWhich();
					CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
					FunctionSources *funcSource = (FunctionSources *)$10;
					int count = get_outarg_num($6);

					n->isOraStyle = true;
					n->isPrivate = false;
					n->replace = $2;
					n->definer = $3;
					if (n->replace && NULL != n->definer) {
						parser_yyerror("not support DEFINER function");
					}
					n->funcname = $5;
					n->parameters = $6;
					n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters);
					if (enable_plpgsql_gsdependency_guc()) {
						n->funcHeadSrc = ParseFuncHeadSrc(yyscanner, false);
					}
					n->returnType = NULL;
					n->isProcedure = true;
					if (0 == count)
					{
						n->returnType = makeTypeName("void");
						n->returnType->typmods = NULL;
						n->returnType->arrayBounds = NULL;
					}
					n->options = $7;
					n->options = lappend(n->options, makeDefElem("as",
										(Node *)list_make1(makeString(funcSource->bodySrc))));
					n->options = lappend(n->options, makeDefElem("language",
										(Node *)makeString("plpgsql")));
					n->withClause = NIL;
                    u_sess->parser_cxt.isCreateFuncOrProc = false;
					$$ = (Node *)n;
				}

			| CREATE opt_or_replace definer_user PROCEDURE func_name_opt_arg proc_args
                       LANGUAGE ColId_or_Sconst AS func_as opt_createproc_opt_list
                               {
                                       CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
                                       int count = get_outarg_num($6);
                                       n->isOraStyle = false;
                                       n->isPrivate = false;
                                       n->replace = $2;
                                       n->definer = $3;
                                       if (n->replace && NULL != n->definer) {
                                               parser_yyerror("not support DEFINER function");
                                       }                       
                                       n->funcname = $5;
                                       n->parameters = $6;
                                       n->returnType = NULL;
                                       if (0 == count)
                                       {
                                               n->returnType = makeTypeName("void");
                                               n->returnType->typmods = NULL;
                                               n->returnType->arrayBounds = NULL;
                                       }
                                       n->options = $11;
                                       n->options = lappend(n->options, makeDefElem("language", (Node *)makeString($8)));
                                       n->options = lappend(n->options, makeDefElem("as", (Node *)$10));
                                       n->withClause = NIL;
                                       n->isProcedure = true;
                                       $$ = (Node *)n;
                               }
		;

CreatePackageStmt:
			CREATE opt_or_replace PACKAGE pkg_name invoker_rights as_is {pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->plsql_cxt.isCreatePkg = true;
			set_function_style_a();}
				{
                    set_create_plsql_type_start();
					u_sess->plsql_cxt.need_create_depend = true;
					u_sess->plsql_cxt.package_as_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @6);
                    CreatePackageStmt *n = makeNode(CreatePackageStmt);
					char *pkgNameBegin = NULL;
					char *pkgNameEnd = NULL;
                    char *pkgName = NULL;
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					yyextra->core_yy_extra.in_slash_proc_body = true;
					switch (list_length($4)) {
						case 1:
							pkgName = strVal(linitial($4));
							break;
						case 2:
							pkgName = strVal(lsecond($4));
							break;
						case 3:
							pkgName = strVal(lthird($4));
							break;
						default:
							parser_yyerror("package name is invalid!");
							break;
					}
                    pkgNameBegin = (char *)palloc(strlen(pkgName) + 1);
                    pkgNameEnd = (char *)palloc(strlen(pkgName) + 1);
                    strcpy(pkgNameBegin, pkgName);
					pkgNameBegin = pg_strtolower(pkgNameBegin);

                    int tok = YYEMPTY;
                    if (yychar == YYEOF || yychar == YYEMPTY)
                        tok = YYLEX;
                    else
                    {
                        tok = yychar;
                        yychar = YYEMPTY;
                    }
                    int proc_start_pos = n->pkgspec_location = yylloc;
                    u_sess->plsql_cxt.package_first_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, yylloc);

                    // Scan whole stmt.        
                    List* toks = NULL;
                    List* positions = NULL;

                    while(true) {
                        if (tok == YYEOF) {
                            break;
                        }

                        toks = lappend_int(toks, tok);
                        positions = lappend_int(positions, yylloc);
                        
                        if (tok == END_P) {
                            tok = YYLEX;
                            // append pkgname into toks
                            toks = lappend_int(toks, tok);
                            positions = lappend_int(positions, yylloc);
                            if (tok != ';') {
                                // append ; into toks
                                tok = YYLEX;
                                toks = lappend_int(toks, tok);
                                positions = lappend_int(positions, yylloc);

                                int start_pos = list_nth_int(positions, positions->length - 2);
                                int end_pos = list_nth_int(positions, positions->length - 1);
                                StringInfoData name_info;
                                initStringInfo(&name_info);
                                appendBinaryStringInfo(&name_info, yyextra->core_yy_extra.scanbuf + start_pos - 1, end_pos - start_pos + 1);
                                char* pkg_name_temp = GetPkgName(name_info.data);
                                pkg_name_temp = pg_strtolower(pkg_name_temp);
                                truncate_identifier(pkg_name_temp, strlen(pkg_name_temp), false);
                                if (strcmp(pkgNameBegin, pkg_name_temp) == 0) {
                                    strcpy(pkgNameEnd, pkg_name_temp);
                                    pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = false;
                                    break;
                                }
                                pfree(name_info.data);
                                pkg_name_temp = NULL;
                            } else {
								parser_yyerror("package spec is not ended correctly");
							}
							u_sess->plsql_cxt.isCreatePkg = false;
                        }
                        tok = YYLEX;
                    }
                	yyextra->core_yy_extra.query_string_locationlist =
                    	lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc);
                    if (toks == NULL || toks->length < 1) {
                        parser_yyerror("package spec is not ended correctly");
                    }
                    int last_tok = list_nth_int(toks, toks->length - 1);
                    if (last_tok != ';') {
                        parser_yyerror("variable/func/proc declare in package spec is not ended correctly");
                    }

                    if (toks->length < 2) {
                        parser_yyerror("package spec is not ended correctly");
                    }

                    // Package spec content.
                    int name_start_pos = list_nth_int(positions, positions->length - 2);
                    StringInfoData content_info;
                    initStringInfo(&content_info);
                    appendStringInfo(&content_info, "%s", PACKAGE_STR);
                    appendStringInfo(&content_info, "%s", DECLARE_STR);
                    n->pkgspec_prefix_len = content_info.len;
                    n->pkgspec_location -= 1;
                    appendBinaryStringInfo(&content_info, yyextra->core_yy_extra.scanbuf + proc_start_pos - 1, name_start_pos - proc_start_pos + 1);
                    char* pkg_spec_str = content_info.data;

                    if (yyextra->lookahead_len != 0) {
                        parser_yyerror("package spec is not ended correctly");
                    } else {
                        const YYLTYPE yyleng = pg_yyget_leng(yyscanner);
                        yyextra->lookaheads[0] = {
                            .token = tok,
                            .yylloc = yylloc,
                            .yyleng = yyleng,
                            .prev_hold_char_loc = yylloc + yyleng,
                            .prev_hold_char = yyextra->core_yy_extra.scanbuf[yylloc + yyleng],
                        };
                        yyextra->lookahead_len = 1;
                    }

                    /* Reset the flag which mark whether we are in slash proc. */
                    yyextra->core_yy_extra.in_slash_proc_body = false;
                    yyextra->core_yy_extra.dolqstart = NULL;
                    /*
                     * Add the end location of slash proc to the locationlist for the multi-query 
                     * processed.
                     */

					u_sess->plsql_cxt.package_as_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @6);
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_common.plsql_show_all_error == true) {
						if (pkgNameBegin != NULL && pkgNameEnd != NULL) {
							if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
							{
								parser_yyerror("package name end is not match the one begin!");
							}
						} else {
							parser_yyerror("package name end is not match the one begin!");
						}
					} else {
						if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
						{
							parser_yyerror("package name end is not match the one begin!");
						}
					}
#else
					if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
					{
						parser_yyerror("package name end is not match the one begin!");
					}
#endif
					n->replace = $2;
					n->pkgname = $4;
					n->pkgspec = pkg_spec_str;
					n->pkgsecdef = $5;
					$$ = (Node *)n;
				}
            
		;
pkg_name:	ColId
				{ $$ = list_make1(makeString($1)); }
			| ColId indirection
				{
					$$ = check_func_name(lcons(makeString($1), $2),
										 yyscanner);
				}
		;
invoker_rights:	 AUTHID DEFINER
				{
					$$ = true;
				}
			| AUTHID CURRENT_USER
				{
					$$ = false;
				}
			|
				{
                    if (PLSQL_SECURITY_DEFINER && u_sess->attr.attr_common.upgrade_mode == 0) {
						$$ = true;
                    } else {
                        $$ = false;
                    }
				}
			;
view_security_option: DEFINER
				{
					$$ = VIEW_SQL_SECURITY_DEFINER;
				}
				| INVOKER
				{
					$$ = VIEW_SQL_SECURITY_INVOKER;
				}
			;
view_security_expression: SQL_P SECURITY view_security_option
				{
					if (u_sess->attr.attr_sql.sql_compatibility ==  B_FORMAT) {
						$$ = $3;
					} else {
						parser_yyerror("not support SQL SECURITY EXPRESSION");
					}
				}
			;

definer_expression: DEFINER '=' UserId
				{
					if (u_sess->attr.attr_sql.sql_compatibility ==  B_FORMAT ||
						u_sess->attr.attr_common.enable_dump_trigger_definer) {
						$$ = $3;
					} else {
						parser_yyerror("not support DEFINER function");
					}
				}
			;

definer_user: definer_expression
				{
					$$ = $1;
				}
			| /* EMPTY */
				{
					$$ = NULL;
				}
			;
pkg_body_subprogram: {
                int proc_b  = 0;
                int proc_e  = 0;
                char *pkg_body_str = NULL;
                char *pkg_name_str = NULL;
                int pkg_name_len    = 0;
                int pkg_body_len    = 0;
                int instantiation_start = 0;
                int instantiation_end = 0;
                int block_level = 0;
                int tok = YYEMPTY;
                int pre_tok_loc = 0;
				int pre_tok = 0;
                int pre_pre_tok = 0;
                bool pkg_end = true;
                char* instantiation_str = NULL;
                base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
                bool in_procedure = false;
                yyextra->core_yy_extra.in_slash_proc_body = true;
                /* the token BEGIN_P have been parsed */
                List* result_list = NULL;
                if (yychar == YYEOF || yychar == YYEMPTY)
                {
                    tok = YYLEX;
                }
                else
                {
                    tok = yychar;
                    yychar = YYEMPTY;
                }
                proc_b = yylloc;
				u_sess->plsql_cxt.package_first_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, yylloc);

                List* toks = NULL;
                List* positions = NULL;

                while(true)
                {
                    if (tok == YYEOF) {
						break;
					}

                    toks = lappend_int(toks, tok);
                    positions = lappend_int(positions, yylloc);

                    if (tok == PROCEDURE || tok == FUNCTION) {
                        in_procedure = true;
					}

                    if (tok == BEGIN_P) {
                        block_level = block_level + 1;
                        if (in_procedure == false) {
                            instantiation_start = yylloc;
                        }
                    }
					
                    if (tok == END_P)
                    {
						pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = false;
						u_sess->plsql_cxt.isCreatePkg = false;
                        tok = YYLEX;
                        proc_e = yylloc;

                        toks = lappend_int(toks, tok);
                        positions = lappend_int(positions, yylloc);
                                                /* If there is a comment before END_P, check pre_pre_tok */
						if ((pre_tok != ';' && pre_tok != BEGIN_P && pre_tok != 0 && pre_tok != COMMENTSTRING) ||
                                                    (pre_tok == COMMENTSTRING && pre_pre_tok != 0 && pre_pre_tok != ';' && pre_pre_tok != BEGIN_P)) {
							continue;
						} else if (block_level == 0 && tok != ';') {
							in_procedure = false;
						}
                        if (tok == ';' || 
							(u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && pre_tok == ';' && tok == IDENT && in_procedure))
                        {
                            block_level = block_level - 1;
                            if (block_level == 0)
                            {
                                in_procedure = false;
                            }
                            continue;
                        }
						if (tok == LOOP || tok == IF_P || tok == CASE || tok == WHILE_P || tok == REPEAT)
						{
							continue;
						}
                        tok = YYLEX;

                        toks = lappend_int(toks, tok);
                        positions = lappend_int(positions, yylloc);

                        if (tok != ';' && tok != 0) {
                          continue;
                        } else if (tok == 0) {
                            parser_yyerror("package is not ended correctly");
							break;
                        }
                        if (proc_e == 0) {
                            parser_yyerror("variable declare in package is not ended correctly");
							break;
						}
                        break;
                    }
                    /* When multiple lines are commented out, pre_pre_tok should not is COMMENTSTRING,
                     * but should be displayed as the tok before the COMMENTSTRING start.
                     */
                    if (tok != COMMENTSTRING || pre_tok != COMMENTSTRING) {
                        pre_pre_tok = pre_tok;
                    }
					pre_tok = tok;
                    tok = YYLEX;
                    pre_tok_loc = yylloc;
                }

                if (toks == NULL || toks->length < 1) {
                    parser_yyerror("package is not ended correctly");
                }
                int last_tok = list_nth_int(toks, toks->length - 1);
                if (last_tok != ';') {
                    parser_yyerror("package is not ended correctly");
                }

                if (toks->length < 2) {
                    parser_yyerror("package is not ended correctly");
                }

                // package name.
                int name_start_pos = list_nth_int(positions, positions->length - 2);
                int name_end_pos = list_nth_int(positions, positions->length -1);
                StringInfoData name_info;
                initStringInfo(&name_info);
                appendBinaryStringInfo(&name_info, yyextra->core_yy_extra.scanbuf + name_start_pos - 1, name_end_pos - name_start_pos + 1);
                pkg_name_str = GetPkgName(name_info.data);
				pkg_name_str = pg_strtolower(pkg_name_str);
                truncate_identifier(pkg_name_str, strlen(pkg_name_str), false);

                if (instantiation_start == 0) {
                    pkg_body_len = proc_e - proc_b + 1;
                    pkg_body_str = (char *)palloc0(pkg_body_len + DECLARE_LEN + PACKAGE_LEN + 1);
                    strncpy_s(pkg_body_str, PACKAGE_LEN + 1, PACKAGE_STR, PACKAGE_LEN);
                    strncpy_s(pkg_body_str + PACKAGE_LEN, DECLARE_LEN + 1, DECLARE_STR, DECLARE_LEN);
                    strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN, pkg_body_len + 1,
                    yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_body_len);
                    pkg_body_str[pkg_body_len + DECLARE_LEN + PACKAGE_LEN] = '\0';
                    proc_b = proc_e;
                    proc_e = yylloc;
                    if (proc_e == 0)
                        parser_yyerror("variable declare in package spec is not ended correctly");
                } else {
                    int proc_end_all = proc_e;
                    proc_e = instantiation_start;
                    pkg_body_len = proc_e - proc_b + 1;
                    pkg_body_str = (char *)palloc0(pkg_body_len + DECLARE_LEN + PACKAGE_LEN + END_LEN + 2); 
                    strncpy_s(pkg_body_str, PACKAGE_LEN + 1, PACKAGE_STR, PACKAGE_LEN);
                    strncpy_s(pkg_body_str + PACKAGE_LEN, DECLARE_LEN + 1, DECLARE_STR, DECLARE_LEN);
                    strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN, pkg_body_len + 1,
                    yyextra->core_yy_extra.scanbuf + proc_b - 1, pkg_body_len);
                    strncpy_s(pkg_body_str + DECLARE_LEN + PACKAGE_LEN + pkg_body_len, END_LEN + 1,
                    END_STR, END_LEN);
                    pkg_body_str[pkg_body_len + DECLARE_LEN + PACKAGE_LEN + END_LEN] = '\0'; 
                    proc_b = proc_end_all;
                    proc_e = yylloc;
                    if (proc_e == 0) 
                        parser_yyerror("variable declare in package spec is not ended correctly");
                    instantiation_end = pre_tok_loc;
                    int pkg_instantiation_len = instantiation_end - instantiation_start;
                    instantiation_str = (char *)palloc0(INSTANTIATION_LEN + pkg_instantiation_len + END_LEN + 2); 
                    strncpy_s(instantiation_str, INSTANTIATION_LEN + 1, INSTANTIATION_STR, INSTANTIATION_LEN);
                    strncpy_s(instantiation_str +  INSTANTIATION_LEN, pkg_instantiation_len + 1,  
                        yyextra->core_yy_extra.scanbuf + instantiation_start - 1, pkg_instantiation_len);
                    strncpy_s(instantiation_str  + INSTANTIATION_LEN + pkg_instantiation_len, END_LEN + 1 , END_STR, END_LEN);
                    instantiation_str[INSTANTIATION_LEN + pkg_instantiation_len + END_LEN] = '\0';
                }

                if (yyextra->lookahead_len != 0)
                    parser_yyerror("package spec is not ended correctly");
                else
                {
                    const YYLTYPE yyleng = pg_yyget_leng(yyscanner);
                    yyextra->lookaheads[0] = {
                        .token = tok,
                        .yylloc = yylloc,
                        .yyleng = yyleng,
                        .prev_hold_char_loc = yylloc + yyleng,
                        .prev_hold_char = yyextra->core_yy_extra.scanbuf[yylloc + yyleng],
                    };
                    yyextra->lookahead_len = 1;
                }
                /* Reset the flag which mark whether we are in slash proc. */
                yyextra->core_yy_extra.in_slash_proc_body = false;
                yyextra->core_yy_extra.dolqstart = NULL;
                /*
                * Add the end location of slash proc to the locationlist for the multi-query 
                * processed.
                */
                yyextra->core_yy_extra.query_string_locationlist = 
                    lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc);
            
                result_list = list_concat(list_make1(makeDefElem("decl", (Node *)makeString(pkg_body_str))), 
                         list_make1(makeDefElem("name", (Node *)makeString(pkg_name_str))));
                if (instantiation_start != 0)  {
                    result_list = list_concat(result_list,list_make1(makeDefElem(("init"), (Node *)makeString(instantiation_str))));
                } else {
                    result_list = list_concat(result_list,list_make1(makeDefElem(("init"), NULL)));
                }
                $$ = result_list;
            }
			;
CreatePackageBodyStmt:
			CREATE opt_or_replace PACKAGE BODY_P pkg_name as_is {pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true;
			u_sess->plsql_cxt.isCreatePkg = true;
			set_function_style_a();} pkg_body_subprogram
				{
					set_create_plsql_type_start();
					u_sess->plsql_cxt.need_create_depend = true;
					char *pkgNameBegin = NULL;
					char *pkgNameEnd = NULL;
                    char *pkgName = NULL;
					DefElem *def = NULL;
					u_sess->plsql_cxt.package_as_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @6);
					switch (list_length($5)) {
						case 1:
							pkgName = strVal(linitial($5));
							break;
						case 2:
							pkgName = strVal(lsecond($5));
							break;
						case 3:
							pkgName = strVal(lthird($5));
							break;
						default:
							parser_yyerror("package name is invalid!");
							break;
					}
                    pkgNameBegin = (char *)palloc(strlen(pkgName) + 1);
                    strcpy(pkgNameBegin, pkgName);
					pkgNameBegin = pg_strtolower(pkgNameBegin);
                    int length = list_length($8);
					def = (DefElem *)lsecond($8);
					if (strcmp(def->defname,"name") != 0)
					{
						parser_yyerror("internal grammer error!");
					}
					pkgNameEnd = GetPkgName(strVal(def->arg));
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_common.plsql_show_all_error == true) {
						if (pkgNameBegin != NULL && pkgNameEnd != NULL) {
							if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
							{
								parser_yyerror("package name end is not match the one begin!");
							}
						} else {
							parser_yyerror("package name end is not match the one begin!");
						}
					} else {
						if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
						{
							parser_yyerror("package name end is not match the one begin!");
						}
					}
#else
					if (strcmp(pkgNameBegin, pkgNameEnd) != 0)
					{
						parser_yyerror("package name end is not match the one begin!");
					}
#endif
					CreatePackageBodyStmt *n = makeNode(CreatePackageBodyStmt);
					n->replace = $2;
					n->pkgname = $5;
					def = (DefElem *)linitial($8);
					if (strcmp(def->defname,"decl") != 0)
					{
						parser_yyerror("internal grammer error!");
					}
					n->pkgbody = strVal(def->arg);
                    def = (DefElem *)lthird($8);
                    if (strcmp(def->defname,"init") != 0) 
                    {     
                        parser_yyerror("internal grammer error!");
                    } 
                    if (def->arg) {
                        n->pkginit = strVal(def->arg);
                    } else {
                        n->pkginit = NULL;
                    }
					u_sess->plsql_cxt.isCreatePkg = false;
					$$ = (Node *)n;
				}
		;
opt_or_replace:
			OR REPLACE								{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

func_args:	'(' func_args_list ')'					{ $$ = $2; }
			| '(' ')'								{ $$ = NIL; }
		;

proc_args:  {
				pg_yyget_extra(yyscanner)->core_yy_extra.func_param_begin = yylloc;
			} func_args_with_defaults				{ pg_yyget_extra(yyscanner)->core_yy_extra.func_param_end = yylloc; $$ = $2;  }
			|/*EMPTY*/								{ $$ = NIL; }
		;

func_args_list:
			func_arg								{ $$ = list_make1($1); }
			| func_args_list ',' func_arg			{ $$ = lappend($1, $3); }
		;

as_is:
		AS
		| IS
		;

as_empty:
                AS
                | /*EMPTY*/     { $$ = NULL; }
                ;

/*
 * func_args_with_defaults is separate because we only want to accept
 * defaults in CREATE FUNCTION, not in ALTER etc.
 */
func_args_with_defaults:
		'(' func_args_with_defaults_list ')'		{ $$ = $2; }
		| '(' ')'									{ $$ = NIL; }
		;

func_args_with_defaults_list:
		func_arg_with_default						{ $$ = list_make1($1); }
		| func_args_with_defaults_list ',' func_arg_with_default
													{ $$ = lappend($1, $3); }
		;

/*
 * The style with arg_class first is SQL99 standard, but A db puts
 * param_name first; accept both since it's likely people will try both
 * anyway.  Don't bother trying to save productions by letting arg_class
 * have an empty alternative ... you'll get shift/reduce conflicts.
 *
 * We can catch over-specified arguments here if we want to,
 * but for now better to silently swallow typmod, etc.
 * - thomas 2000-03-22
 */
func_arg:
			arg_class param_name func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = $2;
					n->argType = $3;
					n->mode = $1;
					n->defexpr = NULL;
					$$ = n;
				}
			| param_name arg_class func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = $1;
					n->argType = $3;
					n->mode = $2;
					n->defexpr = NULL;
					$$ = n;
				}
			| param_name func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = $1;
					n->argType = $2;
					n->mode = FUNC_PARAM_IN;
					n->defexpr = NULL;
					$$ = n;
				}
			| arg_class func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = NULL;
					n->argType = $2;
					n->mode = $1;
					n->defexpr = NULL;
					$$ = n;
				}
			| func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = NULL;
					n->argType = $1;
					n->mode = FUNC_PARAM_IN;
					n->defexpr = NULL;
					$$ = n;
				}
		;

/* INOUT is SQL99 standard, IN OUT is for A db compatibility */
arg_class:	IN_P								{ $$ = FUNC_PARAM_IN; }
			| OUT_P								{ $$ = FUNC_PARAM_OUT; }
			| INOUT								{ $$ = FUNC_PARAM_INOUT; }
			| IN_P OUT_P						{ $$ = FUNC_PARAM_INOUT; }
			| VARIADIC							{ $$ = FUNC_PARAM_VARIADIC; }
		;

/*
 * Ideally param_name should be ColId, but that causes too many conflicts.
 */
param_name:	type_function_name
		;

func_return:
			func_type
				{
					if (enable_plpgsql_gsdependency_guc()) {
						pg_yyget_extra(yyscanner)->core_yy_extra.return_pos_end = yylloc;
					}
					/* 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;
				}
			| func_type {
				if (enable_plpgsql_gsdependency_guc()) {
					pg_yyget_extra(yyscanner)->core_yy_extra.return_pos_end = yylloc;
				}
			} DETERMINISTIC
				{
					$$ = $1;
				}
		;

/*
 * We would like to make the %TYPE productions here be ColId attrs etc,
 * but that causes reduce/reduce conflicts.  type_function_name
 * is next best choice.
 */
func_type:	Typename								{ $$ = $1; }
        | type_function_name attrs '%' ROWTYPE_P opt_array_bounds
            {
                $$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
                $$->location = @1;
                $$->arrayBounds = $5;
                $$->pct_rowtype = true;
            }
        | type_function_name '%' ROWTYPE_P opt_array_bounds
            {
                $$ = makeTypeName($1);
                $$->location = @1;
                $$->arrayBounds = $4;
                $$->pct_rowtype = true;
            }
		| type_function_name attrs '%' TYPE_P opt_array_bounds
	        {
                $$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
                $$->pct_type = true;
                $$->location = @1;
                $$->end_location = @4 + TYPE_LEN;
                $$->arrayBounds = $5;
		    }
        | type_function_name '%' TYPE_P opt_array_bounds
	        {
                $$ = makeTypeName($1);
                $$->pct_type = true;
			    $$->location = @1;
			    $$->end_location = @3 + TYPE_LEN;
                $$->arrayBounds = $4;
		    }
		| SETOF type_function_name attrs '%' TYPE_P opt_array_bounds
		    {
                $$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
                $$->pct_type = true;
                $$->setof = TRUE;
                $$->location = @2;
                $$->end_location = @5 + TYPE_LEN;
                $$->arrayBounds = $6;
		    }
		;

func_arg_with_default:
		func_arg
				{
					$$ = $1;
				}
		| func_arg DEFAULT a_expr
				{
					$$ = $1;
					$$->defexpr = $3;
				}
		| func_arg '=' a_expr
				{
					$$ = $1;
					$$->defexpr = $3;
				}
		| func_arg COLON_EQUALS a_expr
				{
					$$ = $1;
					$$->defexpr = $3;
				}
		;


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); }
	;
opt_createproc_opt_list:
			opt_createproc_opt_list createproc_opt_item
				{
					$$ = lappend($1, $2);
				}
			| /* EMPTY */
				{
					$$ = NIL;
				}
 	 ;

/*
 * 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"));
				}
			| SHIPPABLE
				{
					$$ = makeDefElem("shippable", (Node*)makeInteger(TRUE));
				}
			| NOT SHIPPABLE
				{
					$$ = makeDefElem("shippable", (Node*)makeInteger(FALSE));
				}
			| PARALLEL_ENABLE parallel_partition_opt
				{
					if (!DB_IS_CMPT(A_FORMAT)) {
						ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
										errmsg("PARALLEL_ENABLE is only supported in A compatibility database.")));
					}
					$$ = makeDefElem("parallel_enable", (Node*)$2);
				}
			| 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));
				}
			| AUTHID DEFINER
				{
					$$ = makeDefElem("security", (Node *)makeInteger(TRUE));
				}
			| AUTHID CURRENT_USER
				{
					$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
				}
			| LEAKPROOF
				{
					$$ = makeDefElem("leakproof", (Node *)makeInteger(TRUE));
				}
			| NOT LEAKPROOF
				{
					$$ = makeDefElem("leakproof", (Node *)makeInteger(FALSE));
				}
			| COST NumericOnly
				{
					$$ = makeDefElem("cost", (Node *)$2);
				}
			| ROWS NumericOnly
				{
					$$ = makeDefElem("rows", (Node *)$2);
				}
			| FunctionSetResetClause
				{
					/* we abuse the normal content of a DefElem here */
					$$ = makeDefElem("set", (Node *)$1);
				}
			| FENCED
				{
					$$ = makeDefElem("fenced", (Node *)makeInteger(TRUE));
				}
			| NOT FENCED
				{
					$$ = makeDefElem("fenced", (Node *)makeInteger(FALSE));
				}
			| PACKAGE
				{
					$$ = makeDefElem("package", (Node *)makeInteger(true));
				}
			| COMMENT Sconst
			    {
					BCompatibilityOptionSupportCheck($1);
					$$ = makeDefElem("comment", (Node *)makeString($2));
			    }
		;

parallel_partition_opt:
			'(' PARTITION param_name BY ANY ')'
				{
					$$ = makeNode(FunctionPartitionInfo);
					$$->strategy = FUNC_PARTITION_ANY;
					$$->partitionCursor = $3;

				}
			| '(' PARTITION param_name BY IDENT '(' colid_list ')' ')'
				{
					if (strcmp($5, "hash") != 0) {
						const char* message = "Un-support feature";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("unrecognized option \"%s\"", $3)));	
					}
					$$ = makeNode(FunctionPartitionInfo);
					$$->strategy = FUNC_PARTITION_HASH;
					$$->partitionCursor = $3;
					$$->partitionCols = $7;
				}
			| '(' PARTITION param_name BY RANGE '(' colid_list ')' ')'
				{
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("PARALLEL_ENABLE PARTITION BY RANGE is not yet supported.")));
				}
			| '(' PARTITION param_name BY VALUE_P '(' ColId ')' ')'
				{
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("PARALLEL_ENABLE PARTITION BY VALUE is not yet supported.")));
				}
			| /* EMPTY */
				{
					$$ = NULL;
				}

colid_list:
			ColId
				{
					$$ = list_make1($1);
				}
			| colid_list ',' ColId
				{
					$$ = lappend($1, $3);
				}
		;

createfunc_opt_item:
			AS func_as
				{
					$$ = makeDefElem("as", (Node *)$2);
				}
			| LANGUAGE ColId_or_Sconst
				{
					$$ = makeDefElem("language", (Node *)makeString($2));
				}
			| WINDOW
				{
					$$ = makeDefElem("window", (Node *)makeInteger(TRUE));
				}
			| PIPELINED
				{
					$$ = makeDefElem("pipelined", (Node *)makeInteger(TRUE));
				}
			| common_func_opt_item
				{
					$$ = $1;
				}
		;


createproc_opt_item:
			common_func_opt_item
				{
					$$ = $1;
				}
			| PIPELINED
				{
					$$ = makeDefElem("pipelined", (Node *)makeInteger(TRUE));
				}
		;

func_as:	Sconst						{ $$ = list_make1(makeString($1)); }
			| Sconst ',' Sconst
				{
					$$ = list_make2(makeString($1), makeString($3));
				}
		;
subprogram_body: 	{
				int		proc_b	= 0;
				int		proc_e	= 0;
				char	*proc_body_str	= NULL;
				int		proc_body_len	= 0;
				int		blocklevel		= 0;
				bool	add_declare		= true;  /* Mark if need to add a DECLARE */
				FunctionSources *funSrc = NULL;
				char *proc_header_str = NULL;
				int rc = 0;
				rc = CompileWhich();
				int	tok = YYEMPTY;
				int	pre_tok = 0;
				int in_procedure = 0;
				int max_proc_level = 0;
				bool in_begin = false;
				base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
				int as_count = 0;
				int procedure_count = 0;

				yyextra->core_yy_extra.in_slash_proc_body = true;
				/* the token BEGIN_P have been parsed */
				if (u_sess->parser_cxt.eaten_begin)
					blocklevel = 1;

				if (yychar == YYEOF || yychar == YYEMPTY)
					tok = YYLEX;
				else
				{
					tok = yychar;
					yychar = YYEMPTY;
				}

				if (u_sess->parser_cxt.eaten_declare || DECLARE == tok)
					add_declare = false;

				/* Save procedure header str,start with param exclude brackets */
				proc_header_str = ParseFunctionArgSrc(yyscanner);

				/* Save the beginning of procedure body. */
				proc_b = yylloc;
				if (rc != PLPGSQL_COMPILE_NULL && rc != PLPGSQL_COMPILE_PROC) {
					u_sess->plsql_cxt.procedure_first_line = GetLineNumber(yyextra->core_yy_extra.scanbuf, yylloc);
				}
				/* start procedure body scan */
				while(true)
				{
					if (tok == YYEOF) {
						proc_e = yylloc;
						parser_yyerror("subprogram body is not ended correctly");
						break;
					}
					if (!in_begin && (pre_tok == ';' || pre_tok == DECLARE || pre_tok == 0 || pre_tok == COMMENTSTRING
						|| pre_tok == AS || pre_tok == IS) && (tok == PROCEDURE || tok == FUNCTION)) {
						in_procedure++;
						max_proc_level = max_proc_level > in_procedure ? max_proc_level : in_procedure;
						procedure_count++;
					}
					if (tok == BEGIN_P) {
						blocklevel++;
						in_begin = true;
					}
					if (tok == AS || tok == IS) {
						as_count++;
					}
					/*
					 * End of procedure rules:
					 *	;END [;]
					 * 	| BEGIN END[;]
					 */
					if (tok == END_P)
					{
						tok = YYLEX;

						/* adapt A db's label */
						if (!(tok == ';' || (tok == 0 || tok == END_OF_PROC))
							&& tok != IF_P
							&& tok != CASE
							&& tok != LOOP
							&& tok != WHILE_P
							&& tok != REPEAT)
						{
							if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && blocklevel == 1 && pre_tok == ';' && as_count == 0 && procedure_count ==0)
							{
								proc_e = yylloc;
								break;
							}
							tok = END_P;
							continue;
						}

					 	if (blocklevel == 1
							&& (pre_tok == ';' || pre_tok == BEGIN_P)
							&& (tok == ';' || (tok == 0 || tok == END_OF_PROC)))
						{
							/* Save the end of procedure body. */
							proc_e = yylloc;

							if (tok == ';' )
							{
								if (yyextra->lookahead_len != 0) {
									parser_yyerror("subprogram body is not ended correctly");
									break;
								}
								else
								{
									const YYLTYPE yyleng = pg_yyget_leng(yyscanner);
									yyextra->lookaheads[0] = {
										.token = tok,
										.yylloc = yylloc,
										.yyleng = yyleng,
										.prev_hold_char_loc = yylloc + yyleng,
										.prev_hold_char = yyextra->core_yy_extra.scanbuf[yylloc + yyleng],
									};
									yyextra->lookahead_len = 1;
								}
							}
							if(in_procedure == 0)
								break;
							else {
								blocklevel--;
								in_procedure--;
								if ((procedure_count - as_count - 1) == in_procedure) {
									break;
								}
							}
						}

						/* Cope with nested BEGIN/END pairs.
						 * In fact the tok can not be 0
						 */
					 	if (blocklevel > 1
							 && (pre_tok == ';' || pre_tok == BEGIN_P)
							 && (tok == ';' || tok == 0))
						{
							blocklevel--;
						}
						in_begin = false;
					}

					pre_tok = tok;
					tok = YYLEX;

				}

				if (proc_e == 0) {
					ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("subprogram body is not ended correctly")));
				}
				// record whether there is a subprogram
				if (max_proc_level > 0) {
					u_sess->parser_cxt.has_subprogram = true;
				} else {
					u_sess->parser_cxt.has_subprogram = false;
				}

				proc_body_len = proc_e - proc_b + 1 ;

				/* Add a DECLARE in the start of the subprogram body
				 * 	to compatiable with the A db.
				 * 	XXX : It is best to change the gram.y in plpgsql.
				 */
				if (add_declare)
				{
					proc_body_str = (char *)palloc0(proc_body_len + DECLARE_LEN + 1);
					rc = strcpy_s(proc_body_str, proc_body_len + DECLARE_LEN + 1, DECLARE_STR);
					securec_check(rc, "", "");
					rc = strncpy_s(proc_body_str + DECLARE_LEN, proc_body_len + 1,
							yyextra->core_yy_extra.scanbuf + proc_b, proc_body_len - 1);
					securec_check(rc, "", "");
					proc_body_len = DECLARE_LEN + proc_body_len;
				}
				else
				{
					proc_body_str = (char *)palloc0(proc_body_len + 1);
					rc = strncpy_s(proc_body_str, proc_body_len + 1,
						yyextra->core_yy_extra.scanbuf + proc_b, proc_body_len - 1);
					securec_check(rc, "", "");
				}

				proc_body_str[proc_body_len] = '\0';

				/* Reset the flag which mark whether we are in slash proc. */
				yyextra->core_yy_extra.in_slash_proc_body = false;
				yyextra->core_yy_extra.dolqstart = NULL;

				/*
				 * Add the end location of slash proc to the locationlist for the multi-query 
				 * processed.
				 */
				yyextra->core_yy_extra.query_string_locationlist = 
					lappend_int(yyextra->core_yy_extra.query_string_locationlist, yylloc);

				funSrc = makeNode(FunctionSources);
				funSrc->bodySrc   = proc_body_str;
				funSrc->headerSrc = proc_header_str;

				$$ = funSrc;
			}
		;
opt_definition:
			WITH definition							{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

table_func_column:	param_name func_type
				{
					FunctionParameter *n = makeNode(FunctionParameter);
					n->name = $1;
					n->argType = $2;
					n->mode = FUNC_PARAM_TABLE;
					n->defexpr = NULL;
					$$ = n;
				}
		;

table_func_column_list:
			table_func_column
				{
					$$ = list_make1($1);
				}
			| table_func_column_list ',' table_func_column
				{
					$$ = lappend($1, $3);
				}
		;

/*****************************************************************************
 * ALTER FUNCTION
 *
 * RENAME and OWNER subcommands are already provided by the generic
 * ALTER infrastructure, here we just specify alterations that can
 * only be applied to functions.
 *
 *****************************************************************************/

 RemovePackageStmt:
				DROP PACKAGE pkg_name 
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_PACKAGE;
					n->objects = list_make1($3);
					n->arguments = NULL;
					n->behavior = DROP_CASCADE;
					n->missing_ok = false;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
				| DROP PACKAGE IF_P EXISTS pkg_name
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_PACKAGE;
					n->objects = list_make1($5);
					n->arguments = NULL;
					n->behavior = DROP_CASCADE;
					n->missing_ok = true;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
				| DROP PACKAGE BODY_P pkg_name 
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_PACKAGE_BODY;
					n->objects = list_make1($4);
					n->arguments = NULL;
					n->behavior = DROP_CASCADE;
					n->missing_ok = false;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
				| DROP PACKAGE BODY_P IF_P EXISTS pkg_name
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_PACKAGE_BODY;
					n->objects = list_make1($6);
					n->arguments = NULL;
					n->behavior = DROP_CASCADE;
					n->missing_ok = true;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
		;

AlterFunctionStmt:
			ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict
				{
					AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
					n->func = $3;
					n->actions = $4;
					$$ = (Node *) n;
				}
		;

AlterProcedureStmt:
			ALTER PROCEDURE function_with_argtypes alterfunc_opt_list opt_restrict
				{
					AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
					n->isProcedure = true;
					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 */
		;

compile_pkg_opt:
			BODY_P		{$$ = COMPILE_PKG_BODY;}
			| PACKAGE 	{$$ = COMPILE_PACKAGE;}
			| SPECIFICATION {$$ = COMPILE_PKG_SPECIFICATION;}
			| /* EMPTY */	{$$ = COMPILE_PACKAGE;}
			;
CompileStmt:
			ALTER PROCEDURE function_with_argtypes COMPILE
			{
				u_sess->plsql_cxt.during_compile = true;
				CompileStmt *n = makeNode(CompileStmt);
				if (enable_plpgsql_gsdependency_guc()) {
					n->objName = ((FuncWithArgs*)$3)->funcname;
					n->funcArgs = ((FuncWithArgs*)$3)->funcargs;
					n->compileItem = COMPILE_PROCEDURE;
				}
				$$ = (Node*)n;
			}
			| ALTER PROCEDURE func_name_opt_arg COMPILE
			{
				u_sess->plsql_cxt.during_compile = true;
				CompileStmt *n = makeNode(CompileStmt);
				if (enable_plpgsql_gsdependency_guc()) {
					n->objName = $3;
					n->funcArgs = NULL;
					n->compileItem = COMPILE_PROCEDURE;
				}
				$$ = (Node*)n;
			}
			| ALTER FUNCTION function_with_argtypes COMPILE
			{
				u_sess->plsql_cxt.during_compile = true;
				CompileStmt *n = makeNode(CompileStmt);
				if (enable_plpgsql_gsdependency_guc()) {
					n->objName = ((FuncWithArgs*)$3)->funcname;
					n->funcArgs = ((FuncWithArgs*)$3)->funcargs;
					n->compileItem = COMPILE_FUNCTION;
				}
				$$ = (Node*)n;
			}
			| ALTER FUNCTION func_name_opt_arg COMPILE
			{
				u_sess->plsql_cxt.during_compile = true;
				CompileStmt *n = makeNode(CompileStmt);
				if (enable_plpgsql_gsdependency_guc()) {
					n->objName = $3;
					n->funcArgs = NULL;
					n->compileItem = COMPILE_FUNCTION;
				}
				$$ = (Node*)n;
			}
			| ALTER PACKAGE pkg_name COMPILE compile_pkg_opt
			{
				u_sess->plsql_cxt.during_compile = true;
				CompileStmt *n = makeNode(CompileStmt);
				if (enable_plpgsql_gsdependency_guc()) {
					n->objName = $3;
					n->funcArgs = NULL;
					n->compileItem = (CompileEntry)$5;
				}
				$$ = (Node*)n;
			}
			;

/*****************************************************************************
 *
 *		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
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($3);
					n->arguments = list_make1(extractArgTypes($4));
					n->behavior = $5;
					n->missing_ok = false;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
			| DROP FUNCTION IF_P EXISTS func_name func_args opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($5);
					n->arguments = list_make1(extractArgTypes($6));
					n->behavior = $7;
					n->missing_ok = true;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
            | DROP PROCEDURE func_name func_args opt_drop_behavior
                {
                    DropStmt *n = makeNode(DropStmt);
                    n->removeType = OBJECT_FUNCTION;
                    n->objects = list_make1($3);
                    n->arguments = list_make1(extractArgTypes($4));
                    n->behavior = $5; 
                    n->missing_ok = false;
                    n->concurrent = false;
                    n->isProcedure = true;
                    $$ = (Node *)n;
                }     
            | DROP PROCEDURE IF_P EXISTS func_name func_args opt_drop_behavior
                {
                    DropStmt *n = makeNode(DropStmt);
                    n->removeType = OBJECT_FUNCTION;
                    n->objects = list_make1($5);
                    n->arguments = list_make1(extractArgTypes($6));
                    n->behavior = $7; 
                    n->missing_ok = true; 
                    n->concurrent = false;
                    n->isProcedure = true;
                    $$ = (Node *)n;
                } 
			| DROP PROCEDURE func_name_opt_arg
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($3);
					n->arguments = NULL;
					n->behavior = DROP_RESTRICT;
					n->missing_ok = false;
					n->concurrent = false;
					n->isProcedure = true;
					$$ = (Node *)n;
				}
			| DROP PROCEDURE IF_P EXISTS func_name_opt_arg
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($5);
					n->arguments = NULL;
					n->behavior = DROP_RESTRICT;
					n->missing_ok = true;
					n->concurrent = false;
					n->isProcedure = true;
					$$ = (Node *)n;
				}
			| DROP FUNCTION func_name_opt_arg
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($3);
					n->arguments = NULL;
					n->behavior = DROP_RESTRICT;
					n->missing_ok = false;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
			| DROP FUNCTION IF_P EXISTS func_name_opt_arg
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_FUNCTION;
					n->objects = list_make1($5);
					n->arguments = NULL;
					n->behavior = DROP_RESTRICT;
					n->missing_ok = true;
					n->concurrent = false;
					n->isProcedure = false;
					$$ = (Node *)n;
				}
		;

RemoveAggrStmt:
			DROP AGGREGATE func_name aggr_args opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_AGGREGATE;
					n->objects = list_make1($3);
					n->arguments = list_make1($4);
					n->behavior = $5;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *)n;
				}
			| DROP AGGREGATE IF_P EXISTS func_name aggr_args opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_AGGREGATE;
					n->objects = list_make1($5);
					n->arguments = list_make1($6);
					n->behavior = $7;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *)n;
				}
		;

RemoveOperStmt:
			DROP OPERATOR any_operator oper_argtypes opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_OPERATOR;
					n->objects = list_make1($3);
					n->arguments = list_make1($4);
					n->behavior = $5;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *)n;
				}
			| DROP OPERATOR IF_P EXISTS any_operator oper_argtypes opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_OPERATOR;
					n->objects = list_make1($5);
					n->arguments = list_make1($6);
					n->behavior = $7;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *)n;
				}
		;

oper_argtypes:
			'(' Typename ')'
				{
					const char* message = "missing argument";
                                        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				        ereport(errstate,
						   (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("missing argument"),
							errhint("Use NONE to denote the missing argument of a unary operator."),
							parser_errposition(@3)));
				}
			| '(' Typename ',' Typename ')'
					{ $$ = list_make2($2, $4); }
			| '(' NONE ',' Typename ')'					/* left unary */
					{ $$ = list_make2(NULL, $4); }
			| '(' Typename ',' NONE ')'					/* right unary */
					{ $$ = list_make2($2, NULL); }
		;

any_operator:
			all_Op
					{ $$ = list_make1(makeString($1)); }
			| ColId '.' any_operator
					{ $$ = lcons(makeString($1), $3); }
		;

/*****************************************************************************
 *
 *		DO <anonymous code block> [ LANGUAGE language ]
 *
 * We use a DefElem list for future extensibility, and to allow flexibility
 * in the clause order.
 *
 *****************************************************************************/

DoStmt: DO dostmt_opt_list
				{
					DoStmt *n = makeNode(DoStmt);
					n->args = $2;
					$$ = (Node *)n;
				}
		;

dostmt_opt_list:
			dostmt_opt_item						{ $$ = list_make1($1); }
			| dostmt_opt_list dostmt_opt_item	{ $$ = lappend($1, $2); }
		;

dostmt_opt_item:
			Sconst
				{
					$$ = makeDefElem("as", (Node *)makeString($1));
				}
			| LANGUAGE ColId_or_Sconst
				{
					$$ = makeDefElem("language", (Node *)makeString($2));
				}
		;

AnonyBlockStmt:
		DECLARE { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = false; } subprogram_body
			{
				$$ = (Node *)MakeAnonyBlockFuncStmt(DECLARE, ((FunctionSources*)$3)->bodySrc);
			}
		| BEGIN_P { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = true; } subprogram_body
			{
				$$ = (Node *)MakeAnonyBlockFuncStmt(BEGIN_P, ((FunctionSources*)$3)->bodySrc);
			}
		;
/*****************************************************************************
 *
 *		CREATE CAST / DROP CAST
 *
 *****************************************************************************/

CreateCastStmt: CREATE CAST '(' Typename AS Typename ')'
					WITH FUNCTION function_with_argtypes cast_context
				{
					CreateCastStmt *n = makeNode(CreateCastStmt);
					n->sourcetype = $4;
					n->targettype = $6;
					n->func = $10;
					n->context = (CoercionContext) $11;
					n->inout = false;
					$$ = (Node *)n;
				}
			| CREATE CAST '(' Typename AS Typename ')'
					WITHOUT FUNCTION cast_context
				{
					CreateCastStmt *n = makeNode(CreateCastStmt);
					n->sourcetype = $4;
					n->targettype = $6;
					n->func = NULL;
					n->context = (CoercionContext) $10;
					n->inout = false;
					$$ = (Node *)n;
				}
			| CREATE CAST '(' Typename AS Typename ')'
					WITH INOUT cast_context
				{
					CreateCastStmt *n = makeNode(CreateCastStmt);
					n->sourcetype = $4;
					n->targettype = $6;
					n->func = NULL;
					n->context = (CoercionContext) $10;
					n->inout = true;
					$$ = (Node *)n;
				}
		;

cast_context:  AS IMPLICIT_P					{ $$ = COERCION_IMPLICIT; }
		| AS ASSIGNMENT							{ $$ = COERCION_ASSIGNMENT; }
		| /*EMPTY*/								{ $$ = COERCION_EXPLICIT; }
		;


DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_CAST;
					n->objects = list_make1(list_make1($5));
					n->arguments = list_make1(list_make1($7));
					n->behavior = $9;
					n->missing_ok = $3;
					n->concurrent = false;
					$$ = (Node *)n;
				}
		;

opt_if_exists: IF_P EXISTS						{ $$ = TRUE; }
		| /*EMPTY*/								{ $$ = FALSE; }
		;


/*****************************************************************************
 *
 *		QUERY:
 *
 *		REINDEX type [CONCURRENTLY] <name> [FORCE]
 *
 * FORCE no longer does anything, but we accept it for backwards compatibility
 *****************************************************************************/

ReindexStmt:
			REINDEX reindex_type opt_concurrently qualified_name opt_force
				{
					ReindexStmt *n = makeNode(ReindexStmt);
					n->kind = $2;
					n->concurrent = $3;
					n->relation = $4;
					n->name = NULL;
					$$ = (Node *)n;
				}
			|
			REINDEX reindex_type opt_concurrently qualified_name PARTITION ColId opt_force
				{
					ReindexStmt *n = makeNode(ReindexStmt);
					if ($2 == OBJECT_INDEX)
						n->kind  = OBJECT_INDEX_PARTITION;
					else if($2 == OBJECT_TABLE)
						n->kind  = OBJECT_TABLE_PARTITION;
					else
						n->kind  = OBJECT_INTERNAL_PARTITION;
					n->concurrent = $3;
					n->relation = $4;
					n->name = $6;
					$$ = (Node *)n;
				}
			| REINDEX SYSTEM_P opt_concurrently name opt_force
				{
					ReindexStmt *n = makeNode(ReindexStmt);
					n->kind = OBJECT_DATABASE;
					n->concurrent = $3;
					n->name = $4;
					n->relation = NULL;
					n->do_system = true;
					n->do_user = false;
					$$ = (Node *)n;
				}
			| REINDEX DATABASE opt_concurrently name opt_force
				{
					ReindexStmt *n = makeNode(ReindexStmt);
					n->kind = OBJECT_DATABASE;
					n->concurrent = $3;
					n->name = $4;
					n->relation = NULL;
					n->do_system = true;
					n->do_user = true;
					$$ = (Node *)n;
				}
		;

reindex_type:
			INDEX									{ $$ = OBJECT_INDEX; }
			| TABLE									{ $$ = OBJECT_TABLE; }
			| INTERNAL TABLE						{ $$ = OBJECT_INTERNAL; }
		;

opt_force:	FORCE									{  $$ = TRUE; }
			| /* EMPTY */							{  $$ = FALSE; }
		;


/*****************************************************************************
 *
 * 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;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER COLLATION any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLLATION;
					n->object = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER CONVERSION_P any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_CONVERSION;
					n->object = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER DATABASE database_name RENAME TO database_name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_DATABASE;
					n->subname = $3;
					IsValidIdent($6);
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
            | ALTER DATA_P SOURCE_P name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_DATA_SOURCE;
					n->subname = $4;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER DOMAIN_P any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_DOMAIN;
					n->object = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_CONSTRAINT;
					n->relationType = OBJECT_DOMAIN;
					n->object = $3;
					n->subname = $6;
					n->newname = $8;
					$$ = (Node *)n;
				}
			| ALTER EVENT_TRIGGER name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_EVENT_TRIGGER;
					n->object = list_make1(makeString($3));
					n->newname = $6;
					$$ = (Node *)n;
				}
			| ALTER EVENT_TRIGGER name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_EVENT_TRIGGER;
					n->object = list_make1(makeString($3));
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FDW;
					n->object = list_make1(makeString($5));
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FUNCTION function_with_argtypes RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER PROCEDURE function_with_argtypes RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER GROUP_P RoleId RENAME TO RoleId
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_ROLE;
					n->subname = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER opt_procedural LANGUAGE name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_LANGUAGE;
					n->object = list_make1(makeString($4));
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR CLASS any_name USING access_method RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_OPCLASS;
					n->object = lcons(makeString($6), $4);
					n->newname = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_OPFAMILY;
					n->object = lcons(makeString($6), $4);
					n->newname = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER PUBLICATION name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_PUBLICATION;
					n->object = list_make1(makeString($3));
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_SUBSCRIPTION;
					n->object = list_make1(makeString($3));
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			/* Rename Row Level Security Policy */
			| ALTER RowLevelSecurityPolicyName ON qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_RLSPOLICY;
					n->subname = $2;
					n->relation = $4;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SCHEMA name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_SCHEMA;
					n->subname = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SERVER name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FOREIGN_SERVER;
					n->object = list_make1(makeString($3));
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER MATERIALIZED VIEW qualified_name RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_MATVIEW;
					n->relation = $4;
					n->subname = $7;
					n->newname = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_MATVIEW;
					n->relation = $6;
					n->subname = $9;
					n->newname = $11;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TABLE relation_expr RENAME TO qualified_name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TABLE;
					n->relation = $3;
					n->subname = NULL;
					n->newname = $6->relname;
					n->newschema = $6->schemaname;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLE IF_P EXISTS relation_expr RENAME TO qualified_name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TABLE;
					n->relation = $5;
					n->subname = NULL;
					n->newname = $8->relname;
					n->newschema = $8->schemaname;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER SEQUENCE qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_SEQUENCE;
					n->relation = $3;
					n->subname = NULL;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_LARGE_SEQUENCE;
					n->relation = $4;
					n->subname = NULL;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SEQUENCE IF_P EXISTS qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_SEQUENCE;
					n->relation = $5;
					n->subname = NULL;
					n->newname = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE IF_P EXISTS qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_LARGE_SEQUENCE;
					n->relation = $6;
					n->subname = NULL;
					n->newname = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER VIEW qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_VIEW;
					n->relation = $3;
					n->subname = NULL;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER VIEW IF_P EXISTS qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_VIEW;
					n->relation = $5;
					n->subname = NULL;
					n->newname = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility !=  B_FORMAT)
#endif
					{
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("ALTER VIEW AS is not supported.")));
					}
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $3;
					n->aliases = $4;
					n->query = $6;
					n->replace = true;
					n->sql_statement = NULL;
					n->is_alter = true;
					n->withCheckOption = (ViewCheckOption)$7;
					n->viewSecurityOption = VIEW_SQL_SECURITY_NONE;
					$$ = (Node *) n;
				}
			| ALTER definer_expression VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility !=  B_FORMAT)
#endif
					{
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("ALTER VIEW AS is not supported.")));
					}
					ViewStmt *n = makeNode(ViewStmt);
					n->definer = $2;
					n->view = $4;
					n->aliases = $5;
					n->query = $7;
					n->replace = true;
					n->sql_statement = NULL;
					n->is_alter = true;
					n->viewSecurityOption = VIEW_SQL_SECURITY_NONE;
					n->withCheckOption = (ViewCheckOption)$8;
					$$ = (Node *) n;
				}
			| ALTER view_security_expression VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility !=  B_FORMAT)
#endif
					{
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("ALTER VIEW AS is not supported.")));
					}
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $4;
					n->aliases = $5;
					n->query = $7;
					n->replace = true;
					n->sql_statement = NULL;
					n->is_alter = true;
					n->viewSecurityOption = (ViewSecurityOption)$2;
					n->withCheckOption = (ViewCheckOption)$8;
					$$ = (Node *) n;
				}
			| ALTER definer_expression view_security_expression VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility !=  B_FORMAT)
#endif
					{
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("ALTER VIEW AS is not supported.")));
					}
					ViewStmt *n = makeNode(ViewStmt);
					n->definer = $2;
					n->view = $5;
					n->aliases = $6;
					n->query = $8;
					n->replace = true;
					n->sql_statement = NULL;
					n->is_alter = true;
					n->viewSecurityOption = (ViewSecurityOption)$3;
					n->withCheckOption = (ViewCheckOption)$9;
					$$ = (Node *) n;
				}
			| ALTER MATERIALIZED VIEW qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_MATVIEW;
					n->relation = $4;
					n->subname = NULL;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_MATVIEW;
					n->relation = $6;
					n->subname = NULL;
					n->newname = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER INDEX qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_INDEX;
					n->relation = $3;
					n->subname = NULL;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER INDEX IF_P EXISTS qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_INDEX;
					n->relation = $5;
					n->subname = NULL;
					n->newname = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}

			| ALTER INDEX qualified_name RENAME_PARTITION name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_PARTITION_INDEX;
					n->relation = $3;
					n->subname = $5;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER INDEX IF_P EXISTS qualified_name RENAME_PARTITION name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_PARTITION_INDEX;
					n->relation = $5;
					n->subname = $7;
					n->newname = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}

			| ALTER FOREIGN TABLE relation_expr RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FOREIGN_TABLE;
					n->relation = $4;
					n->subname = NULL;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_FOREIGN_TABLE;
					n->relation = $6;
					n->subname = NULL;
					n->newname = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TABLE relation_expr RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_TABLE;
					n->relation = $3;
					n->subname = $6;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_TABLE;
					n->relation = $5;
					n->subname = $8;
					n->newname = $10;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TABCONSTRAINT;
					n->relation = $3;
					n->subname = $6;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}

			| ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TABCONSTRAINT;
					n->relation = $5;
					n->subname = $8;
					n->newname = $10;
					n->missing_ok = true;
					$$ = (Node *)n;
				}

			| ALTER TABLE relation_expr RENAME_PARTITION name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_PARTITION;
					n->relationType = OBJECT_TABLE;
					n->relation = $3;
					n->subname = $5;
					n->newname = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}

			| ALTER TABLE IF_P EXISTS relation_expr RENAME_PARTITION name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_PARTITION;
					n->relationType = OBJECT_TABLE;
					n->relation = $5;
					n->subname = $7;
					n->newname = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}

			| ALTER TABLE relation_expr RENAME_PARTITION FOR '(' maxValueList ')' TO name
			    {
			        RenameStmt *n = makeNode(RenameStmt);
			        n->renameType = OBJECT_PARTITION;
					n->relationType = OBJECT_TABLE;
			        n->relation = $3;
			        n->object = $7;
			        n->subname = NULL;
			        n->newname = $10;
			        n->missing_ok = false;
			        $$ = (Node *)n;
			    }

			| ALTER TABLE IF_P EXISTS relation_expr RENAME_PARTITION FOR '(' maxValueList ')' TO name
			    {
			        RenameStmt *n = makeNode(RenameStmt);
			        n->renameType = OBJECT_PARTITION;
					n->relationType = OBJECT_TABLE;
			        n->relation = $5;
			        n->object = $9;
			        n->subname = NULL;
			        n->newname = $12;
			        n->missing_ok = true;
			        $$ = (Node *)n;
			    }

			| ALTER FOREIGN TABLE relation_expr RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_FOREIGN_TABLE;
					n->relation = $4;
					n->subname = $7;
					n->newname = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME opt_column name TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_COLUMN;
					n->relationType = OBJECT_FOREIGN_TABLE;
					n->relation = $6;
					n->subname = $9;
					n->newname = $11;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TRIGGER qualified_trigger_name ON qualified_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TRIGGER;
					n->relation = $5;
					n->subname = $3->relname;
					n->newname = $8;
					n->missing_ok = false;
					n->renameTargetList = list_make1($3);
					$$ = (Node *)n;
				}
			| ALTER ROLE RoleId RENAME TO RoleId
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_ROLE;
					n->subname = $3;
					IsValidIdentUsername($6);
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER USER UserId RENAME TO UserId
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_USER;
					n->subname = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLESPACE name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TABLESPACE;
					n->subname = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLESPACE name SET reloptions
				{
					AlterTableSpaceOptionsStmt *n =
						makeNode(AlterTableSpaceOptionsStmt);
					n->tablespacename = $3;
					n->options = $5;
					n->isReset = FALSE;
					$$ = (Node *)n;
				}
			| ALTER TABLESPACE name RESET reloptions
				{
					AlterTableSpaceOptionsStmt *n =
						makeNode(AlterTableSpaceOptionsStmt);
					n->tablespacename = $3;
					n->options = $5;
					n->isReset = TRUE;
					$$ = (Node *)n;
				}
			| ALTER TABLESPACE name RESIZE MAXSIZE size_clause
				{
					AlterTableSpaceOptionsStmt *n =
						makeNode(AlterTableSpaceOptionsStmt);
					n->tablespacename = $3;
					n->options = NIL;
					n->isReset = FALSE;
					n->maxsize = $6;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TSPARSER;
					n->object = $5;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TSDICTIONARY;
					n->object = $5;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TSTEMPLATE;
					n->object = $5;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TSCONFIGURATION;
					n->object = $5;
					n->newname = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TYPE_P any_name RENAME TO name
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_TYPE;
					n->object = $3;
					n->newname = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior
				{
					RenameStmt *n = makeNode(RenameStmt);
					n->renameType = OBJECT_ATTRIBUTE;
					n->relationType = OBJECT_TYPE;
					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
					n->subname = $6;
					n->newname = $8;
					n->behavior = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| RENAME TABLE rename_clause_list
				{
#ifndef ENABLE_MULTIPLE_NODES
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
						RenameStmt *n = makeNode(RenameStmt);
						n->renameType = OBJECT_TABLE;
						n->renameTargetList = $3;
						n->renameTableflag = true;
						n->missing_ok = false;
						$$ = (Node *)n;
					} else {
						const char* message = "rename table syntax is supported on dbcompatibility B.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
                                                        errcode(ERRCODE_SYNTAX_ERROR),
                                                        errmsg("rename table syntax is supported on dbcompatibility B."),
                                                        parser_errposition(@1)));
						$$ = NULL;
					}
#else
                                        const char* message = "rename table syntax don't supported on distributed database.";
                                        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                                        ereport(errstate,
                                                (errmodule(MOD_PARSER),
                                                errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                errmsg("rename table syntax don't supported on distributed database."),
                                                parser_errposition(@1)));
                                        $$ = NULL;
#endif
				}
		;

rename_clause_list:
		rename_clause					{ $$ = $1; }
		| rename_clause_list ',' rename_clause		{ $$ = list_concat($1, $3); }
	;

rename_clause:
		qualified_name TO qualified_name
		{
			RenameCell* n = makeNode(RenameCell);
			n->original_name = $1;
			n->modify_name = $3;
			$$ = list_make1(n);
		}
	;

opt_column: COLUMN									{ $$ = COLUMN; }
			| /*EMPTY*/		%prec lower_than_index	{ $$ = 0; }
		;

opt_set_data: SET DATA_P							{ $$ = 1; }
			| /*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;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER COLLATION any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_COLLATION;
					n->object = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER CONVERSION_P any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_CONVERSION;
					n->object = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER DOMAIN_P any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_DOMAIN;
					n->object = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER EXTENSION any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_EXTENSION;
					n->object = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FUNCTION function_with_argtypes SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER PROCEDURE function_with_argtypes SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_OPERATOR;
					n->object = $3;
					n->objarg = $4;
					n->newschema = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_OPCLASS;
					n->object = lcons(makeString($6), $4);
					n->newschema = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_OPFAMILY;
					n->object = lcons(makeString($6), $4);
					n->newschema = $9;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLE relation_expr SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TABLE;
					n->relation = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TABLE IF_P EXISTS relation_expr SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TABLE;
					n->relation = $5;
					n->newschema = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TSPARSER;
					n->object = $5;
					n->newschema = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TSDICTIONARY;
					n->object = $5;
					n->newschema = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TSTEMPLATE;
					n->object = $5;
					n->newschema = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TSCONFIGURATION;
					n->object = $5;
					n->newschema = $8;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SEQUENCE qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_SEQUENCE;
					n->relation = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_LARGE_SEQUENCE;
					n->relation = $4;
					n->newschema = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_SEQUENCE;
					n->relation = $5;
					n->newschema = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_LARGE_SEQUENCE;
					n->relation = $6;
					n->newschema = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER VIEW qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_VIEW;
					n->relation = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER VIEW IF_P EXISTS qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_VIEW;
					n->relation = $5;
					n->newschema = $8;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_MATVIEW;
					n->relation = $4;
					n->newschema = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_MATVIEW;
					n->relation = $6;
					n->newschema = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN TABLE relation_expr SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_FOREIGN_TABLE;
					n->relation = $4;
					n->newschema = $7;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			| ALTER FOREIGN TABLE IF_P EXISTS relation_expr SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_FOREIGN_TABLE;
					n->relation = $6;
					n->newschema = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			| ALTER TYPE_P any_name SET SCHEMA name
				{
					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
					n->objectType = OBJECT_TYPE;
					n->object = $3;
					n->newschema = $6;
					n->missing_ok = false;
					$$ = (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 COLLATION any_name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_COLLATION;
					n->object = $3;
					n->newowner = $6;
					$$ = (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 DIRECTORY name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_DIRECTORY;
					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 FUNCTION function_with_argtypes OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER PROCEDURE function_with_argtypes OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_FUNCTION;
					n->object = $3->funcname;
					n->objarg = $3->funcargs;
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER PACKAGE pkg_name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_PACKAGE;
					n->object = $3;
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER opt_procedural LANGUAGE name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_LANGUAGE;
					n->object = list_make1(makeString($4));
					n->newowner = $7;
					$$ = (Node *)n;
				}
			| ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_LARGEOBJECT;
					n->object = list_make1($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 = $4;
					n->newowner = $7;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_OPCLASS;
					n->object = lcons(makeString($6), $4);
					n->newowner = $9;
					$$ = (Node *)n;
				}
			| ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_OPFAMILY;
					n->object = lcons(makeString($6), $4);
					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 any_name OWNER TO TypeOwner
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_TYPE;
					n->object = $3;
					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 TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_TSDICTIONARY;
					n->object = $5;
					n->newowner = $8;
					$$ = (Node *)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_TSCONFIGURATION;
					n->object = $5;
					n->newowner = $8;
					$$ = (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 DATA_P SOURCE_P name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_DATA_SOURCE;
					n->object = list_make1(makeString($4));
					n->newowner = $7;
					$$ = (Node *)n;
				}
			| ALTER SYNONYM any_name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_SYNONYM;
					n->object = $3;
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER PUBLICATION name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_PUBLICATION;
					n->object = list_make1(makeString($3));
					n->newowner = $6;
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name OWNER TO RoleId
				{
					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
					n->objectType = OBJECT_SUBSCRIPTION;
					n->object = list_make1(makeString($3));
					n->newowner = $6;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 * CREATE PUBLICATION name [ FOR TABLE ] [ WITH options ]
 *
 *****************************************************************************/

CreatePublicationStmt:
			CREATE PUBLICATION name opt_publication_for_tables opt_definition
				{
					CreatePublicationStmt *n = makeNode(CreatePublicationStmt);
					n->pubname = $3;
					n->options = $5;
					if ($4 != NULL)
					{
						/* FOR TABLE */
						if (IsA($4, List))
							n->tables = (List *)$4;
						/* FOR ALL TABLES */
						else
							n->for_all_tables = TRUE;
					}
					$$ = (Node *)n;
				}
		;

opt_publication_for_tables:
			publication_for_tables					{ $$ = $1; }
			| /* EMPTY */							{ $$ = NULL; }
		;

publication_for_tables:
			FOR TABLE relation_expr_list
				{
					$$ = (Node *) $3;
				}
			| FOR ALL TABLES
				{
					$$ = (Node *) makeInteger(TRUE);
				}
		;

/*****************************************************************************
 *
 * ALTER PUBLICATION name SET ( options )
 *
 * ALTER PUBLICATION name ADD TABLE table [, table2]
 *
 * ALTER PUBLICATION name DROP TABLE table [, table2]
 *
 * ALTER PUBLICATION name SET TABLE table [, table2]
 *
 *****************************************************************************/

AlterPublicationStmt:
			ALTER PUBLICATION name SET definition
				{
					AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
					n->pubname = $3;
					n->options = $5;
					$$ = (Node *)n;
				}
			| ALTER PUBLICATION name ADD_P TABLE relation_expr_list
				{
					AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
					n->pubname = $3;
					n->tables = $6;
					n->tableAction = DEFELEM_ADD;
					$$ = (Node *)n;
				}
			| ALTER PUBLICATION name SET TABLE relation_expr_list
				{
					AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
					n->pubname = $3;
					n->tables = $6;
					n->tableAction = DEFELEM_SET;
					$$ = (Node *)n;
				}
			| ALTER PUBLICATION name DROP TABLE relation_expr_list
				{
					AlterPublicationStmt *n = makeNode(AlterPublicationStmt);
					n->pubname = $3;
					n->tables = $6;
					n->tableAction = DEFELEM_DROP;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 * CREATE SUBSCRIPTION name ...
 *
 *****************************************************************************/

CreateSubscriptionStmt:
			CREATE SUBSCRIPTION name CONNECTION Sconst PUBLICATION publication_name_list opt_definition
				{
					CreateSubscriptionStmt *n =
						makeNode(CreateSubscriptionStmt);
					n->subname = $3;
					n->conninfo = $5;
					n->publication = $7;
					n->options = $8;
					$$ = (Node *)n;
				}
		;

publication_name_list:
			publication_name_item
				{
					$$ = list_make1($1);
				}
			| publication_name_list ',' publication_name_item
				{
					$$ = lappend($1, $3);
				}
		;

publication_name_item:
			ColLabel			{ $$ = makeString($1); };

/*****************************************************************************
 *
 * ALTER SUBSCRIPTION name ...
 *
 *****************************************************************************/

AlterSubscriptionStmt:
			ALTER SUBSCRIPTION name SET definition
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->subname = $3;
					n->refresh = false;
					n->options = $5;
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name CONNECTION Sconst
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->subname = $3;
					n->refresh = false;
					n->options = list_make1(makeDefElem("conninfo",
											(Node *)makeString($5)));
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->subname = $3;
					n->refresh = false;
					n->options = list_make1(makeDefElem("publication",
											(Node *)$6));
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name REFRESH PUBLICATION opt_definition
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->subname = $3;
					n->refresh = true;
					n->options = $6;
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name ENABLE_P
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->refresh = false;
					n->subname = $3;
					n->options = list_make1(makeDefElem("enabled",
											(Node *)makeInteger(TRUE)));
					$$ = (Node *)n;
				}
			| ALTER SUBSCRIPTION name DISABLE_P
				{
					AlterSubscriptionStmt *n =
						makeNode(AlterSubscriptionStmt);
					n->refresh = false;
					n->subname = $3;
					n->options = list_make1(makeDefElem("enabled",
											(Node *)makeInteger(FALSE)));
					$$ = (Node *)n;
				}		;

/*****************************************************************************
 *
 * DROP SUBSCRIPTION [ IF EXISTS ] name
 *
 *****************************************************************************/

DropSubscriptionStmt: DROP SUBSCRIPTION name opt_drop_behavior
				{
					DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt);
					n->subname = $3;
					n->behavior = $4;
					n->missing_ok = false;
					$$ = (Node *) n;
				}
				|  DROP SUBSCRIPTION IF_P EXISTS name opt_drop_behavior
				{
					DropSubscriptionStmt *n = makeNode(DropSubscriptionStmt);
					n->subname = $5;
					n->missing_ok = true;
					n->behavior = $6;
					$$ = (Node *) n;
				}
		;

TypeOwner:	RoleId			{ $$ = $1; }
			| CURRENT_USER	{ $$ = pstrdup($1); }
			| SESSION_USER	{ $$ = pstrdup($1); }
		;

/*****************************************************************************
 *
 *		QUERY:	Define Rewrite Rule
 *
 *****************************************************************************/

RuleStmt:	CREATE opt_or_replace RULE name AS
			ON event TO qualified_name where_clause
			DO opt_instead RuleActionList
				{
					RuleStmt *n = makeNode(RuleStmt);
					n->replace = $2;
					n->relation = $9;
					n->rulename = $4;
					n->whereClause = $10;
					n->event = (CmdType)$7;
					n->instead = $12;
					n->actions = $13;
					$$ = (Node *)n;
				}
		;

RuleActionList:
			NOTHING									{ $$ = NIL; }
			| RuleActionStmt {
#ifndef ENABLE_MULTIPLE_NODES
				if (IsA($1, CopyStmt) || IsA($1, AlterTableStmt)) {
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Unsupported feature"),
									errdetail("copy stmt or alter stmt in action is not allowed")));
				}
#endif
			    $$ = 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
			| CopyStmt
			| NotifyStmt
            | AlterTableStmt
		;
RuleActionStmtOrEmpty:
			RuleActionStmt							{ $$ = $1; }
			|	/*EMPTY*/							{ $$ = NULL; }
		;

event:		SELECT									{ $$ = CMD_SELECT; }
			| UPDATE								{ $$ = CMD_UPDATE; }
			| DELETE_P								{ $$ = CMD_DELETE; }
			| INSERT								{ $$ = CMD_INSERT; }
			| COPY									{ $$ = CMD_UTILITY; }
			| ALTER									{ $$ = CMD_UTILITY; }                           
		 ;

opt_instead:
			INSTEAD									{ $$ = TRUE; }
			| ALSO									{ $$ = FALSE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;


DropRuleStmt:
			DROP RULE name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_RULE;
					n->objects = list_make1(lappend($5, makeString($3)));
					n->arguments = NIL;
					n->behavior = $6;
					n->missing_ok = false;
					n->concurrent = false;
					$$ = (Node *) n;
				}
			| DROP RULE IF_P EXISTS name ON any_name opt_drop_behavior
				{
					DropStmt *n = makeNode(DropStmt);
					n->removeType = OBJECT_RULE;
					n->objects = list_make1(lappend($7, makeString($5)));
					n->arguments = NIL;
					n->behavior = $8;
					n->missing_ok = true;
					n->concurrent = false;
					$$ = (Node *) n;
				}
		;


/*****************************************************************************
 *
 *		QUERY:
 *				NOTIFY <identifier> can appear both in rule bodies and
 *				as a query-level command
 *
 *****************************************************************************/

NotifyStmt: NOTIFY ColId notify_payload
				{
					NotifyStmt *n = makeNode(NotifyStmt);
					n->conditionname = $2;
					n->payload = $3;
					$$ = (Node *)n;
				}
		;

notify_payload:
			',' Sconst							{ $$ = $2; }
			| /*EMPTY*/							{ $$ = NULL; }
		;

ListenStmt: LISTEN ColId
				{
					ListenStmt *n = makeNode(ListenStmt);
					n->conditionname = $2;
					$$ = (Node *)n;
				}
		;

UnlistenStmt:
			UNLISTEN ColId
				{
					UnlistenStmt *n = makeNode(UnlistenStmt);
					n->conditionname = $2;
					$$ = (Node *)n;
				}
			| UNLISTEN '*'
				{
					UnlistenStmt *n = makeNode(UnlistenStmt);
					n->conditionname = NULL;
					$$ = (Node *)n;
				}
		;


/*****************************************************************************
 *
 *		Transactions:
 *
 *		BEGIN / COMMIT / ROLLBACK
 *		(also older versions END / ABORT)
 *
 *****************************************************************************/

TransactionStmt:
			ABORT_P opt_transaction
				{
					TransactionStmt *n = makeNode(TransactionStmt);
					n->kind = TRANS_STMT_ROLLBACK;
					n->options = NIL;
					$$ = (Node *)n;
				}
			| START TRANSACTION transaction_mode_list_or_empty
				{
					TransactionStmt *n = makeNode(TransactionStmt);
					n->kind = TRANS_STMT_START;
					n->options = $3;
					$$ = (Node *)n;
				}
			| START TRANSACTION WITH CONSISTENT SNAPSHOT
				{
					if (!DB_IS_CMPT(B_FORMAT)) {
						const char* message = "WITH CONSISTENT SNAPSHOT is supported only in B-format database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("WITH CONSISTENT SNAPSHOT is supported only in B-format database."),
								parser_errposition(@3)));
					}
					TransactionStmt *n = makeNode(TransactionStmt);
					n->kind = TRANS_STMT_START;
					n->options = NIL;
					n->with_snapshot = true;
					$$ = (Node *)n;
				}
			| BEGIN_NON_ANOYBLOCK opt_transaction transaction_mode_list_or_empty
				{
					TransactionStmt *n = makeNode(TransactionStmt);
					n->kind = TRANS_STMT_BEGIN;
					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;
					n->csn = InvalidCommitSeqNo;
					$$ = (Node *)n;
				}
			| COMMIT PREPARED Sconst WITH Sconst
				{   
					TransactionStmt *n = makeNode(TransactionStmt);
					n->kind = TRANS_STMT_COMMIT_PREPARED;
					n->gid = $3;
					n->csn = strtoull($5, NULL, 10);;
					$$ = (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, @3)); }
			| READ ONLY
					{ $$ = makeDefElem("transaction_read_only",
									   makeIntConst(TRUE, @1)); }
			| READ WRITE
					{ $$ = makeDefElem("transaction_read_only",
									   makeIntConst(FALSE, @1)); }
			| DEFERRABLE
					{ $$ = makeDefElem("transaction_deferrable",
									   makeIntConst(TRUE, @1)); }
			| NOT DEFERRABLE
					{ $$ = makeDefElem("transaction_deferrable",
									   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; }
		;


/*****************************************************************************
 *
 *	CONTVIEW:
 *		CREATE [ OR REPLACE ] CONTVIEW <contquery_name> [WITH ([,...])]
 *			AS <query> 
 *
 *****************************************************************************/

CreateContQueryStmt: CREATE CONTVIEW qualified_name opt_reloptions AS SelectStmt
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $3;
					n->relkind = OBJECT_CONTQUERY;
					n->view->relpersistence = RELPERSISTENCE_PERMANENT;
					n->aliases = NIL;
					n->query = $6;
					n->replace = false;
					n->options = $4;
                    n->sql_statement = NULL;
					$$ = (Node *) n;
                }
		    | CREATE OR REPLACE CONTVIEW qualified_name opt_reloptions AS SelectStmt
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $5;
					n->relkind = OBJECT_CONTQUERY;
					n->view->relpersistence = RELPERSISTENCE_PERMANENT;
					n->aliases = NIL;
					n->query = $8;
					n->replace = true;
					n->options = $6;
                    n->sql_statement = NULL;
					$$ = (Node *) n;
				}
            ;

/*****************************************************************************
 *
 *	QUERY:
 *		CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
 *			AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
 *
 *****************************************************************************/

ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $4;
					n->view->relpersistence = $2;
					n->aliases = $5;
					n->query = $8;
					n->replace = false;
					n->options = $6;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$9;
					n->viewSecurityOption = VIEW_SQL_SECURITY_NONE;
					$$ = (Node *) n;
				}
		| CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $6;
					n->view->relpersistence = $4;
					n->aliases = $7;
					n->query = $10;
					n->replace = true;
					n->options = $8;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$11;
					n->viewSecurityOption = VIEW_SQL_SECURITY_NONE;
					$$ = (Node *) n;
				}
		| CREATE opt_or_replace definer_expression OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->definer = $3;
					n->view = $6;
					n->view->relpersistence = $4;
					n->aliases = $7;
					n->query = $10;
					n->replace = $2;
					n->options = $8;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$11;
					n->viewSecurityOption = VIEW_SQL_SECURITY_NONE;
					$$ = (Node *) n;
				}
		| CREATE view_security_expression OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $5;
					n->view->relpersistence = $3;
					n->aliases = $6;
					n->query = $9;
					n->replace = false;
					n->options = $7;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$10;
					n->viewSecurityOption = (ViewSecurityOption)$2;
					$$ = (Node *) n;
				}
		| CREATE OR REPLACE view_security_expression OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->view = $7;
					n->view->relpersistence = $5;
					n->aliases = $8;
					n->query = $11;
					n->replace = true;
					n->options = $9;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$12;
					n->viewSecurityOption = (ViewSecurityOption)$4;
					$$ = (Node *) n;
				}
		| CREATE opt_or_replace definer_expression view_security_expression OptTemp VIEW qualified_name opt_column_list opt_reloptions
				AS SelectStmt opt_check_option
				{
					ViewStmt *n = makeNode(ViewStmt);
					n->definer = $3;
					n->view = $7;
					n->view->relpersistence = $5;
					n->aliases = $8;
					n->query = $11;
					n->replace = $2;
					n->options = $9;
					n->sql_statement = NULL;
					n->withCheckOption = (ViewCheckOption)$12;
					n->viewSecurityOption = (ViewSecurityOption)$4;
					$$ = (Node *) n;
				}
		;

opt_check_option:
		WITH CHECK OPTION				{ $$ = CASCADED_CHECK_OPTION; }
		| WITH CASCADED CHECK OPTION	{ $$ = CASCADED_CHECK_OPTION; }
		| WITH LOCAL CHECK OPTION		{ $$ = LOCAL_CHECK_OPTION; }
		| /* EMPTY */					{ $$ = NO_CHECK_OPTION; }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				LOAD "filename"
 *
 *****************************************************************************/

LoadStmt:	LOAD file_name
				{
					LoadStmt *n = makeNode(LoadStmt);
					n->filename = $2;
                    n->is_load_data = false;
					$$ = (Node *)n;
				}

        | LOAD {u_sess->parser_cxt.is_load_copy = true;} opt_load_data opt_load_data_options_list load_type_set qualified_name load_oper_table_type load_table_options_list
                {
                    LoadStmt *n = makeNode(LoadStmt);
					n->is_load_data = true;
					n->pre_load_options = NULL;
                    n->load_options = $4;
					n->load_type = (LOAD_DATA_TYPE)GetLoadType($5, $7);
                    n->relation = $6;
					n->rel_options = $8;
                    $$ = (Node *)n;
					u_sess->parser_cxt.is_load_copy = false;
                }
        | OPTIONS '(' load_options_list ')' LOAD {u_sess->parser_cxt.is_load_copy = true;} opt_load_data opt_load_data_options_list load_type_set qualified_name load_oper_table_type load_table_options_list
                {
                    LoadStmt *n = makeNode(LoadStmt);
					n->is_load_data = true;
					n->pre_load_options = $3;
                    n->load_options = $8;
					n->load_type = (LOAD_DATA_TYPE)GetLoadType($9, $11);
                    n->relation = $10;
					n->rel_options = $12;
                    $$ = (Node *)n;
					u_sess->parser_cxt.is_load_copy = false;
                }
	;

load_options_list:
		load_options_item							{ $$ = list_make1($1);  }
		| load_options_list ',' load_options_item 	{ $$ = lappend($1, $3); }
		| /* EMPTY */							    { $$ = NULL; }
	;

load_options_item:
		ERRORS '=' NumericOnly						{ $$ = makeDefElem("errors", (Node *)$3); }
		| SKIP '=' NumericOnly 						{ $$ = makeDefElem("skip", (Node *)$3);   }
		| DATA_P '=' load_quote_str 				{ $$ = makeDefElem("data", (Node *)makeString($3));
		}
	;

opt_load_data:
		DATA_P 									{ }
		| /* EMPTY */							{ }
	;

opt_load_data_options_list:
		opt_load_data_options_list opt_load_data_options_item
		{
			$$ = lappend($1, $2);
		}
		| /* EMPTY */							{ $$ = NIL; }
	;

opt_load_data_options_item:
		INFILE load_quote_str
		{
			$$ = makeDefElem("infile", (Node *)makeString($2));
		}
		| CHARACTERSET load_quote_str
		{
			$$ = makeDefElem("characterset", (Node *)makeString($2));
		}
	;

load_oper_table_type:
		TRUNCATE
		{
			$$ = LOAD_DATA_TRUNCATE;
		}
		| APPEND
		{
			$$ = LOAD_DATA_APPEND;
		}
		| REPLACE
		{
			$$ = LOAD_DATA_REPLACE;
		}
		| INSERT
		{
			$$ = LOAD_DATA_INSERT;
		}
		| /* EMPTY */							{ $$ = LOAD_DATA_UNKNOWN; }
	;

load_type_set:
		load_oper_table_type INTO TABLE 
		{
			$$ = $1;
		}
	;

load_table_options_list: 
		load_table_options_list load_table_options_item
		{
			$$ = lappend($1, $2);
		}
		| /* EMPTY */							{ $$ = NIL; }
	;

load_table_options_item:
		TRAILING NULLCOLS
		{
			$$ = makeDefElem("trailing_nullcols", (Node *)makeInteger(TRUE));
		}
		| FIELDS CSV
		{
			$$ = makeDefElem("fields_csv", (Node *)makeInteger(TRUE));
		}
		| FIELDS TERMINATED load_quote_str
		{
			$$ = makeDefElem("fields_terminated_by", (Node *)makeString($3));
		}
		| FIELDS TERMINATED BY load_quote_str
		{
			$$ = makeDefElem("fields_terminated_by", (Node *)makeString($4));
		}
 		| OPTIONALLY ENCLOSED BY load_quote_str
		{
			$$ = makeDefElem("optionally_enclosed_by", (Node *)makeString($4));
		}		
		| load_when_option
		{
			$$ = $1;
		}
		| '(' load_column_expr_list ')'
		{
			$$ = MakeDefElemWithLoc("fields_list", (Node *)$2, @1, @3);
		}
	;

load_column_expr_list:
		load_column_expr_item
		{
			$$ = list_make1($1);
		}
		| load_column_expr_list ',' load_column_expr_item
		{
			$$ = lappend($1, $3);
		}
	;

load_column_expr_item:
		ColId CONSTANT load_quote_str
		{
			SqlLoadColExpr* n = (SqlLoadColExpr*)MakeSqlLoadNode($1);
			n->const_info = makeStringConst($3, @3);
			$$ = (Node*)n;
		}
		| ColId load_col_sequence
		{
			SqlLoadColExpr* n = (SqlLoadColExpr*)MakeSqlLoadNode($1);
			n->sequence_info = $2;
			$$ = (Node*)n;
		}
		| ColId FILLER load_col_data_type
		{
			SqlLoadColExpr* n = (SqlLoadColExpr*)MakeSqlLoadNode($1);
			n->is_filler = true;
			$$ = (Node*)n;
		}
		| ColId load_col_scalar_spec
		{
			SqlLoadColExpr* n = (SqlLoadColExpr*)MakeSqlLoadNode($1);
			n->scalar_spec = $2;
			$$ = (Node*)n;
		}
	;

load_col_sequence_item_sart:
			Iconst			{ $$ = $1; }
			| FCONST		{ $$ = SequenceStrGetInt64($1); }
			| MAXVALUE		{ $$ = LOADER_SEQUENCE_MAX_FLAG; }
			| ROWS			{ $$ = LOADER_SEQUENCE_COUNT_FLAG; }
		;

load_col_sequence:
		SEQUENCE '(' load_col_sequence_item_sart column_sequence_item_step ')'
		{
			SqlLoadSequInfo* n = makeNode(SqlLoadSequInfo);
			n->start = $3;
			n->step = $4;
			$$ = (Node *)n;
		}
	;	

load_col_scalar_spec:
		load_col_position_spec load_col_data_type load_col_nullif_spec load_col_sql_str 
		{
			SqlLoadScalarSpec* n = makeNode(SqlLoadScalarSpec);
			n->position_info = $1;
			n->typname = $2;
			n->sqlstr = $4;
			n->nullif_col = $3;
			$$ = (Node*)n;
		}
	;

load_col_position_spec:
		POSITION '(' Iconst '-' Iconst ')'
		{
			SqlLoadColPosInfo *n =  makeNode(SqlLoadColPosInfo);
			n->start = $3;
			n->end = $5;
			$$ = (Node *)n;
		}
		| /* EMPTY */							{ $$ = NULL; }
	;

load_col_nullif_spec:
		NULLIF '(' ColId '=' BLANKS ')'
		{
			$$ = $3;
		}
		| /* EMPTY */							{ $$ = NULL; }
	;

load_col_data_type:
		Numeric					{ $$ = $1; }
		| Numeric EXTERNAL		{ $$ = $1; }
		| Character				{ $$ = $1; }
		| ConstDatetime			{ $$ = $1; }
		| ConstSet				{ $$ = $1; }
		| /*EMPTY*/				{ $$ = NULL; }
	;

load_col_sql_str:
		IDENT
		{
			$$ = makeStringConst($1, @1);
		}
		| /* EMPTY */							{ $$ = NULL; }
	;

load_when_option:
		WHEN load_when_option_list
		{
			$$ = MakeDefElemWithLoc("when_expr", (Node *)$2, @1, @2);
		}
	;

load_when_option_list:
		load_when_option_item
		{
			$$ = list_make1($1);
		}
		| load_when_option_list AND load_when_option_item
		{
			$$ = lappend($1, $3);
		}
	;

load_when_option_item:
		'(' Iconst '-' Iconst ')' masking_policy_condition_operator load_quote_str
		{
			LoadWhenExpr *n =  makeNode(LoadWhenExpr);
			n->whentype = 0;
			n->start = $2;
			n->end = $4;
			n->oper = $6;
			n->val = $7;
			$$ = (Node*)n;
		}
		| '(' Iconst ')' masking_policy_condition_operator load_quote_str
		{
				LoadWhenExpr *n =  makeNode(LoadWhenExpr);
				n->whentype = 0;
				n->start = $2;
				n->end = $2;
				n->oper = $4;
				n->val = $5;
				$$ = (Node*)n;
		}
		| ColId masking_policy_condition_operator load_quote_str
		{
				LoadWhenExpr *n =  makeNode(LoadWhenExpr);
				n->whentype = 1;
				n->start = -1;
				n->end = -1;
				n->attname = $1;
				n->oper = $2;
				n->val = $3;
				$$ = (Node*)n;
		}
	;

/*
 three string formats used to be compatible with oracle
	1. string
	2. 'string'
	3. "string"
*/
load_quote_str:
		IDENT					{ $$ = $1; }
		| Sconst                { $$ = $1; }

/*****************************************************************************
 *
 *		CREATE DATABASE
 *
 *****************************************************************************/

CreatedbStmt:
			CREATE DATABASE database_name opt_with createdb_opt_list
				{
					CreatedbStmt *n = makeNode(CreatedbStmt);
					IsValidIdent($3);
					n->dbname = $3;
					n->missing_ok = FALSE;
					n->options = $5;
					$$ = (Node *)n;
				}
			| CREATE DATABASE IF_P NOT EXISTS database_name opt_with createdb_opt_list
				{
					CreatedbStmt *n = makeNode(CreatedbStmt);
					IsValidIdent($6);
					n->dbname = $6;
					n->missing_ok = TRUE;
					n->options = $8;
					$$ = (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);
				}
			| LC_COLLATE_P opt_equal Sconst
				{
					$$ = makeDefElem("lc_collate", (Node *)makeString($3));
				}
			| LC_COLLATE_P opt_equal DEFAULT
				{
					$$ = makeDefElem("lc_collate", NULL);
				}
			| DBCOMPATIBILITY_P opt_equal Sconst
				{
					if (checkCompArgs($3) == false)
					{
						const char* message = "Compatibility args %s is invalid\n";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
							 errmsg("Compatibility args %s is invalid\n", $3)));
					}
					$$ = makeDefElem("dbcompatibility", (Node *)makeString($3));
				}
			| DBCOMPATIBILITY_P opt_equal DEFAULT
				{
					$$ = makeDefElem("dbcompatibility", NULL);
				}
			| LC_CTYPE_P opt_equal Sconst
				{
					$$ = makeDefElem("lc_ctype", (Node *)makeString($3));
				}
			| LC_CTYPE_P opt_equal DEFAULT
				{
					$$ = makeDefElem("lc_ctype", 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;
				 }
			| ALTER DATABASE database_name SET TABLESPACE name
				 {
					AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
					n->dbname = $3;
					n->options = list_make1(makeDefElem("tablespace",
													(Node *)makeString($6)));
					$$ = (Node *)n;
				 }
		;

AlterDatabaseSetStmt:
			ALTER DATABASE database_name SetResetClause
				{
					AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
					n->dbname = $3;
					n->setstmt = $4;
					$$ = (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));
				}
			| ENABLE_P PRIVATE OBJECT_P
				{
					$$ = makeDefElem("privateobject", (Node *)makeInteger(1));
				}
			| DISABLE_P PRIVATE OBJECT_P
				{
					$$ = makeDefElem("privateobject", (Node *)makeInteger(0));
				}
		;


/*****************************************************************************
 *
 *		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;
					SplitColQualList($6, &n->constraints, &n->collClause,
									 yyscanner);
					$$ = (Node *)n;
				}
		;

AlterDomainStmt:
			/* ALTER DOMAIN <domain> {SET DEFAULT <expr>|DROP DEFAULT} */
			ALTER DOMAIN_P any_name alter_column_default
				{
					AlterDomainStmt *n = makeNode(AlterDomainStmt);
					n->subtype = 'T';
					n->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;
					n->missing_ok = false;
					$$ = (Node *)n;
				}
			/* ALTER DOMAIN <domain> DROP CONSTRAINT IF EXISTS <name> [RESTRICT|CASCADE] */
			| ALTER DOMAIN_P any_name DROP CONSTRAINT IF_P EXISTS name opt_drop_behavior
				{
					AlterDomainStmt *n = makeNode(AlterDomainStmt);
					n->subtype = 'X';
					n->typname = $3;
					n->name = $8;
					n->behavior = $9;
					n->missing_ok = true;
					$$ = (Node *)n;
				}
			/* ALTER DOMAIN <domain> VALIDATE CONSTRAINT <name> */
			| ALTER DOMAIN_P any_name VALIDATE CONSTRAINT name
				{
					AlterDomainStmt *n = makeNode(AlterDomainStmt);
					n->subtype = 'V';
					n->typname = $3;
					n->name = $6;
					$$ = (Node *)n;
				}
			;

opt_as:		AS										{}
			| /* EMPTY */							{}
		;


/*****************************************************************************
 *
 * Manipulate a text search dictionary or configuration
 *
 *****************************************************************************/

AlterTSDictionaryStmt:
			ALTER TEXT_P SEARCH DICTIONARY any_name definition
				{
					AlterTSDictionaryStmt *n = makeNode(AlterTSDictionaryStmt);
					n->dictname = $5;
					n->options = $6;
					$$ = (Node *)n;
				}
		;

AlterTSConfigurationStmt:
			ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list WITH any_name_list
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_ADD_MAPPING;
					n->cfgname = $5;
					n->tokentype = $9;
					n->cfoptions = NIL;
					n->dicts = $11;
					n->override = false;
					n->replace = false;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list WITH any_name_list
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN;
					n->cfgname = $5;
					n->tokentype = $9;
					n->cfoptions = NIL;
					n->dicts = $11;
					n->override = true;
					n->replace = false;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_REPLACE_DICT;
					n->cfgname = $5;
					n->tokentype = NIL;
					n->cfoptions = NIL;
					n->dicts = list_make2($9,$11);
					n->override = false;
					n->replace = true;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
					n->cfgname = $5;
					n->tokentype = $9;
					n->cfoptions = NIL;
					n->dicts = list_make2($11,$13);
					n->override = false;
					n->replace = true;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_DROP_MAPPING;
					n->cfgname = $5;
					n->tokentype = $9;
					n->cfoptions = NIL;
					n->missing_ok = false;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_DROP_MAPPING;
					n->cfgname = $5;
					n->tokentype = $11;
					n->cfoptions = NIL;
					n->missing_ok = true;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET cfoptions
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
					n->cfgname = $5;
					n->tokentype = NIL;
					n->cfoptions = $7;
					n->missing_ok = false;
					n->override = false;
					n->replace = false;
					n->is_reset = false;
					$$ = (Node*)n;
				}
			| ALTER TEXT_P SEARCH CONFIGURATION any_name RESET cfoptions
				{
					AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
					n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
					n->cfgname = $5;
					n->tokentype = NIL;
					n->cfoptions = $7;
					n->override = false;
					n->replace = false;
					n->missing_ok = false;
					n->is_reset = true;
					$$ = (Node*)n;
				}
		;


/*****************************************************************************
 *
 * 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 qualified_name cluster_index_specification
				{
					ClusterStmt *n = makeNode(ClusterStmt);
					$3->partitionname = NULL;
					n->relation = $3;
					n->indexname = $4;
					n->verbose = $2;
					$$ = (Node*)n;
				}
			| CLUSTER opt_verbose qualified_name PARTITION '(' name ')' cluster_index_specification
				{
					ClusterStmt *n = makeNode(ClusterStmt);
					$3->partitionname = $6;
					n->relation = $3;
					n->indexname = $8;
					n->verbose = $2;
					$$ = (Node*)n;
				}
			| CLUSTER opt_verbose
				{
					ClusterStmt *n = makeNode(ClusterStmt);
					n->relation = NULL;
					n->indexname = NULL;
					n->verbose = $2;
					$$ = (Node*)n;
				}
			/* kept for pre-8.3 compatibility */
			| CLUSTER opt_verbose index_name ON qualified_name
				{
					ClusterStmt *n = makeNode(ClusterStmt);
					n->relation = $5;
					n->indexname = $3;
					n->verbose = $2;
					$$ = (Node*)n;
				}
		;

cluster_index_specification:
			USING index_name		{ $$ = $2; }
			| /*EMPTY*/				{ $$ = NULL; }
		;


/*****************************************************************************
 *
 *		QUERY:
 *				VACUUM
 *				ANALYZE
 *
 *****************************************************************************/

VacuumStmt:
			VACUUM opt_deltamerge
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					if ($2)
						n->options |= VACOPT_MERGE;
					$$ = (Node *)n;
				}
			| VACUUM opt_deltamerge qualified_name
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					if ($2)
						n->options |= VACOPT_MERGE;
					n->relation = $3;
					$$ = (Node *)n;
				}
			| VACUUM opt_hdfsdirectory
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
					{
						n->options |= VACOPT_HDFSDIRECTORY;
					}
					$$ = (Node *)n;
				}
			| VACUUM opt_hdfsdirectory qualified_name
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
					{
						n->options |= VACOPT_HDFSDIRECTORY;
					}
					n->relation = $3;
					$$ = (Node *)n;
				}
			| VACUUM opt_full opt_freeze opt_verbose opt_compact
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
						n->options |= VACOPT_FULL;
					if ($4)
						n->options |= VACOPT_VERBOSE;
					if ($5)
						n->options |= VACOPT_COMPACT;
					int options = 0;
					options |= VACOPT_VACUUM | VACOPT_FULL | VACOPT_COMPACT;
					if (n->options & VACOPT_COMPACT)
					{
						if (n->options != options)
						{
						const char* message = "COMPACT can only be used with VACUUM FULL";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("COMPACT can only be used with VACUUM FULL")));
						}
						if ($3)
						{
							const char* message = "COMPACT can not be used with FREEZE";
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("COMPACT can not be used with FREEZE")));
						}
					}
					n->freeze_min_age = $3 ? 0 : -1;
					n->freeze_table_age = $3 ? 0 : -1;
					n->relation = NULL;
					n->va_cols = NIL;
					$$ = (Node *)n;
				}
			| VACUUM opt_full opt_freeze opt_verbose opt_compact qualified_name
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
						n->options |= VACOPT_FULL;
					if ($4)
						n->options |= VACOPT_VERBOSE;
					if ($5)
						n->options |= VACOPT_COMPACT;
					int options = 0;
					options |= VACOPT_VACUUM | VACOPT_FULL | VACOPT_COMPACT;
					if (n->options & VACOPT_COMPACT)
					{
						if (n->options != options)
						{
							const char* message = "COMPACT can only be used with VACUUM FULL";
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("COMPACT can only be used with VACUUM FULL")));
						}
						if ($3)
						{
							const char* message = "COMPACT can not be used with FREEZE";
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("COMPACT can not be used with FREEZE")));
						}
					}
					n->freeze_min_age = $3 ? 0 : -1;
					n->freeze_table_age = $3 ? 0 : -1;
					n->relation = $6;
					n->va_cols = NIL;
					$$ = (Node *)n;
				}
			| VACUUM opt_full opt_freeze opt_verbose opt_compact qualified_name PARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
						n->options |= VACOPT_FULL;
					if ($4)
						n->options |= VACOPT_VERBOSE;
					if ($5)
					{
						const char* message = "COMPACT can not be used with PARTITION";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("COMPACT can not be used with PARTITION")));
					}
					n->freeze_min_age = $3 ? 0 : -1;
					n->freeze_table_age = $3 ? 0 : -1;
					n->relation = $6;
					n->va_cols = NIL;
					$6->partitionname = $9;
					$$ = (Node *)n;
				}
			| VACUUM opt_full opt_freeze opt_verbose opt_compact qualified_name SUBPARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM;
					if ($2)
						n->options |= VACOPT_FULL;
					if ($4)
						n->options |= VACOPT_VERBOSE;
					if ($5)
					{
						const char* message = "COMPACT can not be used with SUBPARTITION";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("COMPACT can not be used with SUBPARTITION")));
					}
					n->freeze_min_age = $3 ? 0 : -1;
					n->freeze_table_age = $3 ? 0 : -1;
					n->relation = $6;
					n->va_cols = NIL;
					$6->subpartitionname = $9;
					$$ = (Node *)n;
				}
			| VACUUM opt_full opt_freeze opt_verbose opt_compact AnalyzeStmt
				{
					VacuumStmt *n = (VacuumStmt *) $6;
					n->options |= VACOPT_VACUUM;
					if ($2)
						n->options |= VACOPT_FULL;
					if ($4)
						n->options |= VACOPT_VERBOSE;
					if ($5)
					{
						const char* message = "COMPACT can not be used with ANALYZE";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate, (errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("COMPACT can not be used with ANALYZE")));
					}
					n->freeze_min_age = $3 ? 0 : -1;
					n->freeze_table_age = $3 ? 0 : -1;
					$$ = (Node *)n;
				}
			| VACUUM '(' vacuum_option_list ')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM | $3;
					if (n->options & VACOPT_FREEZE)
						n->freeze_min_age = n->freeze_table_age = 0;
					else
						n->freeze_min_age = n->freeze_table_age = -1;
					n->relation = NULL;
					n->va_cols = NIL;
					$$ = (Node *) n;
				}
			| VACUUM '(' vacuum_option_list ')' qualified_name opt_name_list
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM | $3;
					if (n->options & VACOPT_FREEZE)
						n->freeze_min_age = n->freeze_table_age = 0;
					else
						n->freeze_min_age = n->freeze_table_age = -1;
					n->relation = $5;
					n->va_cols = $6;
					if (n->va_cols != NIL)	/* implies analyze */
						n->options |= VACOPT_ANALYZE;
					$$ = (Node *) n;
				}
			| VACUUM '(' vacuum_option_list ')' qualified_name opt_name_list PARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM | $3;
					if (n->options & VACOPT_FREEZE)
						n->freeze_min_age = n->freeze_table_age = 0;
					else
						n->freeze_min_age = n->freeze_table_age = -1;
					n->relation = $5;
					n->va_cols = $6;
					if (n->va_cols != NIL)	/* implies analyze */
						n->options |= VACOPT_ANALYZE;
					$5->partitionname = $9;
					$$ = (Node *) n;
				}
			| VACUUM '(' vacuum_option_list ')' qualified_name opt_name_list SUBPARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_VACUUM | $3;
					if (n->options & VACOPT_FREEZE)
						n->freeze_min_age = n->freeze_table_age = 0;
					else
						n->freeze_min_age = n->freeze_table_age = -1;
					n->relation = $5;
					n->va_cols = $6;
					if (n->va_cols != NIL)	/* implies analyze */
						n->options |= VACOPT_ANALYZE;
					$5->subpartitionname = $9;
					$$ = (Node *) n;
				}
		;

vacuum_option_list:
			vacuum_option_elem								{ $$ = $1; }
			| vacuum_option_list ',' vacuum_option_elem		{ $$ = $1 | $3; }
		;

vacuum_option_elem:
			analyze_keyword		{ $$ = VACOPT_ANALYZE; }
			| VERBOSE			{ $$ = VACOPT_VERBOSE; }
			| FREEZE			{ $$ = VACOPT_FREEZE; }
			| FULL				{ $$ = VACOPT_FULL; }
		;

AnalyzeStmt:
			analyze_keyword opt_verbose
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_ANALYZE;
					if ($2)
						n->options |= VACOPT_VERBOSE;
					n->freeze_min_age = -1;
					n->freeze_table_age = -1;
					n->relation = NULL;
					n->va_cols = NIL;
					$$ = (Node *)n;
				}
			| analyze_keyword opt_verbose qualified_name opt_analyze_column_define
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_ANALYZE;
					if ($2)
						n->options |= VACOPT_VERBOSE;
					n->freeze_min_age = -1;
					n->freeze_table_age = -1;
					n->relation = $3;
					n->va_cols = $4;
					$$ = (Node *)n;
				}
			| analyze_keyword opt_verbose qualified_name opt_name_list PARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_ANALYZE;
					if ($2)
						n->options |= VACOPT_VERBOSE;
					n->freeze_min_age = -1;
					n->freeze_table_age = -1;
					n->relation = $3;
					n->va_cols = $4;
					$3->partitionname = $7;
					$$ = (Node *)n;
				}
			/*
			 * @analyse subpartition
			 */
			| analyze_keyword opt_verbose qualified_name opt_name_list SUBPARTITION '('name')'
				{
					VacuumStmt *n = makeNode(VacuumStmt);
					n->options = VACOPT_ANALYZE;
					if ($2)
						n->options |= VACOPT_VERBOSE;
					n->freeze_min_age = -1;
					n->freeze_table_age = -1;
					n->relation = $3;
					n->va_cols = $4;
					$3->subpartitionname = $7;
					$$ = (Node *)n;
				}
			/*
			 * @hdfs Support command "analyze [verbose] foreign tables"
			 */
			| analyze_keyword opt_verbose FOREIGN TABLES
				{
					VacuumStmt *n = (VacuumStmt*)makeNode(VacuumStmt);
					n->options = VACOPT_ANALYZE;
					if ($2)
						n->options |= VACOPT_VERBOSE;
					n->freeze_min_age = -1;
					n->freeze_table_age = -1;
					n->relation = NULL;
					n->va_cols = NIL;
					n->isForeignTables = TRUE;
					$$ = (Node *)n;

				}
		;

VerifyStmt:
            /* analyse verify fast|complete*/
            analyze_keyword opt_verify opt_verify_options
                {
                    VacuumStmt *n = makeNode(VacuumStmt);
                    n->options = VACOPT_VERIFY | $3;
                    $$ = (Node *)n;
                    n->isCascade = true;
                    n->curVerifyRel = InvalidOid;
                }

            /* analyse verify fast|complete index_name/table_name*/
            | analyze_keyword opt_verify opt_verify_options qualified_name opt_cascade
                {
                    VacuumStmt *n = makeNode(VacuumStmt);
                    n->options = VACOPT_VERIFY | $3;
                    n->relation = $4;
                    if ($5) {
                        n->isCascade = $5;
                    }
                    n->curVerifyRel = InvalidOid;
                    $$ = (Node *)n;
                }

            /* analyse verify fast|complete table_name partition (partition_name) cascade*/
            | analyze_keyword opt_verify opt_verify_options qualified_name PARTITION '('name')' opt_cascade
                {
                    VacuumStmt *n = makeNode(VacuumStmt);
                    n->options = VACOPT_VERIFY | $3;
                    n->relation = $4;
                    $4->partitionname = $7;
                    if ($9) {
                        n->isCascade = $9;
                    }
                    n->curVerifyRel = InvalidOid;
                    $$ = (Node *)n;
                }
        ;

analyze_keyword:
			ANALYZE									{}
			| ANALYSE /* British */					{}
		;

opt_verify_options:
        	FAST                                    { $$ = VACOPT_FAST;}
            | COMPLETE                               { $$ = VACOPT_COMPLETE;}
	    ;

opt_verbose:
			VERBOSE									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_full:	FULL									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_compact:	COMPACT								{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_hdfsdirectory:	HDFSDIRECTORY 					{ $$ = TRUE; }
		;

opt_freeze: FREEZE									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_deltamerge: DELTAMERGE 							{$$ = TRUE;}
		;

opt_verify: 	VERIFY                                  { $$ = TRUE; }
	        ;

opt_cascade: 	CASCADE                                { $$ = TRUE; }
            	| /*EMPTY*/                            { $$ = FALSE; }
        	;
opt_name_list:
			'(' name_list ')'						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

opt_analyze_column_define:
			'(' opt_multi_name_list ')'
				{
					$$ = $2;
				}
			| '(' name_list ')'						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

opt_multi_name_list:
			'(' name_list ')'
				{
					$$ = list_make1($2);
				}
		;

/* PGXC_BEGIN */
BarrierStmt: CREATE BARRIER opt_barrier_id
				{
					BarrierStmt *n = makeNode(BarrierStmt);
					n->id = $3;
					$$ = (Node *)n;
				}
			;

opt_barrier_id:
				Sconst
				{
					$$ = pstrdup($1);
				}
			| /* EMPTY */
				{
					$$ = NULL;
				}
			;

/*****************************************************************************
 *
 *		QUERY:
 *
 *		CREATE NODE nodename WITH
 *				(
 *					[ TYPE = ('datanode' | 'coordinator'), ]
 *					[ RW [ = boolean ], ]
 *					[ HOST = 'hostname', ]
 *					[ PORT = portnum, ]
 *					[ HOST1 = 'hostname', ]
 *					[ PORT1 = portnum, ]
 *					[ HOSTPRIMARY [ = boolean ], ]
 *					[ PRIMARY [ = boolean ], ]
 *					[ PREFERRED [ = boolean ] ]
 *					[ SCTP_PORT = portnum, ]
 *					[ CONTROL_PORT = portnum, ]
 *					[ SCTP_PORT1 = portnum, ]
 *					[ CONTROL_PORT1 = portnum, ]
 *				)
 *
 *****************************************************************************/

CreateNodeStmt: CREATE NODE pgxcnode_name OptWith
				{
					CreateNodeStmt *n = makeNode(CreateNodeStmt);
					n->node_name = $3;
					n->options = $4;
					$$ = (Node *)n;
				}
		;

pgxcnode_name:
			ColId							{ $$ = $1; };

pgxcgroup_name:
			ColId							{ $$ = $1; };

pgxcnodes:
			'(' pgxcnode_list ')'			{ $$ = $2; }
		;

pgxcnode_list:
			pgxcnode_list ',' pgxcnode_name		{ $$ = lappend($1, makeString($3)); }
			| pgxcnode_name						{ $$ = list_make1(makeString($1)); }
		;

bucket_maps:
			BUCKETS '(' bucket_list ')'			{ $$ = $3; }
			| /*EMPTY*/ 			            { $$ = NIL; }
		;

bucket_list:
			bucket_list ',' Iconst		{ $$ = lappend($1, makeInteger($3)); }
			| Iconst					{ $$ = list_make1(makeInteger($1)); }
		;

bucket_cnt:
			BUCKETCNT Iconst			{ $$ = $2; }
			| /*EMPTY*/ 				{ $$ = -1; }
		;

pgxcgroup_parent:
			GROUPPARENT pgxcnode_name      		{ $$ = $2; }
			| /*EMPTY*/ 				{ $$ = NULL;}
		;

opt_vcgroup: 
            		VCGROUP			{$$ = TRUE;}
			| /* EMPTY */		{$$ = FALSE;}
		;

opt_to_elastic_group: 
            TO ELASTIC GROUP_P	{$$ = TRUE;}
			| /* EMPTY */		{$$ = FALSE;}
		;

opt_redistributed: 
			DISTRIBUTE FROM  ColId  {$$ = $3;}
			| /* EMPTY */      	{$$ = NULL;}
		;

opt_set_vcgroup: 
            		SET VCGROUP		{$$ = AG_SET_VCGROUP;}
            		| SET NOT VCGROUP	{$$ = AG_SET_NOT_VCGROUP;}
			| /* EMPTY */		{$$ = AG_SET_RENAME;}
		;

/*****************************************************************************
 *
 *		QUERY:
 *		ALTER NODE nodename WITH
 *				(
 *					[ TYPE = ('datanode' | 'coordinator'), ]
 *					[ HOST = 'hostname', ]
 *					[ RW [ = boolean ], ]
 *					[ PORT = portnum, ]
 *					[ HOST1 = 'hostname', ]
 *					[ PORT1 = portnum, ]
 *					[ HOSTPRIMARY [ = boolean ], ]
 *					[ PRIMARY [ = boolean ], ]
 *					[ PREFERRED [ = boolean ] ]
 *					[ SCTP_PORT = portnum, ]
 *					[ CONTROL_PORT = portnum, ]
 *					[ SCTP_PORT1 = portnum, ]
 *					[ CONTROL_PORT1 = portnum, ]
 *				)
 *
 *****************************************************************************/

AlterNodeStmt: ALTER NODE pgxcnode_name OptWith
				{
					AlterNodeStmt *n = makeNode(AlterNodeStmt);
					n->node_name = $3;
					n->options = $4;
					$$ = (Node *)n;
				}
		;
/* alter node coordinator set true/false with (cn1,...,cnN) */
AlterCoordinatorStmt: ALTER COORDINATOR pgxcnode_name SET opt_boolean_or_string WITH pgxcnodes
				{
					AlterCoordinatorStmt *n = makeNode(AlterCoordinatorStmt);
					n->node_name = $3;
					n->set_value = $5;
					n->coor_nodes = $7;
					$$ = (Node *)n;	
				}
		;
	

/*****************************************************************************
 *
 *		QUERY:
 *				DROP NODE [IF EXISTS] nodename [WITH (cn1,...,cnN)]
 *
 *****************************************************************************/

DropNodeStmt: DROP NODE pgxcnode_name opt_pgxcnodes
				{
					DropNodeStmt *n = makeNode(DropNodeStmt);
					n->node_name = $3;
					n->missing_ok = FALSE;
					n->remote_nodes = $4;
					$$ = (Node *)n;
				}
			| DROP NODE IF_P EXISTS pgxcnode_name opt_pgxcnodes
				{
					DropNodeStmt *n = makeNode(DropNodeStmt);
					n->node_name = $5;
					n->missing_ok = TRUE;
					n->remote_nodes = $6;
					$$ = (Node *)n;
				}
		;

opt_pgxcnodes:	WITH pgxcnodes
				{
					$$ = $2;
				}
				| /*EMPTY*/
				{
					$$ = NIL;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				CREATE NODE GROUP groupname WITH (node1,...,nodeN) [BUCKETS (0,1,2,...)]
 *
 *****************************************************************************/

CreateNodeGroupStmt: CREATE NODE GROUP_P pgxcgroup_name opt_pgxcnodes bucket_maps opt_vcgroup opt_redistributed bucket_cnt pgxcgroup_parent
				{
					CreateGroupStmt *n = makeNode(CreateGroupStmt);
					IsValidGroupname($4);
					n->group_name = $4;
					n->nodes = $5;
					n->buckets = $6;
					n->vcgroup = $7;
					n->src_group_name = $8;
					n->bucketcnt = $9;
					n->group_parent = $10;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				ALTER NODE GROUP groupname SET DEFAULT
 *
 *****************************************************************************/

AlterNodeGroupStmt: ALTER NODE GROUP_P pgxcgroup_name SET DEFAULT
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->alter_type = AG_SET_DEFAULT;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name opt_set_vcgroup RENAME TO pgxcgroup_name
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = $8;
					n->alter_type = (AlterGroupType)$5;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name SET NOT VCGROUP
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = NULL;
					n->alter_type = AG_SET_NOT_VCGROUP;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name SET TABLE GROUP_P pgxcgroup_name
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = $8;
					n->alter_type = AG_SET_TABLE_GROUP;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name COPY BUCKETS FROM pgxcgroup_name
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = $8;
					n->alter_type = AG_SET_BUCKETS;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name ADD_P NODE pgxcnodes
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = NULL;
					n->alter_type = AG_ADD_NODES;
					n->nodes = $7;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name DELETE_P NODE pgxcnodes
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = NULL;
					n->alter_type = AG_DELETE_NODES;
					n->nodes = $7;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name RESIZE TO pgxcgroup_name
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = $7;
					n->alter_type = AG_RESIZE_GROUP;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name opt_set_vcgroup WITH GROUP_P pgxcgroup_name
				{
					AlterGroupStmt *n = makeNode(AlterGroupStmt);
					n->group_name = $4;
					n->install_name = $8;
					n->alter_type = AG_CONVERT_VCGROUP;
					$$ = (Node *)n;
				}
				| ALTER NODE GROUP_P pgxcgroup_name SET SEQUENCE TO ALL NODE
                                {
                                	AlterGroupStmt *n = makeNode(AlterGroupStmt);
                                        n->group_name = $4;
                                        n->install_name = NULL;
                                        n->alter_type = AG_SET_SEQ_ALLNODES;
                                        $$ = (Node *)n;
                                }
                                | ALTER NODE GROUP_P pgxcgroup_name SET SEQUENCE TO LOCAL
                                {
                                        AlterGroupStmt *n = makeNode(AlterGroupStmt);
                                        n->group_name = $4;
                                        n->install_name = NULL;
                                        n->alter_type = AG_SET_SEQ_SELFNODES;
                                        $$ = (Node *)n;
                                }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				DROP NODE GROUP groupname
 *
 *****************************************************************************/

DropNodeGroupStmt: DROP NODE GROUP_P pgxcgroup_name opt_redistributed opt_to_elastic_group
				{
					DropGroupStmt *n = makeNode(DropGroupStmt);
					n->group_name = $4;
					n->src_group_name = $5;
					n->to_elastic_group = $6;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
/*****************************************************************************
 *
 *     QUERY:
 *
 *     CREATE AUDIT POLICY policy_name
 *
 *****************************************************************************/
CreateAuditPolicyStmt:
        CREATE AUDIT POLICY policy_name PRIVILEGES policy_privileges_list policy_filter_opt policy_status_opt
                {
                    CreateAuditPolicyStmt *n = makeNode(CreateAuditPolicyStmt);
                    n->policy_type = "privileges";
                    n->if_not_exists = false;
                    IsValidIdent($4);
                    n->policy_name = $4;
                    n->policy_targets = $6;
                    n->policy_filters = $7;
                    n->policy_enabled = $8;
                    $$ = (Node *) n;
                }
        | CREATE AUDIT POLICY IF_P NOT EXISTS policy_name PRIVILEGES policy_privileges_list policy_filter_opt policy_status_opt
                {
                    CreateAuditPolicyStmt *n = makeNode(CreateAuditPolicyStmt);
                    n->policy_type = "privileges";
                    n->if_not_exists = true;
                    IsValidIdent($7);
                    n->policy_name = $7;
                    n->policy_targets = $9;
                    n->policy_filters = $10;
                    n->policy_enabled = $11;
                    $$ = (Node *) n;
                }
        | CREATE AUDIT POLICY policy_name ACCESS policy_access_list policy_filter_opt policy_status_opt
                {
                    CreateAuditPolicyStmt *n = makeNode(CreateAuditPolicyStmt);
                    n->policy_type = "access";
                    n->if_not_exists = false;
                    IsValidIdent($4);
                    n->policy_name = $4;
                    n->policy_targets = $6;
                    n->policy_filters = $7;
                    n->policy_enabled = $8;
                    $$ = (Node *) n;
                }
        | CREATE AUDIT POLICY IF_P NOT EXISTS policy_name ACCESS policy_access_list policy_filter_opt policy_status_opt
                {
                    CreateAuditPolicyStmt *n = makeNode(CreateAuditPolicyStmt);
                    n->policy_type = "access";
                    n->if_not_exists = true;
                    IsValidIdent($7);
                    n->policy_name = $7;
                    n->policy_targets = $9;
                    n->policy_filters = $10;
                    n->policy_enabled = $11;
                    $$ = (Node *) n;
                }
        ;

policy_privileges_list:
        policy_privilege_elem
            {
                $$ = list_make1($1);
            }
        | policy_privileges_list ',' policy_privilege_elem
            {
                $$ = lappend($1, $3);
            }
        ;

policy_privilege_elem:
        policy_privilege_type policy_target_elem_opt
            {
                $$ = makeDefElem($1, (Node *)$2);
            }
        ;

policy_privilege_type:
        ALL             { $$ = "all"; }
        | ALTER         { $$ = "alter"; }
        | ANALYZE       { $$ = "analyze"; }
        | COMMENT       { $$ = "comment"; }
        | CREATE        { $$ = "create"; }
        | DROP          { $$ = "drop"; }
        | GRANT         { $$ = "grant"; }
        | REVOKE        { $$ = "revoke"; }
        | SET           { $$ = "set"; }
        | SHOW          { $$ = "show"; }
        | LOGIN_ANY     { $$ = "login_any"; }
        | LOGIN_FAILURE { $$ = "login_failure"; }
        | LOGIN_SUCCESS { $$ = "login_success"; }
        | LOGOUT        { $$ = "logout"; }
        ;

policy_access_list:
        policy_access_elem
            {
                $$ = list_make1($1);
            }
        | policy_access_list ',' policy_access_elem
            {
                $$ = lappend($1, $3);
            }
        ;

policy_access_elem:
        policy_access_type policy_target_elem_opt
            {
                $$ = makeDefElem($1, (Node *)$2);
            }
        ;

// Commented out will be supported in future releases / upon client request
policy_access_type:
        ALL             { $$ = "all"; }
        | COPY          { $$ = "copy"; }
        | DEALLOCATE    { $$ = "deallocate"; }
        | DELETE_P      { $$ = "delete"; }
        | EXECUTE       { $$ = "execute"; }
        | INSERT        { $$ = "insert"; }
        | PREPARE       { $$ = "prepare"; }
        | REINDEX       { $$ = "reindex"; }
        | SELECT        { $$ = "select"; }
        | TRUNCATE      { $$ = "truncate"; }
        | UPDATE        { $$ = "update"; }
        ;

policy_target_elem_opt:
        ON policy_target_type '(' policy_targets_list ')'
            {
                $$ = makeDefElem($2, (Node *)$4);
            }
        | /* EMPTY */ { $$ = NULL; }
		;

policy_targets_list:
        policy_target_name
            {
                $$ = list_make1($1);
            }
        | policy_targets_list ',' policy_target_name
            {
                $$ = lappend($1, $3);
            }
        ;
policy_target_type:
        LABEL         { $$ = "label"; }
        ;

policy_target_name:
        qualified_name     { $$ = $1; }
        ;

policy_filter_opt:
         FILTER ON policy_filter_value
            {
                $$ = list_make1((Node *)$3);
            }
        | /* EMPTY */ { $$ = NULL; }
        ;

policy_filter_value:
        filter_expr     { $$ = $1; }
        | filter_set    { $$ = $1; }
        ; 

filter_set:
        filter_paren                { $$ = $1; }
        | '(' filter_expr_list ')'  { $$ = $2; }
        | filter_expr_list          { $$ = $1; }
        ;

filter_expr_list: 
        filter_expr ',' filter_expr
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "op";
                n->op_value = "and";
                n->left = $1;
                n->right = $3;
                $$ = (Node *) n;
            }
        | filter_expr_list ',' filter_expr
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "op";
                n->op_value = "and";
                n->left = $1;
                n->right = $3;
                $$ = (Node *) n;
            }
        ;

filter_paren:
        '(' filter_expr ')' { $$ = $2; }
        ;

policy_filters_list:
        policy_filter_name
            {
                $$ = list_make1(makeString($1));
            }
        | policy_filters_list ',' policy_filter_name
            {
                $$ = lappend($1, makeString($3));
            }
        ;

policy_filter_type:
          IP            { $$ = "ip"; }
        | APP           { $$ = "app"; }
        | ROLES         { $$ = "roles"; }
        ;

policy_filter_name:
        ColId_or_Sconst { $$ = $1; }
        ;

policy_name:
        ColLabel        { $$ = $1; }
        ;

policy_status_opt:
        ENABLE_P        {$$ = TRUE;}
        | DISABLE_P     {$$ = FALSE;}
        | /* EMPTY */   {$$ = TRUE;}
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     ALTER AUDIT POLICY policy_name
 *
 *****************************************************************************/
AlterAuditPolicyStmt:
        /* alter comments */
        ALTER AUDIT POLICY policy_name policy_comments_alter_clause
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->policy_name = $4;
                    n->policy_action = "add";
                    n->policy_comments = $5;
                    $$ = (Node *) n;
                }
        |        
        ALTER AUDIT POLICY IF_P EXISTS policy_name policy_comments_alter_clause
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_name = $6;
                    n->policy_action = "add";
                    n->policy_comments = $7;
                    $$ = (Node *) n;
                }
        |        
        /* alter add/remove privilege */
        ALTER AUDIT POLICY policy_name alter_policy_action_clause alter_policy_privileges_list
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->policy_type = "privileges";
                    n->policy_name = $4;
                    n->policy_action = $5;
                    n->policy_items = $6;
                    $$ = (Node *) n;
                }
        |
        ALTER AUDIT POLICY IF_P EXISTS policy_name alter_policy_action_clause alter_policy_privileges_list
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_type = "privileges";
                    n->policy_name = $6;
                    n->policy_action = $7;
                    n->policy_items = $8;
                    $$ = (Node *) n;
                }
        |
        /* alter add/remove access */
        ALTER AUDIT POLICY policy_name alter_policy_action_clause alter_policy_access_list
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->policy_type = "access";
                    n->policy_name = $4;
                    n->policy_action = $5;
                    n->policy_items = $6;
                    $$ = (Node *) n;
                }
        |
        ALTER AUDIT POLICY IF_P EXISTS policy_name alter_policy_action_clause alter_policy_access_list
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_type = "access";
                    n->policy_name = $6;
                    n->policy_action = $7;
                    n->policy_items = $8;
                    $$ = (Node *) n;
                }
        |
        /* alter modify filter */
        ALTER AUDIT POLICY policy_name MODIFY_P '(' alter_policy_filter_list ')'
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->policy_name = $4;
                    n->policy_action = "modify";
                    n->policy_filters = $7;
                    $$ = (Node *) n;
                }
        |
        ALTER AUDIT POLICY IF_P EXISTS policy_name MODIFY_P '(' alter_policy_filter_list ')'
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_name = $6;
                    n->policy_action = "modify";
                    n->policy_filters = $9;
                    $$ = (Node *) n;
                }
        |
        /* alter remove filter */
        ALTER AUDIT POLICY policy_name DROP FILTER
            {
                AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "drop_filter";
                $$ = (Node *) n;
            }

        |
        ALTER AUDIT POLICY IF_P EXISTS policy_name DROP FILTER
            {
                AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                n->missing_ok = true;
                n->policy_name = $6;
                n->policy_action = "drop_filter";
                $$ = (Node *) n;
            }

        |
        /* alter policy status */
        ALTER AUDIT POLICY policy_name policy_status_alter_clause
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->policy_name = $4;
                    n->policy_action = "add";
                    n->policy_comments = "";
                    n->policy_enabled = (Node *)$5;
                    $$ = (Node *) n;
                }
        |
        ALTER AUDIT POLICY IF_P EXISTS policy_name policy_status_alter_clause
                {
                    AlterAuditPolicyStmt *n = makeNode(AlterAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_name = $6;
                    n->policy_action = "add";
                    n->policy_comments = "";
                    n->policy_enabled = (Node *)$7;
                    $$ = (Node *) n;
                }

        ;


alter_policy_access_list:
        ACCESS '(' policy_access_list ')' {$$ = $3;}
        ;

alter_policy_privileges_list:
        PRIVILEGES '(' policy_privileges_list ')' {$$ = $3;}
        ;
        
alter_policy_filter_list:
        FILTER ON policy_filter_value
        {
            $$ = list_make1((Node *)$3);
        }
        ;

alter_policy_action_clause:
        ADD_P   { $$ = "add";  }
        | REMOVE  { $$ = "remove"; } 
        ;

policy_status_alter_clause:
        ENABLE_P        { $$ = makeDefElem("status", (Node *)makeString("enable")); } 
        | DISABLE_P     { $$ = makeDefElem("status", (Node *)makeString("disable")); }
        ;

policy_comments_alter_clause:
        COMMENTS Sconst   { $$ = $2; }
        ;
    
    

/*****************************************************************************
 *
 *     QUERY:
 *
 *     DROP AUDIT POLICY policy_name
 *
 *****************************************************************************/
DropAuditPolicyStmt:
        DROP AUDIT POLICY policy_names_list
                {
                    DropAuditPolicyStmt *n = makeNode(DropAuditPolicyStmt);
                    n->policy_names = $4;
                    $$ = (Node *) n;
                }
        | DROP AUDIT POLICY IF_P EXISTS policy_names_list
                {
                    DropAuditPolicyStmt *n = makeNode(DropAuditPolicyStmt);
                    n->missing_ok = true;
                    n->policy_names = $6;
                    $$ = (Node *) n;
                }
        ;
policy_names_list:
        policy_name { $$ = list_make1(makeString($1)); }
        | policy_names_list ',' policy_name { $$ = lappend($1, makeString($3)); }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     CREATE MASKING POLICY policy_name
 *
 *****************************************************************************/
CreateMaskingPolicyStmt:
        CREATE MASKING POLICY policy_name masking_clause policy_condition_opt policy_filter_opt policy_status_opt
                {
                    CreateMaskingPolicyStmt *n = makeNode(CreateMaskingPolicyStmt);
                    n->if_not_exists = false;
                    IsValidIdent($4);
                    n->policy_name = $4;
                    n->policy_data = $5;
                    n->policy_condition = $6;
                    n->policy_filters = $7;
                    n->policy_enabled = $8;
                    $$ = (Node *) n;
                }
        ;

masking_clause:
        masking_clause_elem 
            {
                $$ = list_make1($1);
            }
        | masking_clause ',' masking_clause_elem
            {
                $$ = lappend($1, $3);
            }
        ;

masking_clause_elem:
        /*FUNCTION*/ masking_func masking_func_params_opt ON masking_target
            {
                $$ = makeDefElem($1, (Node *)lappend(list_make1($2) , $4));
            }
        | masking_func_nsp '.' masking_func masking_func_params_opt ON masking_target
            {
                $$ = makeDefElemExtended($1, $3, (Node *)lappend(list_make1($4) , $6), DEFELEM_UNSPEC);
            }
        ;

masking_func_nsp:
        ColLabel        { IsValidIdent($1); $$ = $1; }
        ;

masking_func:
        ColLabel        { IsValidIdent($1); $$ = $1; }
        ;

masking_func_params_opt:
        '(' masking_func_params_list ')'    { $$ = $2; }
        | /* EMPTY */                       { $$ = list_make1(NIL); }
        ;

masking_func_params_list:
        masking_func_param
            { 
                 $$ = list_make1($1);
            }
        | masking_func_params_list ',' masking_func_param
            { 
                $$ = lappend($1, $3);
            }
        ;

masking_func_param:
        Iconst
            {
                char buf[64];
                snprintf(buf, sizeof(buf), "%d", $1);
                $$ = makeDefElem("i"/*int*/, (Node *)makeString(pstrdup(buf)));
            }
        | FCONST         { $$ = makeDefElem("f" /*float*/, (Node *)makeString($1)); }
        | Sconst         { $$ = makeDefElem("s" /*string*/, (Node *)makeString($1)); }
        | ColLabel       { $$ = makeDefElem("q" /*fqdn*/, (Node *)makeString($1)); }
        ;

masking_target:
        masking_policy_target_type '(' policy_targets_list ')'
            {
                $$ = makeDefElem($1, (Node *)$3);
            }
        ;

masking_policy_target_type:
        LABEL         { $$ = "label"; }
        ;

alter_policy_condition:

		    CONDITION '(' policy_label_item masking_policy_condition_operator masking_policy_condition_value ')'
            {
                MaskingPolicyCondition *n = makeNode(MaskingPolicyCondition);
                n->fqdn = $3;
                n->_operator = $4;
                n->arg = $5;
                $$ = (Node *) n;
            }
        ;

policy_condition_opt:
	
		    CONDITION '(' policy_label_item masking_policy_condition_operator masking_policy_condition_value ')'
            {
                MaskingPolicyCondition *n = makeNode(MaskingPolicyCondition);
                n->fqdn = $3;
                n->_operator = $4;
                n->arg = $5;
                $$ = (Node *) n;
            }
			;
	
        | /* EMPTY */
        {
            $$ = NULL;
        }
        ;

masking_policy_condition_operator:
    CmpOp       { $$ = $1; }
    | '<'       { $$ = "<"; }
    | '>'       { $$ = ">"; }
    | '='       { $$ = "="; }
    | '@'       { $$ = "@"; }
    ;

masking_policy_condition_value:
		opt_boolean_or_string
			{ 
				$$ = makeStringConst($1, @1);
			}
		| NumericOnly
			{ 
				$$ = makeAConst($1, @1);
			}
		| CURRENT_USER
			{
				$$ = makeStringConst("current_user", @1);
			}
		;

pp_filter_expr:
        filter_expr         { $$ = $1; }
        | filter_paren      { $$ = $1; }
        ;

filter_expr:
        filter_term
            {
                $$ = $1;
            }
        | pp_filter_expr OR pp_filter_term
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "op";
                n->op_value = "or";
                n->left = $1;
                n->right = $3;
                $$ = (Node *) n;
            }
        ;

pp_filter_term:
        filter_term         { $$ = $1; }
        | filter_paren      { $$ = $1; }
        ;

filter_term:
        policy_filter_elem
            {
                $$ = $1;
            }
        | pp_filter_term AND pp_policy_filter_elem
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "op";
                n->op_value = "and";
                n->left = $1;
                n->right = $3;
                $$ = (Node *) n;
            }
        ;

pp_policy_filter_elem:
        policy_filter_elem  { $$ = $1; }
        | filter_paren      { $$ = $1; }
        ;

policy_filter_elem:
        policy_filter_type '(' policy_filters_list ')'
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "filter";
                n->filter_type = $1;
                n->values = $3;
                n->has_not_operator = false;
                $$ = (Node *) n;
            }
        | policy_filter_type NOT '(' policy_filters_list ')'
            {
                PolicyFilterNode *n = makeNode(PolicyFilterNode);
                n->node_type = "filter";
                n->filter_type = $1;
                n->values = $4;
                n->has_not_operator = true;
                $$ = (Node *) n;
            }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     ALTER MASKING POLICY policy_name
 *
 *****************************************************************************/
AlterMaskingPolicyStmt:
		/* alter comments*/
 ALTER MASKING POLICY policy_name policy_comments_alter_clause
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "add";
                n->policy_comments = $5;
                $$ = (Node *) n;
            }
		|
		
        /* alter modify/add/remove policy actions */
        ALTER MASKING POLICY policy_name alter_masking_policy_action_clause alter_masking_policy_func_items_list
        {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = $5;
                n->policy_items = $6;
                $$ = (Node *) n;
            }
		|

        /* alter modify filter */
        ALTER MASKING POLICY policy_name MODIFY_P '(' alter_policy_filter_list ')'
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "modify";
                n->policy_filters = $7;
                $$ = (Node *) n;
            }
        |
        /* alter remove filter */
        ALTER MASKING POLICY policy_name DROP FILTER
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "drop_filter";
                $$ = (Node *) n;
            }
        |
        /* alter modify condition */
        ALTER MASKING POLICY policy_name MODIFY_P '(' alter_policy_condition ')'
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "modify";
                n->policy_condition = $7;
                $$ = (Node *) n;
            }
        |
        /* alter remove condition */
        ALTER MASKING POLICY policy_name DROP CONDITION
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "drop_condition";
                $$ = (Node *) n;
            }
        |

        /* alter policy status */
        ALTER MASKING POLICY policy_name policy_status_alter_clause
            {
                AlterMaskingPolicyStmt *n = makeNode(AlterMaskingPolicyStmt);
                n->policy_name = $4;
                n->policy_action = "add";
                n->policy_comments = "";
                n->policy_enabled = (Node *)$5;
                $$ = (Node *) n;
            }
        ;

alter_masking_policy_action_clause:
        MODIFY_P { $$ = "modify"; }   /* Modifying is supported only by masking policy */
        | alter_policy_action_clause { $$ = $1; }
        ;

alter_masking_policy_func_items_list:
        alter_masking_policy_func_item { $$ =  list_make1($1); }
        | alter_masking_policy_func_items_list ',' alter_masking_policy_func_item { $$ = lappend($1, $3); }
        ;

alter_masking_policy_func_item:
         masking_clause_elem 
        	{
                $$ = $1;
            }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     DROP MASKING POLICY policy_name 
 *
 *****************************************************************************/
DropMaskingPolicyStmt:
        DROP MASKING POLICY policy_names_list
                {
                    DropMaskingPolicyStmt *n = makeNode(DropMaskingPolicyStmt);
                    n->if_exists = false;
                    n->policy_names = $4;
                    $$ = (Node *) n;
                }
        |   DROP MASKING POLICY IF_P EXISTS policy_names_list
            {
                DropMaskingPolicyStmt *n = makeNode(DropMaskingPolicyStmt);
                n->if_exists = true;
                n->policy_names = $6;
                $$ = (Node *) n;
            }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     CREATE RESOURCE LABEL label_name 
 *
 *****************************************************************************/
CreatePolicyLabelStmt:
        CREATE RESOURCE LABEL policy_label_name opt_add_resources_to_label
                {
                    CreatePolicyLabelStmt *n = makeNode(CreatePolicyLabelStmt);
                    n->label_type = "resource";
                    n->if_not_exists = false; 
                    IsValidIdent($4);
                    n->label_name = $4;
                    n->label_items = $5;
                    $$ = (Node *)n;
                }
        | CREATE RESOURCE LABEL IF_P NOT EXISTS policy_label_name opt_add_resources_to_label
                {
                    CreatePolicyLabelStmt *n = makeNode(CreatePolicyLabelStmt);
                    n->label_type = "resource";
                    n->if_not_exists = true;
                    IsValidIdent($7);
                    n->label_name = $7;
                    n->label_items = $8;
                    $$ = (Node *)n;
                }
        ;

policy_label_name:
        ColLabel        { $$ = $1; }
        ;

opt_add_resources_to_label:
        ADD_P resources_to_label_list { $$ = $2; }
        ;

resources_to_label_list:
        resources_to_label_list_item { $$ =  list_make1($1); }
        | resources_to_label_list ',' resources_to_label_list_item { $$ = lappend($1, $3); }
        ;

resources_to_label_list_item:
        policy_label_resource_type  '(' policy_label_items ')' { $$ = makeDefElem($1, (Node *)$3); }
        | policy_label_resource_type '(' policy_label_any_resource_item ')' { $$ = makeDefElem($1,  (Node *)list_make1($3)); }
        ;

policy_label_resource_type:
                TABLE     { $$ = "table"; }
                | COLUMN    { $$ = "column"; }
                | SCHEMA    { $$ = "schema"; }
                | VIEW      { $$ = "view"; }
                | FUNCTION  { $$ = "function"; }
        ;

policy_label_any_resource_item:
        policy_label_any_resource { $$ = makeRangeVar(NULL, $1, @1); }
        ;

policy_label_any_resource:
        ALL { $$ = "all"; }
        ;

policy_label_items:
        policy_label_item { $$ = list_make1($1); }
        | policy_label_items ',' policy_label_item { $$ =  lappend($1, $3); }
        ;

filters_to_label_list:
        filters_to_label_list_item { $$ =  list_make1($1); }
        | filters_to_label_list ',' filters_to_label_list_item { $$ = lappend($1, $3); }
        ;

filters_to_label_list_item:
        policy_label_filter_type  '(' policy_label_items ')' { $$ = makeDefElem($1, (Node *)$3); }
        ;

policy_label_filter_type: 
          IP            { $$ = "ip"; }
        | APP           { $$ = "app"; }
        | ROLES         { $$ = "roles"; }
        ;

policy_label_item:
        qualified_name     { $$ = $1; }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     ALTER RESOURCE LABEL label_name
 *
 *****************************************************************************/
AlterPolicyLabelStmt:
        ALTER RESOURCE LABEL policy_label_name ADD_P resources_or_filters_to_label_list
                {
                    AlterPolicyLabelStmt *n = makeNode(AlterPolicyLabelStmt);
                    n->stmt_type = "add";
                    n->label_name = $4;
                    n->label_items = $6;
                    $$ = (Node *)n;
                }
        | ALTER RESOURCE LABEL policy_label_name REMOVE resources_or_filters_to_label_list
                {
                    AlterPolicyLabelStmt *n = makeNode(AlterPolicyLabelStmt);
                    n->stmt_type = "remove";
                    n->label_name = $4;
                    n->label_items = $6;
                    $$ = (Node *)n;
                }
        ;

resources_or_filters_to_label_list:
        resources_to_label_list  { $$ = $1; }
        | filters_to_label_list  { $$ = $1; }
        ;

/*****************************************************************************
 *
 *     QUERY:
 *
 *     DROP RESOURCE LABEL label_name
 *
 *****************************************************************************/
DropPolicyLabelStmt:
        DROP RESOURCE LABEL policy_labels_list
            {
                    DropPolicyLabelStmt *n = makeNode(DropPolicyLabelStmt);
                    n->if_exists = false;
                    n->label_names = $4;
                    $$ = (Node *) n;
            }
        | DROP RESOURCE LABEL IF_P EXISTS policy_labels_list
            {
                DropPolicyLabelStmt *n = makeNode(DropPolicyLabelStmt);
                n->if_exists = true;
                n->label_names = $6;
                $$ = (Node *) n;
            }
        ;

policy_labels_list:
        policy_label_name { $$ = list_make1(makeString($1)); }
        | policy_labels_list ',' policy_label_name { $$ =  lappend($1, makeString($3)); }
        ;

/*****************************************************************************
 *
 *		QUERY:
 *
 *		CREATE RESOURCE POOL pool_name WITH
 *				(
 *					[ MEM_PERCENT = mem_percent, ]
 *					[ CPU_AFFINITY = cpu_affinity, ]
 *				)
 *
 *****************************************************************************/

CreateResourcePoolStmt: CREATE RESOURCE POOL resource_pool_name OptWith
				{
					CreateResourcePoolStmt *n = makeNode(CreateResourcePoolStmt);
					n->pool_name = $4;
					n->options = $5;
					$$ = (Node *)n;
				}
		;


 /*****************************************************************************
 *
 *		QUERY:
 *
 *		ALTER RESOURCE POOL pool_name WITH
 *				(
 *					[ MEM_PERCENT = mem_percent, ]
 *					[ CPU_AFFINITY = cpu_affinity, ]
 *				)
 *
 *****************************************************************************/

AlterResourcePoolStmt: ALTER RESOURCE POOL resource_pool_name OptWith
				{
					AlterResourcePoolStmt *n = makeNode(AlterResourcePoolStmt);
					n->pool_name = $4;
					n->options = $5;
					$$ = (Node *)n;
				}
		;

AlterGlobalConfigStmt: ALTER GLOBAL CONFIGURATION OptWith
				{
					AlterGlobalConfigStmt *n = makeNode(AlterGlobalConfigStmt);
					n->options = $4;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				DROP RESOURCE POOL [IF EXISTS] pool_name
 *
 *****************************************************************************/

DropResourcePoolStmt: DROP RESOURCE POOL resource_pool_name
				{
					DropResourcePoolStmt *n = makeNode(DropResourcePoolStmt);
					n->missing_ok = false;
					n->pool_name = $4;
					$$ = (Node *)n;
				}
			| DROP RESOURCE POOL IF_P EXISTS resource_pool_name
				{
					DropResourcePoolStmt *n = makeNode(DropResourcePoolStmt);
					n->missing_ok = true;
					n->pool_name = $6;
					$$ = (Node *)n;
				}
		;

resource_pool_name:
			ColId							{ $$ = $1; };

DropGlobalConfigStmt: DROP GLOBAL CONFIGURATION name_list
				{
					DropGlobalConfigStmt *n = makeNode(DropGlobalConfigStmt);
					n->options = $4;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *
 *		CREATE WORKLOAD GROUP group_name USING RESOURCE POOL pool_name WITH
 *				(
 *					[ ACT_STATEMENTS  = act_statements, ]
 *				)
 *
 *****************************************************************************/

CreateWorkloadGroupStmt: CREATE WORKLOAD GROUP_P workload_group_name USING RESOURCE POOL resource_pool_name OptWith
				{
					CreateWorkloadGroupStmt *n = makeNode(CreateWorkloadGroupStmt);
					n->group_name = $4;
					n->pool_name = $8;
					n->options = $9;
					$$ = (Node *)n;
				}
			| CREATE WORKLOAD GROUP_P workload_group_name OptWith
				{
					CreateWorkloadGroupStmt *n = makeNode(CreateWorkloadGroupStmt);
					n->group_name = $4;
					n->pool_name = NULL;
					n->options = $5;
					$$ = (Node *)n;
				}
		;

 /*****************************************************************************
 *
 *		QUERY:
 *
 *		ALTER WORKLOAD GROUP group_name [USING RESOURCE POOL pool_name] WITH
 *				(
 *					[ ACT_STATEMENTS  = act_statements, ]
 *				)
 *
 *****************************************************************************/

AlterWorkloadGroupStmt: ALTER WORKLOAD GROUP_P workload_group_name USING RESOURCE POOL resource_pool_name OptWith
				{
					AlterWorkloadGroupStmt *n = makeNode(AlterWorkloadGroupStmt);
					n->group_name = $4;
					n->pool_name = $8;
					n->options = $9;
					$$ = (Node *)n;
				}
 			| ALTER WORKLOAD GROUP_P workload_group_name OptWith
 				{
 					AlterWorkloadGroupStmt *n = makeNode(AlterWorkloadGroupStmt);
					n->group_name = $4;
					n->pool_name = NULL;
					n->options = $5;
					$$ = (Node *)n;
 				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				DROP WORKLOAD GROUP [IF EXISTS] group_name
 *
 *****************************************************************************/

DropWorkloadGroupStmt: DROP WORKLOAD GROUP_P workload_group_name
				{
					DropWorkloadGroupStmt *n = makeNode(DropWorkloadGroupStmt);
					n->missing_ok = false;
					n->group_name = $4;
					$$ = (Node *)n;
				}
			| DROP WORKLOAD GROUP_P IF_P EXISTS workload_group_name
				{
					DropWorkloadGroupStmt *n = makeNode(DropWorkloadGroupStmt);
					n->missing_ok = true;
					n->group_name = $6;
					$$ = (Node *)n;
				}
		;

workload_group_name:
			ColId							{ $$ = $1; };


/*****************************************************************************
 *
 *		QUERY:
 *
 *		CREATE APP WORKLOAD GROUP MAPPING app_name WITH
 *				(
 *					[ WORKLOAD_GPNAME  = workload_gpname, ]
 *				)
 *
 *****************************************************************************/

CreateAppWorkloadGroupMappingStmt: CREATE APP WORKLOAD GROUP_P MAPPING application_name OptWith
				{
					CreateAppWorkloadGroupMappingStmt *n = makeNode(CreateAppWorkloadGroupMappingStmt);
					n->app_name = $6;
					n->options = $7;
					$$ = (Node *)n;
				}
		;

 /*****************************************************************************
 *
 *		QUERY:
 *
 *		ALTER APP WORKLOAD GROUP MAPPING app_name WITH
 *				(
 *					[ WORKLOAD_GPNAME  = workload_gpname, ]
 *				)
 *
 *****************************************************************************/

AlterAppWorkloadGroupMappingStmt: ALTER APP WORKLOAD GROUP_P MAPPING application_name OptWith
				{
					AlterAppWorkloadGroupMappingStmt *n = makeNode(AlterAppWorkloadGroupMappingStmt);
					n->app_name = $6;
					n->options = $7;
					$$ = (Node *)n;
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				DROP APP WORKLOAD GROUP MAPPING [IF EXISTS] app_name
 *
 *****************************************************************************/

DropAppWorkloadGroupMappingStmt: DROP APP WORKLOAD GROUP_P MAPPING application_name
				{
					DropAppWorkloadGroupMappingStmt *n = makeNode(DropAppWorkloadGroupMappingStmt);
					n->missing_ok = false;
					n->app_name = $6;
					$$ = (Node *)n;
				}
			| DROP APP WORKLOAD GROUP_P MAPPING IF_P EXISTS application_name
				{
					DropAppWorkloadGroupMappingStmt *n = makeNode(DropAppWorkloadGroupMappingStmt);
					n->missing_ok = true;
					n->app_name = $8;
					$$ = (Node *)n;
				}
		;

application_name:
			ColId							{ $$ = $1; };

/* PGXC_END */

/*****************************************************************************
 *
 *		QUERY:
 *				EXPLAIN [ANALYZE] [VERBOSE] query
 *				EXPLAIN ( options ) query
 *
 *****************************************************************************/

ExplainStmt:
		EXPLAIN ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->query = $2;
					n->options = NIL;
					$$ = (Node *) n;
				}
		| EXPLAIN PERFORMANCE ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->query = $3;
					n->options = list_make1(makeDefElem("performance",NULL));
					$$ = (Node *) n;
				}
		| EXPLAIN analyze_keyword opt_verbose ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->query = $4;
					n->options = list_make1(makeDefElem("analyze", NULL));
					if ($3)
						n->options = lappend(n->options,
											 makeDefElem("verbose", NULL));
					$$ = (Node *) n;
				}
		| EXPLAIN VERBOSE ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->query = $3;
					n->options = list_make1(makeDefElem("verbose", NULL));
					$$ = (Node *) n;
				}
		| EXPLAIN '(' explain_option_list ')' ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->query = $5;
					n->options = $3;
					$$ = (Node *) n;
				}
		| EXPLAIN PLAN SET STATEMENT_ID '=' Sconst FOR ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->statement = makeStringConst($6, @6);
					n->query = $8;
					n->options = list_make1(makeDefElem("plan", NULL));
					$$ = (Node *) n;
				}
		| EXPLAIN PLAN FOR ExplainableStmt
				{
					ExplainStmt *n = makeNode(ExplainStmt);
					n->statement = NULL;
					n->query = $4;
					n->options = list_make1(makeDefElem("plan", NULL));
					$$ = (Node *) n;
				}
		;

ExplainableStmt:
			SelectStmt
			| InsertStmt
			| UpdateStmt
			| DeleteStmt
			| MergeStmt
			| DeclareCursorStmt
			| CreateAsStmt
			| CreateModelStmt
			| SnapshotStmt
			| ExecuteStmt					/* by default all are $$=$1 */
		;

explain_option_list:
			explain_option_elem
				{
					$$ = list_make1($1);
				}
			| explain_option_list ',' explain_option_elem
				{
					$$ = lappend($1, $3);
				}
		;

explain_option_elem:
			explain_option_name explain_option_arg
				{
					$$ = makeDefElem($1, $2);
				}
		;

explain_option_name:
			ColId					{ $$ = $1; }
			| analyze_keyword		{ $$ = "analyze"; }
			| VERBOSE				{ $$ = "verbose"; }
		;

explain_option_arg:
			opt_boolean_or_string	{ $$ = (Node *) makeString($1); }
			| NumericOnly			{ $$ = (Node *) $1; }
			| /* EMPTY */			{ $$ = NULL; }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				EXECUTE DIRECT ON ( nodename [, ... ] ) query
 *				EXECUTE DIRECT ON  [ COORDINATORS | DATANODES | ALL ] query
 *
 *****************************************************************************/

ExecDirectStmt: 
		EXECUTE DIRECT ON pgxcnodes DirectStmt
			{
				ExecDirectStmt *n = makeNode(ExecDirectStmt);
			
				n->node_names = $4;
				n->exec_option = EXEC_DIRECT_ON_LIST;
				n->query = $5;
				n->location = @5;
				$$ = (Node *)n;
				parameter_check_execute_direct(n->query);
			}
		| EXECUTE DIRECT ON COORDINATORS DirectStmt
			{
				ExecDirectStmt *n = makeNode(ExecDirectStmt);
				
				n->exec_option = EXEC_DIRECT_ON_ALL_CN;
				n->query = $5;
				n->location = @5;
				$$ = (Node *)n;
				parameter_check_execute_direct(n->query);
			}
		| EXECUTE DIRECT ON DATANODES DirectStmt
			{
				ExecDirectStmt *n = makeNode(ExecDirectStmt);
			
				n->exec_option = EXEC_DIRECT_ON_ALL_DN;
				n->query = $5;
				n->location = @5;
				$$ = (Node *)n;
				parameter_check_execute_direct(n->query);
			}
		| EXECUTE DIRECT ON ALL DirectStmt
			{
				ExecDirectStmt *n = makeNode(ExecDirectStmt);
				
				n->exec_option = EXEC_DIRECT_ON_ALL_NODES;
				n->query = $5;
				n->location = @5;
				$$ = (Node *)n;
				parameter_check_execute_direct(n->query);
			}
		;

DirectStmt:
			Sconst					/* by default all are $$=$1 */
		;

/*****************************************************************************
 *
 *		QUERY:
 *
 *		CLEAN CONNECTION TO { COORDINATOR ( nodename ) | NODE ( nodename ) | ALL [ CHECK ] [ FORCE ] }
 *				[ FOR DATABASE dbname ]
 *				[ TO USER username ]
 *
 *****************************************************************************/

CleanConnStmt: CLEAN CONNECTION TO COORDINATOR pgxcnodes CleanConnDbName CleanConnUserName
				{
					CleanConnStmt *n = makeNode(CleanConnStmt);
					n->is_coord = true;
					n->nodes = $5;
					n->is_check = false;
					n->is_force = false;
					n->dbname = $6;
					n->username = $7;
					$$ = (Node *)n;
				}
				| CLEAN CONNECTION TO NODE pgxcnodes CleanConnDbName CleanConnUserName
				{
					CleanConnStmt *n = makeNode(CleanConnStmt);
					n->is_coord = false;
					n->nodes = $5;
					n->is_check = false;
					n->is_force = false;
					n->dbname = $6;
					n->username = $7;
					$$ = (Node *)n;
				}
				| CLEAN CONNECTION TO ALL opt_check opt_force CleanConnDbName CleanConnUserName
				{
					CleanConnStmt *n = makeNode(CleanConnStmt);
					n->is_coord = true;
					n->nodes = NIL;
					n->is_check = $5;
					n->is_force = $6;
					n->dbname = $7;
					n->username = $8;
					$$ = (Node *)n;
				}
		;

CleanConnDbName: FOR DATABASE database_name		{ $$ = $3; }
				| FOR database_name				{ $$ = $2; }
				| /* EMPTY */					{ $$ = NULL; }
		;

CleanConnUserName: TO USER RoleId				{ $$ = $3; }
				| TO RoleId						{ $$ = $2; }
				| /* EMPTY */					{ $$ = NULL; }
		;

opt_check:	CHECK								{  $$ = TRUE; }
			| /* EMPTY */						{  $$ = FALSE; }
		;
/* PGXC_END */

/*****************************************************************************
 *
 *		QUERY:
 *				PREPARE <plan_name> [(args, ...)] AS <query>
 *
 *****************************************************************************/

PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
				{
					PrepareStmt *n = makeNode(PrepareStmt);
					n->name = $2;
					n->argtypes = $3;
					n->query = $5;
					$$ = (Node *) n;
				}
		;

prep_type_clause: '(' type_list ')'			{ $$ = $2; }
				| /* EMPTY */				{ $$ = NIL; }
		;

PreparableStmt:
			SelectStmt
			| InsertStmt
			| UpdateStmt
			| DeleteStmt					/* by default all are $$=$1 */
			| MergeStmt
			| uservar_name
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "@var_name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("@var_name is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						$$ = $1;
					} else {
						const char* message = "@var_name is supported only in B-format database, and enable_set_variable_b_format = on.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("@var_name is supported only in B-format database, and enable_set_variable_b_format = on."),
								parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
				}
			;

/*****************************************************************************
 *
 * EXECUTE <plan_name> [(params, ...)]
 * CREATE TABLE <name> AS EXECUTE <plan_name> [(params, ...)]
 *
 *****************************************************************************/

ExecuteStmt: EXECUTE name execute_param_clause
				{
					ExecuteStmt *n = makeNode(ExecuteStmt);
					n->name = $2;
					n->params = $3;
					$$ = (Node *) n;
				}
			| CREATE OptTemp TABLE create_as_target AS
				EXECUTE name execute_param_clause opt_with_data
				{
					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
					ExecuteStmt *n = makeNode(ExecuteStmt);
					n->name = $7;
					n->params = $8;
					ctas->query = (Node *) n;
					ctas->into = $4;
					ctas->relkind = OBJECT_TABLE;
					ctas->is_select_into = false;
					/* cram additional flags into the IntoClause */
					$4->rel->relpersistence = $2;
#ifdef PGXC
					const char* message = "CREATE TABLE AS EXECUTE not yet supported";
    				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("CREATE TABLE AS EXECUTE not yet supported")));
#endif
					$4->skipData = !($9);
					$$ = (Node *) ctas;
				}
		;

execute_param_clause: '(' expr_list ')'				{ $$ = $2; }
					| /* EMPTY */					{ $$ = NIL; }
					;

/*****************************************************************************
 *
 *		QUERY:
 *				DEALLOCATE [PREPARE] <plan_name>
 *
 *****************************************************************************/

DeallocateStmt: DEALLOCATE name
					{
						DeallocateStmt *n = makeNode(DeallocateStmt);
						n->name = $2;
						$$ = (Node *) n;
					}
				| DEALLOCATE PREPARE name
					{
						DeallocateStmt *n = makeNode(DeallocateStmt);
						n->name = $3;
						$$ = (Node *) n;
					}
				| DEALLOCATE ALL
					{
						DeallocateStmt *n = makeNode(DeallocateStmt);
						n->name = NULL;
						$$ = (Node *) n;
					}
				| DEALLOCATE PREPARE ALL
					{
						DeallocateStmt *n = makeNode(DeallocateStmt);
						n->name = NULL;
						$$ = (Node *) n;
					}
		;

insert_partition_clause: update_delete_partition_clause
						{
#ifdef ENABLE_MULTIPLE_NODES
					    const char* message = "In distributed mode, insert/update/delete does not support specified partitions.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
							  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							  errmsg("In distributed mode, insert/update/delete does not support specified partitions."),
							  errdetail("N/A"),errcause("Feature is not supported this operation."),
							  erraction("Contact engineer to support.")));
#endif
							$$ = $1;
						}
					| /* EMPTY */	{ $$ = NULL; }
					;

update_delete_partition_clause: PARTITION '(' name ')'
						{
							$$ = makeRangeVar(NULL, NULL, @3);
							$$->partitionname = $3;
							$$->ispartition = true;
						}
					| SUBPARTITION '(' name ')'
						{
							$$ = makeRangeVar(NULL, NULL, @3);
							$$->subpartitionname = $3;
							$$->issubpartition = true;
						}
					| PARTITION_FOR '(' expr_list ')'
						{
							$$ = makeRangeVar(NULL, NULL, @3);
							$$->partitionKeyValuesList = $3;
							$$->ispartition = true;
						}
					| SUBPARTITION_FOR '(' expr_list ')'
						{
							$$ = makeRangeVar(NULL, NULL, @3);
							$$->partitionKeyValuesList = $3;
							$$->issubpartition = true;
						}
					;


/*****************************************************************************
 *
 *		QUERY:
 *				INSERT STATEMENTS
 *
 *****************************************************************************/

InsertStmt: opt_with_clause INSERT hint_string INTO insert_target insert_rest returning_clause
			{
				$6->relation = $5;
				$6->returningList = $7;
				$6->withClause = $1;
				$6->isReplace = false;
				$6->hintState = create_hintstate($3);
				$6->hasIgnore = ($6->hintState != NULL && $6->hintState->sql_ignore_hint && DB_IS_CMPT(B_FORMAT));
				$$ = (Node *) $6;
			}
            | REPLACE hint_string INTO insert_target insert_rest returning_clause
            {
#ifndef ENABLE_MULTIPLE_NODES
                if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
                {
                    $5->relation = $4;
                    $5->returningList = $6;
                    $5->hintState = create_hintstate($2);
                    $5->isReplace = true;
                    $$ = (Node *) $5;
                }
                else
#endif
                {
                    const char* message = "REPLACE INTO syntax is not supported.";
                    InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                    ereport(errstate,
                            (errmodule(MOD_PARSER),
                            errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("REPLACE INTO syntax is not supported."),
                            parser_errposition(@1)));
                    $$ = NULL;/* not reached */
                }

            }
            | REPLACE hint_string INTO insert_target SET set_clause_list
            {
#ifndef ENABLE_MULTIPLE_NODES
                if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
                {
                     InsertStmt* n = makeNode(InsertStmt);
                     n->relation = $4;
                     n->targetList = $6;
                     n->hintState = create_hintstate($2);
                     n->isReplace = true;
                     $$ = (Node*)n;
                }
                else
#endif
                {
                    const char* message = "REPLACE INTO syntax is not supported.";
                    InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                    ereport(errstate,
                            (errmodule(MOD_PARSER),
                            errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("REPLACE INTO syntax is not supported."),
                            parser_errposition(@1)));
                    $$ = NULL;/* not reached */
                }

            }
			| opt_with_clause INSERT hint_string INTO insert_target insert_rest upsert_clause returning_clause
				{
					if ($1 != NULL) {
						const char* message = "WITH clause is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
							 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("WITH clause is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement.")));
					}

					if (u_sess->attr.attr_sql.enable_upsert_to_merge
#ifdef ENABLE_MULTIPLE_NODES					
					    ||t_thrd.proc->workingVersionNum < UPSERT_ROW_STORE_VERSION_NUM
#endif						
					    ) {

						if ($6 != NULL && $6->cols != NIL) {
							ListCell *c = NULL;
							List *cols = $6->cols;
							foreach (c, cols) {
								ResTarget *rt = (ResTarget *)lfirst(c);
								if (rt->indirection != NIL) {
									const char* message = "Try assign a composite or an array expression to column ";
    								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
									ereport(errstate,
										(errmodule(MOD_PARSER),
										 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
										 errmsg("Subfield name or array subscript of column \"%s\" "
											"is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement.",
											rt->name),
										 errhint("Try assign a composite or an array expression to column \"%s\".", rt->name)));
								}
							}
						}


						MergeStmt *m = makeNode(MergeStmt);
						m->is_insert_update = true;

						/* for UPSERT, keep the INSERT statement as well */
						$6->relation = $5;
						$6->returningList = $8;
						$6->isReplace = false;
						$6->withClause = $1;
						$6->hintState = create_hintstate($3);
						$6->hasIgnore = ($6->hintState != NULL && $6->hintState->sql_ignore_hint && DB_IS_CMPT(B_FORMAT));
#ifdef ENABLE_MULTIPLE_NODES						
						if (t_thrd.proc->workingVersionNum >= UPSERT_ROW_STORE_VERSION_NUM) {
							UpsertClause *uc = makeNode(UpsertClause);
							if ($7 == NULL)
								uc->targetList = NIL;
							else
								uc->targetList = ((MergeWhenClause *)$7)->targetList;
							$6->upsertClause = uc;
						}
#endif						
						m->insert_stmt = (Node *)copyObject($6);

						/* fill a MERGE statement*/
						m->relation = $5;

						Alias *a1 = makeAlias(($5->relname), NIL);
						$5->alias = a1;

						Alias *a2 = makeAlias("excluded", NIL);
						RangeSubselect *r = makeNode(RangeSubselect);
						r->alias = a2;
						r->subquery = (Node *) ($6->selectStmt);
						m->source_relation = (Node *) r;

						MergeWhenClause *n = makeNode(MergeWhenClause);
						n->matched = false;
						n->commandType = CMD_INSERT;
						n->cols = $6->cols;
						n->values = NULL;

						m->mergeWhenClauses = list_make1((Node *) n);
						if ($7 != NULL)
							m->mergeWhenClauses = list_concat(list_make1($7), m->mergeWhenClauses);


						$$ = (Node *)m;
					} else {
						$6->relation = $5;
						$6->returningList = $8;
						$6->withClause = $1;
						$6->upsertClause = (UpsertClause *)$7;
						$6->isReplace = false;
						$6->hintState = create_hintstate($3);   
						$6->hasIgnore = ($6->hintState != NULL && $6->hintState->sql_ignore_hint && DB_IS_CMPT(B_FORMAT));
						$$ = (Node *) $6;
					}
				}
		;

/*
 * It is difficult to use relation_expr_opt_alias as update or delete statement,
 * because VALUES in insert_rest would have a shift/reduce conflict with VALUES
 * as alias if as is optional.
 * We tried to fix such conflict by adding noassoc/left priority to VALUES, but
 * it will make delete statement with VALUES as alias name unable to be resolved.
 * So AS is required for now.
 */
insert_target:
			qualified_name insert_partition_clause
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					$$ = $1;
				}
			| qualified_name insert_partition_clause AS ColId
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					$1->alias = makeAlias($4, NIL);
					$$ = $1;
				}
		;

insert_rest:
			SelectStmt
				{
					$$ = makeNode(InsertStmt);
					$$->cols = NIL;
					$$->selectStmt = $1;
					$$->isRewritten = false;
                    if (((SelectStmt*)$1)->valuesLists == NULL)
                      $$->is_dist_insertselect = true;
				}
			| '(' insert_column_list ')' SelectStmt
				{
					$$ = makeNode(InsertStmt);
					$$->cols = $2;
					$$->selectStmt = $4;
					$$->isRewritten = false;
                    if (((SelectStmt*)$4)->valuesLists == NULL)
                        $$->is_dist_insertselect = true;
				}
			| DEFAULT VALUES
				{
					$$ = makeNode(InsertStmt);
					$$->cols = NIL;
					$$->selectStmt = NULL;
					$$->isRewritten = false;
                    $$->is_dist_insertselect = false;
				}
		;

insert_column_list:
			insert_column_item
					{ $$ = list_make1($1); }
			| insert_column_list ',' insert_column_item
					{ $$ = lappend($1, $3); }
		;

insert_column_item:
			ColId opt_indirection
				{
					$$ = makeNode(ResTarget);
					$$->name = $1;
					$$->indirection = check_indirection($2, yyscanner);
					$$->val = NULL;
					$$->location = @1;
				}
		;

returning_clause:
			RETURNING target_list		{ $$ = $2; }
			| /* EMPTY */				{ $$ = NIL; }
		;

upsert_clause:
			ON DUPLICATE KEY UPDATE set_clause_list where_clause
				{
					if (u_sess->attr.attr_sql.enable_upsert_to_merge
#ifdef ENABLE_MULTIPLE_NODES					
					    || t_thrd.proc->workingVersionNum < UPSERT_ROW_STORE_VERSION_NUM
#endif					    
						) {
						MergeWhenClause *n = makeNode(MergeWhenClause);
						n->matched = true;
						n->commandType = CMD_UPDATE;
						n->targetList = $5;
						$$ = (Node *) n;
					} else {
#ifdef ENABLE_MULTIPLE_NODES
						/* check subquery in set clause*/
						ListCell* cell = NULL;
						ResTarget* res = NULL;
						foreach (cell, $5) {
							res = (ResTarget*)lfirst(cell);
							if (IsA(res->val,SubLink)) {
								const char* message = "Update with subquery is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement.";
    								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
									(errmodule(MOD_PARSER),
									errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									errmsg("Update with subquery is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement.")));
							}
						}
#endif

						UpsertClause *uc = makeNode(UpsertClause);
						uc->targetList = $5;
						uc->location = @1;
						uc->whereClause = $6;
						$$ = (Node *) uc;
					}
				}
			| ON DUPLICATE KEY UPDATE NOTHING
				{
					if (unlikely(u_sess->attr.attr_sql.enable_upsert_to_merge ||
						t_thrd.proc->workingVersionNum < UPSERT_ROW_STORE_VERSION_NUM)) {
						$$ = NULL;
					} else {
						UpsertClause *uc = makeNode(UpsertClause);
						uc->targetList = NIL;
						uc->location = @1;
						$$ = (Node *) uc;
					}
				}
		;

/*****************************************************************************
 *
 *		QUERY:
 *				DELETE STATEMENTS
 *
 *****************************************************************************/

DeleteStmt: opt_with_clause DELETE_P hint_string FROM relation_expr_opt_alias_list
			using_clause where_or_current_clause opt_sort_clause opt_delete_limit returning_clause
				{
					DeleteStmt *n = makeNode(DeleteStmt);
					n->relations = $5;
					if (list_length(n->relations) > 1) {
						checkDeleteRelationError();
					}
					n->usingClause = $6;
					n->whereClause = $7;
					n->sortClause = $8;
					n->limitClause = (Node*)list_nth($9, 1);
					n->returningList = $10;
					n->withClause = $1;
					n->hintState = create_hintstate($3);					
					$$ = (Node *)n;
				}
		| opt_with_clause DELETE_P hint_string relation_expr_opt_alias_list
			using_clause where_or_current_clause opt_sort_clause opt_delete_limit returning_clause
				{
					DeleteStmt *n = makeNode(DeleteStmt);
					n->relations = $4;
					if (list_length(n->relations) > 1) {
						checkDeleteRelationError();
					}
					n->usingClause = $5;
					n->whereClause = $6;
					n->sortClause = $7;
					n->limitClause = (Node*)list_nth($8, 1);
					n->returningList = $9;
					n->withClause = $1;
					n->hintState = create_hintstate($3);				
					$$ = (Node *)n;
				}
		/* this is only used in multi-relation DELETE for compatibility B database. */
		| opt_with_clause DELETE_P hint_string relation_expr_opt_alias_list
			FROM from_list_for_no_table_function where_or_current_clause
				{
					DeleteStmt *n = makeNode(DeleteStmt);
					n->relations = $4;
					checkDeleteRelationError();
					n->usingClause = $6;
					n->whereClause = $7;
					n->withClause = $1;
					n->hintState = create_hintstate($3);				
					$$ = (Node *)n;
				}
		;

using_clause:
				USING from_list						{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;


/*****************************************************************************
 *
 *		QUERY:
 *				LOCK TABLE
 *
 *****************************************************************************/

LockStmt:	LOCK_P opt_table relation_expr_list opt_lock opt_nowait opt_cancelable
				{
					LockStmt *n = makeNode(LockStmt);

					n->relations = $3;
					n->mode = $4;
					n->nowait = $5;
					n->cancelable = $6;
					$$ = (Node *)n;
				}
		;

opt_lock:	IN_P lock_type MODE				{ $$ = $2; }
			| /*EMPTY*/						{ $$ = AccessExclusiveLock; }
		;

lock_type:	ACCESS SHARE					{ $$ = AccessShareLock; }
			| ROW SHARE						{ $$ = RowShareLock; }
			| ROW EXCLUSIVE					{ $$ = RowExclusiveLock; }
			| SHARE UPDATE EXCLUSIVE		{ $$ = ShareUpdateExclusiveLock; }
			| SHARE							{ $$ = ShareLock; }
			| SHARE ROW EXCLUSIVE			{ $$ = ShareRowExclusiveLock; }
			| EXCLUSIVE						{ $$ = ExclusiveLock; }
			| ACCESS EXCLUSIVE				{ $$ = AccessExclusiveLock; }
		;

opt_nowait:	NOWAIT							{ $$ = TRUE; }
			| /*EMPTY*/						{ $$ = FALSE; }
		;

opt_cancelable: CANCELABLE                                              { $$ = TRUE; }
                        | /*EMPTY*/                                             { $$ = FALSE; }
                ;

opt_wait:	WAIT Iconst						{ $$ = $2; }
opt_nowait_or_skip:
			NOWAIT							{ $$ = LockWaitError; }
			| SKIP LOCKED					{ $$ = LockWaitSkip; }
			| /*EMPTY*/						{ $$ = LockWaitBlock; }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				UpdateStmt (UPDATE)
 *
 *****************************************************************************/

UpdateStmt: opt_with_clause UPDATE hint_string from_list_for_no_table_function
			SET set_clause_list
			from_clause
			where_or_current_clause
			opt_sort_clause
			opt_delete_limit
			returning_clause
				{
					UpdateStmt *n = makeNode(UpdateStmt);
					n->relation = NULL;
#ifdef ENABLE_MULTIPLE_NODES
					if (list_length($4) > 1) {
						ereport(errstate, 
							    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("multi-relation update is not yet supported.")));
					}
					if (!IsA(linitial($4), RangeVar)) {
							ereport(errstate,
								    (errcode(ERRCODE_SYNTAX_ERROR),
								     errmsg("invalid target relation name."),
								     parser_errposition(@4)));
					}
#else
					if (!DB_IS_CMPT_BD) {
						if (list_length($4) > 1) {
							ereport(errstate, 
									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
									 errmsg("multi-relation update only support in B-format or D-format database")));
						}
						if (!IsA(linitial($4), RangeVar)) {
							ereport(errstate,
								    (errcode(ERRCODE_SYNTAX_ERROR),
								     errmsg("invalid target relation name."),
								     parser_errposition(@4)));
						}
					}
#endif
					n->relationClause = $4;
					n->targetList = $6;
					n->fromClause = $7;
					n->whereClause = $8;
					n->sortClause = $9;
					n->limitClause = (Node*)list_nth($10, 1);
					n->returningList = $11;
					n->withClause = $1;
					n->hintState = create_hintstate($3);
					n->hasIgnore = (n->hintState != NULL && n->hintState->sql_ignore_hint && DB_IS_CMPT(B_FORMAT));
					$$ = (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;
				}
			/* this is only used in ON DUPLICATE KEY UPDATE col = VALUES(col) case
			 * for mysql compatibility
			 */
			| set_target '=' VALUES '(' columnref ')'
				{
					ColumnRef *c = NULL;
					int nfields = 0;
					if (IsA($5, ColumnRef))
						c = (ColumnRef *) $5;
					else if (IsA($5, A_Indirection))
						c = (ColumnRef *)(((A_Indirection *)$5)->arg);
					nfields = list_length(c->fields);
					/* only allow col.*, col[...], col */
					if (nfields > 1)
					{
						const char* message = "only allow column name within VALUES";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("only allow column name within VALUES"),
								 parser_errposition(@5)));
					}

					c->fields = lcons((Node *)makeString("excluded"), c->fields);
					$$ = $1;
					$$->val = (Node *) $5;
				}
		;

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)) {
						const char* message = "number of columns does not match number of values";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("number of columns does not match number of values"),
								 parser_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_list ')' '=' '(' SELECT hint_string opt_distinct target_list
					from_clause where_clause group_clause having_clause ')'
					{
						SelectStmt *select = makeNode(SelectStmt);
						select->distinctClause = $8;
						select->targetList = $9;
						select->intoClause = NULL;
						select->fromClause = $10;
						select->whereClause = $11;
						select->groupClause = $12;
						select->havingClause = $13;

						if (list_length($2) != list_length($9)) {
							const char* message = "number of columns does not match number of values";
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									errmsg("number of columns does not match number of values")));
						}
						ParseUpdateMultiSet($2, select, yyscanner);

						$$ = $2;
					}

		;

set_target:
			ColId opt_indirection
				{
					$$ = makeNode(ResTarget);
					$$->name = $1;
					$$->indirection = check_indirection($2, yyscanner);
					$$->val = NULL;	/* upper production sets this */
					$$->location = @1;
				}
		;

set_target_list:
			set_target								{ $$ = list_make1($1); }
			| set_target_list ',' set_target		{ $$ = lappend($1,$3); }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				MERGE STATEMENTS
 *
 *****************************************************************************/
MergeStmt:
			MERGE hint_string INTO relation_expr_opt_alias
			USING table_ref
			ON a_expr
			merge_when_list
				{
					MergeStmt *m = makeNode(MergeStmt);

					m->relation = $4;
					m->source_relation = $6;
					m->join_condition = $8;
					m->mergeWhenClauses = $9;

					m->hintState = create_hintstate($2);

					$$ = (Node *)m;
				}
			;

merge_when_list:
			merge_when_clause						{ $$ = list_make1($1); }
			| merge_when_list merge_when_clause 	{ $$ = lappend($1,$2); }
			;

merge_when_clause:
			WHEN MATCHED THEN merge_update opt_merge_where_condition
				{
					$4->matched = true;
					$4->commandType = CMD_UPDATE;
					$4->condition = $5;

					$$ = (Node *) $4;
				}
			| WHEN NOT MATCHED THEN merge_insert opt_merge_where_condition
				{
					$5->matched = false;
					$5->commandType = CMD_INSERT;
					$5->condition = $6;

					$$ = (Node *) $5;
				}
			;

opt_merge_where_condition:
			WHERE a_expr			{ $$ = $2; }
			|						{ $$ = NULL; }
			;

merge_update:
			UPDATE SET set_clause_list
				{
					MergeWhenClause *n = makeNode(MergeWhenClause);
					n->targetList = $3;

					$$ = n;
				}
			;

merge_insert:
			INSERT merge_values_clause
				{
					MergeWhenClause *n = makeNode(MergeWhenClause);
					n->cols = NIL;
					n->values = $2;

					$$ = n;
				}
			| INSERT '(' insert_column_list ')' merge_values_clause
				{
					MergeWhenClause *n = makeNode(MergeWhenClause);
					n->cols = $3;
					n->values = $5;

					$$ = n;
				}
			| INSERT DEFAULT VALUES
				{
					MergeWhenClause *n = makeNode(MergeWhenClause);
					n->cols = NIL;
					n->values = NIL;
					$$ = n;
				}
			;

merge_values_clause:
			VALUES ctext_row
				{
					$$ = $2;
				}
			;

/*****************************************************************************
 *
 *		QUERY:
 *				CURSOR STATEMENTS
 *
 *****************************************************************************/
DeclareCursorStmt: CURSOR cursor_name cursor_options opt_hold FOR SelectStmt
				{
					DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
					n->portalname = $2;
					/* currently we always set FAST_PLAN option */
					n->options = $3 | $4 | CURSOR_OPT_FAST_PLAN;
					n->query = $6;
					$$ = (Node *)n;
				}
			| DECLARE_CURSOR cursor_name cursor_options CURSOR opt_hold FOR SelectStmt
			{
				DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
				n->portalname = $2;
				/* currently we always set FAST_PLAN option */
				n->options = $3 | $5 | CURSOR_OPT_FAST_PLAN;
				n->query = $7;
				$$ = (Node *)n;
			}
	;

cursor_name:	name						{ $$ = $1; }
		;

cursor_options: /*EMPTY*/					{ $$ = 0; }
			| cursor_options NO SCROLL		{ $$ = $1 | CURSOR_OPT_NO_SCROLL; }
			| cursor_options SCROLL
				{
					const char* message = "SCROLL CURSOR is not yet supported";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("SCROLL CURSOR is not yet supported.")));
					$$ = $1 | CURSOR_OPT_SCROLL;
				}
			| cursor_options BINARY			{ $$ = $1 | CURSOR_OPT_BINARY; }
			| cursor_options INSENSITIVE
				{
					const char* message = "INSENSITIVE CURSOR is not yet supported.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("INSENSITIVE CURSOR is not yet supported.")));
					$$ = $1 | CURSOR_OPT_INSENSITIVE;
				}
		;

opt_hold: /* EMPTY */						{ $$ = 0; }
			| WITH HOLD				{$$ = CURSOR_OPT_HOLD; }
			| WITHOUT HOLD				{ $$ = 0; }
		;

/*****************************************************************************
 *
 *		QUERY:
 *				SELECT STATEMENTS
 *
 *****************************************************************************/

/* A complete SELECT statement looks like this.
 *
 * The rule returns either a single SelectStmt node or a tree of them,
 * representing a set-operation tree.
 *
 * There is an ambiguity when a sub-SELECT is within an a_expr and there
 * are excess parentheses: do the parentheses belong to the sub-SELECT or
 * to the surrounding a_expr?  We don't really care, but bison wants to know.
 * To resolve the ambiguity, we are careful to define the grammar so that
 * the decision is staved off as long as possible: as long as we can keep
 * absorbing parentheses into the sub-SELECT, we will do so, and only when
 * it's no longer possible to do that will we decide that parens belong to
 * the expression.	For example, in "SELECT (((SELECT 2)) + 3)" the extra
 * parentheses are treated as part of the sub-select.  The necessity of doing
 * it that way is shown by "SELECT (((SELECT 2)) UNION SELECT 2)".	Had we
 * parsed "((SELECT 2))" as an a_expr, it'd be too late to go back to the
 * SELECT viewpoint when we see the UNION.
 *
 * This approach is implemented by defining a nonterminal select_with_parens,
 * which represents a SELECT with at least one outer layer of parentheses,
 * and being careful to use select_with_parens, never '(' SelectStmt ')',
 * in the expression grammar.  We will then have shift-reduce conflicts
 * which we can resolve in favor of always treating '(' <select> ')' as
 * a select_with_parens.  To resolve the conflicts, the productions that
 * conflict with the select_with_parens productions are manually given
 * precedences lower than the precedence of ')', thereby ensuring that we
 * shift ')' (and then reduce to select_with_parens) rather than trying to
 * reduce the inner <select> nonterminal to something else.  We use UMINUS
 * precedence for this, which is a fairly arbitrary choice.
 *
 * To be able to define select_with_parens itself without ambiguity, we need
 * a nonterminal select_no_parens that represents a SELECT structure with no
 * outermost parentheses.  This is a little bit tedious, but it works.
 *
 * In non-expression contexts, we use SelectStmt which can represent a SELECT
 * with or without outer parentheses.
 */

SelectStmt: select_no_parens			%prec UMINUS
			| select_with_parens		%prec UMINUS
		;

select_with_parens:
			'(' select_no_parens ')'				{ $$ = $2; }
			| '(' select_with_parens ')'			{ $$ = $2; }
		;

/*
 * This rule parses the equivalent of the standard's <query expression>.
 * The duplicative productions are annoying, but hard to get rid of without
 * creating shift/reduce conflicts.
 *
 *	The locking clause (FOR UPDATE etc) may be before or after LIMIT/OFFSET.
 *	In <=7.2.X, LIMIT/OFFSET had to be after FOR UPDATE
 *	We now support both orderings, but prefer LIMIT/OFFSET before the locking clause.
 *	2002-08-28 bjm
 */
select_no_parens:
			simple_select						{ $$ = $1; }
                        | select_clause siblings_clause opt_select_limit
                                {
                                        SelectStmt* stmt = (SelectStmt *) $1;
                                        insertSelectOptions((SelectStmt *) $1, NIL, NIL, $3, NULL, yyscanner);
                                        StartWithClause* swc = (StartWithClause*) stmt->startWithClause;
                                        if (swc == NULL) {
                                            ereport(errstate,
                                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                                     errmsg("order siblings by clause can only be used on start-with qualifed relations"),
                                                     parser_errposition(@2)));
                                        } else {
                                            swc->siblingsOrderBy = $2;
                                        }
                                        $$ = $1;
                                }
                        | select_clause siblings_clause sort_clause opt_select_limit
                                {
                                        SelectStmt* stmt = (SelectStmt *) $1;
										insertSelectOptions((SelectStmt *) $1, $3, NIL, $4, NULL, yyscanner);
                                        StartWithClause* swc = (StartWithClause*) stmt->startWithClause;
                                        if (swc == NULL) {
                                            ereport(errstate,
                                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                                     errmsg("order siblings by clause can only be used on start-with qualifed relations"),
                                                     parser_errposition(@2)));
                                        } else {
                                            swc->siblingsOrderBy = $2;
                                        }
                                        $$ = $1;
                                }
			| select_clause sort_clause
				{
					insertSelectOptions((SelectStmt *) $1, $2, NIL,
										NULL, NULL,
										yyscanner);
					$$ = $1;
				}
			| select_clause opt_sort_clause for_locking_clause opt_select_limit opt_into_clause
				{
					FilterStartWithUseCases((SelectStmt *) $1, $3, yyscanner, @3);
					insertSelectOptions((SelectStmt *) $1, $2, $3, $4,
										NULL,
										yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $1, (IntoClause *) $5);
				}
			| select_clause opt_sort_clause select_limit opt_for_locking_clause
				{
					FilterStartWithUseCases((SelectStmt *) $1, $4, yyscanner, @4);
					insertSelectOptions((SelectStmt *) $1, $2, $4, $3,
										NULL,
										yyscanner);
					$$ = $1;
				}
			| select_clause opt_sort_clause select_limit for_locking_clause into_clause
				{
					FilterStartWithUseCases((SelectStmt *) $1, $4, yyscanner, @4);
					insertSelectOptions((SelectStmt *) $1, $2, $4, $3,
										NULL,
										yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $1, (IntoClause *) $5);
				}
			| select_clause opt_sort_clause opt_select_limit into_clause opt_for_locking_clause
				{
					FilterStartWithUseCases((SelectStmt *) $1, $5, yyscanner, @5);
					insertSelectOptions((SelectStmt *) $1, $2, $5, $3,
										NULL,
										yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $1, (IntoClause *) $4);
				}
			| with_clause select_clause
				{
					insertSelectOptions((SelectStmt *) $2, NULL, NIL,
										NULL, 
										$1,
										yyscanner);
					$$ = $2;
				}
			| with_clause select_clause sort_clause
				{
					insertSelectOptions((SelectStmt *) $2, $3, NIL,
										NULL, 
										$1,
										yyscanner);
					$$ = $2;
				}
			| with_clause select_clause siblings_clause
                                {
                                        SelectStmt* stmt = (SelectStmt *) $2;
					insertSelectOptions((SelectStmt *) $2, NIL, NIL,
										NULL, $1,
										yyscanner);
                                        StartWithClause* swc = (StartWithClause*) stmt->startWithClause;
                                        if (swc == NULL) {
                                            ereport(errstate,
                                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                                     errmsg("order siblings by clause can only be used on start-with qualifed relations"),
                                                     parser_errposition(@2)));
                                        } else {
                                            swc->siblingsOrderBy = $3;
                                        }
                                        $$ = $2;
                                }

			| with_clause select_clause siblings_clause sort_clause
                                {
                                        SelectStmt* stmt = (SelectStmt *) $2;
                                        insertSelectOptions((SelectStmt *) $2, $4, NIL,
                                        NULL, $1,
                                        yyscanner);
                                        StartWithClause* swc = (StartWithClause*) stmt->startWithClause;
                                        if (swc == NULL) {
                                            ereport(errstate,
                                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                                     errmsg("order siblings by clause can only be used on start-with qualifed relations"),
                                                     parser_errposition(@2)));
                                        } else {
                                            swc->siblingsOrderBy = $3;
                                        }
                                        $$ = $2;
                                }
			| with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit opt_into_clause
				{
					FilterStartWithUseCases((SelectStmt *) $2, $4, yyscanner, @4);
					insertSelectOptions((SelectStmt *) $2, $3, $4, $5, $1, yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $2, (IntoClause *) $6);
				}
			| with_clause select_clause opt_sort_clause select_limit for_locking_clause into_clause
				{
                    FilterStartWithUseCases((SelectStmt *) $2, $5, yyscanner, @5);
					insertSelectOptions((SelectStmt *) $2, $3, $5, $4, $1, yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $2, (IntoClause *) $6);
				}
			| with_clause select_clause opt_sort_clause opt_select_limit into_clause opt_for_locking_clause
				{
                    FilterStartWithUseCases((SelectStmt *) $2, $6, yyscanner, @6);
					insertSelectOptions((SelectStmt *) $2, $3, $6, $4, $1, yyscanner);
					$$ = processIntoClauseInSelectStmt((SelectStmt *) $2, (IntoClause *) $5);
				}
			| with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
				{
                    FilterStartWithUseCases((SelectStmt *) $2, $5, yyscanner, @5);
					insertSelectOptions((SelectStmt *) $2, $3, $5, $4, $1, yyscanner);
					$$ = $2;
				}
		;

select_clause:
			simple_select							{ $$ = $1; }
			| select_with_parens					{ $$ = $1; }
		;

/*
 * This rule parses SELECT statements that can appear within set operations,
 * including UNION, INTERSECT and EXCEPT.  '(' and ')' can be used to specify
 * the ordering of the set operations.	Without '(' and ')' we want the
 * operations to be ordered per the precedence specs at the head of this file.
 *
 * As with select_no_parens, simple_select cannot have outer parentheses,
 * but can have parenthesized subclauses.
 *
 * 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 WITH, FOR UPDATE and LIMIT.  Therefore, those clauses are
 * described as part of the select_no_parens production, not simple_select.
 * This does not limit functionality, because you can reintroduce these
 * clauses inside parentheses.
 *
 * NOTE: only the leftmost component SelectStmt should have INTO.
 * However, this is not checked by the grammar; parse analysis must check it.
 */
simple_select:
			SELECT hint_string opt_distinct target_list
			opt_into_clause from_clause where_clause start_with_clause
			group_clause having_clause window_clause
				{
					SelectStmt *n = makeNode(SelectStmt);
					n->distinctClause = $3;
					n->targetList = $4;
					n->intoClause = $5;
					n->fromClause = $6;
					n->whereClause = $7;
					n->startWithClause = $8;
					n->groupClause = $9;
					n->havingClause = $10;
					n->windowClause = $11;
					n->hintState = create_hintstate($2);
					n->hasPlus = getOperatorPlusFlag();
					$$ = (Node *)n;
				}
			| values_clause							{ $$ = $1; }
			| TABLE relation_expr
				{
					/* same as SELECT * FROM relation_expr */
					ColumnRef *cr = makeNode(ColumnRef);
					ResTarget *rt = makeNode(ResTarget);
					SelectStmt *n = makeNode(SelectStmt);

					cr->fields = list_make1(makeNode(A_Star));
					cr->location = -1;
					cr->indnum = 0;

					rt->name = NULL;
					rt->indirection = NIL;
					rt->val = (Node *)cr;
					rt->location = -1;

					n->targetList = list_make1(rt);
					n->fromClause = list_make1($2);
					$$ = (Node *)n;
				}
			| select_clause UNION 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);
				}
			| select_clause MINUS_P opt_all select_clause
				{
					$$ = makeSetOp(SETOP_EXCEPT, $3, $1, $4);
				}
		;

hint_string:
		COMMENTSTRING
			{
				$$ = $1;
			}
		|
			{ 
				$$ = NULL;
			}
		;
/*
 * 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 opt_materialized '(' PreparableStmt ')'
			{
				CommonTableExpr *n = makeNode(CommonTableExpr);
				n->ctename = $1;
				n->aliascolnames = $2;
				n->ctematerialized = (CTEMaterialize)$4;
				n->ctequery = $6;
				n->location = @1;
				n->locator_type = LOCATOR_TYPE_NONE;
				$$ = (Node *) n;
			}
		;

opt_materialized:
		MATERIALIZED							{ $$ = CTEMaterializeAlways; }
		| NOT MATERIALIZED						{ $$ = CTEMaterializeNever; }
		| /*EMPTY*/								{ $$ = CTEMaterializeDefault; }
		;

opt_with_clause:
		with_clause								{ $$ = $1; }
		| /*EMPTY*/								{ $$ = NULL; }
		;

opt_into_clause:
		into_clause								{ $$ = $1; }
		| /*EMPTY*/								%prec INTO
			{ $$ = NULL; }
		;

into_clause:
			INTO OptTempTableName
				{
					$$ = makeNode(IntoClause);
					$$->rel = $2;
					$$->colNames = NIL;
					$$->options = NIL;
					$$->onCommit = ONCOMMIT_NOOP;
					/* Here $$ is a temp table, so row_compress can be any value. To be safe, REL_CMPRS_PAGE_PLAIN is used. */
					$$->row_compress = REL_CMPRS_PAGE_PLAIN;
					$$->tableSpaceName = NULL;
					$$->skipData = false;
					$$->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
				}
			| INTO into_user_var_list
				{
					$$ = makeNode(IntoClause);
					$$->rel = NULL;
					$$->colNames = NIL;
					$$->options = NIL;
					$$->onCommit = ONCOMMIT_NOOP;
					$$->row_compress = REL_CMPRS_PAGE_PLAIN;
					$$->tableSpaceName = NULL;
					$$->skipData = false;
					$$->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
					$$->userVarList = $2;
				}
			| INTO OUTFILE Sconst characterset_option fields_options_fin lines_options_fin
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SELECT INTO OUTFILE is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SELECT INTO OUTFILE is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("SELECT INTO OUTFILE is only supported in B_FORMAT.")));
					}
					IntoClause *n = makeNode(IntoClause);
					n->filename = $3;
					n->copyOption = $5;
					n->is_outfile = true;
					if ($4)
						n->copyOption = lappend(n->copyOption, $4);
					if ($6)
						n->copyOption = lappend3(n->copyOption, $6);
					n->rel = NULL;
					n->colNames = NIL;
					n->options = NIL;
					n->onCommit = ONCOMMIT_NOOP;
					n->row_compress = REL_CMPRS_PAGE_PLAIN;
					n->tableSpaceName = NULL;
					n->skipData = false;
					n->relkind = INTO_CLAUSE_RELKIND_DEFAULT;
					$$ = n;
				}
			| INTO DUMPFILE Sconst
				{
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "SELECT INTO DUMPFILE is not yet supported in distributed database.";
					gsplsql_insert_error_msg(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("SELECT INTO DUMPFILE is not yet supported in distributed database.")));
#endif
					if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
						ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("SELECT INTO DUMPFILE is only supported in B_FORMAT.")));
					}
					$$ = makeNode(IntoClause);
					$$->is_outfile = false;
					$$->filename = $3;
				}
		;
characterset_option:
			CHARACTER SET Sconst
				{
					$$ = makeDefElem("encoding", (Node *)makeString($3));
				}
			| /*EMPTY*/			{ $$ = NULL; }
		;
fields_options_fin:
			FIELDS fields_options_list			{ $$ = $2; }
			| /*EMPTY*/							{ $$ = NIL; }
		;
fields_options_list:
			fields_options_list fields_options_item		{ $$ = lappend($1, $2); }
			| /*EMPTY*/			{ $$ = NIL; }
		;
fields_options_item:
			TERMINATED BY Sconst
				{
					$$ = makeDefElem("delimiter", (Node *)makeString($3));
				}
			| OPTIONALLY ENCLOSED BY Sconst
				{
					$$ = makeDefElem("o_enclosed", (Node *)makeString($4));
				}
			| ENCLOSED BY Sconst
				{
					$$ = makeDefElem("enclosed", (Node *)makeString($3));
				}
			| ESCAPED BY Sconst
				{
					$$ = makeDefElem("escape", (Node *)makeString($3));
				}
		;
lines_options_fin:
			LINES lines_options_list	{ $$ = $2; }
			| /*EMPTY*/			{ $$ = NIL; }
		;
lines_options_list:
			lines_options_list lines_option_item	{ $$ = lappend($1, $2); }
			| /*EMPTY*/			{ $$ = NIL; }
		;
lines_option_item:
			STARTING BY Sconst
				{
					$$ = makeDefElem("line_start", (Node *)makeString($3));
				}
			| TERMINATED BY Sconst
				{
					$$ = makeDefElem("eol", (Node *)makeString($3));
				}
 		;
into_user_var_list:
		uservar_name									{ $$ = list_make1($1); }
		| into_user_var_list ',' uservar_name			{ $$ = lappend($1,$3); }
	;

/*
 * Redundancy here is needed to avoid shift/reduce conflicts,
 * since TEMP is not a reserved word.  See also OptTemp.
 */
OptTempTableName:
			TEMPORARY opt_table qualified_name
				{
					$$ = $3;
					$$->relpersistence = RELPERSISTENCE_TEMP;
				}
			| TEMP opt_table qualified_name
				{
					$$ = $3;
					$$->relpersistence = RELPERSISTENCE_TEMP;
				}
			| LOCAL TEMPORARY opt_table qualified_name
				{
					$$ = $4;
					$$->relpersistence = RELPERSISTENCE_TEMP;
				}
			| LOCAL TEMP opt_table qualified_name
				{
					$$ = $4;
					$$->relpersistence = RELPERSISTENCE_TEMP;
				}
			| GLOBAL TEMPORARY opt_table qualified_name
				{
					$$ = $4;
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "GLOBAL is deprecated in temporary table creation";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(WARNING,
							(errmsg("GLOBAL is deprecated in temporary table creation"),
							 parser_errposition(@1)));
					$$->relpersistence = RELPERSISTENCE_TEMP;
#else
					$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
#endif
				}
			| GLOBAL TEMP opt_table qualified_name
				{
					$$ = $4;
#ifdef ENABLE_MULTIPLE_NODES
					const char* message = "GLOBAL is deprecated in temporary table creation";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(WARNING,
							(errmsg("GLOBAL is deprecated in temporary table creation"),
							 parser_errposition(@1)));
					$$->relpersistence = RELPERSISTENCE_TEMP;
#else
					$$->relpersistence = RELPERSISTENCE_GLOBAL_TEMP;
#endif
				}
			| UNLOGGED opt_table qualified_name
				{
					$$ = $3;
					$$->relpersistence = RELPERSISTENCE_UNLOGGED;
				}
			| TABLE qualified_name
				{
					$$ = $2;
					$$->relpersistence = RELPERSISTENCE_PERMANENT;
				}
			| qualified_name
				{
					$$ = $1;
					$$->relpersistence = RELPERSISTENCE_PERMANENT;
				}
		;

opt_table:	TABLE									{}
			| /*EMPTY*/								{}
		;

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; }
		;

siblings_clause:
                        ORDER SIBLINGS BY sortby_list                           { $$ = (Node*)$4; }
                ;

sortby_list:
			sortby									{ $$ = list_make1($1); }
			| sortby_list ',' sortby				{ $$ = lappend($1, $3); }
		;

sortby:		a_expr USING qual_all_Op opt_nulls_order
				{
					$$ = makeNode(SortBy);
					$$->node = $1;
					$$->sortby_dir = SORTBY_USING;
					$$->sortby_nulls = (SortByNulls)$4;
					$$->useOp = $3;
					$$->location = @3;
				}
			| a_expr opt_asc_desc opt_nulls_order
				{
					$$ = makeNode(SortBy);
					$$->node = $1;
					$$->sortby_dir = (SortByDir)$2;
					$$->sortby_nulls = (SortByNulls)$3;
					$$->useOp = NIL;
					$$->location = -1;		/* no operator */
				}
		;


select_limit:
			limit_clause offset_clause
				{ 
					FetchLimit *limitClause = $1;
					if (limitClause) {
						limitClause->limitOffset = $2;
					}
					$$ = limitClause;
				}
			| offset_clause limit_clause
				{ 
					FetchLimit *limitClause = $2;
					if (limitClause) {
						limitClause->limitOffset = $1;
					}
					$$ = limitClause;
				}
			| limit_clause						{ $$ = $1; }
			| limit_offcnt_clause
				{ 
					FetchLimit *limitClause = (FetchLimit *)palloc0(sizeof(FetchLimit));
					limitClause->limitOffset = (Node *)list_nth($1, 0);
					limitClause->limitCount = (Node *)list_nth($1, 1);
					$$ = limitClause;
				}
			| offset_clause
				{ 
					FetchLimit *limitClause = (FetchLimit *)palloc0(sizeof(FetchLimit));
					limitClause->limitOffset = $1;
					$$ = limitClause;
				}
		;

opt_select_limit:
			select_limit						{ $$ = $1; }
			| /* EMPTY */						{ $$ = NULL; }
		;

opt_delete_limit:
			LIMIT a_expr						{ $$ = list_make2(NULL, $2); }
			| /* EMPTY */						{ $$ = list_make2(NULL, NULL); }
		;

limit_clause:
			LIMIT select_limit_value
				{
					FetchLimit *result = (FetchLimit *)palloc0(sizeof(FetchLimit));
					result->limitCount = $2;
					result->isFetch = false;
					$$ = result;
				}
			/* SQL:2008 syntax */
			| FETCH first_or_next opt_select_fetch_first_value opt_percent row_or_rows only_or_ties
				{
					FetchLimit *result = (FetchLimit *)palloc0(sizeof(FetchLimit));
					result->limitOffset = NULL;
					result->limitCount = $3;
					result->isPercent = $4;
					result->isWithTies = $6;
					result->isFetch = true;
					$$ = result;
				}
		;

limit_offcnt_clause:
			LIMIT select_offset_value ',' select_limit_value
				{
					$$ = list_make2($2, $4);
				}
		;

offset_clause:
			OFFSET select_offset_value
				{ $$ = $2; }
			/* SQL:2008 syntax */
			| OFFSET select_offset_value2 row_or_rows
				{ $$ = $2; }
		;

select_limit_value:
			a_expr									{ $$ = $1; }
			| ALL
				{
					/* LIMIT ALL is represented as a NULL constant */
					$$ = makeNullAConst(@1);
				}
		;

select_offset_value:
			a_expr									{ $$ = $1; }
		;

/*
 * Allowing full expressions without parentheses causes various parsing
 * problems with the trailing ROW/ROWS key words.  SQL only calls for
 * constants, so we allow the rest only with parentheses.  If omitted,
 * default to 1.
 */
opt_select_fetch_first_value:
			SignedIconst						{ $$ = makeIntConst($1, @1); }
			| FCONST         					{ $$ = makeFloatConst($1, @1); }
			| '(' a_expr ')'					{ $$ = $2; }
			| /*EMPTY*/							{ $$ = makeIntConst(1, -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; }
		;

opt_percent:
			PERCENT								{ $$ = true; }
			| /*EMPTY*/							{ $$ = false; }
		;

/* noise words */
row_or_rows: ROW									{ $$ = 0; }
			| ROWS									{ $$ = 0; }
		;

first_or_next: FIRST_P								{ $$ = 0; }
			| NEXT									{ $$ = 0; }
		;

only_or_ties:
			ONLY									{ $$ = false; }
			| WITH TIES									{ $$ = true; }
		;

/*
 * This syntax for group_clause tries to follow the spec quite closely.
 * However, the spec allows only column references, not expressions,
 * which introduces an ambiguity between implicit row constructors
 * (a,b) and lists of column references.
 *
 * We handle this by using the a_expr production for what the spec calls
 * <ordinary grouping set>, which in the spec represents either one column
 * reference or a parenthesized list of column references. Then, we check the
 * top node of the a_expr to see if it's an implicit RowExpr, and if so, just
 * grab and use the list, discarding the node. (this is done in parse analysis,
 * not here)
 *
 * (we abuse the row_format field of RowExpr to distinguish implicit and
 * explicit row constructors; it's debatable if anyone sanely wants to use them
 * in a group clause, but if they have a reason to, we make it possible.)
 *
 * Each item in the group_clause list is either an expression tree or a
 * GroupingSet node of some type.
 */

group_clause:
			GROUP_P BY group_by_list				{ $$ = $3; }
			| /*EMPTY*/								{ $$ = NIL; }
		;
group_by_list:
			group_by_item							{ $$ = list_make1($1); }
			| group_by_list ',' group_by_item		{ $$ = lappend($1,$3); }
		;

group_by_item:
			a_expr									{ $$ = $1; }
			| empty_grouping_set					{ $$ = $1; }
			| cube_clause							{ $$ = $1; }
			| rollup_clause 						{ $$ = $1; }
			| grouping_sets_clause					{ $$ = $1; }
		;

empty_grouping_set:
			'(' ')'
				{
					$$ = (Node *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, @1);
				}
		;
/*
 * These hacks rely on setting precedence of CUBE and ROLLUP below that of '(',
 * so that they shift in these rules rather than reducing the conflicting
 * unreserved_keyword rule.
 */

rollup_clause:
			ROLLUP '(' expr_list ')'
				{
					$$ = (Node *) makeGroupingSet(GROUPING_SET_ROLLUP, $3, @1);
				}
		;

cube_clause:
			CUBE '(' expr_list ')'
				{
					$$ = (Node *) makeGroupingSet(GROUPING_SET_CUBE, $3, @1);
				}
		;

grouping_sets_clause:
			GROUPING_P SETS '(' group_by_list ')'
				{
					$$ = (Node *) makeGroupingSet(GROUPING_SET_SETS, $4, @1);
				}
		;


having_clause:
			HAVING a_expr							{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

start_with_clause:
            START_WITH start_with_expr connect_by_expr
                {
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = $2;
                    n->connectByExpr = $3;
                    n->siblingsOrderBy = NULL;
                    n->priorDirection = false;
                    n->nocycle = false;
                    $$ = (Node *) n;
                }
            | START_WITH start_with_expr CONNECT_BY NOCYCLE a_expr
                {
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = $2;
                    n->connectByExpr = $5;
                    n->siblingsOrderBy = NULL;
                    n->priorDirection = false;
                    n->nocycle = true;
                    $$ = (Node *) n;
                }
            | connect_by_expr START_WITH start_with_expr
                {
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = $3;
                    n->connectByExpr = $1;
                    n->siblingsOrderBy = NULL;
                    n->priorDirection = false;
                    n->nocycle = false;
                    $$ = (Node *) n;
                }
            | CONNECT_BY NOCYCLE a_expr START_WITH start_with_expr
                {
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = $5;
                    n->connectByExpr = $3;
                    n->siblingsOrderBy = NULL;
                    n->priorDirection = false;
                    n->nocycle = true;
                    $$ = (Node *) n;
                }
            | CONNECT_BY NOCYCLE a_expr
                {
#ifdef ENABLE_MULTIPLE_NODES
                      const char* message = "START WITH CONNECT BY is not yet supported.";
                      InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                      ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("START WITH CONNECT BY is not yet supported.")));
#endif
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = NULL;
                    n->connectByExpr = $3;
                    n->siblingsOrderBy = NULL;
                    n->priorDirection = false;
                    n->nocycle = true;
                    $$ = (Node *) n;
                }
            | connect_by_expr
                {
                    StartWithClause *n = makeNode(StartWithClause);
                    n->startWithExpr = NULL;
                    n->connectByExpr = $1;
                    $$ = (Node *) n;
                }
            |  /*EMPTY*/                            { $$ = NULL; }
        ;
start_with_expr:
            a_expr                                  { $$ = $1; }
        ;

connect_by_expr:
            CONNECT_BY a_expr
                {
#ifdef ENABLE_MULTIPLE_NODES
                      const char* message = "START WITH CONNECT BY is not yet supported.";
                      InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                      ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("START WITH CONNECT BY is not yet supported.")));
#endif
                    $$ = $2;
                }
        ;

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 hint_string locked_rels_list opt_nowait_or_skip
				{
                    if (u_sess->parser_cxt.isTimeCapsule) {
						u_sess->parser_cxt.isTimeCapsule = false;
                      	ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("SELECT TIMECAPSULE FOR UPDATE is not supported.")));
                    }
					LockingClause *n = makeNode(LockingClause);
					n->lockedRels = $4;
					n->forUpdate = TRUE;
					n->strength = LCS_FORUPDATE;
					n->waitPolicy = (LockWaitPolicy)$5;
					n->waitSec = 0;
#ifdef ENABLE_MULTIPLE_NODES
					if (n->waitPolicy == LockWaitSkip) {
						DISTRIBUTED_FEATURE_NOT_SUPPORTED();
					}
#endif
					$$ = (Node *) n;
				}
			| FOR UPDATE hint_string locked_rels_list opt_wait
				{
					LockingClause *n = makeNode(LockingClause);
					n->lockedRels = $4;
					n->forUpdate = TRUE;
					n->strength = LCS_FORUPDATE;
					n->waitSec = $5;
					/* When the delay time is 0, the processing is based on the nowait logic. */
					if (n->waitSec == 0) {
						n->waitPolicy = LockWaitError;
					} else {
						n->waitPolicy = LockWaitBlock;
					}
					$$ = (Node *) n;
				}
			| for_locking_strength locked_rels_list opt_nowait_or_skip
				{
					LockingClause *n = makeNode(LockingClause);
					n->lockedRels = $2;
					n->strength = $1;
					n->forUpdate = FALSE;
					if (n->strength == LCS_FORUPDATE) {
						n->forUpdate = true;
					}
					n->waitPolicy = (LockWaitPolicy)$3;
                    n->waitSec = 0;
#ifdef ENABLE_MULTIPLE_NODES
					if (n->waitPolicy == LockWaitSkip) {
						DISTRIBUTED_FEATURE_NOT_SUPPORTED();
					}
#endif
					$$ = (Node *) n;
				}
		;

for_locking_strength:
			FOR NO KEY UPDATE
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("SELECT FOR NO KEY UPDATE is not yet supported.")));
#else
					$$ = LCS_FORNOKEYUPDATE;
#endif
				}
			| FOR SHARE							{ $$ = LCS_FORSHARE; }
			| FOR KEY SHARE
				{
#ifdef ENABLE_MULTIPLE_NODES
					ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("SELECT FOR KEY SHARE is not yet supported.")));
#else
					$$ = LCS_FORKEYSHARE;
#endif
				}
 		;

locked_rels_list:
			OF qualified_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*/								%prec EMPTY_FROM_CLAUSE
				{ $$ = NIL; }
		;
from_list_for_no_table_function:
			table_ref_for_no_table_function								{ $$ = list_make1($1); }
			| from_list_for_no_table_function ',' table_ref_for_no_table_function				{ $$ = lappend($1, $3); }


func_table_with_table:
	TABLE '(' func_expr_windowless ')'			{ $$ = $3; }
	/* function call without parameters */
	| TABLE '(' IDENT ')'                               	{
		List* funcNames = list_make1(makeString(IdentResolveToChar($3, yyscanner)));
		$$ = MakeNoArgFunctionCall(funcNames, @3);
	}
	| TABLE '(' unreserved_keyword ')'			{
		$$ = MakeNoArgFunctionCall(list_make1(makeString(pstrdup($3))), @3);
	}
	| TABLE '(' type_func_name_keyword ')'			{
		$$ = MakeNoArgFunctionCall(list_make1(makeString(pstrdup($3))), @3);
	}
	| TABLE '(' ColId indirection ')'			{
		$$ = MakeNoArgFunctionCall(check_func_name(lcons(makeString($3), $4), yyscanner), @3);
	};


from_list:
			table_ref								{ $$ = list_make1($1); }
			| from_list ',' table_ref				{ $$ = lappend($1, $3); }
		;


table_ref:
	table_ref_for_no_table_function
		{
			$$ = $1;
		}
	| func_table_with_table		%prec UMINUS
		{
			RangeFunction *n = makeNode(RangeFunction);
			n->funccallnode = $1;
			n->coldeflist = NIL;
			$$ = (Node *) n;
		}
	| func_table_with_table alias_clause
		{
			RangeFunction *n = makeNode(RangeFunction);
			n->funccallnode = $1;
			n->alias = $2;
			n->coldeflist = NIL;
			$$ = (Node *) n;
		}
	| func_table_with_table AS '(' TableFuncElementList ')'
		{
			RangeFunction *n = makeNode(RangeFunction);
			n->funccallnode = $1;
			n->coldeflist = $4;
			$$ = (Node *) n;
		}
	| func_table_with_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_with_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;
		}
	;

/*
 * 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_for_no_table_function:	relation_expr		%prec UMINUS
				{
#ifndef ENABLE_MULTIPLE_NODES
        			StringInfoData detailInfo;
        			initStringInfo(&detailInfo);
					RangeVar* r = $1;
					int rc = CompileWhich();
        			if (rc != PLPGSQL_COMPILE_NULL && u_sess->attr.attr_common.plsql_show_all_error) {
						Relation rel = HeapOpenrvExtended(r, NoLock, true, true, &detailInfo);
						CatCList* catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(r->relname));

						if (catlist->n_members == 0 && rel == NULL) {
        					char message[MAXFNAMELEN];
        					int rc = sprintf_s(message, MAXFNAMELEN, "relation \"%s\" does not exist", r->relname);
        					securec_check_ss(rc, "", "");
							ReleaseSysCacheList(catlist);
        					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
            				ereport(ERROR,
                				(errcode(ERRCODE_UNDEFINED_TABLE),
                    				errmsg("relation \"%s\" does not exist", r->relname),
                    				errdetail("%s", detailInfo.data)));
						} 
						if (rel != NULL) {
							heap_close(rel, NoLock);
						}
						if (catlist != NULL) {
							ReleaseSysCacheList(catlist);
						}
        			}
#endif
					$$ = (Node *) $1;
				}
			| relation_expr alias_clause opt_index_hint_list
				{
					$1->alias = $2;
					$1->indexhints = $3;
					$$ = (Node *) $1;
				}
			
			| LATERAL_EXPR func_table alias_clause
				{
					RangeFunction *n = makeNode(RangeFunction);
					n->funccallnode = $2;
					n->alias = $3;
					n->coldeflist = NIL;
					n->lateral = true;
					$$ = (Node *) n;
				}
			| relation_expr index_hint_list
				{
					$1->indexhints = $2;
					$$ = (Node *) $1;
				}
			| relation_expr opt_alias_clause tablesample_clause
				{
					RangeTableSample *n = (RangeTableSample *) $3;
					$1->alias = $2;
					/* relation_expr goes inside the RangeTableSample node */
					n->relation = (Node *) $1;
					$$ = (Node *) n;
				}
			| relation_expr opt_alias_clause timecapsule_clause
				{
					RangeTimeCapsule *n = (RangeTimeCapsule *) $3;
					$1->alias = $2;
					/* relation_expr goes inside the RangeTimeCapsule node */
					n->relation = (Node *) $1;

					if (IsA($1, RangeVar)) {
						RangeVar *rv = (RangeVar *)$1;
						rv->withVerExpr = true;
					}

					$$ = (Node *) n;
				}
			| relation_expr PARTITION '(' name ')'
				{
					$1->partitionname = $4;
					$1->ispartition = true;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION '(' name ')'
				{
					$1->subpartitionname = $4;
					$1->issubpartition = true;
					$$ = (Node *)$1;
				}
			| relation_expr BUCKETS '(' bucket_list ')'
				{
					$1->buckets = $4;
					$1->isbucket = true;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION_FOR '(' expr_list ')'
				{
					$1->partitionKeyValuesList = $4;
					$1->ispartition = true;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION_FOR '(' expr_list ')'
				{
					$1->partitionKeyValuesList = $4;
					$1->issubpartition = true;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION '(' name ')' index_hint_list
				{
					$1->partitionname = $4;
					$1->ispartition = true;
					$1->indexhints = $6;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION '(' name ')' index_hint_list
				{
					$1->subpartitionname = $4;
					$1->issubpartition = true;
					$1->indexhints = $6;
					$$ = (Node *)$1;
				}
			| relation_expr BUCKETS '(' bucket_list ')' index_hint_list
				{
					$1->buckets = $4;
					$1->isbucket = true;
					$1->indexhints = $6;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION_FOR '(' expr_list ')' index_hint_list
				{
					$1->partitionKeyValuesList = $4;
					$1->ispartition = true;
					$1->indexhints = $6;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION_FOR '(' expr_list ')' index_hint_list
				{
					$1->partitionKeyValuesList = $4;
					$1->issubpartition = true;
					$1->indexhints = $6;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION '(' name ')' alias_clause opt_index_hint_list
				{
					$1->partitionname = $4;
					$1->alias = $6;
					$1->ispartition = true;
					$1->indexhints = $7;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION '(' name ')' alias_clause opt_index_hint_list
				{
					$1->subpartitionname = $4;
					$1->alias = $6;
					$1->issubpartition = true;
					$1->indexhints = $7;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION_FOR '(' expr_list ')' alias_clause opt_index_hint_list
				{
					$1->partitionKeyValuesList = $4;
					$1->alias = $6;
					$1->ispartition = true;
					$1->indexhints = $7;
					$$ = (Node *)$1;
				}
			| relation_expr SUBPARTITION_FOR '(' expr_list ')' alias_clause opt_index_hint_list
				{
					$1->partitionKeyValuesList = $4;
					$1->alias = $6;
					$1->issubpartition = true;
					$1->indexhints = $7;
					$$ = (Node *)$1;
				}
			| relation_expr PARTITION '(' name ')' tablesample_clause
				{
					RangeTableSample *n = (RangeTableSample *) $6;
					$1->partitionname = $4;
					$1->ispartition = true;
					/* relation_expr goes inside the RangeTableSample node */
					n->relation = (Node *) $1;
					$$ = (Node *) n;
				}
			| relation_expr SUBPARTITION '(' name ')' tablesample_clause
				{
					RangeTableSample *n = (RangeTableSample *) $6;
					$1->subpartitionname = $4;
					$1->issubpartition = true;
					/* relation_expr goes inside the RangeTableSample node */
					n->relation = (Node *) $1;
					$$ = (Node *) n;
				}
			| relation_expr PARTITION_FOR '(' expr_list ')' tablesample_clause
				{
					RangeTableSample *n = (RangeTableSample *) $6;
					$1->partitionKeyValuesList = $4;
					$1->ispartition = true;
					/* relation_expr goes inside the RangeTableSample node */
					n->relation = (Node *) $1;
					$$ = (Node *) n;
				}
			| relation_expr SUBPARTITION_FOR '(' expr_list ')' tablesample_clause
				{
					RangeTableSample *n = (RangeTableSample *) $6;
					$1->partitionKeyValuesList = $4;
					$1->issubpartition = true;
					/* relation_expr goes inside the RangeTableSample node */
					n->relation = (Node *) $1;
					$$ = (Node *) n;
				}
			| func_table		%prec UMINUS
				{
					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		%prec UMINUS
				{
					/*
					 * 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".
					 */
					/* add select_with_parens whthout alias_clause adapt A db for procedure dubug */
					$$ = NULL;
					if (IsA($1, SelectStmt) &&
						((SelectStmt *) $1)->valuesLists) {
						const char* message = "VALUES in FROM must have an alias";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("VALUES in FROM must have an alias"),
								 errhint("For example, FROM (VALUES ...) [AS] foo."),
								 parser_errposition(@1)));
					}
					else
					{
						/*
						* add a anonymous table name for this subquery
						* simulate A db to support no alias for subquery,
						* give the suqquery a default name "anonymous_table"
						*/
						RangeSubselect *n = makeNode(RangeSubselect);
						Alias *a = makeNode(Alias);
						n->subquery = $1;
						n->alias = NULL;
						a->aliasname = pstrdup("__unnamed_subquery__");
						n->alias = a;
						$$ = (Node *) n;
					}
				}
			| select_with_parens alias_clause
				{
					RangeSubselect *n = makeNode(RangeSubselect);
					n->subquery = $1;
					n->alias = $2;
					$$ = (Node *) n;
				}
			| LATERAL_P select_with_parens opt_alias_clause  %prec LATERAL_P
				{
					RangeSubselect *n = makeNode(RangeSubselect);

					n->lateral = true;
					n->subquery = $2;
					n->alias = $3;
					/* same comment as above */
					if ($3 == NULL)
					{
						if (IsA($2, SelectStmt) &&
							((SelectStmt *) $2)->valuesLists)
						{
							ereport(ERROR,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("VALUES in FROM must have an alias"),
									 errhint("For example, FROM (VALUES ...) [AS] foo."),
									 parser_errposition(@2)));
						}
						else
						{
							Alias *a = makeNode(Alias);
							a->aliasname = pstrdup("__unnamed_subquery__");
							n->alias = a;
						}
					}
					$$ = (Node *) n;
				}
			| joined_table
				{
					$$ = (Node *) $1;
				}
			| '(' joined_table ')' alias_clause
				{
					$2->alias = $4;
					$$ = (Node *) $2;
				}
			| rotate_table
				{
					$$ = (Node *) $1;
				}
			| unrotate_table
				{
					$$ = (Node *) $1;
				}
		;


rotate_table: select_with_parens opt_alias_clause rotate_clause
				{
					RangeSubselect *n = makeNode(RangeSubselect);
					n->lateral = false;
					n->subquery = $1;
					if ( $2 != NULL )
						n->alias = $2;
					else
					{
						n->alias = makeNode(Alias);
						n->alias->aliasname = pstrdup("rotate_as_internal_t");
					}
					n->rotate = $3;
					$$ = (Node *) n;
				}
			| relation_expr opt_alias_clause rotate_clause
				{
					RangeSubselect *n = makeNode(RangeSubselect);
					n->lateral = false;
					n->subquery = make_AStar_subquery($1);
					if($2 != NULL)
						n->alias = $2;
					else
					{
						n->alias = makeNode(Alias);
						n->alias->aliasname = pstrdup("rotate_as_internal_t");
					}
					n->rotate = $3;
					$$ = (Node *) n;
				}
			;


unrotate_table:
	relation_expr unrotate_clause
		{
			SelectStmt *s = (SelectStmt *)make_AStar_subquery($1);
			s->unrotateInfo = $2;

            RangeSubselect *n = makeNode(RangeSubselect);
			n->lateral = false;
			n->subquery = (Node*)s;
			n->alias = generate_alias($2->alias, "not_rotate_as_internal_t");
			$$ = (Node *) n;
		}
	| relation_expr opt_alias_clause unrotate_clause
		{
			RangeSubselect *n = makeNode(RangeSubselect);
			n->lateral = false;

			SelectStmt *subquery_node = (SelectStmt *)make_AStar_subquery($1);
			subquery_node->unrotateInfo = $3;
			n->subquery = (Node*)subquery_node;
			n->alias = generate_alias($3->alias, "not_rotate_as_internal_t");
			$$ = (Node *) n;
		}		
	| select_with_parens opt_alias_clause unrotate_clause
		{
			if (!IsA($1, SelectStmt)) {
				ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("VALUES in FROM must have an alias")));
			}
			SelectStmt* s1 = (SelectStmt*)$1;

			RangeSubselect *rsubselect = makeNode(RangeSubselect);
			rsubselect->subquery = (Node*)s1;
			rsubselect->alias = generate_alias($3->alias, "not_rotate_as_internal_t");
			SelectStmt *s2 = makeNode(SelectStmt);
			ColumnRef *col = makeNode (ColumnRef);
			col->fields = list_make1(makeNode(A_Star));
			col->indnum = 0;

			ResTarget *res = makeNode(ResTarget);
			res->name = NULL;
			res->indirection = NIL;
			res->val = (Node *)col;
			s2->targetList = list_make1(res);
			s2->fromClause = list_make1(rsubselect);
			s2->unrotateInfo = $3;

			RangeSubselect *n = makeNode(RangeSubselect);
			n->lateral = false;
			n->alias = generate_alias($3->alias, "not_rotate_as_internal_t");
			n->subquery = (Node*)s2;
			$$ = (Node *) n;
		}
	| unrotate_table unrotate_clause
		{
			SelectStmt *s = makeNode(SelectStmt);
			ColumnRef *col = makeNode (ColumnRef);
			col->fields = list_make1(makeNode(A_Star));
			col->indnum = 0;

			ResTarget *res = makeNode(ResTarget);
			res->name = NULL;
			res->indirection = NIL;
			res->val = (Node *)col;
			s->targetList = list_make1(res);
			s->fromClause = list_make1($1);
			s->unrotateInfo = $2;

			RangeSubselect *n = makeNode(RangeSubselect);
			n->lateral = false;
			n->subquery = (Node*)s;
			n->alias = generate_alias($2->alias, "not_rotate_as_internal_t");

			$$ = (Node *) n;
		}
	| rotate_table unrotate_clause
		{
			SelectStmt *s = makeNode(SelectStmt);
			ColumnRef *col = makeNode (ColumnRef);
			col->fields = list_make1(makeNode(A_Star));
			col->indnum = 0;

			ResTarget *res = makeNode(ResTarget);
			res->name = NULL;
			res->indirection = NIL;
			res->val = (Node *)col;
			s->targetList = list_make1(res);
			s->fromClause = list_make1($1);
			s->unrotateInfo = $2;

			RangeSubselect *n = makeNode(RangeSubselect);
			n->lateral = false;
			n->subquery = (Node*)s;
			n->alias = generate_alias($2->alias, "not_rotate_as_internal_t");

			$$ = (Node *) n;
		}
	;


/*
 * 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->isAsof = 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->isAsof = 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->isAsof = 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 ASOF_P 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->isAsof = TRUE;
					n->larg = $1;
					n->rarg = $4;
					if ($4 != NULL && IsA($5, List))
						n->usingClause = (List *) $5; /* USING clause */
					else
						n->quals = $5; /* ON clause */
					$$ = n;
				}
			| table_ref NATURAL join_type JOIN table_ref
				{
					JoinExpr *n = makeNode(JoinExpr);
					n->jointype = $3;
					n->isNatural = TRUE;
					n->isAsof = FALSE;
					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->isAsof = FALSE;
					n->larg = $1;
					n->rarg = $4;
					n->usingClause = NIL; /* figure out which columns later... */
					n->quals = NULL; /* fill later */
					$$ = n;
				}
			| table_ref CROSS APPLY table_ref
				{
					/* CROSS JOIN is same as unqualified inner join */
					JoinExpr *n = makeNode(JoinExpr);
					n->jointype = JOIN_INNER;
					n->isNatural = FALSE;
					n->is_apply_join = TRUE;
					n->larg = $1;
					n->rarg = $4;
					if (IsA(n->rarg, RangeSubselect)) {
						((RangeSubselect*)n->rarg)->lateral = true;
					}
					n->usingClause = NIL;
					n->quals = NULL;
					$$ = n;
				}
			| table_ref OUTER_P APPLY table_ref
				{
					/* CROSS JOIN is same as unqualified inner join */
					JoinExpr *n = makeNode(JoinExpr);
					n->jointype = JOIN_LEFT;
					n->isNatural = FALSE;
					n->is_apply_join = TRUE;
					n->larg = $1;
					n->rarg = $4;
					if (IsA(n->rarg, RangeSubselect)) {
						((RangeSubselect*)n->rarg)->lateral = true;
					}
					n->usingClause = NIL;
					n->quals = NULL;
					$$ = n;
				}
		;

alias_clause:
			AS ColId '(' name_list ')'
				{
					$$ = makeNode(Alias);
					$$->aliasname = $2;
					$$->colnames = $4;
				}
			| AS ColId
				{
					$$ = makeNode(Alias);
					$$->aliasname = $2;
				}
			| ColId '(' name_list ')'
				{
					$$ = makeNode(Alias);
					$$->aliasname = $1;
					$$->colnames = $3;
				}
			| ColId
				{
					$$ = makeNode(Alias);
					$$->aliasname = $1;
				}
		;

opt_alias_clause: alias_clause		{ $$ = $1; }
			| /*EMPTY*/	{ $$ = NULL; } %prec higher_than_rotate
		;

rotate_clause:
			ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' %prec ROTATE
				{
					if (!DB_IS_CMPT_AD)
						ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("rotate clause is supported only in A or D FORMAT database.")));
					RotateClause *n = makeNode(RotateClause);
					n->aggregateFuncCallList = $3;
					n->forColName = $4;
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					char* raw_parse_query_string = yyextra->core_yy_extra.scanbuf;
					if (DB_IS_CMPT(D_FORMAT)) {
						n->inExprList = TransformToConstStrNode($5, raw_parse_query_string);
					} else {
						n->inExprList = $5;
					}
					$$ = n;
				}
		;

func_application_list:
			func_application opt_alias_clause
				{
					if (NULL != $2)
						((FuncCall*)$1)->colname = ((Alias*)$2)->aliasname;
					$$ = list_make1($1);
				}
			| func_application_list ',' func_application opt_alias_clause
				{
					if (NULL != $4)
						((FuncCall*)$3)->colname = ((Alias*)$4)->aliasname;
					$$ = lappend ($1, $3);
				}
		;
unrotate_clause:
			NOT ROTATE include_exclude_null_clause '(' unrotate_name_list rotate_for_clause unrotate_in_clause ')' %prec ROTATE
				{
					if (!DB_IS_CMPT_AD)
						ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("not rotate clause is supported only in A or D FORMAT database.")));
					UnrotateClause *n = makeNode(UnrotateClause);
					n->includeNull = $3;
					n->colNameList = $5;
					n->forColName = $6;
					n->inExprList = $7;
					$$ = n;
				}
		;

include_exclude_null_clause:
			INCLUDE NULLS_P { $$ = true; }
			| EXCLUDE NULLS_P { $$ = false; }
			| /*EMPTY*/		{ $$ = false; }
		;
unrotate_name_list:
			ColId				{ $$ = list_make1(makeString($1)); }
			| '(' name_list ')' { $$ = $2; }
		;
rotate_for_clause:
			FOR ColId
				{
					$$ = list_make1(makeString($2));
				}
			| FOR '(' name_list ')'
				{
					$$ = $3;
				}
		;
rotate_in_clause:
			IN_P '(' rotatein_list_single ')'
				{
					$$ = $3;
				}
			| IN_P '(' rotatein_list_multi ')'
				{
					$$ = $3;
				}
		;
unrotate_in_clause:
			IN_P '(' unrotatein_list_single ')'
				{
					$$ = $3;
				}
			| IN_P '(' unrotatein_list_multi ')'
				{
					$$ = $3;
				}
		;
rotatein_list_single:
			target_el
				{
					RotateInCell *incell = makeNode(RotateInCell);
					List *l = list_make1($1);
					incell->rotateInExpr = l;
					incell->aliasname = NULL;
					$$ = list_make1(incell);
				}
			| rotatein_list_single ',' target_el
				{
					RotateInCell *incell = makeNode(RotateInCell);
					List *l = list_make1($3);
					incell->rotateInExpr = l;
					incell->aliasname = NULL;
					$$ = lappend($1, incell);
				}
		;
rotatein_list_multi:
			'(' in_expr_list ')' opt_alias_clause
				{
					RotateInCell *incell = makeNode(RotateInCell);
					incell->rotateInExpr = $2;
					if (NULL != $4){
						incell->aliasname = ((Alias*)$4)->aliasname;
						if (((Alias*)$4)->colnames)
							ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("multiple values cannot be specified in alias clause of ROTATE"),
									 parser_errposition(@4)));
					}
					$$ = list_make1(incell);
				}
			| rotatein_list_multi ',' '(' in_expr_list ')' opt_alias_clause
				{
					RotateInCell *incell = makeNode(RotateInCell);
					incell->rotateInExpr = $4;
					if (NULL != $6){
						incell->aliasname = ((Alias*)$6)->aliasname;
						if (((Alias*)$6)->colnames)
							ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("multiple values cannot be specified in alias clause of ROTATE"),
									 parser_errposition(@6)));
					}
					$$ = lappend($1, incell); 
				}
		;
unrotatein_list_single:
			target_el
				{
					UnrotateInCell *incell = makeNode(UnrotateInCell);
					List *l = list_make1($1);
					incell->unrotateInExpr = l;
					incell->aliaList = NULL;
					$$ = list_make1(incell);
				}
			| unrotatein_list_single ',' target_el
				{
					UnrotateInCell *incell = makeNode(UnrotateInCell);
					List *l = list_make1($3);
					incell->unrotateInExpr = l;
					incell->aliaList = NULL;
					$$ = lappend($1, incell);
				}
		;
unrotatein_list_multi:
			'(' in_expr_list ')' unrotatein_alias_clause
				{
					UnrotateInCell *incell = makeNode(UnrotateInCell);
					incell->unrotateInExpr = $2;
					incell->aliaList = $4;
					$$ = list_make1(incell);
				}
			| unrotatein_list_multi ',' '(' in_expr_list ')' unrotatein_alias_clause
				{
					UnrotateInCell *incell = makeNode(UnrotateInCell);
					incell->unrotateInExpr = $4;
					incell->aliaList = $6;
					$$ = lappend($1, incell);
				}
		;
in_expr_list:
			a_expr %prec ROTATE
				{
					ResTarget *rt = makeNode(ResTarget);
					rt->name = NULL;
					rt->indirection = NIL;
					rt->val = (Node *)$1;
					rt->location = -1;
					$$ = list_make1(rt);
				}
			| a_expr ',' in_expr_list
				{
					ResTarget *rt = makeNode(ResTarget);
					rt->name = NULL;
					rt->indirection = NIL;
					rt->val = (Node *)$1;
					rt->location = -1;
					$$ = lcons(rt, $3);
				}
		;
unrotatein_alias_clause:
			unrotatein_alias		{ $$ = $1; }
			| /*EMPTY*/			{ $$ = NULL; }
		;
unrotatein_alias:
			AS AexprConst
				{
					$$ = list_make1($2);
				}
			| AS '(' expr_list ')' %prec ROTATE
				{
					$$ = $3;
				}
		;


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 OptSnapshotVersion
				{
					/* default inheritance */
					$$ = $1;
					if ($2 != NULL)
					{
						char *snapshot_name = (char *)palloc0(strlen($1->relname) + 1 + strlen($2) + 1);
						sprintf(snapshot_name, "%s%c%s", $1->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $2);
						$$->relname = snapshot_name;
					}
					$$->inhOpt = INH_DEFAULT;
					$$->alias = NULL;
				}
			| relation_expr_common
				{
					$$ = $1;
				}
		;

relation_expr_common:
			 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;
				}
		;

/* used for multi delete stmt, to support writing table's name forms like t.* or schema.t.* */
relation_expr_for_delete:
			qualified_name_for_delete OptSnapshotVersion
				{
					/* default inheritance */
					$$ = $1;
					if ($2 != NULL)
					{
						char *snapshot_name = (char *)palloc0(strlen($1->relname) + 1 + strlen($2) + 1);
						sprintf(snapshot_name, "%s%c%s", $1->relname, DB4AI_SNAPSHOT_VERSION_DELIMITER, $2);
						$$->relname = snapshot_name;
					}
					$$->inhOpt = INH_DEFAULT;
					$$->alias = NULL;
				}
			| relation_expr_common
				{
					$$ = $1;
				}
		;

relation_expr_list:
			relation_expr							{ $$ = list_make1($1); }
			| relation_expr_list ',' relation_expr	{ $$ = lappend($1, $3); }
		;

delete_relation_expr_opt_alias:
    relation_expr_opt_alias_for_delete                 %prec UMINUS
        {
            /*
             * When sql_compatibility is B, name in PARTITION(name) can be
             * a subpartition name instead of a strict partition name.
             * Put it in partitionNameList to avoid error reporting.
             */
            if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT &&
                $1->partitionname != NULL && $1->alias == NULL) {
                $1->partitionNameList = list_make1(makeString($1->partitionname));
                $1->partitionname = NULL;
                $1->ispartition = FALSE;
            }
            $$ = $1;
        }
    | relation_expr_for_delete PARTITION '(' name ',' name_list ')'
        {
#ifdef ENABLE_MULTIPLE_NODES
        const char* message = "partition syntax is not yet supported";
        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
            ereport(errstate,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("partition syntax is not yet supported")));
#endif
	    if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
	        ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
	                        errmsg("this partition syntax is supported only in B-format database")));
	    }
            $1->partitionNameList = lcons(makeString($4), $6);
            $$ = $1;
        }
    | relation_expr_for_delete ColId PARTITION '(' name_list ')'
        {
#ifdef ENABLE_MULTIPLE_NODES
        const char* message = "partition syntax is not yet supported";
        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
            ereport(errstate,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("partition syntax is not yet supported")));
#endif
	    if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
	        ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
	                        errmsg("this partition syntax is supported only in B-format database")));
	    }
            Alias *alias = makeNode(Alias);
            alias->aliasname = $2;
            $1->alias = alias;
            $1->partitionNameList = $5;
            $$ = $1;
        }
    | relation_expr_for_delete AS ColId PARTITION '(' name_list ')'
        {
#ifdef ENABLE_MULTIPLE_NODES
        const char* message = "partition syntax is not yet supported";
        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
            ereport(errstate,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("partition syntax is not yet supported")));
#endif
	    if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
	        ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
	                        errmsg("this partition syntax is supported only in B-format database")));
	    }
            Alias *alias = makeNode(Alias);
            alias->aliasname = $3;
            $1->alias = alias;
            $1->partitionNameList = $6;
            $$ = $1;
        }
;

/*
 * 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;
				}
			| relation_expr  update_delete_partition_clause 			%prec UMINUS
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					$$ = $1;
				}
			| relation_expr update_delete_partition_clause ColId
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					Alias *alias = makeNode(Alias);
					alias->aliasname = $3;
					$1->alias = alias;
					$$ = $1;
				}
			| relation_expr update_delete_partition_clause AS ColId
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					Alias *alias = makeNode(Alias);
					alias->aliasname = $4;
					$1->alias = alias;
					$$ = $1;
				}
		;

/* used for multi delete stmt */
relation_expr_opt_alias_for_delete: relation_expr_for_delete					%prec UMINUS
				{
					$$ = $1;
				}
			| relation_expr_for_delete ColId
				{
					Alias *alias = makeNode(Alias);
					alias->aliasname = $2;
					$1->alias = alias;
					$$ = $1;
				}
			| relation_expr_for_delete AS ColId
				{
					Alias *alias = makeNode(Alias);
					alias->aliasname = $3;
					$1->alias = alias;
					$$ = $1;
				}
			| relation_expr_for_delete  update_delete_partition_clause 			%prec UMINUS
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					$$ = $1;
				}
			| relation_expr_for_delete update_delete_partition_clause ColId
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					Alias *alias = makeNode(Alias);
					alias->aliasname = $3;
					$1->alias = alias;
					$$ = $1;
				}
			| relation_expr_for_delete update_delete_partition_clause AS ColId
				{
					if ($2 != NULL) {
						$1->partitionname = $2->partitionname;
						$1->ispartition = $2->ispartition;
						$1->partitionKeyValuesList = $2->partitionKeyValuesList;
						$1->subpartitionname = $2->subpartitionname;
						$1->issubpartition = $2->issubpartition;
					}
					Alias *alias = makeNode(Alias);
					alias->aliasname = $4;
					$1->alias = alias;
					$$ = $1;
				}
		;

relation_expr_opt_alias_list: 
			delete_relation_expr_opt_alias                                      { $$ = list_make1($1); }
			| relation_expr_opt_alias_list ',' delete_relation_expr_opt_alias   { $$ = lappend($1, $3); }
		;
/*
 * TABLESAMPLE decoration in a FROM item
 */
tablesample_clause:
			TABLESAMPLE func_name '(' expr_list ')' opt_repeatable_clause
				{
					RangeTableSample *n = makeNode(RangeTableSample);
					/* n->relation will be filled in later */
					n->method = $2;
					n->args = $4;
					n->repeatable = $6;
					n->location = @2;
					$$ = (Node *) n;
				}
		;

/*
 * TIMECAPSULE decoration in a FROM item
 */
timecapsule_clause:
			TIMECAPSULE opt_timecapsule_clause { $$ = $2; }
		;

opt_timecapsule_clause:
			 CSN {u_sess->parser_cxt.isTimeCapsule = true;} a_expr
				{
					TcapFeatureEnsure();
					RangeTimeCapsule *n = makeNode(RangeTimeCapsule);
					n->tvtype = TV_VERSION_CSN;
					n->tvver = (Node *)$3;
					n->location = @3;
					$$ = (Node *) n;
				}
			| TIMESTAMP {u_sess->parser_cxt.isTimeCapsule = true;} a_expr
				{
					TcapFeatureEnsure();
					RangeTimeCapsule *n = makeNode(RangeTimeCapsule);
					n->tvtype = TV_VERSION_TIMESTAMP;
					n->tvver = (Node *)$3;
					n->location = @3;
					$$ = (Node *) n;
				}
		;

opt_repeatable_clause:
			REPEATABLE '(' a_expr ')'	{ $$ = (Node *) $3; }
			| /*EMPTY*/			{ $$ = NULL; }
		;


func_table: func_expr_windowless					{ $$ = $1; }
		| CURRENT_SCHEMA					{
			$$ = MakeNoArgFunctionCall(SystemFuncName("current_schema"), @1);
		}
		;


where_clause:
			WHERE a_expr							{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

/* variant for UPDATE and DELETE */
where_or_current_clause:
			WHERE a_expr							{ $$ = $2; }
			| WHERE CURRENT_P OF cursor_name
				{
					CurrentOfExpr *n = makeNode(CurrentOfExpr);
					/* cvarno is filled in by parse analysis */
					n->cursor_name = $4;
					n->cursor_param = 0;
					$$ = (Node *) n;
				}
			| /*EMPTY*/								{ $$ = NULL; }
		;


OptTableFuncElementList:
			TableFuncElementList				{ $$ = $1; }
			| /*EMPTY*/							{ $$ = NIL; }
		;

TableFuncElementList:
			TableFuncElement
				{
					$$ = list_make1($1);
				}
			| TableFuncElementList ',' TableFuncElement
				{
					$$ = lappend($1, $3);
				}
		;

TableFuncElement:	ColId func_type opt_collate_clause
				{
					ColumnDef *n = makeNode(ColumnDef);
					n->colname = $1;
					n->typname = $2;
					n->inhcount = 0;
					n->is_local = true;
					n->is_not_null = false;
					n->is_from_type = false;
					n->storage = 0;
					n->raw_default = NULL;
					n->cooked_default = NULL;
					n->collClause = (CollateClause *) $3;
					n->clientLogicColumnRef=NULL;
					n->collOid = InvalidOid;
					n->constraints = NIL;
					$$ = (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;
				}
			| SimpleTypename ARRAY
				{
					$$ = $1;
					$$->arrayBounds = list_make1(makeInteger(-1));
				}
			| SETOF SimpleTypename ARRAY
				{
					$$ = $2;
					$$->arrayBounds = list_make1(makeInteger(-1));
					$$->setof = TRUE;
				}
		;

opt_array_bounds:
			opt_array_bounds '[' ']'
					{  $$ = lappend($1, makeInteger(-1)); }
			| opt_array_bounds '[' Iconst ']'
					{  $$ = lappend($1, makeInteger($3)); }
			| /*EMPTY*/
					{  $$ = NIL; }
		;

SimpleTypename:
			GenericType								{ $$ = $1; }
			| Numeric								{ $$ = $1; }
			| Bit									{ $$ = $1; }
			| Character								{ $$ = $1; }
			| ConstDatetime							{ $$ = $1; }
			| ConstSet								{ $$ = $1; }
			| ConstInterval opt_interval
				{
					$$ = $1;
					$$->typmods = $2;
				}
			| ConstInterval '(' Iconst ')' opt_interval
				{
					$$ = $1;
					if ($5 != NIL)
					{
						if (list_length($5) != 1) {
							const char* message = "interval precision specified twice";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("interval precision specified twice"),
									 parser_errposition(@1)));
						}
						$$->typmods = lappend($5, makeIntConst($3, @3));
					}
					else
						$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
												 makeIntConst($3, @3));
				}
		;

/* We have a separate ConstTypename to allow defaulting fixed-length
 * types such as CHAR() and BIT() to an unspecified length.
 * SQL9x requires that these default to a length of one, but this
 * makes no sense for constructs like CHAR 'hi' and BIT '0101',
 * where there is an obvious better choice to make.
 * Note that ConstInterval is not included here since it must
 * be pushed up higher in the rules to accommodate the postfix
 * options (e.g. INTERVAL '1' YEAR). Likewise, we have to handle
 * the generic-type-name case in AExprConst to avoid premature
 * reduce/reduce conflicts against function names.
 */
ConstTypename:
			Numeric									{ $$ = $1; }
			| ConstBit								{ $$ = $1; }
			| ConstCharacter						{ $$ = $1; }
			| ConstDatetime							{ $$ = $1; }
			| ConstSet								{ $$ = $1; }
		;

/*
 * GenericType covers all type names that don't have special syntax mandated
 * by the standard, including qualified names.  We also allow type modifiers.
 * To avoid parsing conflicts against function invocations, the modifiers
 * have to be shown as expr_list here, but parse analysis will only accept
 * constants for them.
 */
GenericType:
			type_function_name opt_type_modifiers
				{
					$$ = makeTypeName($1);
					$$->typmods = $2;
					$$->location = @1;
				}
			| type_function_name attrs opt_type_modifiers
				{
					$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
					$$->typmods = $3;
					$$->location = @1;
				}
		;

opt_type_modifiers: '(' expr_list ')'
					{
						$$ = $2;
						if(u_sess->hook_cxt.rewriteTypmodExprHook != NULL) {
							$$ = ((RewriteTypmodExprHookType)(u_sess->hook_cxt.rewriteTypmodExprHook))($2);
						}
					}
                    | '(' Iconst BYTE_P ')'         { $$ = list_make1(makeIntConst($2, @2)); }
                    | '(' Iconst CHAR_P ')'
                        {
                            if (t_thrd.proc->workingVersionNum >= CHARBYTE_SEMANTIC_VERSION_NUMBER)
                                $$ = list_make2(makeIntConst($2, @2), makeIntConst(1, -1));
                            else
                                $$ = list_make1(makeIntConst($2, @2));
                        }
                    | '(' Iconst CHARACTER ')'
                        {
                            if (t_thrd.proc->workingVersionNum >= CHARBYTE_SEMANTIC_VERSION_NUMBER)
                                $$ = list_make2(makeIntConst($2, @2), makeIntConst(1, -1));
                            else
                                $$ = list_make1(makeIntConst($2, @2));
                        }
					| /* EMPTY */					{ $$ = NIL; }
		;

/*
 * SQL92 numeric data types
 */
Numeric:	INT_P
				{
					$$ = SystemTypeName("int4");
					$$->location = @1;
				}
			| INTEGER opt_type_modifiers
				{
					if ($2 != NULL)
					{
						CheckTypmodScale($2, @2, yyscanner);
						$$ = SystemTypeName("numeric");
						$$->typmods = $2;
						$$->location = @1;
					}
					else
				{
					$$ = SystemTypeName("int4");
					$$->location = @1;
				}
				}
			| SMALLINT
				{
					$$ = SystemTypeName("int2");
					$$->location = @1;
				}
			| TINYINT
				{
					$$ = SystemTypeName("int1");
					$$->location = @1;
				}
			| BIGINT
				{
					$$ = SystemTypeName("int8");
					$$->location = @1;
				}
			| REAL
				{
					$$ = SystemTypeName("float4");
					$$->location = @1;
				}
			| FLOAT_P opt_float
				{
					$$ = $2;
					$$->location = @1;
				}
			| BINARY_DOUBLE
				{
					$$ = SystemTypeName("float8");
					$$->location = @1;
				}
			| BINARY_INTEGER
				{
					$$ = SystemTypeName("int4");
					$$->location = @1;
				}
			| DOUBLE_P PRECISION
				{
					$$ = SystemTypeName("float8");
					$$->location = @1;
				}
			| DECIMAL_P opt_type_modifiers
				{
					CheckTypmodScale($2, @2, yyscanner);
					$$ = SystemTypeName("numeric");
					$$->typmods = $2;
					$$->location = @1;
				}
			| NUMBER_P opt_type_modifiers
				{
					CheckTypmodScale($2, @2, yyscanner);
					$$ = SystemTypeName("numeric");
					$$->typmods = $2;
					$$->location = @1;
				}
			| DEC opt_type_modifiers
				{
					CheckTypmodScale($2, @2, yyscanner);
					$$ = SystemTypeName("numeric");
					$$->typmods = $2;
					$$->location = @1;
				}
			| NUMERIC opt_type_modifiers
				{
					CheckTypmodScale($2, @2, yyscanner);
					$$ = SystemTypeName("numeric");
					$$->typmods = $2;
					$$->location = @1;
				}
			| BOOLEAN_P
				{
					$$ = SystemTypeName("bool");
					$$->location = @1;
				}
		;

opt_float:	'(' Iconst ')'
				{
					/*
					 * Check FLOAT() precision limits assuming IEEE floating
					 * types - thomas 1997-09-18
					 */
					if ($2 < 1) {
						const char* message = "precision for type float must be at least 1 bit";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(ERROR,
								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
								 errmsg("precision for type float must be at least 1 bit"),
								 parser_errposition(@2)));
					}
					if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && FLOAT_AS_NUMERIC
					    && t_thrd.proc->workingVersionNum >= FLOAT_VERSION_NUMBER) {
						$$ = ParseFloatByExtentedPrecision($2, @2, yyscanner);
					} else {
						if ($2 <= 24)
							$$ = SystemTypeName("float4");
						else if ($2 <= 53)
							$$ = SystemTypeName("float8");
						else {
							const char* message = "precision for type float must be less than 54 bits";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(ERROR,
									(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
									errmsg("precision for type float must be less than 54 bits"),
									parser_errposition(@2)));
						}
					}
				}
			| /*EMPTY*/
				{
					if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && FLOAT_AS_NUMERIC 
						&& t_thrd.proc->workingVersionNum >= FLOAT_VERSION_NUMBER)
					{
						$$ = SystemTypeName("numeric");
						$$->typmods = list_make2(makeIntConst(126, -1), makeIntConst(-32768, -1));
					} else {
						$$ = SystemTypeName("float8");
					}		
				}
		;

/*
 * 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;
					$$->typmods = NIL;
				}
		;

BitWithLength:
			BIT opt_varying '(' expr_list ')'
				{
					char *typname;

					typname = (char *)($2 ? "varbit" : "bit");
					$$ = SystemTypeName(typname);
					$$->typmods = $4;
					$$->location = @1;
				}
		;

BitWithoutLength:
			BIT opt_varying
				{
					/* bit defaults to bit(1), varbit to no limit */
					if ($2)
					{
						$$ = SystemTypeName("varbit");
					}
					else
					{
						$$ = SystemTypeName("bit");
						$$->typmods = list_make1(makeIntConst(1, -1));
					}
					$$->location = @1;
				}
		;


/*
 * 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;
					$$->typmods = NIL;
				}
		;

CharacterWithLength:  character '(' Iconst opt_charbyte ')'
				{
					$$ = SystemTypeName($1);
					if ((t_thrd.proc->workingVersionNum >= CHARBYTE_SEMANTIC_VERSION_NUMBER) && $4)
					{
					    $$->typmods = list_make2(makeIntConst($3, @3), makeIntConst(1, -1));
					}
					else
					{
					    $$->typmods = list_make1(makeIntConst($3, @3));
					}
                    $$->location = @1;
				}
				| character_national '(' Iconst ')'
				{
				    $$ = SystemTypeName($1);
                    $$->typmods = list_make1(makeIntConst($3, @3));
                    $$->location = @1;
				}
		;

opt_charbyte: CHAR_P	{ $$ = TRUE; }
             | CHARACTER { $$ = TRUE; }
             | BYTE_P    { $$ = FALSE; }
             | /* EMPTY */
             {
                 if (u_sess->attr.attr_common.nls_length_semantics == LENGTH_SEMANTIC_CHAR )
                 {
                     $$ = TRUE;
                 }
                 else
                 {
                     $$ = FALSE;
                 }
             }
         ;

CharacterWithoutLength:	 character
				{
					$$ = SystemTypeName($1);

					/* char defaults to char(1), varchar to no limit */
					if (strcmp($1, "bpchar") == 0)
						$$->typmods = list_make1(makeIntConst(1, -1));

					$$->location = @1;
				}
				| character_national
				{
				    $$ = SystemTypeName($1);

                    /* char defaults to char(1), varchar to no limit */
                    if (strcmp($1, "bpchar") == 0)
                    {
                        $$->typmods = list_make1(makeIntConst(1, -1));
                    }
				}
		;

character:	CHARACTER opt_varying
										{ $$ = (char *)($2 ? "varchar": "bpchar"); }
			| CHAR_P opt_varying
										{ $$ = (char *)($2 ? "varchar": "bpchar"); }
			| VARCHAR
										{ $$ = "varchar"; }
			| VARCHAR2
										{ $$ = "varchar"; }
		;

character_national:	 NVARCHAR
										{ $$ = "nvarchar2"; }
			| NVARCHAR2
										{ $$ = "nvarchar2"; }
			| NATIONAL CHARACTER opt_varying
										{ $$ = (char *)($3 ? "varchar": "bpchar"); }
			| NATIONAL CHAR_P opt_varying
										{ $$ = (char *)($3 ? "varchar": "bpchar"); }
			| NCHAR opt_varying
										{ $$ = (char *)($2 ? "varchar": "bpchar"); }
		;

opt_varying:
			VARYING									{ $$ = TRUE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

character_set:
			CHARACTER SET
			| CHARSET
		;

charset_collate_name:
			ColId									{ $$ = $1; }
			| BINARY								{ $$ = "binary"; }
			| Sconst								{ $$ = $1; }
		;

charset:
			character_set charset_collate_name
			{
#ifdef ENABLE_MULTIPLE_NODES
				const char* message = "specifying character sets and collations is not yet supported";
				InsertErrorMessage(message, u_sess->plsql_cxt.gsplsql_yylloc);
				ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("specifying character sets and collations is not yet supported")));
#endif
				if (!DB_IS_CMPT_BD) {
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("specifying character sets and collations is supported only in B-format database")));
				}
				int encoding = pg_valid_server_encoding($2);
				if (encoding < 0)
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("%s is not a valid encoding name", $2),
						parser_errposition(@2)));			
				$$ = encoding;
			}
		;

convert_charset:
			charset
			{
				$$ = $1;
			}
			| character_set DEFAULT
			{
#ifdef ENABLE_MULTIPLE_NODES
				const char* message = "specifying character sets and collations is not yet supported";
				InsertErrorMessage(message, u_sess->plsql_cxt.gsplsql_yylloc);
				ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("specifying character sets and collations is not yet supported")));
#endif
				if (!DB_IS_CMPT_BD) {
					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("specifying character sets and collations is supported only in B-format or D-format database")));
				}
				$$ = PG_INVALID_ENCODING;
			}
		;

opt_charset:
			charset
			{
				$$ = $1;
			}
			| /*EMPTY*/
			{
				$$ = PG_INVALID_ENCODING;
			}
		;

default_charset:
			DEFAULT character_set opt_equal charset_collate_name
			{
				int encoding = pg_valid_server_encoding($4);
				if (encoding < 0)			
					ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
						errmsg("%s is not a valid encoding name", $4),
						parser_errposition(@4)));
				$$ = encoding;
			}
			| character_set opt_equal charset_collate_name
			{
				int encoding = pg_valid_server_encoding($3);
				if (encoding < 0)	
					ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
						errmsg("%s is not a valid encoding name", $3),
						parser_errposition(@3)));
				$$ = encoding;
			}
		;

optCharsetCollate:
			CharsetCollate			{ $$ = $1; }
			| /* EMPTY */			{ $$ = NULL;}
		;

CharsetCollate:
			charset_collate
			{
				$$ = MakeCharsetCollateOptions(NULL, $1);
			}
			| CharsetCollate charset_collate
			{
				$$ = MakeCharsetCollateOptions($1, $2);
			}
		;

charset_collate:
			default_charset
			{
				CharsetCollateOptions *n = (CharsetCollateOptions*)palloc0(sizeof(CharsetCollateOptions));
				n->cctype = OPT_CHARSET;
				n->charset = $1;
				$$ = n;
			}
			| default_collate
			{
				CharsetCollateOptions *n = (CharsetCollateOptions*)palloc0(sizeof(CharsetCollateOptions));
				n->cctype = OPT_COLLATE;
				n->collate = $1;
				$$ = n;
			}
		;

/*
 * SQL92 date/time types
 */
ConstDatetime:
			TIMESTAMP '(' Iconst ')' opt_timezone
				{
					if ($5)
						$$ = SystemTypeName("timestamptz");
					else
						$$ = SystemTypeName("timestamp");
					$$->typmods = list_make1(makeIntConst($3, @3));
					$$->location = @1;
				}
			| TIMESTAMP opt_timezone
				{
					if ($2)
						$$ = SystemTypeName("timestamptz");
					else
						$$ = SystemTypeName("timestamp");
					$$->location = @1;
				}
			| TIME '(' Iconst ')' opt_timezone
				{
					if ($5)
						$$ = SystemTypeName("timetz");
					else
						$$ = SystemTypeName("time");
					$$->typmods = list_make1(makeIntConst($3, @3));
					$$->location = @1;
				}
			| TIME opt_timezone
				{
					if ($2)
						$$ = SystemTypeName("timetz");
					else
						$$ = SystemTypeName("time");
					$$->location = @1;
				}
			| DATE_P
				{
					if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT)
					{
						$$ = SystemTypeName("timestamp");
						$$->typmods = list_make1(makeIntConst(0,-1));
					}
					else
						$$ = SystemTypeName("date");
					$$->location = @1;
					$$->end_location = @1 + DATE_LEN;
				}
			| SMALLDATETIME
				{
					$$ = SystemTypeName("smalldatetime");
					$$->location = @1;
				}
		;

ConstSet:
            SET '(' opt_enum_val_list ')'
                {
#ifdef ENABLE_MULTIPLE_NODES
                    ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("set type is not yet supported."),
                        parser_errposition(@1)));
#else
                    if (!DB_IS_CMPT(B_FORMAT)) {
                        ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                            errmsg("set type is not yet supported."),
                            parser_errposition(@1)));
                    } else {
                        $$ = makeTypeName("set");
                        $$->typmods = $3;
                        $$->location = @1;
                    }
#endif
                }
        ;

ConstInterval:
			INTERVAL
				{
					$$ = SystemTypeName("interval");
					$$->location = @1;
				}
		;

opt_timezone:
			WITH_TIME ZONE							{ $$ = TRUE; }
			| WITHOUT TIME ZONE						{ $$ = FALSE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

opt_evtime_unit:
			DAY_HOUR_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR), @1));
			}
			| DAY_MINUTE_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
			}
			| DAY_SECOND_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE) |
												 INTERVAL_MASK(SECOND), @1));
			}
			| HOUR_MINUTE_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
			}
			| HOUR_SECOND_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE) |
												 INTERVAL_MASK(SECOND), @1));
			}
			| MINUTE_SECOND_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE) |
												 INTERVAL_MASK(SECOND), @1));
			}
			| YEAR_MONTH_P
			{
				$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
												 INTERVAL_MASK(MONTH), @1));
			}
			;

opt_interval:
			YEAR_P
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); }
			| MONTH_P
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); }
			| DAY_P
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1)); }
			| HOUR_P
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); }
			| MINUTE_P
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); }
			| interval_second
				{ $$ = $1; }
			| YEAR_P TO MONTH_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
												 INTERVAL_MASK(MONTH), @1));
				}
			| DAY_P TO HOUR_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR), @1));
				}
			| DAY_P TO MINUTE_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
				}
			| DAY_P TO interval_second
				{
					$$ = $3;
					linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
												INTERVAL_MASK(HOUR) |
												INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| HOUR_P TO MINUTE_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
				}
			| HOUR_P TO interval_second
				{
					$$ = $3;
					linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
												INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| MINUTE_P TO interval_second
				{
					$$ = $3;
					linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| YEAR_P '(' Iconst ')'
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); }
			| MONTH_P '(' Iconst ')'
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); }
			| DAY_P '(' Iconst ')'
				{  $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1));   }
			| HOUR_P '(' Iconst ')'
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); }
			| MINUTE_P '(' Iconst ')'
				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); }
			| YEAR_P '(' Iconst ')' TO MONTH_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
												 INTERVAL_MASK(MONTH), @1));
				}
			| DAY_P '(' Iconst ')'  TO HOUR_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR), @1));
				}
			| DAY_P '(' Iconst ')'   TO MINUTE_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
												 INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
				}
			| DAY_P '(' Iconst ')' TO interval_second
				{
					$$ = $6;
					linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
												INTERVAL_MASK(HOUR) |
												INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| HOUR_P '(' Iconst ')'  TO MINUTE_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
												 INTERVAL_MASK(MINUTE), @1));
				}
			| HOUR_P '(' Iconst ')'   TO interval_second
				{
					$$ = $6;
					linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
												INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| MINUTE_P  '(' Iconst ')'  TO interval_second
				{
					$$ = $6;
					linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
												INTERVAL_MASK(SECOND), @1);
				}
			| /*EMPTY*/
				{ $$ = NIL; }
		;

interval_second:
			SECOND_P
				{
					$$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1));
				}
			| SECOND_P '(' Iconst ')'
				{
					$$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1),
									makeIntConst($3, @3));
				}
		;

client_logic_type:
			BYTEAWITHOUTORDER
			{
					$$ = SystemTypeName("byteawithoutordercol");
					$$->location = @1;
			}
			| BYTEAWITHOUTORDERWITHEQUAL
			{
					$$ = SystemTypeName("byteawithoutorderwithequalcol");
					$$->location = @1;
			}
		;

/*****************************************************************************
 *
 *	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; }
			| PRIOR '(' a_expr ')'
                                {
                                    List *argList = list_make1($3);
                                    FuncCall *funcNode = MakePriorAsFunc();
                                    funcNode->args = argList;
                                    $$ = (Node *)funcNode;
                                }
			| a_expr TYPECAST Typename
					{ $$ = makeTypeCast($1, $3, NULL, NULL, NULL, @2); }
			| a_expr COLLATE collate_name
				{
					CollateClause *n = makeNode(CollateClause);
					n->arg = $1;
					n->collname = $3;
					n->location = @2;
					$$ = (Node *) n;
				}
			| a_expr AT TIME ZONE a_expr			%prec AT
				{
					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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) n;
				}
		/*
		 * These operators must be called out explicitly in order to make use
		 * of bison's automatic operator-precedence handling.  All other
		 * operator names are handled by the generic productions using "Op",
		 * below; and all those operators will have the same precedence.
		 *
		 * If you add more explicitly-known operators, be sure to add them
		 * also to b_expr and to the MathOp list above.
		 */
			| '+' a_expr					%prec UMINUS
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
			| '-' a_expr					%prec UMINUS
				{ $$ = doNegate($2, @1); }
			| '@' a_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", NULL, $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 '@' a_expr
                                { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", $1, $3, @2); }
			| a_expr CmpNullOp a_expr    %prec IS
				{
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
							NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $3, @2), @2);
					}
					else
					{
						const char* message = "<=> operator is supported only in B-format database";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
                                                                 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                 errmsg("<=> operator is supported only in B-format database"),
                                                                 parser_errposition(@2)));
						$$ = NULL;/* not reached */
					}
				}
			| uservar_name COLON_EQUALS a_expr
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "@var_name := expr is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("@var_name := expr is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						u_sess->parser_cxt.has_equal_uservar = true;
						UserSetElem *n = makeNode(UserSetElem);
						n->name = list_make1((Node *)$1);
						n->val = (Expr *)$3;
						$$ = (Node *) n;
					} else {
						const char* message = "@var_name := expr is supported only in B-format database, and enable_set_variable_b_format = on.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("@var_name := expr is supported only in the SET syntax of B-format database, and enable_set_variable_b_format = on."),
								parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
				}
            | a_expr CmpOp a_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, $2, $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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
				}
			| a_expr NOT_LIKE a_expr	%prec NOT_LIKE
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $3, @2); }
			| a_expr NOT_LIKE a_expr ESCAPE a_expr		%prec NOT_LIKE
				{
					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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
				}
			| a_expr NOT_ILIKE a_expr	%prec NOT_ILIKE
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $3, @2); }
			| a_expr NOT_ILIKE a_expr ESCAPE a_expr		%prec NOT_ILIKE
				{
					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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
				}

			| a_expr SIMILAR TO a_expr				%prec SIMILAR
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("similar_escape");
					n->args = list_make2($4, makeNullAConst(-1));
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
				}
			| a_expr NOT_SIMILAR TO a_expr			%prec NOT_SIMILAR
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("similar_escape");
					n->args = list_make2($4, makeNullAConst(-1));
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
				}
			| a_expr NOT_SIMILAR TO a_expr ESCAPE a_expr	%prec NOT_SIMILAR
				{
					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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (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							%prec IS
				{
					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						%prec IS
				{
					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;
				}
			| a_expr IS NAN_P
			    {
					NanTest *n = makeNode(NanTest);
					n->arg = (Expr *) makeTypeCast($1, SystemTypeName("float8"), NULL, NULL, NULL, @1);
					n->nantesttype = IS_NAN;
					$$ = (Node *)n;
				}
			| a_expr IS NOT NAN_P
			    {
					NanTest *n = makeNode(NanTest);
					n->arg = (Expr *) makeTypeCast($1, SystemTypeName("float8"), NULL, NULL, NULL, @1);
					n->nantesttype = IS_NOT_NAN;
					$$ = (Node *)n;
				}
			| a_expr IS INFINITE_P
			    {
					InfiniteTest *n = makeNode(InfiniteTest);
					n->arg = (Expr *) makeTypeCast($1, SystemTypeName("float8"), NULL, NULL, NULL, @1);
					n->infinitetesttype = IS_INFINITE;
					$$ = (Node *)n;
				}
			| a_expr IS NOT INFINITE_P
			    {
					InfiniteTest *n = makeNode(InfiniteTest);
					n->arg = (Expr *) makeTypeCast($1, SystemTypeName("float8"), NULL, NULL, NULL, @1);
					n->infinitetesttype = IS_NOT_INFINITE;
					$$ = (Node *)n;
				}
			| row OVERLAPS row
				{
					/* Create and populate a FuncCall node to support the OVERLAPS operator. */
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("overlaps");
					if (list_length($1) != 2) {
						const char* message = "wrong number of parameters on left side of OVERLAPS expression";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("wrong number of parameters on left side of OVERLAPS expression"),
								parser_errposition(@1)));
					}
					if (list_length($3) != 2) {
						const char* message = "wrong number of parameters on left side of OVERLAPS expression";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("wrong number of parameters on right side of OVERLAPS expression"),
								parser_errposition(@3)));
					}
					n->args = list_concat($1, $3);
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @2;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| a_expr IS TRUE_P							%prec IS
				{
					BooleanTest *b = makeNode(BooleanTest);
					b->arg = (Expr *) $1;
					b->booltesttype = IS_TRUE;
					$$ = (Node *)b;
				}
			| a_expr IS NOT TRUE_P						%prec IS
				{
					BooleanTest *b = makeNode(BooleanTest);
					b->arg = (Expr *) $1;
					b->booltesttype = IS_NOT_TRUE;
					$$ = (Node *)b;
				}
			| a_expr IS FALSE_P							%prec IS
				{
					BooleanTest *b = makeNode(BooleanTest);
					b->arg = (Expr *) $1;
					b->booltesttype = IS_FALSE;
					$$ = (Node *)b;
				}
			| a_expr IS NOT FALSE_P						%prec IS
				{
					BooleanTest *b = makeNode(BooleanTest);
					b->arg = (Expr *) $1;
					b->booltesttype = IS_NOT_FALSE;
					$$ = (Node *)b;
				}
			| a_expr IS UNKNOWN							%prec IS
				{
					BooleanTest *b = makeNode(BooleanTest);
					b->arg = (Expr *) $1;
					b->booltesttype = IS_UNKNOWN;
					$$ = (Node *)b;
				}
			| a_expr IS NOT UNKNOWN						%prec IS
				{
					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 NOT_BETWEEN
				{
					$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
						(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $4, @2),
						(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $6, @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 NOT_BETWEEN
				{
					$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
						(Node *) makeA_Expr(AEXPR_OR, NIL,
							(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $4, @2),
							(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $6, @2),
											@2),
						(Node *) makeA_Expr(AEXPR_OR, NIL,
							(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $6, @2),
							(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $4, @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 in_expr		%prec NOT_IN
				{
					/* in_expr returns a SubLink or a list of a_exprs */
					if (IsA($3, SubLink))
					{
						/* generate NOT (foo = ANY (subquery)) */
						/* Make an = ANY node */
						SubLink *n = (SubLink *) $3;
						n->subLinkType = ANY_SUBLINK;
						n->testexpr = $1;
						n->operName = list_make1(makeString("="));
						n->location = @2;
						/* 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, $3, @2);
					}
				}
			| a_expr subquery_Op sub_type select_with_parens	%prec Op
				{
					SubLink *n = makeNode(SubLink);
					n->subLinkType = (SubLinkType)$3;
					n->testexpr = $1;
					n->operName = $2;
					n->subselect = $4;
					n->location = @2;
					$$ = (Node *)n;
				}
			| a_expr subquery_Op sub_type '(' a_expr ')'		%prec Op
				{
					if ($3 == ANY_SUBLINK)
						$$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
					else
						$$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
				}
			| UNIQUE select_with_parens
				{
					/* Not sure how to get rid of the parentheses
					 * but there are lots of shift/reduce errors without them.
					 *
					 * Should be able to implement this by plopping the entire
					 * select into a node, then transforming the target expressions
					 * from whatever they are into count(*), and testing the
					 * entire result equal to one.
					 * But, will probably implement a separate node in the executor.
					 */
					const char* message = "UNIQUE predicate is not yet implemented";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							 errmsg("UNIQUE predicate is not yet implemented"),
							 parser_errposition(@1)));
				}
			| a_expr IS DOCUMENT_P					%prec IS
				{
					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
									 list_make1($1), @2);
				}
			| a_expr IS NOT DOCUMENT_P				%prec IS
				{
					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
														 list_make1($1), @2),
											 @2);
				}
			| PREDICT BY ColId '(' FEATURES func_arg_list ')'
				{
					PredictByFunction * n = makeNode(PredictByFunction);
					n->model_name = $3;
					n->model_name_location = @3;
					n->model_args = $6;	
					n->model_args_location = @6;
					$$ = (Node*) n;				
				}
		;

/*
 * Restricted expressions
 *
 * b_expr is a subset of the complete expression syntax defined by a_expr.
 *
 * Presently, AND, NOT, IS, and IN are the a_expr keywords that would
 * cause trouble in the places where b_expr is used.  For simplicity, we
 * just eliminate all the boolean-keyword-operator productions from b_expr.
 */
b_expr:		c_expr
				{ $$ = $1; }
			| b_expr TYPECAST Typename
				{ $$ = makeTypeCast($1, $3, NULL, NULL, NULL, @2); }
			| '+' b_expr					%prec UMINUS
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
			| '-' b_expr					%prec UMINUS
				{ $$ = doNegate($2, @1); }
			| '@' b_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", NULL, $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 '@' b_expr
                                { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "@", $1, $3, @2); }
			| b_expr CmpOp b_expr
				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, $2, $1, $3, @2); }
			| b_expr qual_Op b_expr				%prec Op
				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
			| b_expr CmpNullOp b_expr    %prec IS
				{
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
							NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $3, @2), @2);
					}
					else
					{
						const char* message = "<=> operator is supported only in B-format database";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
                                                                 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                 errmsg("<=> operator is supported only in B-format database"),
                                                                 parser_errposition(@2)));
						$$ = NULL;/* not reached */
					}
				}
			| 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);
				}
			| b_expr IS DOCUMENT_P					%prec IS
				{
					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
									 list_make1($1), @2);
				}
			| b_expr IS NOT DOCUMENT_P				%prec IS
				{
					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
														 list_make1($1), @2),
											 @2);
				}
		;

/*
 * Productions that can be used in both a_expr and b_expr.
 *
 * Note: productions that refer recursively to a_expr or b_expr mostly
 * cannot appear here.	However, it's OK to refer to a_exprs that occur
 * inside parentheses, such as function arguments; that cannot introduce
 * ambiguity to the b_expr syntax.
 */
c_expr:		columnref %prec UMINUS						        { $$ = $1; }
			| AexprConst							{ $$ = $1; }
                        | PRIOR '(' columnref ')'
                                {
                                    ColumnRef *col = (ColumnRef *)$3;
                                    col->prior = true;
                                    /*
                                     * Setting the location to a non-default 0
                                     * to indicate that this is a parenthetical
                                     * case of PRIOR reference.
                                     */
                                    col->location = 0;
                                    $$ = (Node *)col;
                                }
                        | PRIOR '(' c_expr ',' func_arg_list ')'
                                {
                                    List* argList = list_concat(list_make1($3), $5);
                                    FuncCall* funcNode = MakePriorAsFunc();
                                    funcNode->args = argList;
                                    $$ = (Node *)funcNode;
                                }
		        | PRIOR columnref
		                {
		                    ColumnRef *n = (ColumnRef *)$2;
		                    n->prior = true;
		                    $$ = (Node *)n;
		                }
			| PARAM opt_indirection
				{
					if (u_sess->parser_cxt.is_load_copy == false) {
						ParamRef *p = makeNode(ParamRef);
						p->number = $1;
						p->location = @1;
						if ($2)
						{
							A_Indirection *n = makeNode(A_Indirection);
							n->arg = (Node *) p;
							n->indirection = check_indirection($2, yyscanner);
							$$ = (Node *) n;
						}
						else
							$$ = (Node *) p;
#ifndef ENABLE_MULTIPLE_NODES
					} 
					else {
						char *colname = u_sess->parser_cxt.copy_fieldname;
						if (CheckWhetherInColList(colname, u_sess->parser_cxt.col_list) == true) {
							$$ = makeColumnRef(colname, NIL, @1, yyscanner);
						} else {
							ereport(errstate,
									(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
									 errmsg("Col \"%s\" is not in the col list", colname),
									 parser_errposition(@1)));
						}
#endif
					}
				}
			| '(' a_expr ')' opt_indirection
				{
					if ($4)
					{
						A_Indirection *n = makeNode(A_Indirection);
						n->arg = $2;
						n->indirection = check_indirection($4, yyscanner);
						$$ = (Node *)n;
					}
					else
						$$ = $2;
				}
			| case_expr
				{ $$ = $1; }
			| func_expr
				{ $$ = $1; }
			| select_with_parens			%prec UMINUS
				{
					SubLink *n = makeNode(SubLink);
					n->subLinkType = EXPR_SUBLINK;
					n->testexpr = NULL;
					n->operName = NIL;
					n->subselect = $1;
					n->location = @1;
					$$ = (Node *)n;
				}
			| select_with_parens indirection
				{
					/*
					 * Because the select_with_parens nonterminal is designed
					 * to "eat" as many levels of parens as possible, the
					 * '(' a_expr ')' opt_indirection production above will
					 * fail to match a sub-SELECT with indirection decoration;
					 * the sub-SELECT won't be regarded as an a_expr as long
					 * as there are parens around it.  To support applying
					 * subscripting or field selection to a sub-SELECT result,
					 * we need this redundant-looking production.
					 */
					SubLink *n = makeNode(SubLink);
					A_Indirection *a = makeNode(A_Indirection);
					n->subLinkType = EXPR_SUBLINK;
					n->testexpr = NULL;
					n->operName = NIL;
					n->subselect = $1;
					n->location = @1;
					a->arg = (Node *)n;
					a->indirection = check_indirection($2, yyscanner);
					$$ = (Node *)a;
				}
			| EXISTS select_with_parens
				{
					SubLink *n = makeNode(SubLink);
					n->subLinkType = EXISTS_SUBLINK;
					n->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
				{
					A_ArrayExpr *n = (A_ArrayExpr *) $2;
					AssertEreport(IsA(n, A_ArrayExpr),
									MOD_OPT,
									"Node type inconsistant");
					/* point outermost A_ArrayExpr to the ARRAY keyword */
					n->location = @1;
					$$ = (Node *)n;
				}
			| explicit_row
				{
					RowExpr *r = makeNode(RowExpr);
					r->args = $1;
					r->row_typeid = InvalidOid;	/* not analyzed yet */
					r->colnames = NIL;	/* to be filled in during analysis */
					r->row_format = COERCE_EXPLICIT_CALL; /* abuse */
					r->location = @1;
					$$ = (Node *)r;
				}
			| implicit_row
				{
					RowExpr *r = makeNode(RowExpr);
					r->args = $1;
					r->row_typeid = InvalidOid;	/* not analyzed yet */
					r->colnames = NIL;	/* to be filled in during analysis */
					r->row_format = COERCE_IMPLICIT_CAST; /* abuse */
					r->location = @1;
					$$ = (Node *)r;
				}
			| GROUPING_P '(' expr_list ')'
			  {
				  GroupingFunc *g = makeNode(GroupingFunc);
				  g->args = $3;
				  g->location = @1;
				  $$ = (Node *)g;
			  }
			| uservar_name           %prec UMINUS
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "@var_name is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("@var_name is not yet supported in distributed database.")));
#endif
					if (DB_IS_CMPT(B_FORMAT) && (u_sess->attr.attr_common.enable_set_variable_b_format || ENABLE_SET_VARIABLES)) {
						$$ = $1;
					} else {
						const char* message = "@var_name is supported only in B-format database, and enable_set_variable_b_format = on.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errmodule(MOD_PARSER),
								errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("@var_name is supported only in B-format database, and enable_set_variable_b_format = on."),
								parser_errposition(@1)));
						$$ = NULL;/* not reached */
					}
				}
			| set_ident_expr
				{
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "@@config_parameter is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("@@config_parameter is not yet supported in distributed database.")));
#endif
					$$ = $1;
				}
		;


/* Used for List Distribution to avoid reduce/reduce conflict. This is unavoidable, since Bison is LALR(1) compiler */
c_expr_noparen:		columnref								{ $$ = $1; }
			| AexprConst							{ $$ = $1; }
			| PARAM opt_indirection
				{
					ParamRef *p = makeNode(ParamRef);
					p->number = $1;
					p->location = @1;
					if ($2)
					{
						A_Indirection *n = makeNode(A_Indirection);
						n->arg = (Node *) p;
						n->indirection = check_indirection($2, yyscanner);
						$$ = (Node *) n;
					}
					else
						$$ = (Node *) p;
				}
			| case_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;
				}
			| select_with_parens indirection
				{
					/*
					 * Because the select_with_parens nonterminal is designed
					 * to "eat" as many levels of parens as possible, the
					 * '(' a_expr ')' opt_indirection production above will
					 * fail to match a sub-SELECT with indirection decoration;
					 * the sub-SELECT won't be regarded as an a_expr as long
					 * as there are parens around it.  To support applying
					 * subscripting or field selection to a sub-SELECT result,
					 * we need this redundant-looking production.
					 */
					SubLink *n = makeNode(SubLink);
					A_Indirection *a = makeNode(A_Indirection);
					n->subLinkType = EXPR_SUBLINK;
					n->testexpr = NULL;
					n->operName = NIL;
					n->subselect = $1;
					n->location = @1;
					a->arg = (Node *)n;
					a->indirection = check_indirection($2, yyscanner);
					$$ = (Node *)a;
				}
			| EXISTS select_with_parens
				{
					SubLink *n = makeNode(SubLink);
					n->subLinkType = EXISTS_SUBLINK;
					n->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
				{
					A_ArrayExpr *n = (A_ArrayExpr *) $2;
					AssertEreport(IsA(n, A_ArrayExpr),
									MOD_OPT,
									"Node type inconsistant");
					/* point outermost A_ArrayExpr to the ARRAY keyword */
					n->location = @1;
					$$ = (Node *)n;
				}
			| explicit_row
				{
					RowExpr *r = makeNode(RowExpr);
					r->args = $1;
					r->row_typeid = InvalidOid;	/* not analyzed yet */
					r->colnames = NIL;	/* to be filled in during analysis */
					r->row_format = COERCE_EXPLICIT_CALL; /* abuse */
					r->location = @1;
					$$ = (Node *)r;
				}
			| GROUPING_P '(' expr_list ')'
			  {
				  GroupingFunc *g = makeNode(GroupingFunc);
				  g->args = $3;
				  g->location = @1;
				  $$ = (Node *)g;
			  }
		;



/*
 * func_expr and its cousin func_expr_windowless are 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 places like "FROM functions()" or the
 * backwards-compatible functional-index syntax for CREATE INDEX.
 * (Note that many of the special SQL functions wouldn't actually make any
 * sense as functional index entries, but we ignore that consideration here.)
 */
func_expr:	func_application within_group_clause filter_clause keep_clause opt_over_clause
				{
					FuncCall *n = (FuncCall *) $1;

					/*
					 * We currently only use listagg function with WITHIN GROUP. Besides, this function
					 * has up to 2 parameters and cannot use DISTINCT, VARIADIC and ORDER BY clauses.
					 */
					if (pg_strcasecmp(strVal(linitial(n->funcname)), "listagg") == 0)
					{
						if ($2 == NIL)
						{
							const char* message = "missing WITHIN keyword.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
								(errcode(ERRCODE_SYNTAX_ERROR),
								 errmsg("missing WITHIN keyword."),
								 parser_errposition(@2)));
						}
						else
						{
							if (n->agg_order != NIL)
							{
								const char* message = "cannot use multiple ORDER BY clauses with WITHIN GROUP.";
								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use multiple ORDER BY clauses with WITHIN GROUP."),
									 parser_errposition(@2)));
							}
							if (n->agg_distinct)
							{
								const char* message = "cannot use DISTINCT with WITHIN GROUP.";
								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use DISTINCT with WITHIN GROUP."),
									 parser_errposition(@2)));
							}
							if (n->func_variadic)
							{
								const char* message = "cannot use VARIADIC with WITHIN GROUP.";
								InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
								ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use VARIADIC with WITHIN GROUP."),
									 parser_errposition(@2)));
							}
						}
						n->agg_order = $2;
						if ($4 != NULL)
						{
							const char* message = "KEEP for this function is not supported.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("KEEP for this function is not supported."),
								 parser_errposition(@2)));
						}
						WindowDef *wd = (WindowDef*) $5;
						if (wd != NULL)
							wd->frameOptions = FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS | 
												FRAMEOPTION_START_UNBOUNDED_PRECEDING |
												(FRAMEOPTION_START_UNBOUNDED_FOLLOWING << 1) | 
												FRAMEOPTION_BETWEEN;
						n->over = wd;
					}
					else if ($2 != NIL)
					{
						if (n->agg_order != NIL) {
							const char* message = "cannot use multiple ORDER BY clauses with WITHIN GROUP";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use multiple ORDER BY clauses with WITHIN GROUP"),
									 parser_errposition(@2)));
						}
						if (n->agg_distinct) {
							const char* message = "cannot use DISTINCT with WITHIN GROUP.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use DISTINCT with WITHIN GROUP"),
									 parser_errposition(@2)));
						}
						if (n->func_variadic) {
							const char* message = "cannot use VARIADIC with WITHIN GROUP.";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("cannot use VARIADIC with WITHIN GROUP"),
									 parser_errposition(@2)));
						}
						n->agg_order = $2;
						n->agg_within_group = TRUE;
						n->agg_filter = $3;
						n->over = $5;
						$$ = (Node *) n;
					}
					else
					{
						n->agg_filter = $3;
                                                n->aggKeep = $4;
                                                if ($4 !=  NULL &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "MIN") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "MAX") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "SUM") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "AVG") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "COUNT") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "VARIANCE") != 0 &&
                                                        pg_strcasecmp(strVal(linitial(n->funcname)), "STDDEV") != 0)
                                                {
                                                        const char* message = "KEEP for this function is not supported.";
                                                        InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
                                                        ereport(errstate,
                                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                         errmsg("KEEP for this function is not supported."),
                                                                         parser_errposition(@2)));
                                                }
						n->over = $5;

					}
					if (pg_strcasecmp(strVal(linitial(n->funcname)), "group_concat") == 0)
					{
#ifdef			ENABLE_MULTIPLE_NODES
						const char* message = "group_concat is not yet supported in distributed database.";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								errmsg("group_concat is not yet supported in distributed database.")));
#endif
						WindowDef *wd = (WindowDef*) $5;
						if (wd != NULL) {
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("group_concat does not support window function"),
									 parser_errposition(@1)));
						}
						n->args = lappend3(list_make1(makeStringConst(",", n->location)), n->args);
					}
				}
			| func_with_separator
				{ 
#ifdef			ENABLE_MULTIPLE_NODES
					const char* message = "group_concat is not yet supported in distributed database.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);			
					ereport(errstate,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("group_concat is not yet supported in distributed database.")));
#endif
					$$ = $1; 
				}
			| func_expr_common_subexpr
				{ $$ = $1; }
			| CURRENT_SCHEMA
				{
					$$ = MakeNoArgFunctionCall(SystemFuncName("current_schema"), @1);
				}
			| analytic_func_expr
				{ $$ = $1; }
		;
opt_over_clause:
			over_clause				{ $$ = $1; }
			| /*EMPTY*/				{ $$ = NULL; }
		;
analytic_func_expr:
 NTH_VALUE_P '(' func_arg_list ')' fromLast ignNulls over_clause
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("nth_value");
					n->args = $3;
					n->is_from_last = $5;
					n->is_ignore_nulls = $6;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = $7;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			|  NTH_VALUE_P '(' func_arg_list ')' fromLast over_clause
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("nth_value");
					n->args = $3;
					n->is_from_last = $5;
					n->is_ignore_nulls = FALSE;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = $6;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			|  NTH_VALUE_P '(' func_arg_list ')' ignNulls over_clause
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("nth_value");
					n->args = $3;
					n->is_from_last = FALSE;
					n->is_ignore_nulls = $5;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = $6;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			|  NTH_VALUE_P '(' func_arg_list ')' over_clause
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("nth_value");
					n->args = $3;
					n->is_from_last = FALSE;
					n->is_ignore_nulls = FALSE;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = $5;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			;
fromLast:	 FROM FIRST_P
			{
				$$ = false;
			}
		| FROM LAST_P
			{
				$$ = true;
			}
		;
ignNulls: 	IGNORE NULLS_P
			{
				$$ = true;
			}
		| RESPECT_P NULLS_P
			{
				$$ = false;
			}
		;

func_application:	func_name '(' func_arg_list opt_sort_clause ')'
				{
					FuncCall *n = makeNode(FuncCall);
					ListCell* l = list_head($1);
					n->funcname = $1;
					n->args = $3;
					n->agg_order = $4;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					Node* name = (Node*)lfirst(l);
					if (IsA(name, String) && (strcmp(strVal(name), "gms_lob") == 0)) {
						ListCell* lc = list_head($3);
						Node* n1  = (Node*)lfirst(lc);
						if (IsA(n1, ColumnRef)) {
							char* lobname = lobname = strVal(linitial(((ColumnRef*)n1)->fields));
							Node* funcname = (Node*)lfirst(list_tail($1));
							if (strcmp(strVal(funcname), "createtemporary") == 0) {
								if (list_length($4) == 2) {
									n->args = lappend(n->args, makeIntConst(10, -1));
								};
							}
							if (strcmp(strVal(funcname), "getlength") != 0) {
								n->args = lappend(n->args, makeStringConst(lobname, -1));
							}
						} else if (IsA(n1, NamedArgExpr)) {
							Node* n2 = ((Node*)((NamedArgExpr*)n1)->arg);
							if (IsA(n2, ColumnRef)) {
								char* lobname = strVal(linitial(((ColumnRef*)$1)->fields));
								Node* funcname = (Node*)lfirst(list_tail($1));
								if (strcmp(strVal(funcname), "createtemporary") == 0) {
									if (list_length(n->args) == 2) {
										n->args = lappend(n->args, makeIntConst(10, -1));
									}
								}
								NamedArgExpr *na = makeNode(NamedArgExpr);
								na->name = pstrdup("lobname");
								na->arg = (Expr *)makeStringConst(lobname, -1);
								na->argnumber = -1;		/* until determined */
								na->location = @1;
								n->args = lappend(n->args, (Node *) na);
							}
						}
					}
					$$ = (Node *)n;
				}
			| func_application_special { $$ = $1; }
		;

func_application_special:	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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| func_name '(' func_arg_list DEFAULT func_arg_expr ON CONVERSION_P ERROR_P ')'
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT) {
						ereport(ERROR,
						       (errcode(ERRCODE_SYNTAX_ERROR),
							   errmsg("The syntax or function is not supported. \"%s\"", $4)));
					}

					FuncCall *n = makeNode(FuncCall);
                    n->funcname = $1;

                    n->args = lappend($3, $5);
					// is DEFAULT gramy
					n->args = lappend(n->args, makeBoolAConst(TRUE, -1));
					// default expr is column ref
					bool is_column_ref = false; 
					contain_unsupport_node($5, &is_column_ref);
					n->args = lappend(n->args, makeBoolAConst(is_column_ref, -1));
					// fmt constraints is NULL
                    n->args = lappend(n->args, makeNullAConst(-1));
					// nls param constraints is NULL
                    n->args = lappend(n->args, makeNullAConst(-1));

					n->agg_order = NIL;
                    n->agg_star = FALSE;
                    n->agg_distinct = FALSE;
                    n->func_variadic = FALSE;
                    n->over = NULL;
                    n->location = @1;
                    n->call_func = false;
                    $$ = (Node *) n;
				}
			| func_name '(' func_arg_list DEFAULT func_arg_expr ON CONVERSION_P ERROR_P opt_default_fmt_clause ')'
				{
					if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT) {
						ereport(ERROR,
						       (errcode(ERRCODE_SYNTAX_ERROR),
							   errmsg("The syntax or function is not supported. \"%s\"", $4)));
					}

					FuncCall *n = makeNode(FuncCall);
                    n->funcname = $1;

					// args:
					//   input_expr, default_val,
					//   is DEFAULT gramy, default expr is column ref,
					//   fmt constraints, nls param constraints
                    n->args = lappend($3, $5);
					// is DEFAULT gramy
					n->args = lappend(n->args, makeBoolAConst(TRUE, -1));
					// default expr is column ref
					bool is_column_ref = false; 
					contain_unsupport_node($5, &is_column_ref);
					n->args = lappend(n->args, makeBoolAConst(is_column_ref, -1));
					// There may be fmt constraints
                    n->args = lappend(n->args, $9);
					// nls param constraints is NULL
                    n->args = lappend(n->args, makeNullAConst(-1));

					n->agg_order = NIL;
                    n->agg_star = FALSE;
                    n->agg_distinct = FALSE;
                    n->func_variadic = FALSE;
                    n->over = NULL;
                    n->location = @1;
                    n->call_func = false;
                    $$ = (Node *) n;
				}
			| func_name '(' func_arg_list DEFAULT func_arg_expr ON CONVERSION_P ERROR_P opt_default_fmt_clause opt_default_nls_clause ')'
				{
					FuncCall *n = makeNode(FuncCall);
                    n->funcname = $1;

					// args: 
					//   input_expr, default_val,
					//   is DEFAULT gramy, default expr is column ref,
					//   fmt constraints, nls param constraints
                    n->args = lappend($3, $5);
					// is DEFAULT gramy
					n->args = lappend(n->args, makeBoolAConst(TRUE, -1));
					// default expr is column ref
					bool is_column_ref = false; 
					contain_unsupport_node($5, &is_column_ref);
					n->args = lappend(n->args, makeBoolAConst(is_column_ref, -1));
					// There may be fmt constraints
                    n->args = lappend(n->args, $9);
					// nls param constraints is NULL
                    n->args = lappend(n->args, $10);
					
					n->agg_order = NIL;
                    n->agg_star = FALSE;
                    n->agg_distinct = FALSE;
                    n->func_variadic = FALSE;
                    n->over = NULL;
                    n->location = @1;
                    n->call_func = false;
                    $$ = (Node *) n;
				}
			| func_name '(' VARIADIC func_arg_expr opt_sort_clause ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = $1;
					n->args = list_make1($4);
					n->agg_order = $5;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = TRUE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| func_name '(' func_arg_list ',' VARIADIC func_arg_expr opt_sort_clause ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = $1;
					n->args = lappend($3, $6);
					n->agg_order = $7;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = TRUE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| func_name '(' ALL func_arg_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;
					/* Ideally we'd mark the FuncCall node to indicate
					 * "must be an aggregate", but there's no provision
					 * for that in FuncCall at the moment.
					 */
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| func_name '(' DISTINCT func_arg_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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| JSON_EXISTS '(' func_arg_list opt_on_error_clause ')'
				{
					FuncCall* n = makeNode(FuncCall);
					Node* onError;
					n->funcname = list_make1(makeString("json_exists"));
					if ($4 == NULL)
						onError = makeIntConst(0, @4);
					else
						onError = $4;
					n->args = lappend($3, onError);
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = FALSE;
					$$ = (Node *)n;
				}
		;


opt_default_fmt_clause:
            ',' a_expr {
                $$ = $2;
            }
	;

opt_default_nls_clause:
            ',' a_expr {
                $$ = $2;
            }
	;

opt_on_error_clause: /* EMPTY */ { $$ = NULL; }
				   | on_error_clause { $$ = $1; };

on_error_clause:	ERROR_ON_ERROR { $$ = makeIntConst(2, @1); }
				| TRUE_ON_ERROR { $$ = makeIntConst(1, @1); }
				| FALSE_ON_ERROR { $$ = makeIntConst(0, @1); };

/*
 * Function with SEPARATOR keword arguments;
 */
func_with_separator:
		func_name '(' func_arg_list opt_sort_clause SEPARATOR_P Sconst ')'
			{
				if (pg_strcasecmp(strVal(linitial($1)), "group_concat") != 0)
				{
					const char* message = "SEPARATOR can only be used in GROUP_CONCAT.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
							errmsg("SEPARATOR can only be used in GROUP_CONCAT."),
							parser_errposition(@5)));
				} else {
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("group_concat");
					n->args = lappend3(list_make1(makeStringConst($6, @6)), $3);
					n->agg_order = $4;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			}
		| func_name '(' DISTINCT func_arg_list opt_sort_clause SEPARATOR_P Sconst ')'
			{
				if (pg_strcasecmp(strVal(linitial($1)), "group_concat") != 0)
				{
					const char* message = "SEPARATOR can only be used in GROUP_CONCAT.";
					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
					ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("SEPARATOR can only be used in GROUP_CONCAT."),
						parser_errposition(@6)));
				} else {
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("group_concat");
					n->args = lappend3(list_make1(makeStringConst($7, @7)), $4);
					n->agg_order = $5;
					n->agg_star = FALSE;
					n->agg_distinct = TRUE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			}
	;

/*
 * As func_expr but does not accept WINDOW functions directly
 * (but they can still be contained in arguments for functions etc).
 * Use this when window expressions are not allowed, where needed to disambiguate the grammar.
 * e.g. in FROM clause, window function or function with 'within group' clause are not allowed.
 * in CREATE INDEX, they are also not allowed.
 */
func_expr_windowless:
            func_application            { $$ = $1; }
            | func_expr_common_subexpr  { $$ = $1; }
        ;

/*
 * Special expressions that are considered to be functions;
 */
func_expr_common_subexpr:
			COLLATION FOR '(' a_expr ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("pg_collation_for");
					n->args = list_make1($4);
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| CURRENT_DATE
				{
					/*
					 * Translate as "text_date('now'::text)".
					 *
					 * Notice that we cannot use 'now'::text::date because when 
					 * we go FQS plan, it will deparsed as 'now'::text::date which is
					 * equal to 'now'::text::timestamp under A_FORMAT.
					 *
					 * We cannot use "text_date('now')" because it 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.)
					 *
					 * The token location is attached to the run-time
					 * typecast, not to the Const, for the convenience of
					 * pg_stat_statements (which doesn't want these constructs
					 * to appear to be replaceable constants).
					 */
					FuncCall *n = makeNode(FuncCall);
					Node *d = makeStringConstCast("now", -1, SystemTypeName("text"));

					n->funcname = SystemFuncName("text_date");
					n->colname = pstrdup("date");
					n->args = list_make1(d);
					n->agg_order = NIL;
					n->agg_star = false;
					n->agg_distinct = false;
					n->func_variadic = false;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| CURRENT_TIME
				{
					/*
					 * Translate as "'now'::text::timetz".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					$$ = makeTypeCast(n, SystemTypeName("timetz"), NULL, NULL, NULL, @1);
				}
			| CURRENT_TIME '(' Iconst ')'
				{
					/*
					 * Translate as "'now'::text::timetz(n)".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("timetz");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast(n, d, NULL, NULL, NULL, @1);
				}
			| CURRENT_TIMESTAMP
				{
					/*
					 * Translate as "now()", since we have a function that
					 * does exactly what is needed.
					 */
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("pg_systimestamp");
					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;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| CURRENT_TIMESTAMP '(' Iconst ')'
				{
					/*
					 * Translate as "'now'::text::timestamptz(n)".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("timestamptz");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast(n, d, NULL, NULL, NULL, @1);
				}		
			| CURSOR_EXPR SelectStmt ')'
			    {
					int cursor_start;
					int cursor_end;
					CursorExpression *n = makeNode(CursorExpression);
					n->portalname = NULL;
					n->options = CURSOR_OPT_FAST_PLAN;
					n->location = @1;
					cursor_start = @2;
					cursor_end = @3;
					StringInfoData buf;
					initStringInfo(&buf);
					base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
					char* raw_parse_query_string = yyextra->core_yy_extra.scanbuf;
					appendBinaryStringInfo(&buf, raw_parse_query_string + cursor_start, cursor_end - cursor_start);
					n->raw_query_str = pstrdup(buf.data);
					FreeStringInfo(&buf);
					$$ = (Node *)n;
				}
			| LOCALTIME
				{
					/*
					 * Translate as "'now'::text::time".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					$$ = makeTypeCast((Node *)n, SystemTypeName("time"), NULL, NULL, NULL, @1);
				}
			| LOCALTIME '(' Iconst ')'
				{
					/*
					 * Translate as "'now'::text::time(n)".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("time");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast((Node *)n, d, NULL, NULL, NULL, @1);
				}
			| LOCALTIMESTAMP
				{
					/*
					 * Translate as "'now'::text::timestamp".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					$$ = makeTypeCast(n, SystemTypeName("timestamp"), NULL, NULL, NULL, @1);
				}
			| LOCALTIMESTAMP '(' Iconst ')'
				{
					/*
					 * Translate as "'now'::text::timestamp(n)".
					 * See comments for CURRENT_DATE.
					 */
					Node *n;
					TypeName *d;
					n = makeStringConstCast("now", -1, SystemTypeName("text"));
					d = SystemTypeName("timestamp");
					d->typmods = list_make1(makeIntConst($3, @3));
					$$ = makeTypeCast(n, d, NULL, NULL, NULL, @1);
				}
			| SYSDATE
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("sysdate");
					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;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| ROWNUM 
				{
#ifdef ENABLE_MULTIPLE_NODES
        				const char* message = "ROWNUM is not yet supported.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
    					ereport(errstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
							errmsg("ROWNUM is not yet supported.")));
#endif
					Rownum *r = makeNode(Rownum);
				    	r->location = @1;
					$$ = (Node *)r;
				}			
			| 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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| CAST '(' a_expr AS Typename ')'
				{ $$ = makeTypeCast($3, $5, NULL, NULL, NULL, @1); }
			| CAST '(' a_expr AS Typename opt_default_fmt_clause')'
				{ $$ = makeTypeCast($3, $5, $6, NULL, NULL, @1); }
			| CAST '(' a_expr AS Typename opt_default_fmt_clause opt_default_nls_clause ')'
				{ $$ = makeTypeCast($3, $5, $6, $7, NULL, @1); }											
			| CAST '(' a_expr AS Typename default_on_err_expr opt_default_fmt_clause ')'
				{ $$ = makeTypeCast($3, $5, $7, NULL, $6, @1); }	
			| CAST '(' a_expr AS Typename default_on_err_expr opt_default_fmt_clause opt_default_nls_clause ')'
				{ $$ = makeTypeCast($3, $5, $7, $8, $6, @1); }
			| CAST '(' a_expr AS Typename default_on_err_expr ')'
				{ $$ = makeTypeCast($3, $5, NULL, NULL, $6, @1); }	
			| EXTRACT '(' extract_list ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("date_part");
					if (list_length($3) > 0) {
						ListCell *lc = list_head($3);
						Node *firstElement = (Node *)lfirst(lc);
						A_Const* con = (A_Const*)firstElement;
						char *firstElementStr = strVal(&con->val);
						if (strcmp(firstElementStr, "timezone_abbr") == 0 || strcmp(firstElementStr, "timezone_region") == 0) {
							n->funcname = SystemFuncName("timezone_extract");
						}
					}
					n->args = $3;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| EXTRACT '(' expr_list ')'
				{
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("extract_internal");
					n->args = $3;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| TIMESTAMPDIFF '(' timestamp_arg_list ')'
				{
					if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT)
					{
						FuncCall *n = makeNode(FuncCall);
						n->funcname = SystemFuncName("timestamp_diff");
						n->args = $3;
						n->agg_order = NIL;
						n->agg_star = FALSE;
						n->agg_distinct = FALSE;
						n->func_variadic = FALSE;
						n->over = NULL;
						n->location = @1;
						n->call_func = false;
						$$ = (Node *)n;
					}
					else
					{
        				const char* message = "timestampdiff syntax is not supported.";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errmodule(MOD_PARSER),
                                                                 errcode(ERRCODE_SYNTAX_ERROR),
                                                                 errmsg("timestampdiff syntax is not supported."),
                                                                 parser_errposition(@1)));
  					        $$ = NULL;/* not reached */
					}
				}
			| OVERLAY '(' overlay_list ')'
				{
					/* overlay(A PLACING B FROM C FOR D) is converted to
					 * overlay(A, B, C, D)
					 * overlay(A PLACING B FROM C) is converted to
					 * overlay(A, B, C)
					 */
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("overlay");
					n->args = $3;
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (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->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| NULLIF '(' a_expr ',' a_expr ')'
				{
					$$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
				}
			| NVL '(' a_expr ',' a_expr ')'
				{
					CoalesceExpr *c = makeNode(CoalesceExpr);
					c->args = list_make2($3,$5);
					// modify NVL display to A db's style "NVL" instead of "COALESCE"
					c->isnvl = true;
					$$ = (Node *)c;
				}
			| COALESCE '(' expr_list ')'
				{
					CoalesceExpr *c = makeNode(CoalesceExpr);
					c->args = $3;
					c->location = @1;
					// modify NVL display to A db's style "NVL" instead of "COALESCE"
					c->isnvl = false;
					$$ = (Node *)c;
				}
			| GREATEST '(' expr_list ')'
				{
					MinMaxExpr *v = makeNode(MinMaxExpr);
					v->args = $3;
					v->op = IS_GREATEST;
					v->location = @1;
					$$ = (Node *)v;
				}
			| LEAST '(' expr_list ')'
				{
					MinMaxExpr *v = makeNode(MinMaxExpr);
					v->args = $3;
					v->op = IS_LEAST;
					v->location = @1;
					$$ = (Node *)v;
				}
			| XMLCONCAT '(' expr_list ')'
				{
					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
				}
			| XMLELEMENT '(' NAME_P ColLabel ')'
				{
					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
				}
			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
				{
					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
				}
			| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
				{
					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
				}
			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
				{
					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
				}
			| XMLEXISTS '(' c_expr xmlexists_argument ')'
				{
					/* xmlexists(A PASSING [BY REF] B [BY REF]) is
					 * converted to xmlexists(A, B)*/
					FuncCall *n = makeNode(FuncCall);
					n->funcname = SystemFuncName("xmlexists");
					n->args = list_make2($3, $4);
					n->agg_order = NIL;
					n->agg_star = FALSE;
					n->agg_distinct = FALSE;
					n->func_variadic = FALSE;
					n->over = NULL;
					n->location = @1;
					n->call_func = false;
					$$ = (Node *)n;
				}
			| XMLFOREST '(' xml_attribute_list ')'
				{
					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
				}
			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
				{
					XmlExpr *x = (XmlExpr *)
						makeXmlExpr(IS_XMLPARSE, NULL, NIL,
									list_make2($4, makeBoolAConst($5, -1)),
									@1);
					x->xmloption = (XmlOptionType)$3;
					$$ = (Node *)x;
				}
			| XMLPI '(' NAME_P ColLabel ')'
				{
					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
				}
			| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
				{
					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
				}
			| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
				{
					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
									 list_make3($3, $5, $6), @1);
				}
			| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
				{
					XmlSerialize *n = makeNode(XmlSerialize);
					n->xmloption = (XmlOptionType)$3;
					n->expr = $4;
					n->typname = $6;
					n->location = @1;
					$$ = (Node *)n;
				}
		;

default_on_err_expr:
	DEFAULT a_expr ON CONVERSION_P ERROR_P {
		$$ = $2;
	}
	;
/*
 * SQL/XML support
 */
xml_root_version: VERSION_P a_expr
				{ $$ = $2; }
			| VERSION_P NO VALUE_P
				{ $$ = makeNullAConst(-1); }
		;

opt_xml_root_standalone: ',' STANDALONE_P YES_P
				{ $$ = makeIntConst(XML_STANDALONE_YES, -1); }
			| ',' STANDALONE_P NO
				{ $$ = makeIntConst(XML_STANDALONE_NO, -1); }
			| ',' STANDALONE_P NO VALUE_P
				{ $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
			| /*EMPTY*/
				{ $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
		;

xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
		;

xml_attribute_list:	xml_attribute_el					{ $$ = list_make1($1); }
			| xml_attribute_list ',' xml_attribute_el	{ $$ = lappend($1, $3); }
		;

xml_attribute_el: a_expr AS ColLabel
				{
					$$ = makeNode(ResTarget);
					$$->name = $3;
					$$->indirection = NIL;
					$$->val = (Node *) $1;
					$$->location = @1;
				}
			| a_expr
				{
					$$ = makeNode(ResTarget);
					$$->name = NULL;
					$$->indirection = NIL;
					$$->val = (Node *) $1;
					$$->location = @1;
				}
		;

document_or_content: DOCUMENT_P						{ $$ = XMLOPTION_DOCUMENT; }
			| CONTENT_P								{ $$ = XMLOPTION_CONTENT; }
		;

xml_whitespace_option: PRESERVE WHITESPACE_P		{ $$ = TRUE; }
			| STRIP_P WHITESPACE_P					{ $$ = FALSE; }
			| /*EMPTY*/								{ $$ = FALSE; }
		;

/* We allow several variants for SQL and other compatibility. */
xmlexists_argument:
			PASSING c_expr
				{
					$$ = $2;
				}
			| PASSING c_expr BY REF
				{
					$$ = $2;
				}
			| PASSING BY REF c_expr
				{
					$$ = $4;
				}
			| PASSING BY REF c_expr BY REF
				{
					$$ = $4;
				}
		;

keep_clause:
                        KEEP '(' DENSE_RANK FIRST_P sort_clause ')'
                                {
                                        if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT )
                                               ereport(ERROR,
                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                               errmsg("keep clause is supported only in A_FORMAT database.")));
                                        KeepClause *n = makeNode(KeepClause);
                                        n->rank_first = true;
                                        n->keep_order =$5;
                                        n->location = @1;
 
                                        $$ = n; 
                                }
                        | KEEP '(' DENSE_RANK LAST_P sort_clause ')'
                                {
                                        if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT )
                                               ereport(ERROR,
                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                               errmsg("keep clause is supported only in A_FORMAT database.")));
                                        KeepClause *n = makeNode(KeepClause);
                                        n->rank_first = false;
                                        n->keep_order =$5;
                                        n->location = @1;
                                        
                                        $$ = n; 
                                }
                        | /*EMPTY*/
                                { 
                                        $$ = NULL; 
                                }
                ;

/*
 * Aggregate decoration clauses
 */
within_group_clause:
			WITHIN GROUP_P '(' sort_clause ')'		{ $$ = $4; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

filter_clause:
			FILTER '(' WHERE a_expr ')'				{ $$ = $4; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

/*
 * Window Definitions
 */
window_clause:
			WINDOW window_definition_list			{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

window_definition_list:
			window_definition						{ $$ = list_make1($1); }
			| window_definition_list ',' window_definition
													{ $$ = lappend($1, $3); }
		;

window_definition:
			ColId AS window_specification
				{
					WindowDef *n = $3;
					n->name = $1;
					$$ = n;
				}
		;

over_clause: OVER window_specification
				{ $$ = $2; }
			| OVER ColId
				{
					WindowDef *n = makeNode(WindowDef);
					n->name = $2;
					n->refname = NULL;
					n->partitionClause = NIL;
					n->orderClause = NIL;
					n->frameOptions = FRAMEOPTION_DEFAULTS;
					n->startOffset = NULL;
					n->endOffset = NULL;
					n->location = @2;
					$$ = n;
				}
		;

window_specification: '(' opt_existing_window_name opt_partition_clause
						opt_sort_clause opt_frame_clause ')'
				{
					WindowDef *n = makeNode(WindowDef);
					n->name = NULL;
					n->refname = $2;
					n->partitionClause = $3;
					n->orderClause = $4;
					/* copy relevant fields of opt_frame_clause */
					n->frameOptions = $5->frameOptions;
					n->startOffset = $5->startOffset;
					n->endOffset = $5->endOffset;
					n->location = @1;
					$$ = n;
				}
		;

/*
 * If we see PARTITION, RANGE, or ROWS as the first token after the '('
 * of a window_specification, we want the assumption to be that there is
 * no existing_window_name; but those keywords are unreserved and so could
 * be ColIds.  We fix this by making them have the same precedence as IDENT
 * and giving the empty production here a slightly higher precedence, so
 * that the shift/reduce conflict is resolved in favor of reducing the rule.
 * These keywords are thus precluded from being an existing_window_name but
 * are not reserved for any other purpose.
 */
opt_existing_window_name: ColId						{ $$ = $1; }
			| /*EMPTY*/				%prec Op		{ $$ = NULL; }
		;

opt_partition_clause: PARTITION BY expr_list		{ $$ = $3; }
			| /*EMPTY*/								{ $$ = NIL; }
		;

/*
 * For frame clauses, we return a WindowDef, but only some fields are used:
 * frameOptions, startOffset, and endOffset.
 *
 * This is only a subset of the full SQL:2008 frame_clause grammar.
 * We don't support <window frame exclusion> yet.
 */
opt_frame_clause:
			RANGE frame_extent
				{
					WindowDef *n = $2;
					n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_RANGE;
					if (n->frameOptions & (FRAMEOPTION_START_VALUE_PRECEDING |
										   FRAMEOPTION_END_VALUE_PRECEDING)) {
        				const char* message = "RANGE PRECEDING is only supported with UNBOUNDED";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("RANGE PRECEDING is only supported with UNBOUNDED"),
								 parser_errposition(@1)));
					}
					if (n->frameOptions & (FRAMEOPTION_START_VALUE_FOLLOWING |
										   FRAMEOPTION_END_VALUE_FOLLOWING)) {
        				const char* message = "RANGE PRECEDING is only supported with UNBOUNDED";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
								 errmsg("RANGE FOLLOWING is only supported with UNBOUNDED"),
								 parser_errposition(@1)));
					}
					$$ = n;
				}
			| ROWS frame_extent
				{
					WindowDef *n = $2;
					n->frameOptions |= FRAMEOPTION_NONDEFAULT | FRAMEOPTION_ROWS;
					$$ = n;
				}
			| /*EMPTY*/
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_DEFAULTS;
					n->startOffset = NULL;
					n->endOffset = NULL;
					$$ = n;
				}
		;

frame_extent: frame_bound
				{
					WindowDef *n = $1;
					/* reject invalid cases */
					if (n->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
        				const char* message = "frame start cannot be UNBOUNDED FOLLOWING";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
								 parser_errposition(@1)));
					}
					if (n->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) {
        				const char* message = "frame starting from following row cannot end with current row";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame starting from following row cannot end with current row"),
								 parser_errposition(@1)));
					}
					n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
					$$ = n;
				}
			| BETWEEN frame_bound AND frame_bound
				{
					WindowDef *n1 = $2;
					WindowDef *n2 = $4;
					/* form merged options */
					int		frameOptions = n1->frameOptions;
					/* shift converts START_ options to END_ options */
					frameOptions |= n2->frameOptions << 1;
					frameOptions |= FRAMEOPTION_BETWEEN;
					/* reject invalid cases */
					if (frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
        				const char* message = "frame start cannot be UNBOUNDED FOLLOWING";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
								 parser_errposition(@2)));
					}
					if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) {
        				const char* message = "frame start cannot be UNBOUNDED PRECEDING";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame end cannot be UNBOUNDED PRECEDING"),
								 parser_errposition(@4)));
					}
					if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
						(frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)) {
        				const char* message = "frame starting from current row cannot have preceding rows";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame starting from current row cannot have preceding rows"),
								 parser_errposition(@4)));
					}
					if ((frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) &&
						(frameOptions & (FRAMEOPTION_END_VALUE_PRECEDING |
										 FRAMEOPTION_END_CURRENT_ROW))) {
        				const char* message = "frame starting from current row cannot have preceding rows";
    					InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
								(errcode(ERRCODE_WINDOWING_ERROR),
								 errmsg("frame starting from following row cannot have preceding rows"),
								 parser_errposition(@4)));
					}
					n1->frameOptions = frameOptions;
					n1->endOffset = n2->startOffset;
					$$ = n1;
				}
		;

/*
 * This is used for both frame start and frame end, with output set up on
 * the assumption it's frame start; the frame_extent productions must reject
 * invalid cases.
 */
frame_bound:
			UNBOUNDED PRECEDING
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_START_UNBOUNDED_PRECEDING;
					n->startOffset = NULL;
					n->endOffset = NULL;
					$$ = n;
				}
			| UNBOUNDED FOLLOWING
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_START_UNBOUNDED_FOLLOWING;
					n->startOffset = NULL;
					n->endOffset = NULL;
					$$ = n;
				}
			| CURRENT_P ROW
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_START_CURRENT_ROW;
					n->startOffset = NULL;
					n->endOffset = NULL;
					$$ = n;
				}
			| a_expr PRECEDING
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_START_VALUE_PRECEDING;
					n->startOffset = $1;
					n->endOffset = NULL;
					$$ = n;
				}
			| a_expr FOLLOWING
				{
					WindowDef *n = makeNode(WindowDef);
					n->frameOptions = FRAMEOPTION_START_VALUE_FOLLOWING;
					n->startOffset = $1;
					n->endOffset = NULL;
					$$ = 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); }
		;
explicit_row:	ROW '(' expr_list ')'				{ $$ = $3; }
			| ROW '(' ')'							{ $$ = NIL; }
		;

implicit_row:	'(' expr_list ',' a_expr ')'		{ $$ = lappend($2, $4); }
		;

sub_type:	ANY										{ $$ = ANY_SUBLINK; }
			| SOME									{ $$ = ANY_SUBLINK; }
			| ALL									{ $$ = ALL_SUBLINK; }
		;

all_Op:		Op										{ $$ = $1; }
			| CmpOp									{ $$ = $1; }
			| CmpNullOp								{ $$ = $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	%prec NOT_LIKE
					{ $$ = list_make1(makeString("!~~")); }
			| ILIKE
					{ $$ = list_make1(makeString("~~*")); }
			| NOT_ILIKE	%prec 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 %prec higher_than_rotate
				{
					$$ = list_make1($1);
				}
			| expr_list ',' a_expr
				{
					$$ = lappend($1, $3);
				}
		;

/* function arguments can have names */
func_arg_list:  func_arg_expr
				{
					$$ = list_make1($1);
				}
			| func_arg_list ',' func_arg_expr
				{
					$$ = lappend($1, $3);
				}
		;

func_arg_expr:  a_expr
				{
					$$ = $1;
				}
			| param_name COLON_EQUALS a_expr
				{
					NamedArgExpr *na = makeNode(NamedArgExpr);
					na->name = $1;
					na->arg = (Expr *) $3;
					na->argnumber = -1;		/* until determined */
					na->location = @1;
					$$ = (Node *) na;
				}
			/* add PARA_EQUALS for simulating A db assignment with argument name as "=>"*/
			| param_name PARA_EQUALS a_expr
				{
					NamedArgExpr *na = makeNode(NamedArgExpr);
					na->name = $1;
					na->arg = (Expr *) $3;
					na->argnumber = -1;		/* until determined */
					na->location = @1;
					$$ = (Node *) na;
				}
		;

type_list:	Typename								{ $$ = list_make1($1); }
			| type_list ',' Typename				{ $$ = lappend($1, $3); }
		;

array_expr: '[' expr_list ']'
				{
					$$ = makeAArrayExpr($2, @1);
				}
			| '[' array_expr_list ']'
				{
					$$ = makeAArrayExpr($2, @1);
				}
			| '[' ']'
				{
					$$ = makeAArrayExpr(NIL, @1);
				}
		;

array_expr_list: array_expr							{ $$ = list_make1($1); }
			| array_expr_list ',' array_expr		{ $$ = lappend($1, $3); }
		;


extract_list:
			extract_arg FROM a_expr
				{
					$$ = list_make2(makeStringConst($1, @1), $3);
				}
			| /*EMPTY*/								{ $$ = NIL; }
		;

/* 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"; }
			| TIMEZONE_HOUR_P						{ $$ = "timezone_hour"; }
			| TIMEZONE_MINUTE_P						{ $$ = "timezone_minute"; }
			| Sconst								{ $$ = $1; }
		;

timestamp_arg_list:
			timestamp_units ',' a_expr ',' a_expr
				{
					$$ = list_make3(makeStringConst($1, @1), $3, $5);
				}
			| /*EMPTY*/								{ $$ = NIL; }
		;

timestamp_units:
			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)
 * and similarly for binary strings
 */
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.
					 */
					$$ = list_make3($1, makeIntConst(1, -1),
									makeTypeCast($2,
												 SystemTypeName("int4"), NULL, NULL, NULL, -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;
					c->location = @1;
					$$ = (Node *)c;
				}
		| DECODE '(' a_expr ',' expr_list ')'
				{
					if(list_length($5) < 2)
					{
						FuncCall *n = makeNode(FuncCall);
						n->funcname = SystemFuncName("decode");
						n->args = list_concat(list_make1($3), $5);
						n->agg_order = NIL;
						n->agg_star = FALSE;
						n->agg_distinct = FALSE;
						n->func_variadic = FALSE;
						n->over = NULL;
						n->location = @1;
						n->call_func = false;
						$$ = (Node *)n;
					}
					else
					{
						ListCell *cell = NULL;
						CaseExpr *c = makeNode(CaseExpr);
						c->casetype = InvalidOid; /* not analyzed yet */
						c->arg = NULL;
						c->args = NULL;
						c->defresult = NULL;
						c->fromDecode = true;

						foreach(cell,$5)
						{
							Expr *expr1 = NULL;
							Expr *expr2 = NULL;
							CaseWhen *w = NULL;
							expr1 = (Expr*) lfirst(cell);
							cell = lnext(cell);
							if(NULL == cell)
							{
								c->defresult = expr1;
								break;
							}
							expr2 = (Expr*) lfirst(cell);
							w = makeNode(CaseWhen);
							w->expr = makeNodeDecodeCondtion((Expr*)$3,expr1);
							w->result = expr2;
							c->args = lappend(c->args,w);
						}
						$$ = (Node *)c;
					}
				}
		;

when_clause_list:
			/* There must be at least one */
			when_clause								{ $$ = list_make1($1); }
			| when_clause_list when_clause			{ $$ = lappend($1, $2); }
		;

when_clause:
			WHEN a_expr THEN a_expr
				{
					CaseWhen *w = makeNode(CaseWhen);
					w->expr = (Expr *) $2;
					w->result = (Expr *) $4;
					w->location = @1;
					$$ = (Node *)w;
				}
		;

case_default:
			ELSE a_expr								{ $$ = $2; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

case_arg:	a_expr									{ $$ = $1; }
			| /*EMPTY*/								{ $$ = NULL; }
		;

columnref:	ColId
				{
					$$ = makeColumnRef($1, NIL, @1, yyscanner);
				}
			| ColId indirection
				{
					$$ = makeColumnRef($1, $2, @1, yyscanner);
				}
			| EXCLUDED indirection
				{
					$$ = makeColumnRef("excluded", $2, @2, yyscanner);
				}
		;

indirection_el:
			'.' attr_name
				{
					$$ = (Node *) makeString($2);
				}
			| ORA_JOINOP
				{
					$$ = (Node *) makeString("(+)");
				}
			| '.' '*'
				{
					$$ = (Node *) makeNode(A_Star);
				}
			| '[' 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;
				}
			| '[' 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
				{
					SetToDefault *n = makeNode(SetToDefault);
					n->location = @1;
					$$ = (Node *) n;
				}
		;

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;
				}
			| a_expr AS Sconst
				{
					$$ = makeNode(ResTarget);
					$$->name = $3;
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;
				}
			/*
			 * We support 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.
			 */
			| a_expr IDENT
				{
					$$ = makeNode(ResTarget);
					$$->name = IdentResolveToChar($2, yyscanner);
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;
                                        if (IsConnectByRootIdent($1)) {
                                           Node* cr = (Node*) makeColumnRef($2, NIL, @1, yyscanner);
                                           Node* n = MakeConnectByRootNode((ColumnRef*) cr, @1);
                                           $$->name = MakeConnectByRootColName(NULL, $2);
                                           $$->val = (Node*) n;
                                        }
				}
			| a_expr
				{
					$$ = makeNode(ResTarget);
					$$->name = NULL;
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;

                                        ColumnRef* cr = (ColumnRef*) $1;
                                        /* PRIOR(x) in target list implies func call */
                                        if (IsA($1, ColumnRef) && cr->prior && cr->location == 0) {
                                            FuncCall *fn = MakePriorAsFunc();
                                            cr->prior = false;
                                            fn->args = list_make1(cr);
                                            $$->val = (Node *)fn;
                                        }
                                }
			| '*'
				{
					ColumnRef *n = makeNode(ColumnRef);
					n->fields = list_make1(makeNode(A_Star));
					n->location = @1;
					n->indnum = 0;

					$$ = makeNode(ResTarget);
					$$->name = NULL;
					$$->indirection = NIL;
					$$->val = (Node *)n;
					$$->location = @1;
				}
			| c_expr VALUE_P
				{
					$$ = makeNode(ResTarget);
					$$->name = pstrdup($2);
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;
				}
			| c_expr NAME_P
				{
					$$ = makeNode(ResTarget);
					$$->name = pstrdup($2);
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;
				}
			| c_expr TYPE_P
				{
					$$ = makeNode(ResTarget);
					$$->name = pstrdup($2);
					$$->indirection = NIL;
					$$->val = (Node *)$1;
					$$->location = @1;
				}
                        | connect_by_root_expr
                                {
                                        $$ = (ResTarget*) $1;
                                }
		;

connect_by_root_expr:   a_expr IDENT '.' IDENT
                                {
                                       ValidateTripleTuple((Node*)$1, yyscanner, @2, $2);
                                       Node* cr = (Node*) makeColumnRef($2, list_make1(makeString($4)), @1, yyscanner);
                                       Node* n = MakeConnectByRootNode((ColumnRef*) cr, @1);
                                       $$ = makeNode(ResTarget);
                                       $$->name = MakeConnectByRootColName($2, $4);
                                       $$->val = (Node*) n;
                                       $$->indirection = NIL;
                                       $$->location = @1;
                                }
                        | a_expr IDENT '.' IDENT as_empty IDENT
                                {
                                       ValidateTripleTuple((Node*)$1, yyscanner, @2, $2);
                                       Node* cr = (Node*) makeColumnRef($2, list_make1(makeString($4)), @1, yyscanner);
                                       Node* n = MakeConnectByRootNode((ColumnRef*) cr, @1);
                                       $$ = makeNode(ResTarget);
                                       $$->name = $6;
                                       $$->val = (Node*) n;
                                       $$->indirection = NIL;
                                       $$->location = @1;
                                }
                        | a_expr IDENT as_empty IDENT
                                {
                                       ValidateTripleTuple((Node*) $1, yyscanner, @2, $2);
                                       Node* cr = (Node*) makeColumnRef($2, NIL, @1, yyscanner);
                                       Node* n = MakeConnectByRootNode((ColumnRef*) cr, @1);
                                       $$ = makeNode(ResTarget);
                                       $$->name = $4;
                                       $$->val = (Node *) n;
                                       $$->indirection = NIL;
                                       $$->location = @1;
				}
                ;

/*****************************************************************************
 *
 *	ALTER TALBE FOR IMCSTORE
 *
 *****************************************************************************/
imcstored_clause:
			IMCSTORED
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_Imcstored;
					$$ = (Node *) n;
				}
			| IMCSTORED '(' name_list ')'
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_Imcstored;
					n->def = (Node *)$3;
					$$ = (Node *) n;
				}
			| UNIMCSTORED
				{
					AlterTableCmd *n = makeNode(AlterTableCmd);
					n->subtype = AT_UnImcstored;
					$$ = (Node *) n;
				}
		;

/*****************************************************************************
 *
 *	Names and constants
 *
 *****************************************************************************/

qualified_name_list:
			qualified_name							{ $$ = list_make1($1); }
			| qualified_name_list ',' qualified_name { $$ = lappend($1, $3); }
		;

/*
 * The production for a qualified relation name has to exactly match the
 * production for a qualified func_name, because in a FROM clause we cannot
 * tell which we are parsing until we see what comes after it ('(' for a
 * func_name, something else for a relation). Therefore we allow 'indirection'
 * which may contain subscripts, and reject that case in the C code.
 */
qualified_name:
			ColId
				{
					$$ = makeRangeVar(NULL, $1, @1);
				}
			| ColId indirection
				{
					check_qualified_name($2, yyscanner);
					$$ = makeRangeVar(NULL, NULL, @1);
					const char* message = "improper qualified name (too many dotted names)";
					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:
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("improper qualified name (too many dotted names): %s",
											NameListToString(lcons(makeString($1), $2))),
									 parser_errposition(@1)));
							break;
					}
				}
		;

/*
 * used for multi delete stmt, to support writing table's name forms like t.* or schema.t.*
 * when modify qualified_name, please check whether need to sync modifications here.
 */
qualified_name_for_delete:
			ColId
				{
					$$ = makeRangeVar(NULL, $1, @1);
				}
			| ColId indirection
				{
					$$ = makeRangeVar(NULL, NULL, @1);
					const char* message = "improper qualified name (too many dotted names)";
					switch (list_length($2))
					{
						case 1:
							if (IsA(linitial($2), A_Star)) {
								$$->catalogname = NULL;
								$$->schemaname = NULL;
								$$->relname = $1;
							} else {
								check_qualified_name($2, yyscanner);
								$$->catalogname = NULL;
								$$->schemaname = $1;
								$$->relname = strVal(linitial($2));
							}
							break;
						case 2:
							if (IsA(lsecond($2), A_Star)) {
								$$->catalogname = NULL;
								$$->schemaname = $1;
								if (!(IsA(linitial($2), String))) {
									parser_yyerror("syntax error");
								}
								$$->relname = strVal(linitial($2));
							} else {
								check_qualified_name($2, yyscanner);
								$$->catalogname = $1;
								$$->schemaname = strVal(linitial($2));
								$$->relname = strVal(lsecond($2));
							}
							break;
						default:
    						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("improper qualified name (too many dotted names): %s",
											NameListToString(lcons(makeString($1), $2))),
									 parser_errposition(@1)));
							break;
					}
				}
		;

name_list:	name
					{ $$ = list_make1(makeString($1)); }
			| name_list ',' name
					{ $$ = lappend($1, makeString($3)); }
		;


name:		ColId									{ $$ = $1; };

database_name:
			ColId									{ $$ = $1; };

imcs_partition_name:
			ColId									{ $$ = $1; };

access_method:
			ColId									{ $$ = $1; };

attr_name:	ColLabel_with_rownum					{ $$ = $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 ('(' or Sconst for a func_name,
 * anything else for a columnref).  Therefore we allow 'indirection' which
 * may contain subscripts, and reject that case in the C code.  (If we
 * ever implement SQL99-like methods, such syntax may actually become legal!)
 */
func_name:	type_function_name
					{ $$ = list_make1(makeString($1)); }
			| ColId indirection
					{
						$$ = check_func_name(lcons(makeString($1), $2),
											 yyscanner);
					}
		;

func_name_opt_arg:
						func_name
						/* This rule is never used. */
						| IDENT BOGUS							{ $$ = NIL; }
						/* This rule is never used. */
						| unreserved_keyword BOGUS				{ $$ = NIL; };

/*
 * Constants
 */
AexprConst: Iconst
				{
					$$ = makeIntConst($1, @1);
				}
			| FCONST
				{
					$$ = makeFloatConst($1, @1);
				}
			| FCONST_F
				{
					Node *num = makeFloatConst($1, @1);
					$$ = makeTypeCast(num, SystemTypeName("float4"), NULL, NULL, NULL, @1);	
				}
			| FCONST_D
				{
					Node *num = makeFloatConst($1, @1);
					$$ = makeTypeCast(num, SystemTypeName("float8"), NULL, NULL, NULL, @1);	
				}
			| Sconst
				{
					$$ = makeStringConst($1, @1);
				}
			| BCONST
				{
					$$ = makeBitStringConst($1, @1);
				}
			| XCONST
				{
					/* This is a bit constant per SQL99:
					 * Without Feature F511, "BIT data type",
					 * a <general literal> shall not be a
					 * <bit string literal> or a <hex string literal>.
					 */
					$$ = makeBitStringConst($1, @1);
				}
			| UNDERSCORE_CHARSET Sconst
				{
					const char* encoding_name = $1;
					char *original_str = pg_server_to_client($2, strlen($2));
					int encoding = pg_valid_server_encoding(encoding_name);
					Assert(encoding >= 0);

					A_Const *con = makeNode(A_Const);
					con->val.type = T_String;
					con->val.val.str = original_str;
					con->location = @2;

					CharsetClause *n = makeNode(CharsetClause);
					n->arg = (Node *)con;
					n->charset = encoding;
					n->is_binary = (strcmp(encoding_name, "binary") == 0);
					n->location = @1;
					$$ = (Node *) n;
				}
			| UNDERSCORE_CHARSET BCONST
				{
					const char* encoding_name = $1;
					int encoding = pg_valid_server_encoding(encoding_name);
					Assert(encoding >= 0);

					CharsetClause *n = makeNode(CharsetClause);
					n->arg = makeBitStringConst($2, @2);
					n->charset = encoding;
					n->is_binary = (strcmp(encoding_name, "binary") == 0);
					n->location = @1;
					$$ = (Node *) n;
				}
			| UNDERSCORE_CHARSET XCONST
				{
					const char* encoding_name = $1;
					int encoding = pg_valid_server_encoding(encoding_name);
					Assert(encoding >= 0);

					CharsetClause *n = makeNode(CharsetClause);
					n->arg = makeBitStringConst($2, @2);
					n->charset = encoding;
					n->is_binary = (strcmp(encoding_name, "binary") == 0);
					n->location = @1;
					$$ = (Node *) n;
				}
			| func_name Sconst
				{
					/* generic type 'literal' syntax */
					TypeName *t = makeTypeNameFromNameList($1);
					t->location = @1;
					$$ = makeStringConstCast($2, @2, t);
				}
			| func_name '(' func_arg_list opt_sort_clause ')' Sconst
				{
					/* generic syntax with a type modifier */
					TypeName *t = makeTypeNameFromNameList($1);
					ListCell *lc;

					/*
					 * We must use func_arg_list and opt_sort_clause in the production to avoid
					 * reduce/reduce conflicts, but we don't actually wish
					 * to allow NamedArgExpr in this context, nor ORDER BY.
					 */
					foreach(lc, $3)
					{
						NamedArgExpr *arg = (NamedArgExpr *) lfirst(lc);

						if (IsA(arg, NamedArgExpr)) {
							const char* message = "type modifier cannot have parameter name";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("type modifier cannot have parameter name"),
									 parser_errposition(arg->location)));
						}
					}

					if ($4 != NIL) {
							const char* message = "type modifier cannot have ORDER BY";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("type modifier cannot have ORDER BY"),
									 parser_errposition(@4)));
					}
					t->typmods = $3;
					t->location = @1;
					$$ = makeStringConstCast($6, @6, t);
				}
			| ConstTypename Sconst
				{
					$$ = makeStringConstCast($2, @2, $1);
				}
			| ConstInterval Sconst opt_interval
				{
					TypeName *t = $1;
					t->typmods = $3;
					$$ = makeStringConstCast($2, @2, t);
				}
			| ConstInterval '(' Iconst ')' Sconst opt_interval
				{
					TypeName *t = $1;
					if ($6 != NIL)
					{
						if (list_length($6) != 1) {
							const char* message = "interval precision specified twice";
							InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
							ereport(errstate,
									(errcode(ERRCODE_SYNTAX_ERROR),
									 errmsg("interval precision specified twice"),
									 parser_errposition(@1)));
						}
						t->typmods = lappend($6, makeIntConst($3, @3));
					}
					else
						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
												makeIntConst($3, @3));
					$$ = makeStringConstCast($5, @5, t);
				}
			| TRUE_P
				{
					$$ = makeBoolAConst(TRUE, @1);
				}
			| FALSE_P
				{
					$$ = makeBoolAConst(FALSE, @1);
				}
			| NULL_P
				{
					$$ = makeNullAConst(@1);
				}
		;

Iconst:		ICONST									{ $$ = $1; };
Sconst:		SCONST									{ $$ = $1; };
RoleId:		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
				{
					if (u_sess->attr.attr_sql.enable_ignore_case_in_dquotes)
					{
						$$ = pg_strtolower(pstrdup($1));
					}
					else
					{
						$$ = $1;
					}
				}
			| unreserved_keyword					{ $$ = pstrdup($1); }
			| col_name_keyword						{ $$ = pstrdup($1); }
		;

/* Type/function identifier --- names that can be type or function names.
 */
type_function_name:	IDENT
				{
					$$ = IdentResolveToChar($1, yyscanner);
				}
			| unreserved_keyword					{ $$ = pstrdup($1); }
			| type_func_name_keyword				{ $$ = pstrdup($1); }
		;

/* Column label --- allowed labels in "AS" clauses.
 * This presently includes *all* Postgres keywords.
 */
ColLabel:	IDENT
				{
					$$ = IdentResolveToChar($1, yyscanner);
				}
			| '\''IDENT'\''							{ $$ = $2; }
			| unreserved_keyword					{ $$ = pstrdup($1); }
			| col_name_keyword						{ $$ = pstrdup($1); }
			| type_func_name_keyword				{ $$ = pstrdup($1); }
			| reserved_keyword
				{
					/* ROWNUM can not be used as alias */
					if (strcmp($1, "rownum") == 0) {
						const char* message = "ROWNUM cannot be used as an alias";
						InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
						ereport(errstate,
							(errcode(ERRCODE_SYNTAX_ERROR),
								errmsg("ROWNUM cannot be used as an alias"),
										parser_errposition(@1)));
					}
					$$ = pstrdup($1);
				}
		;
ColLabel_with_rownum:	IDENT
				{
					$$ = IdentResolveToChar($1, yyscanner);
				}
			| '\''IDENT'\''							{ $$ = $2; }
			| unreserved_keyword					{ $$ = pstrdup($1); }
			| col_name_keyword						{ $$ = pstrdup($1); }
			| type_func_name_keyword				{ $$ = pstrdup($1); }
			| reserved_keyword
				{
					$$ = pstrdup($1);
				}
		;

DelimiterStmt: DELIMITER delimiter_str_names END_OF_INPUT
			   {
					VariableSetStmt *n = makeNode(VariableSetStmt);
					setDelimiterName(yyscanner, $2, n);
					$$ = (Node *)n;
				}
			|	DELIMITER delimiter_str_names END_OF_INPUT_COLON
				{
					VariableSetStmt *n = makeNode(VariableSetStmt);
					setDelimiterName(yyscanner, $2, n);
					$$ = (Node *)n;
				}
			;

delimiter_str_names: delimiter_str_names delimiter_str_name
					{
						$$ = $1 ;
					}
                |    delimiter_str_name
					{
						$$ = $1;
					}
				;

delimiter_str_name: ColId_or_Sconst 
					{
						$$ = $1;
					}
				|   all_Op
				    {
						$$ = $1;
					}
				|   ';'
				    {
						$$ = ";";
					}
				;

/*
 * Keyword category lists.  Generally, every keyword present in
 * the Postgres grammar should appear in exactly one of these lists.
 *
 * Put a new keyword into the first list that it can go into without causing
 * shift or reduce conflicts.  The earlier lists define "less reserved"
 * categories of keywords.
 *
 * Make sure that each keyword's category in kwlist.h matches where
 * it is listed here.  (Someday we may be able to generate these lists and
 * kwlist.h's table from a common master list.)
 */

/* "Unreserved" keywords --- available for use as any kind of name.
 */
/* PGXC - added DISTRIBUTE, DIRECT, COORDINATOR, DATANODES, CLEAN, NODE, BARRIER, SLICE, DATANODE */
unreserved_keyword:
			  ABORT_P
			| ABSOLUTE_P
			| ACCESS
			| ACCOUNT
			| ACTION
			| ADD_P
			| ADMIN
			| AFTER
			| AGGREGATE
			| ALGORITHM
			| ALSO
			| ALTER
			| ALWAYS
			| APP
			| APPEND
			| APPLY
			| ARCHIVE
			| ASOF_P
			| ASSERTION
			| ASSIGNMENT
			| AT
			| ATTRIBUTE
			| AUDIT
			| AUTOEXTEND
			| AUTOMAPPED
			| AUTO_INCREMENT
			| BACKWARD
/* PGXC_BEGIN */
			| BARRIER
/* PGXC_END */
			| BEFORE
			| BEGIN_P
			| BEGIN_NON_ANOYBLOCK
			| BLANKS
			| BLOB_P
			| BLOCKCHAIN
			| BODY_P %prec lower_than_under
			| BUILD
			| BY
			| BYTE_P
			| CACHE
			| CALL
			| CALLED
			| CANCELABLE
			| CASCADE
			| CASCADED
			| CATALOG_P
			| CATALOG_NAME
			| CHAIN
			| CHANGE
			| CHARACTERISTICS
			| CHARACTERSET
			| CHARSET
			| CHECKPOINT
			| CLASS
			| CLASS_ORIGIN
			| CLEAN
			| CLIENT
            | CLIENT_MASTER_KEY
            | CLIENT_MASTER_KEYS
			| CLOB
			| CLOSE
			| CLUSTER
            | COLUMN_ENCRYPTION_KEY
            | COLUMN_ENCRYPTION_KEYS
			| COLUMN_NAME
			| COLUMNS
			| COMMENT
			| COMMENTS
			| COMMIT
			| COMMITTED
			| COMPATIBLE_ILLEGAL_CHARS
			| COMPLETE
			| COMPILE
			| COMPLETION
			| COMPRESS
			| CONDITION
			| CONFIGURATION
			| CONNECT
			| CONNECTION
			| CONSISTENT
			| CONSTANT
			| CONSTRAINT_CATALOG
			| CONSTRAINT_NAME
			| CONSTRAINT_SCHEMA
			| CONSTRAINTS
			| CONSTRUCTOR
			| CONTENT_P
			| CONTINUE_P
			| CONTVIEW
			| CONVERSION_P
			| CONVERT_P
			| COORDINATOR
			| COORDINATORS
			| COPY
			| COST
			| CSV
			| CUBE
			| CURRENT_P
			| CURSOR
			| CURSOR_NAME
			| CYCLE
			| DATA_P
			| DATABASE
			| DATAFILE
			| DATANODE
			| DATANODES
			| DATATYPE_CL
			| DATE_FORMAT_P
			| DAY_HOUR_P
			| DAY_MINUTE_P
			| DAY_P
			| DAY_SECOND_P
			| DBCOMPATIBILITY_P
			| DEALLOCATE
			| DECLARE
			| DEFAULTS
			| DEFERRED
			| DEFINER
			| DELETE_P
			| DELIMITER
			| DELIMITERS
			| DELTA
			| DENSE_RANK
			| DETERMINISTIC
			| DIAGNOSTICS
			| DICTIONARY
			| DIRECT
			| DIRECTORY
			| DISABLE_P
			| DISCARD
			| DISCONNECT
/* PGXC_BEGIN */
			| DISTRIBUTE
			| DISTRIBUTION
/* PGXC_END */
			| DOCUMENT_P
			| DOMAIN_P
			| DOUBLE_P
			| DROP
			| DUMPFILE
			| DUPLICATE
			| EACH
			| ELASTIC
			| ENABLE_P
			| ENCLOSED
			| ENCODING
			| ENCRYPTED       
            | ENCRYPTED_VALUE
			| ENCRYPTION
            | ENCRYPTION_TYPE
			| ENDS
			| ENFORCED
			| ENUM_P
			| EOL
			| ERROR_P
			| ERRORS
			| ESCAPE
			| ESCAPED
			| ESCAPING
			| EVENT
			| EVENTS
			| EVERY
			| EXCHANGE
			| EXCLUDE
			| EXCLUDING
			| EXCLUSIVE
			| EXECUTE
			| EXPIRED_P
			| EXPLAIN
			| EXTENSION
			| EXTERNAL
			| FAMILY
			| FAST
			| FEATURES 			// DB4AI
			| FENCED
			| FIELDS
			| FILEHEADER_P
			| FILLER
			| FILL_MISSING_FIELDS
			| FILTER
			| FINAL
			| FIRST_P
			| FIXED_P
			| FOLLOWING
			| FOLLOWS_P
			| FORCE
			| FORMATTER
			| FORWARD
			| FUNCTION
			| FUNCTIONS
			| GENERATED
			| GET
			| GLOBAL
			| GRANTED
			| HANDLER
			| HEADER_P
			| HOLD
			| HOUR_MINUTE_P
			| HOUR_P
			| HOUR_SECOND_P
			| IDENTIFIED
			| IDENTITY_P
			| IF_P
			| IGNORE
			| IGNORE_EXTRA_DATA
			| IMMEDIATE
			| IMMUTABLE
			| IMPLICIT_P
			| INCLUDE
			| INCLUDING
			| INCREMENT
			| INCREMENTAL
			| INDEX
			| INDEXES
			| INFILE
			| INFINITE_P
			| INHERIT
			| INHERITS
			| INITIAL_P
			| INITRANS
			| INLINE_P
			| INPUT_P
			| INSENSITIVE
			| INSERT
			| INSTEAD
			| INTERNAL
			| INVISIBLE
			| INVOKER
			| IP
			| ISNULL
			| ISOLATION
			| KEEP
			| KEY
			| KEY_PATH
			| KEY_STORE
			| KILL
			| LABEL
			| LANGUAGE
			| LARGE_P
			| LAST_P
			| LATERAL_P
			| LC_COLLATE_P
			| LC_CTYPE_P
			| LEAKPROOF
			| LEVEL
			| LINES
			| LIST
			| LISTEN
			| LOAD
			| LOCAL
			| LOCATION
			| LOCK_P
			| LOCKED
			| LOG_P
			| LOGGING
			| LOGIN_ANY
			| LOGIN_FAILURE
			| LOGIN_SUCCESS
			| LOGOUT
			| LOOP
			| MAP
			| MAPPING
			| MASKING
			| MASTER
			| MATCH
			| MATCHED
			| MATERIALIZED
			| MAXEXTENTS
			| MAXSIZE
			| MAXTRANS
			| MAXVALUE
			| MEMBER
			| MERGE
			| MESSAGE_TEXT
			| METHOD
			| MINEXTENTS
			| MINUTE_P
			| MINUTE_SECOND_P
			| MINVALUE
			| MODE
			| MODEL      // DB4AI
			| MONTH_P
			| MOVE
			| MOVEMENT
			| MYSQL_ERRNO
			| NAME_P
			| NAMES
			| NAN_P
			| NEXT
			| NO
			| NOCOMPRESS
			| NODE
			| NOLOGGING
			| NOMAXVALUE
			| NOMINVALUE
			| NOTHING
			| NOTIFY
			| NOVALIDATE
			| NOWAIT
			| NULLCOLS
			| NULLS_P
			| NUMSTR
			| OBJECT_P
			| OF
			| OFF
			| OIDS
			| OPERATOR
			| OPTIMIZATION
			| OPTION
			| OPTIONALLY
			| OPTIONS
			| OVER
			| OUTFILE
			| OWNED
			| OWNER
			| PACKAGE
			| PACKAGES
			| PARALLEL_ENABLE
			| PARSER
			| PARTIAL %prec PARTIAL_EMPTY_PREC
			| PARTITION
			| PARTITIONS
			| PASSING
			| PASSWORD
			| PCTFREE
			| PER_P
			| PERCENT
			| PERM
			| PIPELINED
			| PLAN
			| PLANS
			| POLICY
			| POOL
			| PRECEDES_P
			| PRECEDING
			| PREDICT   // DB4AI
/* PGXC_BEGIN */
			| PREFERRED
/* PGXC_END */
			| PREFIX
			| PREPARE
			| PREPARED
			| PRESERVE
			| PRIOR
			| PRIORER
			| PRIVATE
			| PRIVILEGE
			| PRIVILEGES
			| PROCEDURAL
			| PROFILE
			| PUBLICATION
			| PUBLISH
			| PURGE
			| QUERY
			| QUOTE
			| RANDOMIZED
			| RANGE
			| RATIO
			| RAW  				{	$$ = "raw";}
			| READ
			| REASSIGN
			| REBUILD
			| RECHECK
			| RECURSIVE
			| REDISANYVALUE
			| REF
			| REFRESH
			| REINDEX
			| RELATIVE_P
			| RELEASE
			| RELOPTIONS
			| REMOTE_P
			| REMOVE
			| RENAME
			| REPEAT
			| REPEATABLE
			| REPLACE
			| REPLICA
			| RESET
			| RESIZE
			| RESOURCE
			| RESPECT_P
			| RESTART
			| RESTRICT
			| RESULT
			| RETURN
			| RETURNED_SQLSTATE
			| RETURNS
			| REUSE
			| REVOKE
			| ROLE
			| ROLES
			| ROLLBACK
			| ROLLUP
			| ROTATE
			| ROTATION
			| ROW_COUNT
			| ROWS
			| ROWTYPE_P
			| RULE
			| SAMPLE
			| SAVEPOINT
			| SCHEDULE
			| SCHEMA
			| SCHEMA_NAME
			| SCROLL
			| SEARCH
			| SECOND_P
			| SECURITY
			| SELF
			| SEPARATOR_P
			| SEQUENCE
			| SEQUENCES
			| SERIALIZABLE
			| SERVER
			| SESSION
			| SET
			| SETS
			| SHARE
			| SHIPPABLE
			| SHOW
			| SHUTDOWN
			| SIBLINGS
			| SIMPLE
			| SIZE
			| SKIP
			| SLAVE
			| SLICE
			| SMALLDATETIME_FORMAT_P
			| SNAPSHOT
			| SOURCE_P
			| SPACE
			| SPECIFICATION
			| SPILL
			| SPLIT
			| SQL_P
			| STABLE
			| STACKED_P
			| STANDALONE_P
			| START
			| STARTING
			| STARTS
			| STATEMENT
			| STATEMENT_ID
			| STATIC_P
			| STATISTICS
			| STDIN
			| STDOUT
			| STORAGE
			| STORE_P
			| STORED
			| STRATIFY
			| STREAM
			| STRICT_P
			| STRIP_P
			| SUBCLASS_ORIGIN
			| SUBPARTITION
			| SUBPARTITIONS
			| SUBSCRIPTION
			| SYNONYM
			| SYSID
			| SYS_REFCURSOR					{ $$ = "refcursor"; }
			| SYSTEM_P
			| TABLE_NAME
			| TABLES
			| TABLESPACE
			| TARGET
			| TEMP
			| TEMPLATE
			| TEMPORARY
			| TERMINATED
			| TEXT_P
			| THAN
			| TIES
			| TIMESTAMP_FORMAT_P
			| TIMEZONE_HOUR_P
			| TIMEZONE_MINUTE_P
			| TIME_FORMAT_P
			| TRANSACTION
			| TRANSFORM
			| TRIGGER
			| TRUNCATE
			| TRUSTED
			| TSFIELD
			| TSTAG
			| TSTIME 
			| TYPE_P
			| TYPES_P
			| UNBOUNDED
			| UNCOMMITTED
			| UNDER
			| UNENCRYPTED
			| UNKNOWN
			| UNLIMITED
			| UNLISTEN
			| UNLOCK
			| UNLOGGED
			| UNTIL
			| UNUSABLE
			| UPDATE
			| USE_P
			| USEEOF
			| VACUUM
			| VALID
			| VALIDATE
			| VALIDATION
			| VALIDATOR
			| VALUE_P
			| VARIABLES
			| VARRAY
			| VARYING
			| VCGROUP
			| VERSION_P
			| VIEW
			| VISIBLE
			| VOLATILE
			| WAIT
			| WARNINGS
			| WEAK
			| WHILE_P
			| WHITESPACE_P
			| WITHIN
			| WITHOUT
			| WORK
			| WORKLOAD
			| WRAPPER
			| WRITE
			| XML_P
			| YEAR_MONTH_P
			| YEAR_P
			| YES_P
			| ZONE
		;

/* Column identifier --- keywords that can be column, table, etc names.
 *
 * Many of these keywords will in fact be recognized as type or function
 * names too; but they have special productions for the purpose, and so
 * can't be treated as "generic" type or function names.
 *
 * The type names appearing here are not usable as function names
 * because they can be followed by '(' in typename productions, which
 * looks too much like a function call for an LR(1) parser.
 *
 * If the new col_name_keyword is not used in func_expr_common_subexpr,
 * add it to col_name_keyword_nonambiguous too!
 */
col_name_keyword:
			  BETWEEN
			| BIGINT
			| BINARY_DOUBLE
			| BINARY_DOUBLE_INF
			| BINARY_DOUBLE_NAN
			| BINARY_INTEGER
			| BIT
			| BOOLEAN_P
			| BUCKETCNT
			| BYTEAWITHOUTORDER
			| BYTEAWITHOUTORDERWITHEQUAL
			| CHAR_P
			| CHARACTER
			| COALESCE
			| DATE_P
			| DEC
			| DECIMAL_P
			| DECODE
			| EXISTS
			| EXTRACT
			| FLOAT_P
			| GREATEST
			| GROUPING_P
			| INOUT
			| INT_P
			| INTEGER
			| INTERVAL
			| JSON_EXISTS
			| LEAST
			| NATIONAL
			| NCHAR
			| NONE
                        | NTH_VALUE_P
			| NULLIF
			| NUMBER_P
			| NUMERIC
			| NVARCHAR
			| NVARCHAR2
			| NVL
			| OUT_P
			| OVERLAY
			| POSITION
			| PRECISION
			| REAL
			| ROW
			| SETOF
			| SMALLDATETIME
			| SMALLINT
			| SUBSTRING
			| TIME
			| TIMESTAMP
			| TIMESTAMPDIFF
			| TINYINT
			| TREAT
			| TRIM
			| VALUES
			| VARCHAR
			| VARCHAR2
			| XMLATTRIBUTES
			| XMLCONCAT
			| XMLELEMENT
			| XMLEXISTS
			| XMLFOREST
			| XMLPARSE
			| XMLPI
			| XMLROOT
			| XMLSERIALIZE
		;

/* Column identifier --- keywords that can be column, table, etc names.
 *
 * These keywords will not be recognized as function names. These keywords
 * are used to distinguish index prefix keys from function keys.
 */
col_name_keyword_nonambiguous:
			  BETWEEN
			| BIGINT
			| BINARY_DOUBLE
			| BINARY_DOUBLE_INF
			| BINARY_DOUBLE_NAN
			| BINARY_INTEGER
			| BIT
			| BOOLEAN_P
			| BUCKETCNT
			| BYTEAWITHOUTORDER
			| BYTEAWITHOUTORDERWITHEQUAL
			| CHAR_P
			| CHARACTER
			| DATE_P
			| DEC
			| DECIMAL_P
			| DECODE
			| EXISTS
			| FLOAT_P
			| GROUPING_P
			| INOUT
			| INT_P
			| INTEGER
			| INTERVAL
			| NATIONAL
			| NCHAR
			| NONE
			| NUMBER_P
			| NUMERIC
			| NVARCHAR2
			| OUT_P
			| PRECISION
			| REAL
			| ROW
			| SETOF
			| SMALLDATETIME
			| SMALLINT
			| TIME
			| TIMESTAMP
			| TINYINT
			| VALUES
			| VARCHAR
			| VARCHAR2
			| XMLATTRIBUTES
		;

/* Type/function identifier --- keywords that can be type or function names.
 *
 * Most of these are keywords that are used as operators in expressions;
 * in general such keywords can't be column names because they would be
 * ambiguous with variables, but they are unambiguous as function identifiers.
 *
 * Do not include POSITION, SUBSTRING, etc here since they have explicit
 * productions in a_expr to support the goofy SQL9x argument syntax.
 * - thomas 2000-11-28
 */
type_func_name_keyword:
			 AUTHORIZATION
			| BINARY
			| COLLATION
			| COMPACT
			| CONCURRENTLY
			| CROSS
			| CSN
			| CURRENT_SCHEMA
			| DELTAMERGE
			| FREEZE
			| FULL
			| HDFSDIRECTORY
			| ILIKE
			| INNER_P
			| JOIN
			| LEFT
			| LIKE
			| NATURAL
			| NOTNULL
			| OUTER_P
			| OVERLAPS
			| RECYCLEBIN
			| RIGHT
			| SIMILAR
			| TABLESAMPLE
			| TIMECAPSULE
			| 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
			| AUTHID
			| BOTH
			| BUCKETS
			| CASE
			| CAST
			| CHECK
			| COLLATE
			| COLUMN
			| CONSTRAINT
			| CREATE
			| CURRENT_CATALOG
			| CURRENT_DATE
			| CURRENT_ROLE
			| CURRENT_TIME
			| CURRENT_TIMESTAMP
			| CURRENT_USER
			| DEFAULT
			| DEFERRABLE
			| DESC
			| DISTINCT
			| DO
			| ELSE
			| END_P
			| EXCEPT
			| EXCLUDED
			| FALSE_P
			| FETCH
			| FOR
			| FOREIGN
			| FROM
			| GRANT
			| GROUP_P
			| GROUPPARENT
			| HAVING
			| IMCSTORED
			| IN_P
			| INITIALLY
			| INTERSECT
			| INTO
			| IS
			| LEADING
			| LESS
			| LIMIT
			| LOCALTIME
			| LOCALTIMESTAMP
			| MINUS_P
			| MODIFY_P
			| NOCYCLE
			| NOT
			| NULL_P
			| OFFSET
			| ON
			| ONLY
			| OR
			| ORDER
			| PERFORMANCE
			| PLACING
			| PRIMARY
			| PROCEDURE
			| REFERENCES
			| REJECT_P
			| RETURNING
                        | ROWNUM
			| SELECT
			| SESSION_USER
			| SHRINK
			| SOME
			| SYMMETRIC
			| SYSDATE
			| TABLE
			| THEN
			| TO
			| TRAILING
			| TRUE_P
			| UNIMCSTORED
			| UNION
			| UNIQUE
			| USER
			| USING
			| VARIADIC
			| VERIFY
			| WHEN
			| WHERE
			| WINDOW
			| WITH
		;

/* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */
/*$$include "gram-tsql-rule.y"*/

%%

/*
 * The signature of this function is required by bison.  However, we
 * ignore the passed yylloc and instead use the last token position
 * available from the scanner.
 */
static void
base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg)
{
	parser_yyerror(msg);
}

static Node *
makeColumnRef(char *colname, List *indirection,
			  int location, core_yyscan_t yyscanner)
{
	/*
	 * Generate a ColumnRef node, with an A_Indirection node added if there
	 * is any subscripting in the specified indirection list.  However,
	 * any field selection at the start of the indirection list must be
	 * transposed into the "fields" part of the ColumnRef node.
	 */
	ColumnRef  *c = makeNode(ColumnRef);
	int		nfields = 0;
	int     indnum = 0;
	ListCell *l;

	c->location = location;
	c->indnum = 0;
	foreach(l, indirection)
	{
		if (IsA(lfirst(l), A_Indices))
		{
			A_Indirection *i = makeNode(A_Indirection);
			indnum++;

			if (nfields == 0)
			{
				/* easy case - all indirection goes to A_Indirection */
				c->fields = list_make1(makeString(colname));
				i->indirection = check_indirection(indirection, yyscanner);
			}
			else
			{
				/* got to split the list in two */
				i->indirection = check_indirection(list_copy_tail(indirection,
																  nfields),
												   yyscanner);
				indirection = list_truncate(indirection, nfields);
				c->fields = lcons(makeString(colname), indirection);
			}
			c->indnum = indnum;
			i->arg = (Node *) c;
			return (Node *) i;
		}
		else if (IsA(lfirst(l), A_Star))
		{
			/* We only allow '*' at the end of a ColumnRef */
			if (lnext(l) != NULL)
				parser_yyerror("improper use of \"*\"");
		}
		else if (IsA(lfirst(l), String) && strncmp(strVal(lfirst(l)), "(+)", 3) == 0)
		{
			u_sess->parser_cxt.stmt_contains_operator_plus = true;
		}
		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, Node *fmt_list, Node *nls_fmt, Node *default_expr, int location)
{
	TypeCast *n = makeNode(TypeCast);
	n->arg = arg;
	n->typname = typname;
	n->fmt_str = fmt_list;
	n->nls_fmt_str = nls_fmt;
	n->default_expr = default_expr;
	n->location = location;
	return (Node *) n;
}

static void StrCopy(char *dst, char *src) 
{
    char *p = src;
    char *q = dst;
    int len = strlen(src);
	int i = 0;
    while (*p != '\"' && *p != ' ' && i < len)
    {
        *(q++) = *(p++);
		i++;
    }
    *(q++)='\0'; 
}

static char*
GetPkgName(char* pkgName) 
{
	if (pkgName == NULL) {
		return NULL;
	}
	int begin = 0;
	char* destName = (char *) palloc(strlen(pkgName) + 1);
	while ((isspace(*pkgName) || isquote(*pkgName)) && begin < strlen(pkgName)) {
		pkgName++;
		begin++;
	}
	StrCopy(destName, pkgName);
	return destName;
}

static Node *
makeStringConst(char *str, int location)
{
	A_Const *n = makeNode(A_Const);


	if (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT)
	{
		if (NULL == str || (0 == strlen(str) && !ACCEPT_EMPTY_STR))
		{
			n->val.type = T_Null;
			n->val.val.str = str;
			n->location = location;
		}
		else
		{
			n->val.type = T_String;
			n->val.val.str = str;
			n->location = location;
		}
	}
	else
	{
		n->val.type = T_String;
		n->location = location;
		if (NULL == str) {
			n->val.val.str = str;
		} else {
			n->val.val.str = pg_server_to_any(str, strlen(str), GetCharsetConnection());
		}
	}

	return (Node *)n;
}

static Node *
makeStringConstCast(char *str, int location, TypeName *typname)
{
	Node *s = makeStringConst(str, location);

	return makeTypeCast(s, typname, NULL, NULL, NULL, -1);
}

static Node *
makeIntConst(int val, int location)
{
	A_Const *n = makeNode(A_Const);

	n->val.type = T_Integer;
	n->val.val.ival = val;
	n->location = location;

	return (Node *)n;
}

static Node *
makeFloatConst(char *str, int location)
{
	A_Const *n = makeNode(A_Const);

	n->val.type = T_Float;
	n->val.val.str = str;
	n->location = location;

	return (Node *)n;
}

static Node *
makeBitStringConst(char *str, int location)
{
	A_Const *n = makeNode(A_Const);

	n->val.type = T_BitString;
	n->val.val.str = str;
	n->location = location;

	return (Node *)n;
}

Node *
makeAConst(Value *v, int location)
{
	Node *n;

	switch (v->type)
	{
		case T_Float:
			n = makeFloatConst(v->val.str, location);
			break;

		case T_Integer:
			n = makeIntConst(v->val.ival, location);
			break;

		case T_String:
		default:
			n = makeStringConst(v->val.str, location);
			break;
	}

	return n;
}

/* makeBoolAConst()
 * Create an A_Const string node and put it inside a boolean cast.
 */
Node *
makeBoolAConst(bool state, int location)
{
	A_Const *n = makeNode(A_Const);

	n->val.type = T_String;
	n->val.val.str = (char *)(state ? "t" : "f");
	n->location = location;

	return makeTypeCast((Node *)n, SystemTypeName("bool"), NULL, NULL, NULL, -1);
}

/* check_qualified_name --- check the result of qualified_name production
 *
 * It's easiest to let the grammar production for qualified_name allow
 * subscripts and '*', which we then must reject here.
 */
static void
check_qualified_name(List *names, core_yyscan_t yyscanner)
{
	ListCell   *i;

	foreach(i, names)
	{
		if (!IsA(lfirst(i), String))
			parser_yyerror("syntax error");
	}
}

/* check_func_name --- check the result of func_name production
 *
 * It's easiest to let the grammar production for func_name allow subscripts
 * and '*', which we then must reject here.
 */
static List *
check_func_name(List *names, core_yyscan_t yyscanner)
{
	ListCell   *i;

	foreach(i, names)
	{
		if (!IsA(lfirst(i), String))
			parser_yyerror("syntax error");
	}
	return names;
}

bool
IsValidIdentClientKey(const char *input)
{
	if (input == NULL || strlen(input) <= 0) {
		return false;
	}
	char c = input[0];
	/*The first character id numbers or dollar or point*/
	if ((c >= '0' && c <= '9') || c == '$' || c == '.')
	{
		return false;
	}

	int len = strlen(input);
	for (int i = 0; i < len; i++)
	{
		c = input[i];
		if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$'|| c=='.')
		{
			continue;
		}
		else
		{
			return false;
		}
	}
	return true;
}

static List *
check_setting_name(List *names, core_yyscan_t yyscanner)
{
	ListCell   *i;

	foreach(i, names)
	{
		Value* v = (Value *)lfirst(i);
		if (v == NULL || v->type != T_String) {
			const char* message = "invalid name";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("invalid name")));
		}
		if (!IsValidIdentClientKey(v->val.str)) {
			const char* message = "invalid name";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("invalid name")));
		}
	}
	return names;
}

/* check_indirection --- check the result of indirection production
 *
 * We only allow '*' at the end of the list, but it's hard to enforce that
 * in the grammar, so do it here.
 */
static List *
check_indirection(List *indirection, core_yyscan_t yyscanner)
{
	ListCell *l;

	foreach(l, indirection)
	{
		if (IsA(lfirst(l), A_Star))
		{
			if (lnext(l) != NULL)
				parser_yyerror("improper use of \"*\"");
		}
	}
	return indirection;
}

/* extractArgTypes()
 * Given a list of FunctionParameter nodes, extract a list of just the
 * argument types (TypeNames) for input parameters only.  This is what
 * is needed to look up an existing function, which is what is wanted by
 * the productions that use this call.
 */
static List *
extractArgTypes(List *parameters)
{
    List *result = NIL;
    ListCell *i;

    foreach(i, parameters)
    {
        FunctionParameter *p = (FunctionParameter *) lfirst(i);
#ifndef ENABLE_MULTIPLE_NODES
        if ((p->mode == FUNC_PARAM_OUT && enable_out_param_override())
                || p->mode == FUNC_PARAM_IN
                || p->mode == FUNC_PARAM_INOUT
                || p->mode == FUNC_PARAM_VARIADIC) {
#else
        if (p->mode == FUNC_PARAM_IN
                || p->mode == FUNC_PARAM_INOUT
                || p->mode == FUNC_PARAM_VARIADIC) {
#endif
            result = lappend(result, p->argType);
        }
    }
    return result;
}

/* 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,
					FetchLimit* limitClause,
					WithClause *withClause,
					core_yyscan_t yyscanner)
{
	AssertEreport(IsA(stmt, SelectStmt), MOD_OPT, "Node type inconsistant");

	/*
	 * Tests here are to reject constructs like
	 *	(SELECT foo ORDER BY bar) ORDER BY baz
	 */
	if (sortClause)
	{
		if (stmt->sortClause) {
			const char* message = "multiple ORDER BY clauses not allowed";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("multiple ORDER BY clauses not allowed"),
					 parser_errposition(exprLocation((Node *) sortClause))));
		}
		stmt->sortClause = sortClause;
	}
	/* We can handle multiple locking clauses, though */
	stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);

	if (limitClause) {
		if (limitClause->limitOffset)
		{
			Node *limitOffset = limitClause->limitOffset;
			if (stmt->limitOffset) {
				const char* message = "multiple OFFSET clauses not allowed";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("multiple OFFSET clauses not allowed"),
						parser_errposition(exprLocation(limitOffset))));
			}
			stmt->limitOffset = limitOffset;
			if (DB_IS_CMPT(D_FORMAT) && stmt->limitCount) {
				const char* message = "A TOP clause cannot be used together with an OFFSET clause in D-format database";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("A TOP clause cannot be used together with an OFFSET clause in D-format database"),
						parser_errposition(exprLocation(limitOffset))));
			}
		}
		if (limitClause->limitCount)
		{
			Node *limitCount = limitClause->limitCount;
			if (stmt->limitCount) {
				const char* message = "multiple OFFSET clauses not allowed";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						errmsg("multiple LIMIT clauses not allowed"),
						parser_errposition(exprLocation(limitCount))));
			}
			stmt->limitCount = limitCount;
		}
		stmt->isFetch = limitClause->isFetch;
        stmt->limitIsPercent = limitClause && limitClause->isPercent;
	    stmt->limitWithTies = limitClause && limitClause->isWithTies;
	}

	if (withClause)
	{
		if (stmt->withClause) {
			const char* message = "multiple OFFSET clauses not allowed";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("multiple WITH clauses not allowed"),
					 parser_errposition(exprLocation((Node *) withClause))));
		}
		stmt->withClause = withClause;
	}
}

static Node *
makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg)
{
	SelectStmt *n = makeNode(SelectStmt);

	n->op = op;
	n->all = all;
	n->larg = (SelectStmt *) larg;
	n->rarg = (SelectStmt *) rarg;
	return (Node *) n;
}

/* SystemFuncName()
 * Build a properly-qualified reference to a built-in function.
 */
List *
SystemFuncName(char *name)
{
	return list_make2(makeString("pg_catalog"), makeString(name));
}

/* SystemTypeName()
 * Build a properly-qualified reference to a built-in type.
 *
 * typmod is defaulted, but may be changed afterwards by caller.
 * Likewise for the location.
 */
TypeName *
SystemTypeName(char *name)
{
	return makeTypeNameFromNameList(list_make2(makeString("pg_catalog"),
											   makeString(name)));
}

/* doNegate()
 * Handle negation of a numeric constant.
 *
 * Formerly, we did this here because the optimizer couldn't cope with
 * indexquals that looked like "var = -4" --- it wants "var = const"
 * and a unary minus operator applied to a constant didn't qualify.
 * As of Postgres 7.0, that problem doesn't exist anymore because there
 * is a constant-subexpression simplifier in the optimizer.  However,
 * there's still a good reason for doing this here, which is that we can
 * postpone committing to a particular internal representation for simple
 * negative constants.	It's better to leave "-123.456" in string form
 * until we know what the desired type is.
 */
static Node *
doNegate(Node *n, int location)
{
	if (IsA(n, A_Const))
	{
		A_Const *con = (A_Const *)n;

		/* report the constant's location as that of the '-' sign */
		con->location = location;

		if (con->val.type == T_Integer)
		{
			con->val.val.ival = -con->val.val.ival;
			return n;
		}
		if (con->val.type == T_Float)
		{
			doNegateFloat(&con->val);
			return n;
		}
	}

	return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location);
}

static void
doNegateFloat(Value *v)
{
	char   *oldval = v->val.str;

	AssertEreport(IsA(v, Float), MOD_OPT, "Node Type inconsistant");
	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;
	}
}

static Node *
makeAArrayExpr(List *elements, int location)
{
	A_ArrayExpr *n = makeNode(A_ArrayExpr);

	n->elements = elements;
	n->location = location;
	return (Node *) n;
}

static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
			int location)
{
	XmlExpr		*x = makeNode(XmlExpr);

	x->op = op;
	x->name = name;
	/*
	 * named_args is a list of ResTarget; it'll be split apart into separate
	 * expression and name lists in transformXmlExpr().
	 */
	x->named_args = named_args;
	x->arg_names = NIL;
	x->args = args;
	/* xmloption, if relevant, must be filled in by caller */
	/* type and typmod will be filled in during parse analysis */
	x->type = InvalidOid;			/* marks the node as not analyzed */
	x->location = location;
	return (Node *) x;
}

/*
 * Merge the input and output parameters of a table function.
 */
static List *
mergeTableFuncParameters(List *func_args, List *columns)
{
	ListCell   *lc;

	/* Explicit OUT and INOUT parameters shouldn't be used in this syntax */
	foreach(lc, func_args)
	{
		FunctionParameter *p = (FunctionParameter *) lfirst(lc);

		if (p->mode != FUNC_PARAM_IN && p->mode != FUNC_PARAM_VARIADIC) {
			const char* message = "OUT and INOUT arguments aren't allowed in TABLE functions";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("OUT and INOUT arguments aren't allowed in TABLE functions")));
		}
	}

	return list_concat(func_args, columns);
}

/*
 * Determine return type of a TABLE function.  A single result column
 * returns setof that column's type; otherwise return setof record.
 */
static TypeName *
TableFuncTypeName(List *columns)
{
	TypeName *result;

	if (list_length(columns) == 1)
	{
		FunctionParameter *p = (FunctionParameter *) linitial(columns);

		result = (TypeName *) copyObject(p->argType);
	}
	else
		result = SystemTypeName("record");

	result->setof = true;

	return result;
}

/*
 * Convert a list of (dotted) names to a RangeVar (like
 * makeRangeVarFromNameList, but with position support).  The
 * "AnyName" refers to the any_name production in the grammar.
 */
static RangeVar *
makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner)
{
	RangeVar *r = makeNode(RangeVar);
	const char* message = "improper qualified name (too many dotted names)";
	switch (list_length(names))
	{
		case 1:
			r->catalogname = NULL;
			r->schemaname = NULL;
			r->relname = strVal(linitial(names));
			break;
		case 2:
			r->catalogname = NULL;
			r->schemaname = strVal(linitial(names));
			r->relname = strVal(lsecond(names));
			break;
		case 3:
			r->catalogname = strVal(linitial(names));;
			r->schemaname = strVal(lsecond(names));
			r->relname = strVal(lthird(names));
			break;
		default:
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("improper qualified name (too many dotted names): %s",
							NameListToString(names)),
					 parser_errposition(position)));
			break;
	}

	r->relpersistence = RELPERSISTENCE_PERMANENT;
	r->location = position;
	r->ispartition = false;
	r->isbucket = false;
	r->buckets = NIL;

	return r;
}

/* Separate Constraint nodes from COLLATE clauses in a ColQualList */
static void
SplitColQualList(List *qualList,
				 List **constraintList, CollateClause **collClause,
				 core_yyscan_t yyscanner)
{
	ListCell   *cell;
	ListCell   *prev;
	ListCell   *next;

	*collClause = NULL;
	prev = NULL;
	for (cell = list_head(qualList); cell; cell = next)
	{
		Node   *n = (Node *) lfirst(cell);

		next = lnext(cell);
		if (IsA(n, Constraint))
		{
			/* keep it in list */
			prev = cell;
			continue;
		}
		if (IsA(n, CollateClause))
		{
			CollateClause *c = (CollateClause *) n;

			if (*collClause) {
				const char* message = "multiple COLLATE clauses not allowed";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("multiple COLLATE clauses not allowed"),
						 parser_errposition(c->location)));
			}
			*collClause = c;
		}
		else if (IsA(n, ClientLogicColumnRef))
		{
			const char* message = "unsupported syntax: ENCRYPTED WITH in this operation";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate, (errmodule(MOD_SEC), errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("unsupported syntax: ENCRYPTED WITH in this operation"), errdetail("N/A"),
					errcause("client encryption feature is not supported this operation."),
						erraction("Check client encryption feature whether supported this operation.")));
		}
		else {
			const char* message = "unexpected node type";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
						errmsg("unexpected node type %d", (int) n->type)));
		}
		/* remove non-Constraint nodes from qualList */
		qualList = list_delete_cell(qualList, cell, prev);
	}
	*constraintList = qualList;
}

/* Separate Constraint nodes from COLLATE clauses in a ColQualList */
static void
SplitColQualList(List *qualList,
				 List **constraintList, CollateClause **collClause,ClientLogicColumnRef **clientLogicColumnRef,
				 core_yyscan_t yyscanner)
{
	ListCell   *cell;
	ListCell   *prev;
	ListCell   *next;

	*collClause = NULL;
	*clientLogicColumnRef =NULL;
	prev = NULL;
	for (cell = list_head(qualList); cell; cell = next)
	{
		Node   *n = (Node *) lfirst(cell);

		next = lnext(cell);
		if (IsA(n, Constraint))
		{
			/* keep it in list */
			prev = cell;
			continue;
		}
		if (IsA(n, CollateClause))
		{
			CollateClause *c = (CollateClause *) n;

			if (*collClause) {
				const char* message = "multiple COLLATE clauses not allowed";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("multiple COLLATE clauses not allowed"),
						 parser_errposition(c->location)));
			}
			*collClause = c;
		}
		else if (IsA(n, ClientLogicColumnRef))
		{
			ClientLogicColumnRef *e = (ClientLogicColumnRef *) n;

			if (*clientLogicColumnRef) {
				const char* message = "multiple encrypted columns are not allowed";
				InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("multiple encrypted columns are not allowed"),
						 parser_errposition(e->location)));
			}
			*clientLogicColumnRef = e;
		}
		else {
			const char* message = "unexpected node type";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
						errmsg("unexpected node type %d", (int) n->type)));
		}
		/* remove non-Constraint nodes from qualList */
		qualList = list_delete_cell(qualList, cell, prev);
	}
	*constraintList = qualList;
}

/*
 * Process result of ConstraintAttributeSpec, and set appropriate bool flags
 * in the output command node.  Pass NULL for any flags the particular
 * command doesn't support.
 */
static void
processCASbits(int cas_bits, int location, const char *constrType,
			   bool *deferrable, bool *initdeferred, bool *not_valid,
			   bool *no_inherit, core_yyscan_t yyscanner)
{
	/* defaults */
	if (deferrable)
		*deferrable = false;
	if (initdeferred)
		*initdeferred = false;
	if (not_valid)
		*not_valid = false;

	if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED))
	{
		if (deferrable)
			*deferrable = true;
		else {
			const char* message = "constraints cannot be marked DEFERRABLE";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 /* translator: %s is CHECK, UNIQUE, or similar */
					 errmsg("%s constraints cannot be marked DEFERRABLE",
							constrType),
					 parser_errposition(location)));
		}
	}

	if (cas_bits & CAS_INITIALLY_DEFERRED)
	{
		if (initdeferred)
			*initdeferred = true;
		else {
			const char* message = "constraints cannot be marked DEFERRABLE";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 /* translator: %s is CHECK, UNIQUE, or similar */
					 errmsg("%s constraints cannot be marked DEFERRABLE",
							constrType),
					 parser_errposition(location)));
		}
	}

	if (cas_bits & (CAS_NOT_VALID | CAS_DISABLE_NO_VALIDATE))
	{
		if (not_valid)
			*not_valid = true;
		else {
			const char* message = "constraints cannot be marked NOT VALID";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 /* translator: %s is CHECK, UNIQUE, or similar */
					 errmsg("%s constraints cannot be marked NOT VALID",
							constrType),
					 parser_errposition(location)));
		}
	}

	if (cas_bits & CAS_NO_INHERIT)
	{
		if (no_inherit)
			*no_inherit = true;
		else {
			const char* message = "constraints cannot be marked NO INHERIT";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 /* translator: %s is CHECK, UNIQUE, or similar */
					 errmsg("%s constraints cannot be marked NO INHERIT",
							constrType),
					 parser_errposition(location)));
		}
	}
}

/* parser_init()
 * Initialize to parse one query string
 */
void
parser_init(base_yy_extra_type *yyext)
{
	yyext->parsetree = NIL;		/* in case grammar forgets to set it */
	yyext->core_yy_extra.query_string_locationlist = NIL;
	yyext->core_yy_extra.paren_depth = 0;
}

static Expr *
makeNodeDecodeCondtion(Expr* firstCond,Expr* secondCond)
{
	A_Expr   *equal_oper	= makeSimpleA_Expr(AEXPR_OP, "=", (Node*)copyObject( firstCond), (Node*)copyObject(secondCond), -1);
	NullTest *isnull_oper1	= makeNode(NullTest);
	NullTest *isnull_oper2	= makeNode(NullTest);
	A_Expr   *and_oper	= makeA_Expr(AEXPR_AND,NIL,(Node*)isnull_oper1, (Node*)isnull_oper2, -1);
	CaseExpr *c		= makeNode(CaseExpr);
	CaseWhen *w		= makeNode(CaseWhen);

	isnull_oper1->arg = (Expr*) copyObject( firstCond);
	isnull_oper1->nulltesttype = IS_NULL;
	isnull_oper2->arg = (Expr*) copyObject(secondCond);
	isnull_oper2->nulltesttype = IS_NULL;

	w->expr  = (Expr*)and_oper;
	w->result = (Expr*)makeBoolAConst(TRUE, -1);

	c->casetype = InvalidOid;
	c->arg = NULL;
	c->args = NULL;
	c->args = lappend(c->args,w);
	c->defresult = (Expr*)equal_oper;
	c->fromDecode = true;

	return (Expr*)c;
}

// make function infomation to kill the session
// make "ResTarget" for invoking function "pg_terminate_session",
// the first cell of arguments is pid, the second is sessionId
static List*
make_action_func(List *arguments)
{
	FuncCall		*func = NULL;
	ResTarget	*restarget = NULL;

	func = (FuncCall*)makeNode(FuncCall);
	func->funcname = list_make1(makeString("pg_terminate_session"));
	func->args = arguments;
	func->agg_star = FALSE;
	func->agg_distinct = FALSE;
	func->location = -1;
	func->call_func = false;

	restarget = makeNode(ResTarget);
	restarget->name = NULL;
	restarget->indirection = NIL;
	restarget->val = (Node *)func;
	restarget->location = -1;

	return (list_make1(restarget));
}

/*
 * @Description:  get arguments of function "pg_terminate_session" from a string.
 * @in sid : the pid and sessionId info which need be terminated.
 * @return : the list include pid and sessionId information.
 */
static List *
get_func_args(char *sid)
{
	char *token = NULL;
	List *sidlist = NIL;
	long long pid = 0;
	long long sessionId = 0;
	const char *sep = ",";

	/*
	 * split the string with denotation 'sep'.
	 */
	while ((token = pg_strsep(&sid, sep)))
		sidlist = lappend(sidlist, token);

	/*
	 * it is incorrect unless the number of parameter equals 2
	 */
	if (2 != sidlist->length)
	{
		const char* message = "missing or invalid session ID";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				errmsg("missing or invalid session ID")));
		return NIL;
	}

	pid = get_pid((const char *)linitial(sidlist));
	sessionId = get_pid((const char *)lsecond(sidlist));

	/*
	 * negative is illegal for session id
	 */
	if (pid < 0 || sessionId < 0)
	{
		const char* message = "missing or invalid session ID";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				errmsg("missing or invalid session ID")));
		return NIL;
	}

	return list_make2(makeStringConst((char *)linitial(sidlist), -1), 
		              makeStringConst((char *)lsecond(sidlist), -1));
}

// transform a string to a Oid
static long long
get_pid(const char *strsid)
{
	char cur_char = 0;
	int counter = 0;
	bool start =false;
	bool end = false;

	/*
	 * it is illegal format if the string is null
	 */
	if (!strsid)
	{
		const char* message = "missing or invalid session ID";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				errmsg("missing or invalid session ID")));
		return 0;
	}

	cur_char = strsid[counter];
	while (cur_char)
	{
		/*
		 * it is illegal if the string has a character that it is not a alphanumeric
		 */
		if (!isdigit(cur_char) && !isspace(cur_char))
		{
			const char* message = "missing or invalid session ID";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				errmsg("missing or invalid session ID")));
			return 0;
		}

		if (!start && isdigit(cur_char))
			start = true;

		if (!end && isspace(cur_char) && start)
			end = true;
		/*
		 * it is illegal if the string is aplited by a space
		 */
		if (start && end && !isspace(cur_char))
		{
			const char* message = "missing or invalid session ID";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				errmsg("missing or invalid session ID")));
			return 0;
		}
		cur_char = strsid[++counter];
	}

	if (!start)
	{
		const char* message = "missing or invalid session ID";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_UNDEFINED_OBJECT),
			errmsg("missing or invalid session ID")));
		return 0;
	}

	return atoll(strsid);
}

// Get next token from string *stringp, where tokens are
// possibly-empty strings separated by characters from delim.
// Writes NULs into the string at *stringp to end tokens,
// delim need not remain constant from call to call.
// On return, *stringp points past the last NUL written (if there
// might be further tokens), or is NULL (if there are definitely no
// moretokens).
// If *stringp is NULL, strsep returns NULL
static char *
pg_strsep(char **stringp, const char *delim)
{
	char	 *s = NULL;
	const char *spanp = NULL;
	int c = 0;
	int sc = 0;
	char	 *tok = NULL;

	if (NULL == (s = *stringp))
		return NULL;

	for (tok = s;;)
	{
		c = *s++;
		spanp = delim;
		do
		{
			if ((sc =*spanp++) == c)
			{
				if (0 == c)
					s = NULL;
				else
					s[-1] = 0;
				*stringp = s;
				return (tok);
			}
		} while (0 != sc);
	}
}

static int
get_outarg_num (List *fun_args)
{
	int count = 0;
	FunctionParameter *arg = NULL;
	ListCell* cell = NULL;

	if (NIL == fun_args)
		return 0;

	foreach (cell, fun_args)
	{
		arg = (FunctionParameter*) lfirst(cell);
		if ( FUNC_PARAM_OUT == arg->mode || FUNC_PARAM_INOUT == arg->mode )
			count++;
	}
	return count;
}

// To make a node for anonymous block
static Node *
MakeAnonyBlockFuncStmt(int flag, const char *str)
{
	DoStmt *n = makeNode(DoStmt);
	char *str_body	= NULL;
	DefElem * body	= NULL;
	errno_t		rc = EOK;

	if (BEGIN_P == flag)
	{
		int len1 = strlen("DECLARE \nBEGIN ");
		int len2 = strlen(str);
		str_body = (char *)palloc(len1 + len2 + 1);
		rc = strncpy_s(str_body, len1 + len2 + 1, "DECLARE \nBEGIN ",len1);
		securec_check(rc, "\0", "\0");
		rc = strcpy_s(str_body + len1, len2 + 1, str);
		securec_check(rc, "\0", "\0");
	}
	else
	{
		int len1 = strlen("DECLARE ");
		int len2 = strlen(str);
		str_body = (char *)palloc(len1 + len2 + 1);
		rc = strncpy_s(str_body, len1 + len2 + 1, "DECLARE ", len1);
		securec_check(rc, "\0", "\0");
		rc = strcpy_s(str_body + len1, len2 + 1, str);
		securec_check(rc, "\0", "\0");
	}

	body = makeDefElem("as", (Node*)makeString(str_body));
	n->args = list_make1(makeDefElem("language", (Node *)makeString("plpgsql")));
	n->args = lappend( n->args, body);

	return (Node*)n;
}

static Node *make_AStar_subquery(RangeVar *rangeVar)
{
	SelectStmt *n = makeNode(SelectStmt);
	ColumnRef *col = makeNode (ColumnRef);
	col->fields = list_make1(makeNode(A_Star));
	col->indnum = 0;
	ResTarget *res = makeNode(ResTarget);
	res->name = NULL;
	res->indirection = NIL;
	res->val = (Node *)col;
	n->targetList = list_make1(res);
	n->fromClause = list_make1(rangeVar);
	return (Node*)n;
}

// get arg info with arg position or arg name
static void
get_arg_mode_by_name(const char *argname, const char * const *argnames,
			const char *argmodes,const int proargnum, bool *have_assigend, char *argmode)
{
	int	curpos = 0;
	const char *paraname= NULL;

	if (argnames == NULL) {
		const char* message = "No function matches the given arguments names.";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			errmsg("No function matches the given arguments names. "
			"You might need to add explicit declare arguments names.")));
	}

	if (unlikely(argname == NULL)) {
		const char* message = "argname should not be null";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate, 
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE), 
			errmsg("argname should not be null")));
	}

	for (curpos = 0; curpos < proargnum; curpos++)
	{
		paraname = argnames[curpos];

		if (paraname && !strcmp(paraname, argname))
		{
			if (!argmodes)
				*argmode = FUNC_PARAM_IN;
			else
				*argmode = argmodes[curpos];

			break;
		}
	}

	if (curpos < proargnum && have_assigend[curpos])
	{
		const char* message = "aparameter is assigned more than once";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_DUPLICATE_OBJECT),
			errmsg("parameter \"%s\" is assigned more than once", argname)));
		return;
	}

	if (curpos == proargnum)
	{
		const char* message = "parameter is undefined";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_PARAMETER),
				errmsg("parameter \"%s\" is undefined", argname)));
		return;
	}

	have_assigend[curpos] = true;
}

// get arg info with arg position or arg position
static void
get_arg_mode_by_pos(const int pos, const char *argmodes,
			const int narg, bool *have_assigend, char *argmode)
{
	AssertEreport(pos >= 0, MOD_OPT, "para should not be negative");

	if (have_assigend[pos])
	{
		const char* message = "the parameter located have been assigned";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_DUPLICATE_OBJECT),
			errmsg("the parameter located \"%d\" have been assigned", pos + 1)));
		return;
	}

	if (argmodes)
		*argmode = argmodes[pos];
	else
		*argmode = FUNC_PARAM_IN;

	have_assigend[pos] = true;
}

// return count of table function output column
static int get_table_modes(int narg, const char *p_argmodes)
{
	int count = 0;
	if (p_argmodes == NULL)
		return 0;
	for (; narg > 0; narg--, p_argmodes++)
		if (*p_argmodes == FUNC_PARAM_TABLE)
			count++;
	return count;
}

// check and append a cell to a list
static List *
append_inarg_list(const char argmode,const ListCell *cell,List *in_parameters)
{
	const char* message = "parameter mode doesn't exist";
	switch(argmode)
	{
		case FUNC_PARAM_IN:
			in_parameters = lappend(in_parameters,lfirst(cell));
			break;
		case FUNC_PARAM_INOUT:
			in_parameters = lappend(in_parameters,lfirst(cell));
			break;
		case FUNC_PARAM_OUT:
			break;
		// get the all "in" parameters, except "out" or "table_colums" parameters
		case FUNC_PARAM_TABLE:
			break;
		default:
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
					errmsg("parameter mode %c doesn't exist",argmode)));
			break;
	}

	return in_parameters;
}

// check wheather all the out parameters have been assigned
static void
check_outarg_info(const bool *have_assigend, const char *argmodes,const int proargnum)
{
	int counter = 0;

	if (!argmodes)
		return;

	for (counter = 0; counter < proargnum; counter++)
	{
		if (!have_assigend[counter] && (FUNC_PARAM_OUT == argmodes[counter]))
		{
			const char* message = "output argument located does not assigned";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				errmsg("output argument located \"%d\" doesnot assigned",
				counter + 1)));
			return;
		}
	}
}

static bool HasVariadic(int nargs, const char* argmodes)
{
	if (!argmodes) {
		return false;
	}

	for (int i = nargs - 1; i >= 0; --i) {
		if (argmodes[i] == FUNC_PARAM_VARIADIC) {
			return true;
		}
	}
	return false;
}

// Added CALL for procedure and function
static Node *
makeCallFuncStmt(List* funcname,List* parameters, bool is_call)
{
	SelectStmt *newm = NULL;
	ColumnRef *column = NULL;
	ResTarget *resTarget = NULL;
	FuncCall *funcCall = NULL;
	List *userVarList = NIL;
	RangeFunction *rangeFunction = NULL;
	char *schemaname = NULL;
	char *name = NULL;
	char *pkgname = NULL;
	Oid pkgoid = InvalidOid;
	FuncCandidateList clist = NULL;
	HeapTuple proctup = NULL;
	Form_pg_proc procStruct;
	Oid *p_argtypes = NULL;
	char **p_argnames = NULL;
	char *p_argmodes = NULL;
	List *in_parameters = NULL;
	int i = 0;
	ListCell *cell = NULL;
	int narg = 0;
	int ndefaultargs = 0;
	int ntable_colums = 0;
	bool *have_assigend = NULL;
	bool	has_overload_func = false;
	Datum package_oid_datum;
	/* deconstruct the name list */
	DeconstructQualifiedName(funcname, &schemaname, &name, &pkgname);

	/* search the function */
	clist = FuncnameGetCandidates(funcname, -1, NIL, false, false, false);
	if (!clist)
	{
		const char* message = "function doesn't exist ";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("function \"%s\" doesn't exist ", name)));
		return NULL;
	}

	if (clist->next)
	{
		has_overload_func = true;
        if (IsPackageFunction(funcname) == false && IsPackageSchemaOid(SchemaNameGetSchemaOid(schemaname, true)) == false &&
			(schemaname == NULL || strncmp(schemaname, "gms_lob", strlen("gms_lob")))) 
		{
			const char* message = "function isn't exclusive ";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
					(errcode(ERRCODE_DUPLICATE_FUNCTION),
					errmsg("function \"%s\" isn't exclusive ", name)));
			return NULL;
		}
	}

	proctup = SearchSysCache(PROCOID,
							ObjectIdGetDatum(clist->oid),
							0, 0, 0);
	/*
	 * function may be deleted after clist be searched.
	 */
	if (!HeapTupleIsValid(proctup))
	{
		const char* message = "function doesn't exist";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
					errmsg("function \"%s\" doesn't exist ", name)));
		return NULL;
	}

	/* get the all args informations, only "in" parameters if p_argmodes is null */
	narg = get_func_arg_info(proctup, &p_argtypes, &p_argnames, &p_argmodes);
	bool hasVariadic = HasVariadic(narg, p_argmodes);
	bool is_null;
	char prokind = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prokind, &is_null);
	bool is_pipelined = !is_null && PROC_IS_PIPELINED(DatumGetChar(prokind));
	if (is_pipelined) {
			const char* message = "call pipelined function is not allowed";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
				ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("call pipelined function \"%s\" is not allowed", name)));
	}

#ifndef ENABLE_MULTIPLE_NODES
	if (!hasVariadic && !has_overload_func && !enable_out_param_override())
#else
        if (!hasVariadic && !has_overload_func)
#endif
	{
		/* get the all "in" parameters, except "out" or "table_colums" parameters */
		ntable_colums = get_table_modes(narg, p_argmodes);
		narg -= ntable_colums;

		procStruct = (Form_pg_proc) GETSTRUCT(proctup);
		ndefaultargs = procStruct->pronargdefaults;

		/* check the parameters' count*/
		if (narg - ndefaultargs > (parameters ? parameters->length : 0) )
		{
			const char* message = "function with %d parameters doesn't exist";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("function \"%s\" with %d parameters doesn't exist ",
					name,parameters? parameters->length : 0)));
		}

		if (parameters && (narg < parameters->length))
		{
			const char* message = "function with %d parameters doesn't exist";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_UNDEFINED_FUNCTION),
				errmsg("function \"%s\" with %d parameters doesn't exist ",
					name, parameters->length)));
		}

		/* analyse all parameters */
		i = 0;
		have_assigend = (bool *)palloc(sizeof(bool) * narg);
		memset(have_assigend, 0, sizeof(bool) * narg);

		foreach(cell,parameters)
		{
			Node	*arg = (Node *)lfirst(cell);
			char *argname = NULL;
			char	argmode = 0;

			if (IsA(arg, NamedArgExpr))
			{
				NamedArgExpr *na = (NamedArgExpr *) arg;

				argname = na->name;
				get_arg_mode_by_name(argname, p_argnames,
							p_argmodes, narg, have_assigend,&argmode);
				in_parameters = append_inarg_list(argmode, cell, in_parameters);
			}
			else
			{
				get_arg_mode_by_pos(i, p_argmodes, narg, have_assigend, &argmode);
				in_parameters = append_inarg_list(argmode, cell, in_parameters);

				if (argmode == FUNC_PARAM_OUT || argmode == FUNC_PARAM_INOUT) {
					if (IsA(arg, TypeCast)) {
						arg = (*(TypeCast *)arg).arg;
					}
					if (IsA(arg, UserVar)) {
						userVarList = lappend(userVarList,arg);
					}
				}
			}
			i++;
		}

		check_outarg_info(have_assigend, p_argmodes, narg);
	}
	else
	{
		in_parameters = parameters;
	}
	ReleaseSysCache(proctup);

	column = makeNode(ColumnRef);
	column->fields = list_make1(makeNode(A_Star));
	column->location = -1;
	column->indnum = 0;

	resTarget = makeNode(ResTarget);
	resTarget->name = NULL;
	resTarget->indirection = NIL;
	resTarget->val = (Node *)column;
	resTarget->location = -1;

	funcCall = (FuncCall*)makeNode(FuncCall);
	funcCall->funcname = funcname;
	funcCall->args = in_parameters;
	funcCall->agg_star = FALSE;
	funcCall->func_variadic = false;
	funcCall->agg_distinct = FALSE;
	funcCall->agg_order = NIL;
	funcCall->over = NULL;
	funcCall->location = -1;

	/*funcCall->pkgoid = pkgoid;*/
#ifndef ENABLE_MULTIPLE_NODES
	if (has_overload_func || is_call)
#else
        if (has_overload_func)
#endif
            funcCall->call_func = true;
	else
            funcCall->call_func = false;

	rangeFunction = makeNode(RangeFunction);
	rangeFunction->funccallnode = (Node*)funcCall;
	rangeFunction->coldeflist = NIL;

	newm =  (SelectStmt*)makeNode(SelectStmt);
	newm->distinctClause = NIL;
	newm->intoClause  = NULL;
	newm->targetList  = list_make1(resTarget);
	newm->fromClause  = list_make1(rangeFunction);
	newm->whereClause = NULL;
	newm->havingClause= NULL;
    newm->groupClause = NIL;
	if (userVarList != NIL) {
		IntoClause *n = makeNode(IntoClause);
		n->userVarList = userVarList;
		newm->intoClause  = n;
	}
	return (Node*)newm;
}

/* judge if ident is valid
 * Only letters, numbers, dollar signs ($) and the underscore are allowed in name
 * and The first character must be letter or underscore
*/
bool
IsValidIdent(char *input)
{
	char c = input[0];
	/*The first character id numbers or dollar*/
	if ((c >= '0' && c <= '9') || c == '$')
	{
		const char* message = "invalid name";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_SYNTAX_ERROR),
			errmsg("invalid name: %s", input)));
		return false;
	}

	int len = strlen(input);
	for (int i = 0; i < len; i++)
	{
		c = input[i];
		if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$')
		{
			continue;
		}
		else
		{
			const char* message = "invalid name";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("invalid name: %s", input)));
			return false;
		}
	}
	return true;
}

/* judge if username is valid
 * Only letters, numbers, dollar signs ($), number signs (#) and the underscore are allowed in name
 * and The first character must be letter or underscore
*/
bool
IsValidIdentUsername(char *input)
{
	if (u_sess->hook_cxt.checkVaildUserHook != NULL) {
		return ((checkValidUsername)(u_sess->hook_cxt.checkVaildUserHook))(input);
	}
	char c = input[0];
	/*The first character id numbers or dollar*/
	if ((c >= '0' && c <= '9') || c == '$')
	{
		ereport(ERROR,
			(errcode(ERRCODE_SYNTAX_ERROR),
			errmsg("invalid name: %s", input)));
		return false;
	}

	int len = strlen(input);
	for (int i = 0; i < len; i++)
	{
		c = input[i];
		if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$' || c == '#')
		{
			continue;
		}
		else
		{
			ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("invalid name: %s", input)));
			return false;
		}
	}
	return true;
}

/* judge if node group name is valid
 * Only ASCII character set is allowed in group name
*/
bool
IsValidGroupname(const char *input)
{
	int len = strlen(input);
	for (int i = 0; i < len; i++)
	{
		if (IS_HIGHBIT_SET(input[i]))
		{
			const char* message = "node group name is not allowed to contain multibyte characters";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(errstate,
				(errcode(ERRCODE_SYNTAX_ERROR),
				errmsg("node group name is not allowed to contain multibyte characters")));
		}	
	}
	return true;
}

static void ParseUpdateMultiSet(List *set_target_list, SelectStmt *stmt, core_yyscan_t yyscanner)
{
	/*
	 * Here we transfrom the original sql to handle multicolumn update, we transform the
	 * original sql like this:
	 * the original sql:      UPDATE t1 SET (c1,c2) = (SELECT AVG(d1), 154 a2 FROM t2 GROUP BY a2);
	 * after transformed sql: UPDATE t1 SET (c1,c2) =
								(SELECT s1,s2 FROM (SELECT AVG(d1), 154 a2 FROM t2 GROUP BY a2) as S(s1,s2));
	 */
	List *col_names = NIL;
	ListCell *col_cell = NULL;
	int loop = 1;
	StringInfoData buf;

	initStringInfo(&buf);
	appendStringInfoChar(&buf, 's');

	/* we need construct complete alias at first */
	foreach(col_cell, set_target_list) {
		pg_ltoa(loop++, &buf.data[1]);
		col_names = lappend(col_names, makeString(pstrdup(buf.data)));
	}

	RangeSubselect *rsubselect = makeNode(RangeSubselect);
	rsubselect->subquery = (Node*)stmt;
	rsubselect->alias = makeAlias(pstrdup("S"), col_names);

	/* now we can separate the multi columns. */
	ListCell* colName = list_head(col_names);

	foreach(col_cell, set_target_list) {
		ResTarget *res_col = (ResTarget *) lfirst(col_cell);

		/* create a new selectstmt as : */
		SelectStmt *stmt_new = makeNode(SelectStmt);
		ResTarget *res_new = makeNode(ResTarget);
		SubLink *res_val = makeNode(SubLink);

		/* we need assign the column for each set_target according to the sequence of column name in alias */
		res_new->val = makeColumnRef(pstrdup(strVal(lfirst(colName))), NIL, res_col->location, yyscanner);
		res_new->location = res_col->location;

		stmt_new->targetList = list_make1(res_new);
		stmt_new->fromClause = list_make1(
			(res_col == linitial(set_target_list)) ? rsubselect : copyObject(rsubselect));

		res_val->subLinkType = EXPR_SUBLINK;
		res_val->testexpr = NULL;
		res_val->operName = NIL;
		res_val->subselect = (Node*)stmt_new;
		res_col->val = (Node*)res_val;

		colName = lnext(colName);
	}
	pfree_ext(buf.data);
}

/* get proc header sting len and start pos in scanbuffer */
static int GetProcHeaderLen(core_yyscan_t yyscanner, int *startPos)
{
	int param_pos_b = 0;
	int param_pos_e = 0;
	int proc_header_len = 0;
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);

	param_pos_b = yyextra->core_yy_extra.func_param_begin;
	param_pos_e = yyextra->core_yy_extra.func_param_end;
	/* exclude left parenthesis at beginning of param */
	param_pos_b++;
	/* exclude right parenthesis at end of param */
	proc_header_len = param_pos_e - param_pos_b;

	*startPos = param_pos_b;

	return proc_header_len;
}

/* get pg_dump type name by input name */
static char *GetTargetFuncArgTypeName(char *typeString, TypeName* t)
{
	char *target = NULL;

	if (t->pct_type)
	{
		Type typtup;
		Oid toid;
		TypeDependExtend* dependExtend = NULL;
		if (enable_plpgsql_gsdependency()) {
			InstanceTypeNameDependExtend(&dependExtend);
		}
		typtup = LookupTypeName(NULL, t, NULL, false, dependExtend);
		pfree_ext(dependExtend);
		if (typtup)
		{
			toid = typeTypeId(typtup);
			target = format_type_be(toid);
			ReleaseSysCache(typtup);
		}
	}
	else
	{
		if (t->end_location - t->location == DATE_LEN
			&& (u_sess->attr.attr_sql.sql_compatibility == A_FORMAT)
			&& pg_strncasecmp(typeString, "date", DATE_LEN) == 0)
		{
			target = pstrdup("timestamp without time zone");
		}
	}

	return target;
}

/* covert input type name into pg_dump type name */
static char *FormatFuncArgType(core_yyscan_t yyscanner, char *argsString, List* parameters)
{
	ListCell* x = NULL;
	char *tmp_pos = argsString;
	int param_pos_b = 0;
	int proc_header_len = 0;
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
	StringInfoData buf;
	char *target = NULL;
	int token_offset = 0;

	if (argsString == NULL)
	{
		return NULL;
	}

	proc_header_len = GetProcHeaderLen(yyscanner, &param_pos_b);
	initStringInfo(&buf);

	foreach (x, parameters)
	{
		FunctionParameter* fp = (FunctionParameter*)lfirst(x);
		TypeName* t = fp->argType;

		if (t->end_location > 0)
		{
			token_offset = t->location - param_pos_b;
			target = GetTargetFuncArgTypeName(argsString + token_offset, t);
			if (target != NULL)
			{
				*(argsString + token_offset) = '\0';
				appendStringInfoString(&buf, tmp_pos);
				appendStringInfoString(&buf, target);
				tmp_pos = argsString + (t->end_location - param_pos_b);
				pfree(target);
			}
		}
	}
	appendStringInfoString(&buf, tmp_pos);
	pfree(argsString);
	proc_header_len = proc_header_len;

	if (!enable_plpgsql_gsdependency_guc()) {
		yyextra->core_yy_extra.func_param_begin = 0;
		yyextra->core_yy_extra.func_param_end = 0;
	} 
	return buf.data;
}

/*
 * get function and procedure args input string
 */
static char *ParseFunctionArgSrc(core_yyscan_t yyscanner)
{
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
	int param_pos_b = 0;
	int proc_header_len = 0;
	char *proc_header_str = NULL;

	if (yyextra->core_yy_extra.include_ora_comment == false)
	{
		return NULL;
	}

	/* exclude right parenthesis at end of param */
	proc_header_len = GetProcHeaderLen(yyscanner, &param_pos_b);
	if (proc_header_len > 0)
	{
		proc_header_str = (char *)palloc0(proc_header_len + 1);
		strncpy_s(proc_header_str, (proc_header_len + 1), yyextra->core_yy_extra.scanbuf + param_pos_b, proc_header_len);
		proc_header_str[proc_header_len] = '\0';
	}

	yyextra->core_yy_extra.include_ora_comment = false;

	return proc_header_str;
}

static char *ParseFuncHeadSrc(core_yyscan_t yyscanner, bool is_function)
{
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
	int proc_header_src_end = 0;
	char *proc_header_info = NULL;
	if (is_function) {
		proc_header_src_end = yyextra->core_yy_extra.return_pos_end - 1;
	} else {
		proc_header_src_end = yyextra->core_yy_extra.func_param_end + 1;
	}
	if (proc_header_src_end == 1) {
		return proc_header_info;
	}
	yyextra->core_yy_extra.return_pos_end = 0;
	yyextra->core_yy_extra.func_param_begin = 0;
	yyextra->core_yy_extra.func_param_end = 0;
	if (proc_header_src_end > 0) {
		proc_header_info = (char*)palloc0(proc_header_src_end + 1);
		errno_t rc = EOK;
		rc = strncpy_s(proc_header_info, (proc_header_src_end + 1), yyextra->core_yy_extra.scanbuf, proc_header_src_end);
		securec_check(rc, "\0", "\0");
		proc_header_info[proc_header_src_end] = '\0';
	}
	return proc_header_info;
}

static void parameter_check_execute_direct(const char* query)
{
#ifndef ENABLE_MULTIPLE_NODES					
    if (IS_SINGLE_NODE) {
		const char* message = "Un-support feature";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				errmsg("Un-support feature"),
				errdetail("The distributed capability is not supported currently.")));
	}
#endif
	/*
	 * when enable_nonsysadmin_execute_direct is off, only system admin can use EXECUTE DIRECT;
	 * when enable_nonsysadmin_execute_direct is on, any user can use EXECUTE DIRECT;
	*/
	if (!g_instance.attr.attr_security.enable_nonsysadmin_execute_direct &&
		!CheckExecDirectPrivilege(query)) {
		const char* message = "must be system admin or monitor admin to use EXECUTE DIRECT";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(errstate,
			(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				errmsg("must be system admin or monitor admin to use EXECUTE DIRECT")));
	}
}

static TypeName *ParseFloatByExtentedPrecision(int ival, int location, core_yyscan_t yyscanner)
{
	TypeName *typnam = NULL;
	
	/* Float binary precision must be between 1 and 126 */
	if (ival <= 126) {
		typnam = SystemTypeName("numeric");
		typnam->typmods = list_make2(makeIntConst(ival, location), makeIntConst(-32768, -1));
	} else {
		const char* message = "precision for type float must be less than 127 bits";
		InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
		ereport(ERROR,
			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				errmsg("precision for type float must be less than 127 bits"),
				parser_errposition(location)));
	}
	return typnam;
}

static void CheckTypmodScale(List* arglist, int location, core_yyscan_t yyscanner)
{
	if (t_thrd.proc->workingVersionNum >= FLOAT_VERSION_NUMBER &&
		u_sess->attr.attr_sql.sql_compatibility == A_FORMAT && list_length(arglist) == 2) {
		Node *arg = (Node*)lsecond(arglist);
		A_Const *n = IsA(arg, A_Const) ? (A_Const *)arg : NULL;
		if (n != NULL && (n->val.val.ival > NUMERIC_MAX_SCALE || n->val.val.ival < NUMERIC_MIN_SCALE)) {
			const char* message = "NUMERIC scale must be between -84 and 1000";
			InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
			ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					errmsg("NUMERIC scale must be between -84 and 1000"),
					parser_errposition(location)));
		}
	}
}

static Node *make_node_from_scanbuf(int start_pos, int end_pos, core_yyscan_t yyscanner)
{
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
	int len = end_pos - 1;

	/* trim trailing blanks */
	while (yyextra->core_yy_extra.scanbuf[len] == ' ')
		len--;

	len = len - start_pos + 1;
	char *str = (char *)palloc0(len + 1);
	strncpy(str, yyextra->core_yy_extra.scanbuf + start_pos, len);
	str[len] = '\0';
	return makeStringConst(str, start_pos);
}

static int64 SequenceStrGetInt64(const char *str)
{
    const char *ptr = str;

    while (*ptr && isspace((unsigned char)*ptr)) {
        ptr++;
    }

    /* handle sign */
    if (*ptr == '-') {
        ereport(errstate,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Sequence args %s is negative number\n", str)));
    } else if (*ptr == '+') {
        ptr++;
    }

    while (*ptr) {
        if (!isdigit((unsigned char)*ptr)) {
            ereport(errstate, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Sequence args %s is invalid\n", str)));
        }
        ptr++;
    }

    return strtol(str, NULL, 10);
}

static int GetLoadType(int load_type_f, int load_type_s)
{
	if (load_type_s != LOAD_DATA_UNKNOWN) {
		return load_type_s;
	} else if (load_type_f != LOAD_DATA_UNKNOWN) {
		return load_type_f;
	}

	return LOAD_DATA_INSERT;
}

static Node *MakeSqlLoadNode(char *colname)
{
	SqlLoadColExpr* n = makeNode(SqlLoadColExpr);
	n->colname = colname;
	n->const_info = NULL;
	n->sequence_info = NULL;
	n->is_filler = false;
	n->scalar_spec = NULL;

	return (Node *)n;
}

static bool IsConnectByRootIdent(Node* node)
{
    if (!IsA(node, ColumnRef)) {
        return false;
    }
    ColumnRef* cr = (ColumnRef*) node;
    List* l = (cr != NULL) ? cr->fields : NULL;
    Node* sn = list_length(l) > 0 ? linitial_node(Node, l) : NULL;
    if (sn != NULL && !IsA(sn, String)){
        return false;
    }
    char* colname = strVal(sn);
    return (strcasecmp("connect_by_root", colname) == 0);
}

static void ValidateTripleTuple(Node* node, core_yyscan_t yyscanner, int location, char* token)
{
    if (!IsConnectByRootIdent(node)) {
        ereport(ERROR,
            (errmodule(MOD_PARSER), errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("Invalid use of identifiers."),
                parser_errposition(location),
                errdetail("Syntax error found near token \"%s\"", token),
                errcause("Unsupported expression found in SELECT statement"),
                erraction("Check and revise your query or contact Huawei engineers.")));
    }
}

static void FilterStartWithUseCases(SelectStmt* stmt, List* locking_clause, core_yyscan_t yyscanner, int location)
{
    if (stmt->startWithClause != NULL && locking_clause != NULL) {
        ereport(ERROR,
            (errmodule(MOD_PARSER), errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("Syntax error found."),
                parser_errposition(location),
                errdetail("FOR UPDATE/SHARE cannot be used with START WITH CONNECT BY clauses"),
                errcause("Unsupported expression found in SELECT statement"),
                erraction("Check and revise your query or contact Huawei engineers.")));
    }
}

static Node *processIntoClauseInSelectStmt(SelectStmt *stmt, IntoClause *itc)
{
	if (itc != NULL) {
		if (stmt->intoClause != NULL) {
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("select statement can contain only one into_clause")));
		}
		if (itc->rel != NULL && u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
			ereport(errstate,
					(errcode(ERRCODE_SYNTAX_ERROR),
					errmsg("select statement can contain only one into_clause")));	}
		stmt->intoClause = itc;
	}
	return (Node *)stmt;
}

static Node* MakeConnectByRootNode(ColumnRef* cr, int location)
{
    FuncCall *n = makeNode(FuncCall);
    n->funcname = list_make1(makeString("connect_by_root"));
    n->args = list_make1(cr);
    n->agg_order = NIL;
    n->agg_star = FALSE;
    n->agg_distinct = FALSE;
    n->func_variadic = FALSE;
    n->over = NULL;
    n->location = location;
    n->call_func = false;
    return (Node*) n;
}

static char* MakeConnectByRootColName(char* tabname, char* colname)
{
    char* ret = NULL;
    if (tabname != NULL) {
        int max_len = strlen("connect_by_root") + strlen(tabname) + 1 + strlen(colname) + 1;
        ret = (char *)palloc(max_len);
        strcpy_s(ret, max_len, "connect_by_root");
        strcat_s(ret, max_len, tabname);
        strcat_s(ret, max_len, ".");
        strcat_s(ret, max_len,colname);
    } else {
        int max_len = strlen("connect_by_root") + strlen(colname) + 1;
        ret = (char *)palloc(max_len);
        strcpy_s(ret, max_len, "connect_by_root");
        strcat_s(ret, max_len, colname);
    }
    return ret;
}

#ifndef ENABLE_MULTIPLE_NODES
static bool CheckWhetherInColList(char *colname, List *col_list)
{
	ListCell* lc = NULL;
	char *colname_l = pg_strtolower(colname);

	if (col_list == NULL) {
		return true;
	}

	foreach (lc, col_list) {
		char* name = strVal(lfirst(lc));
		if (strcmp(name, colname_l) == 0) {
			return true;
		}
	}

	return false;
}
#endif

static void BCompatibilityOptionSupportCheck(const char* keyword)
{
#ifdef ENABLE_MULTIPLE_NODES
    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("%s is not yet supported.", keyword)));
#endif
    if (DB_IS_CMPT(B_FORMAT)) {
        return;
    }
    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
        errmsg("%s is supported only in B compatible database.", keyword)));
}

static int GetFillerColIndex(char *filler_col_name, List *col_list)
{
	ListCell* lc = NULL;
	int index = 0;

	if (col_list == NULL) {
		ereport(errstate, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
			errmsg("Column list cannot be empty for \"FILLER\"")));
		return InvalidAttrNumber;
	}

	foreach (lc, col_list) {
		index++;
		char* colname = strVal(lfirst(lc));
		if (strcmp(colname, filler_col_name) == 0) {
			return index;
		}
	}

	ereport(errstate, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
			errmsg("Filler col \"%s\" is not in the col list", filler_col_name)));
	return InvalidAttrNumber;
}

static void RemoveFillerCol(List *filler_list, List *col_list)
{
	ListCell* filler_cell = NULL;
	ListCell* col_cell = NULL;
	ListCell* prev = NULL;
	SqlLoadFillerInfo *fillerInfo = NULL;
	char* colname = NULL;

	if (filler_list == NULL || col_list == NULL) {
		return;
	}

	foreach (filler_cell, filler_list) {
		fillerInfo = (SqlLoadFillerInfo *)lfirst(filler_cell);
		prev = NULL;
		foreach (col_cell, col_list) {
			colname = strVal(lfirst(col_cell));
			if (strcmp(fillerInfo->colname, colname) == 0) {
				list_delete_cell(col_list, col_cell, prev);
				break;
			}
			prev = col_cell;
		}
	}

	return;
}

static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStmt*n)
{
	errno_t rc = 0;
	base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner);
	if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT) {
		if(strlen(input) == 0) {
			parser_yyerror("DELIMITER must be followed by a 'delimiter' character or string");
		}
		if (strlen(input) >= DELIMITER_LENGTH) {
			parser_yyerror("'delimiter' length should less than 16");
		}
		n->is_local = false;
		n->kind = VAR_SET_VALUE;
		n->name = "delimiter_name";
		n->args = list_make1(makeStringConst(input, -1));
	}
}


static FuncCall* MakePriorAsFunc()
{
    List *funcName = list_make1(makeString("prior"));
    FuncCall *n = makeNode(FuncCall);
    n->funcname = funcName;
    n->args = NIL;
    n->agg_order = NIL;
    n->agg_star = FALSE;
    n->agg_distinct = FALSE;
    n->func_variadic = FALSE;
    n->over = NULL;
    n->call_func = false;
    return n;
}

static void checkDeleteRelationError()
{
#ifdef ENABLE_MULTIPLE_NODES
	ereport(errstate, 
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				errmsg("multi-relation delete is not yet supported.")));
#endif
	if (!DB_IS_CMPT_BD)						
		ereport(errstate, 
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					errmsg("multi-relation delete only support in B-format or D-format database")));
}

#ifndef MAX_SUPPORTED_FUNC_FOR_PART_EXPR
#define MAX_SUPPORTED_FUNC_FOR_PART_EXPR 25
#endif

static void CheckPartitionExpr(Node* expr, int* colCount)
{
	CheckPartitionExprInner(expr, colCount, true);
}

static void CheckPartitionExprInner(Node* expr, int* colCount, bool checkTypeCast)
{
	if (expr == NULL)
		ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("The expr can't be NULL")));
	if (expr->type == T_A_Expr) {
		A_Expr* a_expr = (A_Expr*)expr;
		if (a_expr->name == NULL) {
			ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The expr is not supported for Partition Expr")));
		}
		char* name = strVal(linitial(a_expr->name));
		if (strcmp(name, "+") != 0 && strcmp(name, "-") != 0 && strcmp(name, "*") != 0)
			ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The %s operator is not supported for Partition Expr", name)));
		CheckPartitionExprInner(a_expr->lexpr, colCount, false);
		CheckPartitionExprInner(a_expr->rexpr, colCount, false);
	} else if (expr->type == T_FuncCall) {
		char* validFuncName[MAX_SUPPORTED_FUNC_FOR_PART_EXPR] = {"abs","ceiling","datediff","day","dayofmonth","dayofweek","dayofyear","extract","floor","hour",
		"microsecond","minute","mod","month","quarter","second","time_to_sec","to_days","to_seconds","unix_timestamp","weekday","year","yearweek","date_part","div"};
		char* funcname = strVal(llast(((FuncCall*)expr)->funcname));
		int count = 0;
		for (;count < MAX_SUPPORTED_FUNC_FOR_PART_EXPR;count++) {
			if (strcmp(funcname, validFuncName[count]) == 0)
				break;
			else
				continue;
		}
		if (count == MAX_SUPPORTED_FUNC_FOR_PART_EXPR)
			ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The %s func is not supported for Partition Expr", funcname)));
		ListCell* cell = NULL;
		foreach (cell, ((FuncCall*)expr)->args) {
			CheckPartitionExprInner((Node*)(lfirst(cell)), colCount, false);
		}
	} else if (expr->type == T_ColumnRef) {
		(*colCount)++;
	} else if (expr->type == T_A_Const) {
		return;
	} else if (expr->type == T_TypeCast) {
		if (checkTypeCast) {
			ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The Partition Expr can't be a Type Cast")));
		} else {
			return;
		}
	} else {
		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The Partition Expr can't be %d type", expr->type)));
	}
}

static char* transformIndexOptions(List* list)
{
    char* method = NULL;
    ListCell* cell = NULL;
    int first = 0;

    /* check every access method name in index_options, if not exist, return error */
    foreach (cell, list) {
        void* pointer = lfirst(cell);
        if (IsA(pointer, A_Const)) {
            A_Const* con = (A_Const*) pointer;
            if (IsA((Node*)&con->val, String)) {
                /* return the last access method name */
                char* am = strVal(&con->val);
                if (am && get_am_oid(am, false) && first < 1) {
                    method = am;
                    first++;
                }
            }
        }
    }
    return method;
}

static void setAccessMethod(Constraint *n)
{
	char* method = transformIndexOptions(n->constraintOptions);
	if (method != NULL) {
		/* check current index access method name is exist? If not, return error */
		if (n->access_method == NULL) {
			n->access_method = method;
		} else {
			get_am_oid(n->access_method, false);
			n->access_method = method;
		}
	}
}

static CharsetCollateOptions* MakeCharsetCollateOptions(CharsetCollateOptions *options, CharsetCollateOptions *option)
{
	if (options == NULL) {
		options = makeNode(CharsetCollateOptions);
		options->cctype = OPT_CHARSETCOLLATE;
		options->charset = PG_INVALID_ENCODING;
		options->collate = NULL;
	}
	switch (option->cctype) {
		case OPT_CHARSET:
			options->charset = option->charset;
			break;
		case OPT_COLLATE:
			options->collate = option->collate;
			break;
		default:
			break;
	}
	return options;
}

static char* GetValidUserHostId(char* userName, char* hostId)
{
	CheckUserHostIsValid();
	if (strchr(userName,'@'))
		ereport(ERROR,(errcode(ERRCODE_INVALID_NAME),errmsg("@ can't be allowed in username")));
	char* userHostId = NULL;
	if (*hostId == '\'') {
		userHostId = hostId + 1;
		hostId[strlen(hostId)-1] = '\0';
	} else {
		userHostId = hostId;
	}
	if (strcmp("localhost", userHostId) != 0)
		CheckHostId(userHostId);
	StringInfoData buf;
	initStringInfo(&buf);
	appendStringInfoString(&buf, userName);
	appendStringInfoString(&buf, "@");
	appendStringInfoString(&buf, userHostId);
	if (strlen(buf.data) >= NAMEDATALEN) {
		ereport(ERROR,(errcode(ERRCODE_INVALID_NAME),errmsg("String %s is too long for user name (should be no longer than 64)", buf.data)));
	}
	return buf.data;
}

static void CheckHostId(char* hostId)
{
	char* tmp = hostId;
	for (; *tmp != '\0'; tmp++) {
		if (((*tmp < '0') || (*tmp > '9')) && (*tmp != '%') && (*tmp != '.'))
			ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("The hostname %s is not supported, it only support IP.", hostId)));
	}
}

static void CheckUserHostIsValid()
{
	if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT && u_sess->attr.attr_common.b_compatibility_user_host_auth)
		return;
	ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("user@host is only supported in b database when the b_compatibility_user_host_auth is on")));
}

static Node *checkNullNode(Node *n)
{
	A_Const *c = (A_Const *)n;
	A_Const *r = makeNode(A_Const);
	if (c->val.val.str == NULL || strlen(c->val.val.str) == 0)
	{
		r->val.type = T_Null;
		r->val.val.str = c->val.val.str;
		r->location = c->location;
		return (Node *)r;
	}
	return n;
}

static Node* MakeNoArgFunctionCall(List* funcNames, int location)
{
	FuncCall *n = makeNode(FuncCall);
	n->funcname = funcNames;
	n->args = NIL;
	n->agg_order = NIL;
	n->agg_star = FALSE;
	n->agg_distinct = FALSE;
	n->func_variadic = FALSE;
	n->over = NULL;
	n->location = location;
	n->call_func = false;
	return (Node *)n;
}

static char* IdentResolveToChar(char *ident, core_yyscan_t yyscanner)
{
	if (u_sess->attr.attr_sql.enable_ignore_case_in_dquotes
	    && (pg_yyget_extra(yyscanner))->core_yy_extra.ident_quoted)
	{
		return pg_strtolower(pstrdup(ident));
	}
	else
	{
		return ident;
	}
}



void contain_unsupport_node(Node* node, bool* has_unsupport_default_node)
{
    if (node != NULL && IsA(node, ColumnRef)) {
		*has_unsupport_default_node = true;
		return;
    }
    (void)raw_expression_tree_walker(node, (bool (*)())contain_unsupport_node, (void*)has_unsupport_default_node);
}


static List* TransformToConstStrNode(List *inExprList, char* raw_str)
{
	ListCell* cell = NULL;
	ListCell *exprCell = NULL;
	ResTarget *resTarget = NULL;
	errno_t rc;

	foreach (cell, inExprList)
	{
		RotateInCell *rotateinCell = (RotateInCell *)lfirst(cell);
		foreach (exprCell, rotateinCell->rotateInExpr) {
			resTarget = (ResTarget *)lfirst(exprCell);
			if (NULL == rotateinCell->aliasname && IsA(resTarget->val, ColumnRef)) {
				ColumnRef* column_ref = (ColumnRef*)resTarget->val;
				if (list_length(column_ref->fields) != 1) {
					ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("ROTATE in clause error")));
				}
				// column_ref info has been convert to lower case, so we need to extact the not convert lower case info in raw str
				char * lower_column_name = strVal(linitial(column_ref->fields));
				int len = strlen(lower_column_name);
				pfree(lower_column_name);
				char *raw_col_name = (char *)palloc(len + 1);
				raw_col_name[len] = '\0';
				errno_t rc = EOK;
				int column_offset = 0;
				if (raw_str[column_ref->location] == '[' || raw_str[column_ref->location] == '"') {
					column_offset++;
				}
				rc = strncpy_s(raw_col_name, len + 1, raw_str + column_ref->location + column_offset, len);
				securec_check(rc, "\0", "\0");
				Node* const_node = makeStringConst(raw_col_name, column_ref->location);
				resTarget->val = const_node;
			} if (NULL == rotateinCell->aliasname && IsA(resTarget->val, A_Const)) {
				const Value *val = &((A_Const *)resTarget->val)->val;
				char * column_to_const_str = NULL;
				switch (val->type) {
					case T_Integer: {
						char* new_col_name = (char*)palloc(NAMEDATALEN);
						rc = memset_s(new_col_name, NAMEDATALEN, 0, NAMEDATALEN);
						securec_check_c(rc, "\0", "\0");
						rc = snprintf_s(new_col_name, NAMEDATALEN, NAMEDATALEN - 1, "%ld", intVal(val));
						securec_check_ss(rc, "\0", "\0");
						column_to_const_str = new_col_name;
						break;
					}

					case T_Float:
					case T_String:
					case T_BitString:
						column_to_const_str = strVal(val);
						break;
					
					default:
						break;
				}
				if (column_to_const_str != NULL) {
					Node* const_node = makeStringConst(column_to_const_str, ((A_Const *)resTarget)->location);
					resTarget->val = const_node;
				}
			}
		}
	}
	return inExprList;
}


static Alias* generate_alias(Alias* clone_target, const char* default_alias_name)
{
	if (clone_target != NULL) {
		return (Alias*)copyObject(clone_target);
	} else {
		Alias* result = makeNode(Alias);
		result->aliasname = pstrdup(default_alias_name);
		return result;
	}
}

/*
 * Must undefine this stuff before including scan.c, since it has different
 * definitions for these macros.
 */
#undef yyerror
#undef yylval
#undef yylloc
#undef yylex

#define SCANINC

/* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */
/*$$include "gram-tsql-epilogue.y.cpp"*/

#ifdef SCANINC
#include "scan.inc"
#endif