From 4bd9f4345f6850d95e4a6de8f1496f5f91c9c9bd Mon Sep 17 00:00:00 2001 From: suncan <1006949218@qq.com> Date: Thu, 8 Sep 2022 16:26:58 +0800 Subject: [PATCH] =?UTF-8?q?multi=20set=20=E6=94=AF=E6=8C=81=E5=A4=9Aset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/nodes/copyfuncs.cpp | 13 + src/common/backend/nodes/equalfuncs.cpp | 11 + src/common/backend/nodes/nodeFuncs.cpp | 7 +- src/common/backend/nodes/nodes.cpp | 3 +- src/common/backend/parser/analyze.cpp | 107 +-- src/common/backend/parser/gram.y | 720 +++++++++--------- src/common/backend/parser/parse_expr.cpp | 3 +- src/common/backend/utils/misc/guc.cpp | 4 + .../interfaces/libpq/frontend_parser/gram.y | 4 +- src/common/pl/plpgsql/src/gram.y | 2 +- src/common/pl/plpgsql/src/pl_exec.cpp | 7 +- .../optimizer/rewrite/rewriteHandler.cpp | 63 +- src/gausskernel/process/tcop/postgres.cpp | 4 +- src/gausskernel/process/tcop/utility.cpp | 39 +- src/gausskernel/runtime/executor/execQual.cpp | 5 + .../runtime/executor/nodeModifyTable.cpp | 11 - src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes_common.h | 6 + src/include/parser/parse_expr.h | 1 + src/include/rewrite/rewriteHandler.h | 1 + .../input/set_system_variables_test.source | 76 +- .../output/set_system_variables_test.source | 166 +++- 22 files changed, 818 insertions(+), 436 deletions(-) diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp index 37f1ff0c7..2672e27ac 100644 --- a/src/common/backend/nodes/copyfuncs.cpp +++ b/src/common/backend/nodes/copyfuncs.cpp @@ -5627,6 +5627,16 @@ static VariableSetStmt* _copyVariableSetStmt(const VariableSetStmt* from) COPY_NODE_FIELD(args); COPY_SCALAR_FIELD(is_local); COPY_NODE_FIELD(defined_args); + COPY_SCALAR_FIELD(is_multiset); + + return newnode; +} + +static VariableMultiSetStmt* _copyVariableMultiSetStmt(const VariableMultiSetStmt* from) +{ + VariableMultiSetStmt* newnode = makeNode(VariableMultiSetStmt); + + COPY_NODE_FIELD(args); return newnode; } @@ -7742,6 +7752,9 @@ void* copyObject(const void* from) case T_VariableSetStmt: retval = _copyVariableSetStmt((VariableSetStmt*)from); break; + case T_VariableMultiSetStmt: + retval = _copyVariableMultiSetStmt((VariableMultiSetStmt*)from); + break; case T_VariableShowStmt: retval = _copyVariableShowStmt((VariableShowStmt*)from); break; diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 09c882721..c9f031f0a 100644 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -1805,6 +1805,14 @@ static bool _equalVariableSetStmt(const VariableSetStmt* a, const VariableSetStm COMPARE_NODE_FIELD(args); COMPARE_SCALAR_FIELD(is_local); COMPARE_NODE_FIELD(defined_args); + COMPARE_SCALAR_FIELD(is_multiset); + + return true; +} + +static bool _equalVariableMultiSetStmt(const VariableMultiSetStmt* a, const VariableMultiSetStmt* b) +{ + COMPARE_NODE_FIELD(args); return true; } @@ -3768,6 +3776,9 @@ bool equal(const void* a, const void* b) case T_VariableSetStmt: retval = _equalVariableSetStmt((VariableSetStmt*)a, (VariableSetStmt*)b); break; + case T_VariableMultiSetStmt: + retval = _equalVariableMultiSetStmt((VariableMultiSetStmt*)a, (VariableMultiSetStmt*)b); + break; case T_VariableShowStmt: retval = _equalVariableShowStmt((VariableShowStmt*)a, (VariableShowStmt*)b); break; diff --git a/src/common/backend/nodes/nodeFuncs.cpp b/src/common/backend/nodes/nodeFuncs.cpp index 8e93aac1a..7602b28c4 100644 --- a/src/common/backend/nodes/nodeFuncs.cpp +++ b/src/common/backend/nodes/nodeFuncs.cpp @@ -2648,9 +2648,10 @@ Node* expression_tree_mutator(Node* node, Node* (*mutator)(Node*, void*), void* return (Node*)newnode; } break; case T_SetVariableExpr: { - SetVariableExpr* oldnode = (SetVariableExpr *)node; - Const* newnode = NULL; - FLATCOPY(newnode, (Const *)(oldnode->value), Const, isCopy); + SetVariableExpr* oldnode = (SetVariableExpr*)node; + SetVariableExpr* newnode = NULL; + FLATCOPY(newnode, oldnode, SetVariableExpr, isCopy); + MUTATE(newnode->value, oldnode->value, Expr*); return (Node*)newnode; } break; default: diff --git a/src/common/backend/nodes/nodes.cpp b/src/common/backend/nodes/nodes.cpp index a27255af3..050e14e18 100755 --- a/src/common/backend/nodes/nodes.cpp +++ b/src/common/backend/nodes/nodes.cpp @@ -595,7 +595,8 @@ static const TagStr g_tagStrArr[] = {{T_Invalid, "Invalid"}, {T_AdvanceCatalogXminCmd, "AdvanceCatalogXminCmd"}, {T_UserSetElem, "UserSetElem"}, {T_UserVar, "UserVar"}, - {T_SetVariableExpr, "SetVariableExpr"} + {T_SetVariableExpr, "SetVariableExpr"}, + {T_VariableMultiSetStmt, "VariableMultiSetStmt"} }; char* nodeTagToString(NodeTag tag) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 40d44ed57..8c9503e2a 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -102,7 +102,8 @@ static Query* transformInsertStmt(ParseState* pstate, InsertStmt* stmt); static void checkUpsertTargetlist(Relation targetTable, List* updateTlist); static UpsertExpr* transformUpsertClause(ParseState* pstate, UpsertClause* upsertClause); static int count_rowexpr_columns(ParseState* pstate, Node* expr); -static Query* transformVariableSetStmt(ParseState* pstate, VariableSetStmt* stmt); +static void transformVariableSetStmt(ParseState* pstate, VariableSetStmt* stmt); +static Query* transformVariableMutiSetStmt(ParseState* pstate, VariableMultiSetStmt* muti_stmt); static Query* transformSelectStmt( ParseState* pstate, SelectStmt* stmt, bool isFirstNode = true, bool isCreateView = false); static Query* transformValuesClause(ParseState* pstate, SelectStmt* stmt); @@ -117,7 +118,7 @@ static Query* transformExplainStmt(ParseState* pstate, ExplainStmt* stmt); static Query* transformCreateTableAsStmt(ParseState* pstate, CreateTableAsStmt* stmt); static void CheckDeleteRelation(Relation targetrel); static void CheckUpdateRelation(Relation targetrel); -static Query* transformVariableSetValueStmt(ParseState* pstate, VariableSetStmt* stmt, bool is_alter_sys); +static void transformVariableSetValueStmt(ParseState* pstate, VariableSetStmt* stmt); #ifdef PGXC static Query* transformExecDirectStmt(ParseState* pstate, ExecDirectStmt* stmt); static bool IsExecDirectUtilityStmt(const Node* node); @@ -458,30 +459,22 @@ Query* transformStmt(ParseState* pstate, Node* parseTree, bool isFirstNode, bool result->utilityStmt = (Node*)parseTree; } break; - case T_AlterSystemStmt: case T_VariableSetStmt: { VariableSetStmt* stmt; - bool is_alter_sys = false; - - if (nodeTag(parseTree) == T_AlterSystemStmt) { - AlterSystemStmt* alter_sys_stmt = (AlterSystemStmt*)parseTree; - stmt = alter_sys_stmt->setstmt; - is_alter_sys = true; - } else { - stmt = (VariableSetStmt*)parseTree; - } + stmt = (VariableSetStmt*)parseTree; if (DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_common.enable_set_variable_b_format && stmt->kind == VAR_SET_VALUE) { - result = transformVariableSetValueStmt(pstate, stmt, is_alter_sys); - } else if (stmt->kind == VAR_SET_DEFINED) { - result = transformVariableSetStmt(pstate, stmt); - } else { - result = makeNode(Query); - result->commandType = CMD_UTILITY; - result->utilityStmt = (Node*)parseTree; + transformVariableSetValueStmt(pstate, stmt); } + result = makeNode(Query); + result->commandType = CMD_UTILITY; + result->utilityStmt = (Node*)parseTree; } break; + case T_VariableMultiSetStmt: + result = transformVariableMutiSetStmt(pstate, (VariableMultiSetStmt*)parseTree); + break; + default: /* @@ -564,12 +557,11 @@ bool analyze_requires_snapshot(Node* parseTree) } break; - case T_VariableSetStmt: + case T_VariableMultiSetStmt: /* user-defined variables support sublink */ - if (((VariableSetStmt *)parseTree)->defined_args != NULL) { result = true; - } break; + default: /* other utility statements don't have any real parse analysis */ result = false; @@ -2486,12 +2478,56 @@ static bool shouldTransformStartWithStmt(ParseState* pstate, SelectStmt* stmt, Q } /* - * transformVariableSetStmt - transforms a user-defined variable + * transformVariableSetValueStmt - + * transforms a VariableSetStmt */ -static Query* transformVariableSetStmt(ParseState* pstate, VariableSetStmt* stmt) +static Query* transformVariableMutiSetStmt(ParseState* pstate, VariableMultiSetStmt* muti_stmt) { Query *query = makeNode(Query); List *resultList = NIL; + + List* stmts = muti_stmt->args; + ListCell* cell = NULL; + VariableSetStmt* set_stmt; + + foreach(cell, stmts) { + Node* stmt = (Node*)lfirst(cell); + + if (nodeTag(stmt) == T_AlterSystemStmt) { + AlterSystemStmt *alter_sys_stmt = (AlterSystemStmt *)stmt; + set_stmt = alter_sys_stmt->setstmt; + } else { + set_stmt = (VariableSetStmt*)stmt; + } + + if (set_stmt->kind == VAR_SET_DEFINED) + transformVariableSetStmt(pstate, set_stmt); + if (set_stmt->kind == VAR_SET_VALUE) + transformVariableSetValueStmt(pstate, set_stmt); + + if (nodeTag(stmt) == T_AlterSystemStmt) { + AlterSystemStmt *newnode = makeNode(AlterSystemStmt); + newnode->setstmt = set_stmt; + resultList = lappend(resultList, newnode); + } else { + resultList = lappend(resultList, set_stmt); + } + } + + list_free(muti_stmt->args); + muti_stmt->args = resultList; + + query->commandType = CMD_UTILITY; + query->utilityStmt = (Node*)muti_stmt; + return query; +} + +/* + * transformVariableSetStmt - transforms a user-defined variable + */ +static void transformVariableSetStmt(ParseState* pstate, VariableSetStmt* stmt) +{ + List *resultList = NIL; ListCell *temp = NULL; foreach (temp, stmt->defined_args) { @@ -2511,21 +2547,14 @@ static Query* transformVariableSetStmt(ParseState* pstate, VariableSetStmt* stmt resultList = lappend(resultList, newUserElem); } stmt->defined_args = resultList; - - query->commandType = CMD_UTILITY; - query->utilityStmt = (Node*)stmt; - - return query; } /* * transformVariableSetValueStmt - * transforms a VariableSetStmt */ -static Query* transformVariableSetValueStmt(ParseState* pstate, VariableSetStmt* stmt, bool is_alter_sys) +static void transformVariableSetValueStmt(ParseState* pstate, VariableSetStmt* stmt) { - Query *query = makeNode(Query); - List *resultlist = NIL; ListCell* l = NULL; @@ -2543,21 +2572,11 @@ static Query* transformVariableSetValueStmt(ParseState* pstate, VariableSetStmt* node = transformExpr(pstate, expr); } - resultlist = lappend(resultlist, (Expr *)node); + resultlist = lappend(resultlist, (Expr*)node); } + list_free(stmt->args); stmt->args = resultlist; - - query->commandType = CMD_UTILITY; - if (is_alter_sys) { - AlterSystemStmt* alter_sys_stmt = makeNode(AlterSystemStmt); - alter_sys_stmt->setstmt = stmt; - query->utilityStmt = (Node*)alter_sys_stmt; - } else { - query->utilityStmt = (Node*)stmt; - } - - return query; } /* diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index a45086d59..e2fde0431 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -355,7 +355,7 @@ static int errstate; RuleActionStmt RuleActionStmtOrEmpty RuleStmt SecLabelStmt SelectStmt TimeCapsuleStmt TransactionStmt TruncateStmt CallFuncStmt UnlistenStmt UpdateStmt VacuumStmt - VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt ShutdownStmt + VariableResetStmt VariableSetStmt VariableShowStmt VerifyStmt ShutdownStmt VariableMultiSetStmt ViewStmt CheckPointStmt CreateConversionStmt DeallocateStmt PrepareStmt ExecuteStmt DropOwnedStmt ReassignOwnedStmt @@ -577,6 +577,8 @@ static int errstate; %type merge_insert merge_update %type generic_set set_rest set_rest_more SetResetClause FunctionSetResetClause set_session_extension set_global_extension guc_variable_set generic_set_extension +%type VariableSetElemsList +%type set_global VariableSetElem %type TableElement TypedTableElement ConstraintElem TableFuncElement ForeignTableElement @@ -635,7 +637,7 @@ static int errstate; %type Iconst SignedIconst %type Sconst comment_text notify_payload %type RoleId TypeOwner opt_granted_by opt_boolean_or_string ColId_or_Sconst definer_user definer_expression -%type var_list guc_value_list guc_value_extension_list +%type var_list guc_value_extension_list %type ColId ColLabel var_name type_function_name param_name %type var_value zone_value @@ -672,7 +674,6 @@ static int errstate; %type with_clause opt_with_clause %type cte_list -%type user_defined_list %type uservar_name user_defined_single %type within_group_clause pkg_body_subprogram @@ -787,6 +788,8 @@ static int errstate; %type load_col_data_type %type load_col_sequence_item_sart column_sequence_item_step column_sequence_item_sart %type trigger_order + + /* * 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 @@ -1239,6 +1242,7 @@ stmt : | VacuumStmt | VariableResetStmt | VariableSetStmt + | VariableMultiSetStmt | VariableShowStmt | VerifyStmt | ViewStmt @@ -2053,33 +2057,6 @@ VariableSetStmt: n->is_local = false; $$ = (Node *) n; } - | SET user_defined_list - { -#ifdef ENABLE_MULTIPLE_NODES - const char* message = "SET @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("SET @var_name := expr is not yet supported in distributed database."))); -#endif - if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT && u_sess->attr.attr_common.enable_set_variable_b_format) { - VariableSetStmt *n = makeNode(VariableSetStmt); - n->kind = VAR_SET_DEFINED; - n->name = "USER DEFINED VARIABLE"; - n->defined_args = $2; - n->is_local = false; - $$ = (Node *)n; - } else { - const char* message = "SET @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("SET @var_name := expr is supported only in B-format database, and enable_set_variable_b_format = on."), - parser_errposition(@1))); - $$ = NULL;/* not reached */ - } - } | SET generic_set_extension { #ifdef ENABLE_MULTIPLE_NODES @@ -2100,7 +2077,7 @@ VariableSetStmt: (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 @@ -2122,321 +2099,8 @@ VariableSetStmt: errmsg("SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on."))); } } - | SET set_session_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 - VariableSetStmt *n = $2; - n->is_local = false; - $$ = (Node *) n; - } - | SET 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 = $2; - $$ = (Node *) n; -#endif - } ; -set_session_extension: - SET_IDENT_SESSION '.' guc_variable_set - { - VariableSetStmt *n = $3; - n->is_local = false; - $$ = n; - } - | SET_IDENT '=' guc_value_list - { - 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 = $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 '=' guc_value_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 '=' DEFAULT - { - VariableSetStmt *n = makeNode(VariableSetStmt); - n->kind = VAR_SET_DEFAULT; - n->name = $1; - $$ = n; - } - | CURRENT_SCHEMA '=' var_list - { - VariableSetStmt *n = makeNode(VariableSetStmt); - n->kind = VAR_SET_VALUE; - n->name = "current_schema"; - n->args = $3; - $$ = n; - } - | CURRENT_SCHEMA '=' DEFAULT - { - VariableSetStmt *n = makeNode(VariableSetStmt); - n->kind = VAR_SET_DEFAULT; - n->name = "current_schema"; - $$ = n; - } - ; - -guc_value_list: set_expr { $$ = list_make1($1); } - | guc_value_list ',' set_expr { $$ = lappend($1, $3); } - ; - -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 (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT && u_sess->attr.attr_common.enable_set_variable_b_format) { - $$ = $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, @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); - } - ; - set_rest: TRANSACTION transaction_mode_list { @@ -2655,11 +2319,70 @@ set_rest_more: /* Generic SET syntaxes: */ $$ = n; } ; - -user_defined_list: - user_defined_single { $$ = list_make1($1); } - | user_defined_list ',' user_defined_single { $$ = lappend($1, $3); } - ; + +/***************************************************************************** + * + * 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) + { + 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 @@ -2678,6 +2401,21 @@ user_defined_single: } ; +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 { @@ -2711,6 +2449,290 @@ generic_set_extension: } ; +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 (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT && u_sess->attr.attr_common.enable_set_variable_b_format) { + $$ = $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, @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 { diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp index 297540ad5..9d6f087d2 100644 --- a/src/common/backend/parser/parse_expr.cpp +++ b/src/common/backend/parser/parse_expr.cpp @@ -82,7 +82,6 @@ static Node* transformWholeRowRef(ParseState* pstate, RangeTblEntry* rte, int lo static Node* transformIndirection(ParseState* pstate, Node* basenode, List* indirection); static Node* transformTypeCast(ParseState* pstate, TypeCast* tc); static Node* transformCollateClause(ParseState* pstate, CollateClause* c); -static Node* transformSetVariableExpr(SetVariableExpr* set); static Node* make_row_comparison_op(ParseState* pstate, List* opname, List* largs, List* rargs, int location); static Node* make_row_distinct_op(ParseState* pstate, List* opname, RowExpr* lrow, RowExpr* rrow, int location); static Node* convertStarToCRef(RangeTblEntry* rte, char* catname, char* nspname, char* relname, int location); @@ -1850,7 +1849,7 @@ static Node* transformCaseExpr(ParseState* pstate, CaseExpr* c) /* * transformSetVariableExpr gets variable's value according to name and saves it in ConstExpr */ -static Node* transformSetVariableExpr(SetVariableExpr* set) +Node* transformSetVariableExpr(SetVariableExpr* set) { SetVariableExpr *result = makeNode(SetVariableExpr); result->name = set->name; diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 4b357a600..90c7325fb 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -8706,6 +8706,10 @@ void AlterSystemSetConfigFile(AlterSystemStmt * altersysstmt) release_file_lock(&filelock); /* release thread lock for config file */ LWLockRelease(ConfigFileLock); + + if (altersysstmt->setstmt->is_multiset) { + ereport(NOTICE, (errmsg("global parameter %s has been set", name))); + } } #endif diff --git a/src/common/interfaces/libpq/frontend_parser/gram.y b/src/common/interfaces/libpq/frontend_parser/gram.y index a0cab6e7e..1770e1012 100755 --- a/src/common/interfaces/libpq/frontend_parser/gram.y +++ b/src/common/interfaces/libpq/frontend_parser/gram.y @@ -481,9 +481,9 @@ extern THR_LOCAL bool stmt_contains_operator_plus; * DOT_DOT is unused in the core SQL grammar, and so will always provoke * parse errors. It is needed by PL/pgsql. */ -%token IDENT FCONST SCONST BCONST XCONST Op CmpOp COMMENTSTRING SET_USER_IDENT +%token IDENT FCONST SCONST BCONST XCONST Op CmpOp COMMENTSTRING SET_USER_IDENT SET_IDENT %token ICONST PARAM -%token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS +%token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS SET_IDENT_SESSION SET_IDENT_GLOBAL /* * If you want to make any keyword changes, update the keyword table in diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index 336797c52..84c87c21b 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -394,7 +394,7 @@ static void processFunctionRecordOutParam(int varno, Oid funcoid, int* outparam) */ %token IDENT FCONST SCONST BCONST VCONST XCONST Op CmpOp CmpNullOp COMMENTSTRING SET_USER_IDENT SET_IDENT %token ICONST PARAM -%token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS +%token TYPECAST ORA_JOINOP DOT_DOT COLON_EQUALS PARA_EQUALS SET_IDENT_SESSION SET_IDENT_GLOBAL /* * Other tokens recognized by plpgsql's lexer interface layer (pl_scanner.c). diff --git a/src/common/pl/plpgsql/src/pl_exec.cpp b/src/common/pl/plpgsql/src/pl_exec.cpp index 3966bc80b..3f75e0d92 100644 --- a/src/common/pl/plpgsql/src/pl_exec.cpp +++ b/src/common/pl/plpgsql/src/pl_exec.cpp @@ -12664,11 +12664,8 @@ static bool needRecompilePlan(SPIPlanPtr plan) /* * if stmt is user_defined variables, recompile the query. */ - if (plansource->raw_parse_tree != NULL && IsA(plansource->raw_parse_tree, VariableSetStmt)) { - VariableSetStmt *stmt = (VariableSetStmt *)plansource->raw_parse_tree; - if (stmt->kind == VAR_SET_DEFINED) { - return true; - } + if (plansource->raw_parse_tree != NULL && IsA(plansource->raw_parse_tree, VariableMultiSetStmt)) { + return true; } ret_val = checkRecompileCondition(plansource); diff --git a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp index fa1d5942a..8d56434ff 100644 --- a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp +++ b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp @@ -3363,17 +3363,63 @@ char* GetInsertIntoStmt(CreateTableAsStmt* stmt) return cquery->data; } +List *query_rewrite_multiset_stmt(Query *query) +{ + List* querytree_list = NIL; + VariableMultiSetStmt* muti_stmt = (VariableMultiSetStmt*)query->utilityStmt; + List* stmts = muti_stmt->args; + ListCell* cell = NULL; + VariableSetStmt *set_stmt; + + foreach(cell, stmts) { + Node* stmt = (Node*)lfirst(cell); + + if (nodeTag(stmt) == T_AlterSystemStmt) { + AlterSystemStmt* alter_sys_stmt = (AlterSystemStmt *)stmt; + set_stmt = alter_sys_stmt->setstmt; + } else { + set_stmt = (VariableSetStmt*)stmt; + } + + if (list_length(set_stmt->args) > 1) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("set %s takes only one argument", set_stmt->name))); + } + + if(set_stmt->kind == VAR_SET_VALUE) { + List *resultlist = NIL; + ListCell *l = NULL; + + foreach(l, set_stmt->args) { + Node* expr = (Node*)lfirst(l); + Node* node = NULL; + + if(IsA(expr, A_Const)) { + node = expr; + } else { + node = eval_const_expression_value(NULL, expr, NULL); + + if(nodeTag(node) != T_Const) { + node = QueryRewriteNonConstant(expr); + } + node = transferConstToAconst(node); + } + resultlist = lappend(resultlist, (A_Const*)node); + } + list_free(set_stmt->args); + set_stmt->args = resultlist; + } + } + + querytree_list = list_make1(query); + return querytree_list; +} + List *query_rewrite_set_stmt(Query *query) { List* querytree_list = NIL; - VariableSetStmt *stmt; - - if(IsA(query->utilityStmt, AlterSystemStmt)) { - AlterSystemStmt* alter_sys_stmt = (AlterSystemStmt*)query->utilityStmt; - stmt = alter_sys_stmt->setstmt; - } else { - stmt = (VariableSetStmt *)query->utilityStmt; - } + VariableSetStmt *stmt = (VariableSetStmt *)query->utilityStmt; if(DB_IS_CMPT(B_FORMAT) && stmt->kind == VAR_SET_VALUE && u_sess->attr.attr_common.enable_set_variable_b_format) { List *resultlist = NIL; @@ -3402,7 +3448,6 @@ List *query_rewrite_set_stmt(Query *query) return querytree_list; } - List *QueryRewriteRefresh(Query *parse_tree) { RefreshMatViewStmt* stmt = NULL; diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index 8375ef316..ac8195d03 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -1181,7 +1181,9 @@ static List* pg_rewrite_query(Query* query) } else { querytree_list = list_make1(query); } - } else if (IsA(query->utilityStmt, VariableSetStmt) || IsA(query->utilityStmt, AlterSystemStmt)) { + } else if (IsA(query->utilityStmt, VariableMultiSetStmt)) { + querytree_list = query_rewrite_multiset_stmt(query); + } else if (IsA(query->utilityStmt, VariableSetStmt)) { querytree_list = query_rewrite_set_stmt(query); } else { querytree_list = list_make1(query); diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index 09c29218c..26372c799 100755 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -5637,15 +5637,22 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi #ifndef ENABLE_MULTIPLE_NODES case T_AlterSystemStmt: + { /* * 1.AlterSystemSet don't care whether the node is PRIMARY or STANDBY as same as gs_guc. * 2.AlterSystemSet don't care whether the database is read-only, as same as gs_guc. * 3.It cannot be executed in a transaction because it is not rollbackable. */ - PreventTransactionChain(is_top_level, "ALTER SYSTEM SET"); + + AlterSystemStmt* stmt = (AlterSystemStmt*)parse_tree; + if (stmt->setstmt->is_multiset) { + PreventTransactionChain(true, "ALTER SYSTEM SET"); + } else { + PreventTransactionChain(is_top_level, "ALTER SYSTEM SET"); + } AlterSystemSetConfigFile((AlterSystemStmt*)parse_tree); - break; + } break; #endif case T_VariableSetStmt: @@ -5716,6 +5723,24 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi #endif break; + case T_VariableMultiSetStmt: { + VariableMultiSetStmt* n = (VariableMultiSetStmt*)parse_tree; + List* stmts = n->args; + ListCell* l = NULL; + + foreach (l, stmts) { + Node* stmt = (Node*)lfirst(l); + + ProcessUtility(stmt, + query_string, + params, + false, + None_Receiver, + true, + NULL); + } + } break; + case T_VariableShowStmt: { VariableShowStmt* n = (VariableShowStmt*)parse_tree; @@ -7196,6 +7221,7 @@ static bool is_stmt_allowed_in_locked_mode(Node* parse_tree, const char* query_s case T_ClusterStmt: case T_ExplainStmt: case T_VariableSetStmt: + case T_VariableMultiSetStmt: case T_VariableShowStmt: case T_DiscardStmt: case T_LockStmt: @@ -8596,6 +8622,11 @@ const char* CreateCommandTag(Node* parse_tree) } break; + case T_VariableMultiSetStmt: + { + tag = "Set"; + } break; + case T_VariableShowStmt: tag = "SHOW"; break; @@ -9567,6 +9598,10 @@ LogStmtLevel GetCommandLogLevel(Node* parse_tree) lev = LOGSTMT_ALL; break; + case T_VariableMultiSetStmt: + lev = LOGSTMT_ALL; + break; + case T_UserVar: lev = LOGSTMT_ALL; break; diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp index db13033d6..1a22a3486 100644 --- a/src/gausskernel/runtime/executor/execQual.cpp +++ b/src/gausskernel/runtime/executor/execQual.cpp @@ -73,6 +73,7 @@ #include "db4ai/gd.h" #include "catalog/pg_proc_fn.h" #include "access/tuptoaster.h" +#include "parser/parse_expr.h" /* static function decls */ static bool isAssignmentIndirectionExpr(ExprState* exprstate); @@ -1072,6 +1073,9 @@ static Datum ExecEvalConst(ExprState* exprstate, ExprContext* econtext, bool* is /* if not found, return a null const */ con = found ? entry->value : makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum)0, true, false); + } else if (IsA(exprstate->expr, SetVariableExpr)) { + SetVariableExpr* setvar = (SetVariableExpr*)transformSetVariableExpr((SetVariableExpr*)exprstate->expr); + con = (Const*)setvar->value; } else { con = (Const*)exprstate->expr; } @@ -5290,6 +5294,7 @@ ExprState* ExecInitExpr(Expr* node, PlanState* parent) break; case T_Const: case T_UserVar: + case T_SetVariableExpr: state = (ExprState*)makeNode(ExprState); state->evalfunc = ExecEvalConst; break; diff --git a/src/gausskernel/runtime/executor/nodeModifyTable.cpp b/src/gausskernel/runtime/executor/nodeModifyTable.cpp index fa387dfb2..7348b3704 100644 --- a/src/gausskernel/runtime/executor/nodeModifyTable.cpp +++ b/src/gausskernel/runtime/executor/nodeModifyTable.cpp @@ -3253,17 +3253,6 @@ static TupleTableSlot* ExecReplace(EState* estate, ModifyTableState* node, Tuple } -static TupleTableSlot* FetchPlanSlot(ModifyTableState* node, PlanState* subPlanState) -{ - EState* estate = node->ps.state; - - if (estate->result_rel_index > 0) { - return ExecProject(node->mt_ProjInfos[estate->result_rel_index], NULL); - } else { - return ExecProcNode(subPlanState); - } -} - /* ---------------------------------------------------------------- * ExecModifyTable * diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 252d82376..1748cfe7a 100755 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -517,6 +517,7 @@ typedef enum NodeTag { T_AlterSubscriptionStmt, T_DropSubscriptionStmt, T_ShrinkStmt, + T_VariableMultiSetStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) */ diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index 6a89947af..3d2d9eba6 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -545,8 +545,14 @@ typedef struct VariableSetStmt { List *args; /* List of A_Const nodes */ bool is_local; /* SET LOCAL? */ List *defined_args; /* List of user_defined variable */ + bool is_multiset; /* VariableMultiSetStmt ? */ } VariableSetStmt; +typedef struct VariableMultiSetStmt { + NodeTag type; + List *args; /* List of VariableSetStmt nodes */ +} VariableMultiSetStmt; + typedef struct UserVar { Expr xpr; char* name; diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h index 4e625a750..8fe32dc95 100644 --- a/src/include/parser/parse_expr.h +++ b/src/include/parser/parse_expr.h @@ -22,6 +22,7 @@ extern Oid getMultiFuncInfo(char* fun_expr, PLpgSQL_expr* expr, bool isoutparamc extern void CheckOutParamIsConst(PLpgSQL_expr* expr); extern void lockSeqForNextvalFunc(Node* node); +extern Node* transformSetVariableExpr(SetVariableExpr* set); /* start with ... connect by related output routines */ extern bool IsPseudoReturnColumn(const char *colname); diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index b2d5d6352..27dd29762 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -22,6 +22,7 @@ extern void AcquireRewriteLocks(Query* parsetree, bool forUpdatePushedDown); extern Node* build_column_default(Relation rel, int attrno, bool isInsertCmd = false, bool needOnUpdate = false); extern List* pull_qual_vars(Node* node, int varno = 0, int flags = 0, bool nonRepeat = false); extern void rewriteTargetListMerge(Query* parsetree, Index result_relation, List* range_table); +extern List *query_rewrite_multiset_stmt(Query* parse_tree); extern List *query_rewrite_set_stmt(Query* parse_tree); #ifdef PGXC diff --git a/src/test/regress/input/set_system_variables_test.source b/src/test/regress/input/set_system_variables_test.source index dcaa0e332..410da46fb 100644 --- a/src/test/regress/input/set_system_variables_test.source +++ b/src/test/regress/input/set_system_variables_test.source @@ -13,12 +13,38 @@ select @@session.codegen_cost_threshold = 1001; set @@global.dcf_connect_timeout = 6000; select @@global.dcf_connect_timeout; +set global dcf_connect_timeout = 6000; +set global dcf_connect_timeout = abs(6000); +set session codegen_cost_threshold = 10000 * 1; +set codegen_cost_threshold = 10000 * 1; +set codegen_cost_threshold = (select 10000); + +create database test_set dbcompatibility 'b'; +\c test_set +-- dbcompatibility is B Format, enable_set_variable_b_format=off +set codegen_cost_threshold = default; +set codegen_cost_threshold = 10000; + +set @@codegen_cost_threshold = 10000; +set @@session.codegen_cost_threshold = 10000; +set @@session.codegen_cost_threshold = default; + +select @@session.codegen_cost_threshold; +select @@session.codegen_cost_threshold = 1001; + +set @@global.dcf_connect_timeout = 6000; +select @@global.dcf_connect_timeout; + +set global dcf_connect_timeout = 6000; +set global dcf_connect_timeout = abs(6000); +set session codegen_cost_threshold = 10000 * 1; +set codegen_cost_threshold = 10000 * 1; +set codegen_cost_threshold = (select 10000); + \! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_set_variable_b_format=on" >/dev/null 2>&1 \! sleep 1 --- dbcompatibility is B Format -create database test_set dbcompatibility 'b'; -\c test_set +-- dbcompatibility is B Format, enable_set_variable_b_format=on -- test integer params, e.g. codegen_cost_threshold set codegen_cost_threshold = default; @@ -202,6 +228,50 @@ set @@session.backwrite_quantity = (select * from t1); insert into t1 values (1025); set @@session.backwrite_quantity = (select * from t1); +-- test multiset +set global log_destination = 'stderr,syslog', @v1:=@v2:='aaa' ,@@codegen_cost_threshold = 10000, @v3:= 1, @@session.cpu_index_tuple_cost = default, @@application_name = (select 'gsql'); +set global log_destination = 'stderr,syslog', @@codegen_cost_threshold = 10000, @v1:= 1; +set global log_destination = 'stderr', @@codegen_cost_threshold = abs(10000), @v1:= @@codegen_cost_threshold; +set @@session.codegen_cost_threshold = 10000, @v2:=@v1:= 1; +set global log_destination = 'stderr,syslog', @@codegen_cost_threshold = 10000, @v1:= 1, global checkpoint_completion_target = 0.3 * 1; +set @v1 := 10000; +set @v2:=@v1:= 9999,@@session.codegen_cost_threshold = @v1 ; + +-- fail e.g. +set global log_destination = stderr,syslog; +set global log_destination = stderr,syslog , @v1:= 1, @@codegen_cost_threshold = 10000; +set global log_destination = stderr,syslog , @v1:= 1, @@codegen_cost_threshold = aa; +set global log_destination = 'stderr', @v1:= 1, @@codegen_cost_threshold = 'aa'; + +-- test procedure +create table test_pro(a int); + +create or replace procedure pro1() +as +begin + insert into test_pro values(@@session_timeout); +end; +/ +call pro1(); +set @@session_timeout = 700; +call pro1(); +set @@session_timeout = 800; +call pro1(); +select * from test_pro; + +create or replace procedure proc1 as +declare +v1 integer; +v2 integer; +begin +set @@session.session_timeout = 240; +set @@global.dcf_connect_timeout = 60000; +select @@session.session_timeout, @@global.dcf_connect_timeout into v1,v2; +raise info 'v1:%', v1; +raise info 'v2:%', v2; +end; +/ + \c regression drop database if exists test_set; diff --git a/src/test/regress/output/set_system_variables_test.source b/src/test/regress/output/set_system_variables_test.source index b4f095684..550a47e74 100644 --- a/src/test/regress/output/set_system_variables_test.source +++ b/src/test/regress/output/set_system_variables_test.source @@ -29,11 +29,70 @@ select @@global.dcf_connect_timeout; ERROR: missing FROM-clause entry for table "global" LINE 1: select @@global.dcf_connect_timeout; ^ -\! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_set_variable_b_format=on" >/dev/null 2>&1 -\! sleep 1 --- dbcompatibility is B Format +set global dcf_connect_timeout = 6000; +ERROR: SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on. +LINE 1: set global dcf_connect_timeout = 6000; + ^ +set global dcf_connect_timeout = abs(6000); +ERROR: SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on. +LINE 1: set global dcf_connect_timeout = abs(6000); + ^ +set session codegen_cost_threshold = 10000 * 1; +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. +set codegen_cost_threshold = 10000 * 1; +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. +set codegen_cost_threshold = (select 10000); +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. create database test_set dbcompatibility 'b'; \c test_set +-- dbcompatibility is B Format, enable_set_variable_b_format=off +set codegen_cost_threshold = default; +set codegen_cost_threshold = 10000; +set @@codegen_cost_threshold = 10000; +ERROR: syntax error at or near "@@" +LINE 1: set @@codegen_cost_threshold = 10000; + ^ +set @@session.codegen_cost_threshold = 10000; +ERROR: syntax error at or near "@@" +LINE 1: set @@session.codegen_cost_threshold = 10000; + ^ +set @@session.codegen_cost_threshold = default; +ERROR: syntax error at or near "@@" +LINE 1: set @@session.codegen_cost_threshold = default; + ^ +select @@session.codegen_cost_threshold; +ERROR: missing FROM-clause entry for table "session" +LINE 1: select @@session.codegen_cost_threshold; + ^ +select @@session.codegen_cost_threshold = 1001; +ERROR: missing FROM-clause entry for table "session" +LINE 1: select @@session.codegen_cost_threshold = 1001; + ^ +set @@global.dcf_connect_timeout = 6000; +ERROR: syntax error at or near "@@" +LINE 1: set @@global.dcf_connect_timeout = 6000; + ^ +select @@global.dcf_connect_timeout; +ERROR: missing FROM-clause entry for table "global" +LINE 1: select @@global.dcf_connect_timeout; + ^ +set global dcf_connect_timeout = 6000; +ERROR: SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on. +LINE 1: set global dcf_connect_timeout = 6000; + ^ +set global dcf_connect_timeout = abs(6000); +ERROR: SET UserVar/GLOBAL/SESSION is supported only in B-format database, and enable_set_variable_b_format = on. +LINE 1: set global dcf_connect_timeout = abs(6000); + ^ +set session codegen_cost_threshold = 10000 * 1; +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. +set codegen_cost_threshold = 10000 * 1; +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. +set codegen_cost_threshold = (select 10000); +ERROR: SET supported expr value only in B_FORMAT and enable_set_variable_b_format is on. +\! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_set_variable_b_format=on" >/dev/null 2>&1 +\! sleep 1 +-- dbcompatibility is B Format, enable_set_variable_b_format=on -- test integer params, e.g. codegen_cost_threshold set codegen_cost_threshold = default; set codegen_cost_threshold = 10000; @@ -80,14 +139,19 @@ select abs(@@session.codegen_cost_threshold) + 1; set @@global.dcf_connect_timeout = '6000'; NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +NOTICE: global parameter dcf_connect_timeout has been set set @@global.dcf_connect_timeout = 6000 + 1; NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +NOTICE: global parameter dcf_connect_timeout has been set set @@global.dcf_connect_timeout = @@global.dcf_connect_timeout * 2; NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +NOTICE: global parameter dcf_connect_timeout has been set set @@global.dcf_connect_timeout = (select 6000 + 1); NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +NOTICE: global parameter dcf_connect_timeout has been set set @@global.dcf_connect_timeout = 6000; NOTICE: please restart the database for the POSTMASTER level parameter to take effect. +NOTICE: global parameter dcf_connect_timeout has been set select pg_sleep(1); pg_sleep ---------- @@ -180,12 +244,19 @@ select @@session.enable_broadcast = 'true'; (1 row) set global most_available_sync = t; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = t; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = true; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = 'true'; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = false; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = on; +NOTICE: global parameter most_available_sync has been set set @@global.most_available_sync = off; +NOTICE: global parameter most_available_sync has been set -- fail example set enable_broadcast = 10000; ERROR: parameter "enable_broadcast" requires a Boolean value @@ -235,10 +306,15 @@ select char_length(@@session.application_name); (1 row) set @@global.syslog_ident = 'postgres1'; +NOTICE: global parameter syslog_ident has been set set global syslog_ident = 'postgres1'; +NOTICE: global parameter syslog_ident has been set set global syslog_ident = left('postgres1',8); +NOTICE: global parameter syslog_ident has been set set @@global.syslog_ident = ('postgres1' = 'postgres1'); +NOTICE: global parameter syslog_ident has been set set @@global.syslog_ident = 'postgres'; +NOTICE: global parameter syslog_ident has been set select pg_sleep(1); pg_sleep ---------- @@ -304,8 +380,11 @@ select @@session.explain_perf_mode = 'normal'; (1 row) set global trace_recovery_messages = log; +NOTICE: global parameter trace_recovery_messages has been set set @@global.trace_recovery_messages = info; +NOTICE: global parameter trace_recovery_messages has been set set @@global.trace_recovery_messages = log; +NOTICE: global parameter trace_recovery_messages has been set select pg_sleep(1); pg_sleep ---------- @@ -365,9 +444,13 @@ select abs(@@cpu_index_tuple_cost); (1 row) set global checkpoint_completion_target = 0.3; +NOTICE: global parameter checkpoint_completion_target has been set set global checkpoint_completion_target = 0.3 * 1; +NOTICE: global parameter checkpoint_completion_target has been set set global checkpoint_completion_target = abs(0.3); +NOTICE: global parameter checkpoint_completion_target has been set set @@global.checkpoint_completion_target = abs(0.3); +NOTICE: global parameter checkpoint_completion_target has been set select pg_sleep(1); pg_sleep ---------- @@ -410,6 +493,83 @@ insert into t1 values (1025); set @@session.backwrite_quantity = (select * from t1); ERROR: more than one row returned by a subquery used as an expression CONTEXT: referenced column: f1 +-- test multiset +set global log_destination = 'stderr,syslog', @v1:=@v2:='aaa' ,@@codegen_cost_threshold = 10000, @v3:= 1, @@session.cpu_index_tuple_cost = default, @@application_name = (select 'gsql'); +NOTICE: global parameter log_destination has been set +set global log_destination = 'stderr,syslog', @@codegen_cost_threshold = 10000, @v1:= 1; +NOTICE: global parameter log_destination has been set +set global log_destination = 'stderr', @@codegen_cost_threshold = abs(10000), @v1:= @@codegen_cost_threshold; +NOTICE: global parameter log_destination has been set +set @@session.codegen_cost_threshold = 10000, @v2:=@v1:= 1; +set global log_destination = 'stderr,syslog', @@codegen_cost_threshold = 10000, @v1:= 1, global checkpoint_completion_target = 0.3 * 1; +NOTICE: global parameter log_destination has been set +NOTICE: global parameter checkpoint_completion_target has been set +set @v1 := 10000; +set @v2:=@v1:= 9999,@@session.codegen_cost_threshold = @v1 ; +-- fail e.g. +set global log_destination = stderr,syslog; +ERROR: syntax error at or near "syslog" +LINE 1: set global log_destination = stderr,syslog; + ^ +set global log_destination = stderr,syslog , @v1:= 1, @@codegen_cost_threshold = 10000; +ERROR: syntax error at or near "syslog" +LINE 1: set global log_destination = stderr,syslog , @v1:= 1, @@code... + ^ +set global log_destination = stderr,syslog , @v1:= 1, @@codegen_cost_threshold = aa; +ERROR: syntax error at or near "syslog" +LINE 1: set global log_destination = stderr,syslog , @v1:= 1, @@code... + ^ +set global log_destination = 'stderr', @v1:= 1, @@codegen_cost_threshold = 'aa'; +NOTICE: global parameter log_destination has been set +ERROR: invalid value for parameter "codegen_cost_threshold": "aa" +-- test procedure +create table test_pro(a int); +create or replace procedure pro1() +as +begin + insert into test_pro values(@@session_timeout); +end; +/ +call pro1(); + pro1 +------ + +(1 row) + +set @@session_timeout = 700; +call pro1(); + pro1 +------ + +(1 row) + +set @@session_timeout = 800; +call pro1(); + pro1 +------ + +(1 row) + +select * from test_pro; + a +----- + 600 + 700 + 800 +(3 rows) + +create or replace procedure proc1 as +declare +v1 integer; +v2 integer; +begin +set @@session.session_timeout = 240; +set @@global.dcf_connect_timeout = 60000; +select @@session.session_timeout, @@global.dcf_connect_timeout into v1,v2; +raise info 'v1:%', v1; +raise info 'v2:%', v2; +end; +/ \c regression drop database if exists test_set; \! @abs_bindir@/gs_guc reload -Z datanode -D @abs_srcdir@/tmp_check/datanode1 -c "enable_set_variable_b_format=off" >/dev/null 2>&1