From 7be67ae4b071fb8ea5c40e91c4e03ebb3351e5db Mon Sep 17 00:00:00 2001 From: yanghao Date: Mon, 13 Mar 2023 22:13:02 +0800 Subject: [PATCH] select_into_fix Offering: openGaussDev More detail: fix the lost of targetlist data Match-id-18da7d885125b5bbd6c1cbe3b1588751ca89f554 --- src/common/backend/parser/parse_expr.cpp | 7 --- src/common/backend/utils/misc/guc.cpp | 11 +++- .../dbmind/kernel/index_advisor.cpp | 36 ------------- .../optimizer/rewrite/rewriteHandler.cpp | 9 ++-- src/gausskernel/optimizer/util/clauses.cpp | 34 ++----------- src/gausskernel/process/tcop/postgres.cpp | 3 +- src/include/commands/sqladvisor.h | 2 +- src/include/optimizer/clauses.h | 2 +- src/include/rewrite/rewriteHandler.h | 2 +- src/include/tcop/tcopprot.h | 1 - .../select_into_user_defined_variables.source | 25 +++++++++ .../select_into_user_defined_variables.source | 51 +++++++++++++++++++ 12 files changed, 101 insertions(+), 82 deletions(-) diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp index c188cbdad..decc1e754 100644 --- a/src/common/backend/parser/parse_expr.cpp +++ b/src/common/backend/parser/parse_expr.cpp @@ -2134,13 +2134,6 @@ static Node* transformSelectIntoVarList(ParseState* pstate, SelectIntoVarList* s ereport(ERROR, (errcode(ERRCODE_INVALID_OPERATION), errmsg("unexpected non-SELECT command in SubLink"))); } sublink->subselect = (Node*)qtree; - - if (list_length(qtree->targetList) != list_length(sis->userVarList)) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("number of variables must equal the number of columns"), - parser_errposition(pstate, sublink->location))); - } return (Node *)sis; } diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 10b0fda46..ad0cdf525 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -9150,8 +9150,15 @@ void ExecSetVariableStmt(VariableSetStmt* stmt, ParamListInfo paramInfo) ListCell *head = list_head(stmt->defined_args); UserSetElem *elem = (UserSetElem *)lfirst(head); Node *node = (Node *)copyObject(((SelectIntoVarList *)elem->val)->sublink); - node = simplify_select_into_expression(node, paramInfo); - List *val_list = QueryRewriteSelectIntoVarList(node); + + int real_targetlist_len = 0; + node = simplify_select_into_expression(node, paramInfo, &real_targetlist_len); + if (real_targetlist_len != list_length(elem->name)) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("number of variables must equal the number of columns"))); + } + List *val_list = QueryRewriteSelectIntoVarList(node, real_targetlist_len); ListCell *name_cur = NULL; ListCell *val_cur = NULL; diff --git a/src/gausskernel/dbmind/kernel/index_advisor.cpp b/src/gausskernel/dbmind/kernel/index_advisor.cpp index b86ce0dc7..c0ee882d3 100755 --- a/src/gausskernel/dbmind/kernel/index_advisor.cpp +++ b/src/gausskernel/dbmind/kernel/index_advisor.cpp @@ -707,42 +707,6 @@ StmtResult *execute_stmt(const char *query_string, bool need_result) return (StmtResult *)receiver; } -StmtResult *execute_select_into_varlist(Query *parsetree) -{ - int16 format = 0; - DestReceiver *receiver = NULL; - - PG_TRY(); - { - Portal portal = NULL; - - List *querytree_list = NULL; - List *plantree_list = NULL; - - const char *commandTag = CreateCommandTag((Node *)parsetree); - - querytree_list = pg_rewrite_query(parsetree); - plantree_list = pg_plan_queries(querytree_list, 0, NULL); - - portal = CreatePortal("SELECT_INTO_STMT", true, true); - portal->visible = false; - PortalDefineQuery(portal, NULL, "SELECT_INTO_STMT", commandTag, plantree_list, NULL); - receiver = create_stmt_receiver(); - - PortalStart(portal, NULL, 0, NULL); - PortalSetResultFormat(portal, 1, &format); - (void)PortalRun(portal, FETCH_ALL, true, receiver, receiver, NULL); - PortalDrop(portal, false); - } - PG_CATCH(); - { - PG_RE_THROW(); - } - PG_END_TRY(); - - return (StmtResult *)receiver; -} - /* create_stmt_receiver * * The existing code cannot store the execution results of SQL statements to the list structure. diff --git a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp index 16a8e672b..7f00f2c24 100644 --- a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp +++ b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp @@ -5178,13 +5178,16 @@ Node* QueryRewriteNonConstant(Node *node) return res; } -List* QueryRewriteSelectIntoVarList(Node *node) +List* QueryRewriteSelectIntoVarList(Node *node, int res_len) { Query *parsetree = (Query *)((SubLink *)node)->subselect; List *resList = NIL; - int res_len = parsetree->targetList->length; - StmtResult *result = execute_select_into_varlist(parsetree); + StringInfo select_sql = makeStringInfo(); + deparse_query(parsetree, select_sql, NIL, false, false); + + StmtResult *result = execute_stmt(select_sql->data, true); + DestroyStringInfo(select_sql); if (result->tuples == NULL) { for (int i = 0; i < res_len; i++) { diff --git a/src/gausskernel/optimizer/util/clauses.cpp b/src/gausskernel/optimizer/util/clauses.cpp index f7c0d1bc1..140806240 100644 --- a/src/gausskernel/optimizer/util/clauses.cpp +++ b/src/gausskernel/optimizer/util/clauses.cpp @@ -137,7 +137,6 @@ static bool is_exec_external_param_const(PlannerInfo* root, Node* node); static bool is_operator_pushdown(Oid opno); static bool contain_var_unsubstitutable_functions_walker(Node* node, void* context); static bool is_accurate_estimatable_func(Oid funcId); -static void optbase_eval_user_var_in_opexpr(List *args); /***************************************************************************** * OPERATOR clause functions @@ -2451,7 +2450,7 @@ Node* estimate_expression_value(PlannerInfo* root, Node* node, EState* estate) * for the following process to calculate the value. * -------------------- */ -Node* simplify_select_into_expression(Node* node, ParamListInfo boundParams) +Node* simplify_select_into_expression(Node* node, ParamListInfo boundParams, int *targetlist_len) { eval_const_expressions_context context; @@ -2476,44 +2475,21 @@ Node* simplify_select_into_expression(Node* node, ParamListInfo boundParams) } ListCell *lc = NULL; - AttrNumber attno = 1; List *newTargetList = NIL; foreach (lc, qt->targetList) { TargetEntry *te = (TargetEntry *)lfirst(lc); - Node *tn = (Node *)te->expr; - if (IsA(tn, OpExpr)) { - /* If the user-defined variable has been defined, - * then find the existed value. - */ - optbase_eval_user_var_in_opexpr(((OpExpr *)tn)->args); + if (!te->resjunk) { + (*targetlist_len)++; } + Node *tn = (Node *)te->expr; tn = eval_const_expressions_mutator(tn, &context); - te = makeTargetEntry((Expr *)tn, attno++, te->resname, false); + te->expr = (Expr *)tn; newTargetList = lappend(newTargetList, te); } - qt->targetList = newTargetList; return node; } -static void optbase_eval_user_var_in_opexpr(List *args) -{ - ListCell *argcell = NULL; - foreach (argcell, args) { - if (IsA(lfirst(argcell), UserVar)) { - bool found = false; - GucUserParamsEntry *entry = (GucUserParamsEntry *)hash_search( - u_sess->utils_cxt.set_user_params_htab, - ((UserVar *)lfirst(argcell))->name, - HASH_ENTER, - &found); - if (found) { - ((UserVar *)lfirst(argcell))->value = (Expr *)copyObject(entry->value); - } - } - } -} - Node* eval_const_expressions_mutator(Node* node, eval_const_expressions_context* context) { if (node == NULL) diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index 1bc421d69..1aa4c8549 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -277,6 +277,7 @@ static int ReadCommand(StringInfo inBuf); bool check_log_statement(List* stmt_list); static int errdetail_execute(List* raw_parsetree_list); int errdetail_params(ParamListInfo params); +static List* pg_rewrite_query(Query* query); static int errdetail_recovery_conflict(void); bool IsTransactionExitStmt(Node* parsetree); static bool IsTransactionExitStmtList(List* parseTrees); @@ -1180,7 +1181,7 @@ List* pg_analyze_and_rewrite_params( * Note: query must just have come from the parser, because we do not do * AcquireRewriteLocks() on it. */ -List* pg_rewrite_query(Query* query) +static List* pg_rewrite_query(Query* query) { List* querytree_list = NIL; PGSTAT_INIT_TIME_RECORD(); diff --git a/src/include/commands/sqladvisor.h b/src/include/commands/sqladvisor.h index 3e50739cf..0bc67bb32 100644 --- a/src/include/commands/sqladvisor.h +++ b/src/include/commands/sqladvisor.h @@ -278,5 +278,5 @@ extern Datum analyze_workload(PG_FUNCTION_ARGS); extern bool checkSelectIntoParse(SelectStmt* stmt); extern PLpgSQL_datum* copypPlpgsqlDatum(PLpgSQL_datum* datum); extern StmtResult *execute_stmt(const char *query_string, bool need_result = false); -extern StmtResult *execute_select_into_varlist(Query* parsetree); + #endif /* SQLADVISOR_H */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 34a988b01..a185da953 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -116,7 +116,7 @@ extern Node* eval_const_expressions_params(PlannerInfo* root, Node* node, ParamL extern Node *eval_const_expression_value(PlannerInfo* root, Node* node, ParamListInfo boundParams); -extern Node* simplify_select_into_expression(Node* node, ParamListInfo boundParams); +extern Node* simplify_select_into_expression(Node* node, ParamListInfo boundParams, int *targetlist_len); extern Node* estimate_expression_value(PlannerInfo* root, Node* node, EState* estate = NULL); diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index d584543e4..4c5558781 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -35,6 +35,6 @@ extern List* QueryRewriteRefresh(Query *parsetree); #endif extern List* QueryRewritePrepareStmt(Query *parsetree); extern Node* QueryRewriteNonConstant(Node *node); -extern List* QueryRewriteSelectIntoVarList(Node *node); +extern List* QueryRewriteSelectIntoVarList(Node *node, int res_len); #endif /* REWRITEHANDLER_H */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 101c7dcd2..447f73055 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -39,7 +39,6 @@ typedef enum { extern List* pg_parse_query(const char* query_string, List** query_string_locationlist = NULL, List* (*parser_hook)(const char*, List**) = NULL); extern List* pg_analyze_and_rewrite(Node* parsetree, const char* query_string, Oid* paramTypes, int numParams); -extern List* pg_rewrite_query(Query* query); extern List* pg_analyze_and_rewrite_params( Node* parsetree, const char* query_string, ParserSetupHook parserSetup, void* parserSetupArg); extern PlannedStmt* pg_plan_query( diff --git a/src/test/regress/input/select_into_user_defined_variables.source b/src/test/regress/input/select_into_user_defined_variables.source index 3a38fbf8c..73bf5dcd3 100644 --- a/src/test/regress/input/select_into_user_defined_variables.source +++ b/src/test/regress/input/select_into_user_defined_variables.source @@ -54,7 +54,17 @@ select * from t where i isnull into @aa,@bb,@cc,@dd,@ee,@ff; select @aa,@bb,@cc,@dd,@ee,@ff; select * from t where i=100 into @aa,@bb,@cc,@dd,@ee,@ff; select @aa,@bb,@cc,@dd,@ee,@ff; +create table int_tb(c1 TINYINT,c2 SMALLINT,c3 INTEGER,c5 BIGINT); +insert into int_tb values(0,-32768,-2147483648,-9223372036854775808),(0,1,100000,100000000); +select c1 into @my_var from int_tb order by c1 limit 1; +select @my_var; +CREATE TABLE t001(c1 int, c2 int, c3 int); +insert into t001 values(100,100,100),(100,101,101); +SELECT SUM(c2) as f1, @aa as f2 INTO @aa,@bb FROM t001 GROUP BY c1; +SELECT @aa,@bb; +SELECT SUM(c2) as f1, SUM(c1) as f2 INTO @aa,@bb FROM t001 GROUP BY c1; +SELECT @aa,@bb; create or replace procedure my_pro() as declare outfile int default 0; @@ -200,6 +210,21 @@ delete t1 where a = 200; select @num; drop trigger tri_delete_after on t1; +drop table if exists trigger_t2; +create table trigger_t2(a int); +create or replace function tri_func3() returns trigger as +$$ +begin + select abs(@num)+1 into @num; + return NEW; +end +$$ LANGUAGE PLPGSQL; +create trigger tri_insert_before before insert on trigger_t2 for each row execute procedure tri_func3(); +select -1 into @num; +select @num; +insert into trigger_t2 values(10); +select @num; +drop trigger tri_insert_before on trigger_t2; select 10,@v1/2 into @v1,@v2; select @v1,@v2; diff --git a/src/test/regress/output/select_into_user_defined_variables.source b/src/test/regress/output/select_into_user_defined_variables.source index 14fb96701..347ddc72b 100644 --- a/src/test/regress/output/select_into_user_defined_variables.source +++ b/src/test/regress/output/select_into_user_defined_variables.source @@ -132,6 +132,31 @@ select @aa,@bb,@cc,@dd,@ee,@ff; | | | | | (1 row) +create table int_tb(c1 TINYINT,c2 SMALLINT,c3 INTEGER,c5 BIGINT); +insert into int_tb values(0,-32768,-2147483648,-9223372036854775808),(0,1,100000,100000000); +select c1 into @my_var from int_tb order by c1 limit 1; +select @my_var; + @my_var +--------- + 0 +(1 row) + +CREATE TABLE t001(c1 int, c2 int, c3 int); +insert into t001 values(100,100,100),(100,101,101); +SELECT SUM(c2) as f1, @aa as f2 INTO @aa,@bb FROM t001 GROUP BY c1; +SELECT @aa,@bb; + @aa | @bb +-----+----- + 201 | +(1 row) + +SELECT SUM(c2) as f1, SUM(c1) as f2 INTO @aa,@bb FROM t001 GROUP BY c1; +SELECT @aa,@bb; + @aa | @bb +-----+----- + 201 | 200 +(1 row) + create or replace procedure my_pro() as declare outfile int default 0; @@ -395,6 +420,32 @@ select @num; (1 row) drop trigger tri_delete_after on t1; +drop table if exists trigger_t2; +NOTICE: table "trigger_t2" does not exist, skipping +create table trigger_t2(a int); +create or replace function tri_func3() returns trigger as +$$ +begin + select abs(@num)+1 into @num; + return NEW; +end +$$ LANGUAGE PLPGSQL; +create trigger tri_insert_before before insert on trigger_t2 for each row execute procedure tri_func3(); +select -1 into @num; +select @num; + @num +------ + -1 +(1 row) + +insert into trigger_t2 values(10); +select @num; + @num +------ + 2 +(1 row) + +drop trigger tri_insert_before on trigger_t2; select 10,@v1/2 into @v1,@v2; select @v1,@v2; @v1 | @v2