From f76c79cf69b6a6ae1219b2918679bef12f6f2796 Mon Sep 17 00:00:00 2001 From: chenbd Date: Thu, 25 Jan 2024 19:51:40 +0800 Subject: [PATCH] fix prepare @var b bug --- .../optimizer/commands/prepare.cpp | 57 +++++++++++++++++++ .../optimizer/rewrite/rewriteHandler.cpp | 56 ------------------ src/gausskernel/process/tcop/postgres.cpp | 4 +- src/include/rewrite/rewriteHandler.h | 1 - .../regress/expected/mysql_compatibility.out | 39 +++++++++++++ src/test/regress/sql/mysql_compatibility.sql | 19 +++++++ 6 files changed, 116 insertions(+), 60 deletions(-) diff --git a/src/gausskernel/optimizer/commands/prepare.cpp b/src/gausskernel/optimizer/commands/prepare.cpp index e138c99bf..ac1b2fcea 100755 --- a/src/gausskernel/optimizer/commands/prepare.cpp +++ b/src/gausskernel/optimizer/commands/prepare.cpp @@ -134,6 +134,60 @@ void TryMotJitCodegenQuery(const char* queryString, CachedPlanSource* psrc, Quer } } #endif +/* + * User_defined variables is a string in prepareStmt. + * Get selectStmt/insertStmt/updateStmt/deleteStmt/mergeStmt from user_defined variables by pg_parse_query. + * Then, execute SQL: PREPARE stmt AS selectStmt/insertStmt/updateStmt/deleteStmt/mergeStmt. + */ +static void QueryRewritePrepareStmt(Node* parsetree) +{ + char *sqlstr = NULL; + List* raw_parsetree_list = NIL; + PrepareStmt *stmt = (PrepareStmt *)parsetree; + ParseState* state = make_parsestate(NULL); + UserVar *uservar = (UserVar *)transformExpr(state, (Node *)stmt->query, EXPR_KIND_EXECUTE_PARAMETER); + free_parsestate(state); + Const* value = (Const *)uservar->value; + + if (value->consttype != TEXTOID) { + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), + errmsg("userdefined variable in prepare statement must be text type."))); + } + if (value->constvalue == (Datum)0) { + ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("Query was empty"))); + } + + sqlstr = TextDatumGetCString(value->constvalue); + + raw_parsetree_list = pg_parse_query(sqlstr); + if (raw_parsetree_list == NIL) { + ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("Query was empty"))); + } + + if (raw_parsetree_list->length != 1) { + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), + errmsg("prepare user_defined variable can contain only one SQL statement."))); + } + + switch (nodeTag(linitial(raw_parsetree_list))) { + case T_SelectStmt: + case T_InsertStmt: + case T_UpdateStmt: + case T_DeleteStmt: + case T_MergeStmt: + stmt->query = (Node *)copyObject((Node *)linitial(raw_parsetree_list)); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("the statement in prepare is not supported."))); + break; + } + + return ; +} /* * Implements the 'PREPARE' utility statement. @@ -155,6 +209,9 @@ void PrepareQuery(PrepareStmt* stmt, const char* queryString) ereport(ERROR, (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION), errmsg("invalid statement name: must not be empty"))); + if (IsA(stmt->query, UserVar)) { + QueryRewritePrepareStmt((Node*)stmt); + } /* * Create the CachedPlanSource before we do parse analysis, since it needs * to see the unmodified raw parse tree. diff --git a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp index 41251bd41..0f0301098 100644 --- a/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp +++ b/src/gausskernel/optimizer/rewrite/rewriteHandler.cpp @@ -5146,62 +5146,6 @@ List* QueryRewriteCTAS(Query* parsetree) } } -/* - * User_defined variables is a string in prepareStmt. - * Get selectStmt/insertStmt/updateStmt/deleteStmt/mergeStmt from user_defined variables by pg_parse_query. - * Then, execute SQL: PREPARE stmt AS selectStmt/insertStmt/updateStmt/deleteStmt/mergeStmt. - */ -List* QueryRewritePrepareStmt(Query* parsetree) -{ - char *sqlstr = NULL; - List* raw_parsetree_list = NIL; - List* querytree_list = NULL; - - PrepareStmt *stmt = (PrepareStmt *)parsetree->utilityStmt; - UserVar *uservar = (UserVar *)stmt->query; - Const* value = (Const *)uservar->value; - - if (value->consttype != TEXTOID) { - ereport(ERROR, - (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("userdefined variable in prepare statement must be text type."))); - } - if (value->constvalue == (Datum)0) { - ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("Query was empty"))); - } - - sqlstr = TextDatumGetCString(value->constvalue); - - raw_parsetree_list = pg_parse_query(sqlstr); - if (raw_parsetree_list == NIL) { - ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("Query was empty"))); - } - - if (raw_parsetree_list->length != 1) { - ereport(ERROR, - (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("prepare user_defined variable can contain only one SQL statement."))); - } - - switch (nodeTag(linitial(raw_parsetree_list))) { - case T_SelectStmt: - case T_InsertStmt: - case T_UpdateStmt: - case T_DeleteStmt: - case T_MergeStmt: - stmt->query = (Node *)copyObject((Node *)linitial(raw_parsetree_list)); - break; - default: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("the statement in prepare is not supported."))); - break; - } - - querytree_list = pg_analyze_and_rewrite((Node*)stmt, sqlstr, NULL, 0); - return querytree_list; -} - /* * Get value from a subquery or non-constant expression by constructing SQL. * input: diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index de887cdf5..8986a6493 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -1276,9 +1276,7 @@ static List* pg_rewrite_query(Query* query) } } else if (IsA(query->utilityStmt, PrepareStmt)) { PrepareStmt *stmt = (PrepareStmt *)query->utilityStmt; - if (IsA(stmt->query, UserVar)) { - querytree_list = QueryRewritePrepareStmt(query); - } else if (IsA(stmt->query, Const)) { + if (IsA(stmt->query, Const)) { if (((Const *)stmt->query)->constisnull) { ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("userdefined variable in prepare statement must be text type."))); diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index cc2d136fa..e48e4a4fa 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -33,7 +33,6 @@ extern bool view_has_instead_trigger(Relation view, CmdType event); extern List* QueryRewriteCTAS(Query* parsetree); extern List* QueryRewriteRefresh(Query *parsetree); #endif -extern List* QueryRewritePrepareStmt(Query *parsetree); extern Node* QueryRewriteNonConstant(Node *node); extern List* QueryRewriteSelectIntoVarList(Node *node, int res_len); extern Const* processResToConst(char* value, Oid atttypid, Oid collid); diff --git a/src/test/regress/expected/mysql_compatibility.out b/src/test/regress/expected/mysql_compatibility.out index 503e2c462..6584fc3d4 100644 --- a/src/test/regress/expected/mysql_compatibility.out +++ b/src/test/regress/expected/mysql_compatibility.out @@ -842,6 +842,45 @@ begin perform @plg := @plg + 1 from t_plg; end; $$; +-- bugfix for in plpgsql +prepare stmtabv as select 123; +CREATE OR REPLACE PROCEDURE pppabc (id text) as +begin + set @abcttt = concat('select ' , id ); + DEALLOCATE prepare stmtabv; + prepare stmtabv as @abcttt; +end; +/ +execute stmtabv; + ?column? +---------- + 123 +(1 row) + +call pppabc(12334); + pppabc +-------- + +(1 row) + +execute stmtabv; + ?column? +---------- + 12334 +(1 row) + +call pppabc(123345); + pppabc +-------- + +(1 row) + +execute stmtabv; + ?column? +---------- + 123345 +(1 row) + --test in where CREATE TABLE employee ( id int , diff --git a/src/test/regress/sql/mysql_compatibility.sql b/src/test/regress/sql/mysql_compatibility.sql index 50434d80e..7bccc5e25 100644 --- a/src/test/regress/sql/mysql_compatibility.sql +++ b/src/test/regress/sql/mysql_compatibility.sql @@ -250,6 +250,25 @@ begin perform @plg := @plg + 1 from t_plg; end; $$; +-- bugfix for in plpgsql +prepare stmtabv as select 123; +CREATE OR REPLACE PROCEDURE pppabc (id text) as +begin + set @abcttt = concat('select ' , id ); + DEALLOCATE prepare stmtabv; + prepare stmtabv as @abcttt; +end; +/ + +execute stmtabv; + +call pppabc(12334); + +execute stmtabv; + +call pppabc(123345); + +execute stmtabv; --test in where CREATE TABLE employee (