!4793 修复: prepare 结合@变量 导致的计划缓存问题

Merge pull request !4793 from chenbd/fix_mas_prepare
This commit is contained in:
opengauss_bot
2024-03-12 12:45:16 +00:00
committed by Gitee
6 changed files with 116 additions and 60 deletions

View File

@ -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.

View File

@ -5156,62 +5156,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:

View File

@ -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.")));

View File

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

View File

@ -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 ,

View File

@ -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 (