diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp index a05b870e5..82bc63ef0 100644 --- a/src/common/backend/parser/parse_expr.cpp +++ b/src/common/backend/parser/parse_expr.cpp @@ -1567,16 +1567,27 @@ static Node* transformUserVar(UserVar *uservar) GucUserParamsEntry *entry = (GucUserParamsEntry *)hash_search(u_sess->utils_cxt.set_user_params_htab, uservar->name, HASH_FIND, &found); - if (!found) { /* return a null const */ Const *nullValue = makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum)0, true, false); return (Node *)nullValue; } + entry = (GucUserParamsEntry *)hash_search(u_sess->utils_cxt.set_user_params_htab, uservar->name, HASH_ENTER, &found); + if (entry == NULL) { + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("Failed to create user_defined entry due to out of memory"))); + } + UserVar *result = makeNode(UserVar); + Const *con = (Const *)copyObject(entry->value); result->name = uservar->name; - result->value = (Expr *)copyObject(entry->value); + result->value = (Expr *)con; + + USE_MEMORY_CONTEXT(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB)); + /* if uservar is parsed, set to true */ + entry->value = (Const *)copyObject(con); + entry->isParse = true; return (Node *)result; } diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 09edd6757..819ab5dde 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -12975,11 +12975,13 @@ void check_variable_value_info(const char* var_name, const Expr* var_expr) if (found) { entry->value = (Const *)copyObject((Const *)(var_expr)); + entry->isParse = false; } else { errno_t errval = strncpy_s(entry->name, sizeof(entry->name), var_name, sizeof(entry->name) - 1); securec_check_errval(errval, , LOG); entry->value = (Const *)copyObject((Const *)(var_expr)); + entry->isParse = false; } } diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp index c50cebada..2b5429406 100644 --- a/src/gausskernel/runtime/executor/execQual.cpp +++ b/src/gausskernel/runtime/executor/execQual.cpp @@ -1083,7 +1083,22 @@ static Datum ExecEvalConst(ExprState* exprstate, ExprContext* econtext, bool* is GucUserParamsEntry *entry = (GucUserParamsEntry *)hash_search(u_sess->utils_cxt.set_user_params_htab, uservar->name, HASH_FIND, &found); /* if not found, return a null const */ - con = found ? entry->value : makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum)0, true, false); + if (found) { + if (entry->isParse) { + con = (Const *)uservar->value; + } else { + Node *node = coerce_type(NULL, (Node *)entry->value, entry->value->consttype, ((Const *)uservar->value)->consttype, + -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + node = eval_const_expression_value(NULL, node, NULL); + if (nodeTag(node) != T_Const) { + ereport(ERROR, (errcode(ERRCODE_INVALID_OPERATION), + errmsg("The value of a user_defined variable must be convertible to a constant."))); + } + con = (Const *)node; + } + } else { + con = 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; diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 6c8f885af..3fde019bc 100755 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -191,6 +191,7 @@ typedef struct { typedef struct { char name[NAMEDATALEN]; /* user-defined name */ Const *value; + bool isParse; } GucUserParamsEntry; #define GUC_QUALIFIER_SEPARATOR '.' diff --git a/src/test/regress/input/set_user_defined_variables_test.source b/src/test/regress/input/set_user_defined_variables_test.source index 06b051e56..94bca34e1 100644 --- a/src/test/regress/input/set_user_defined_variables_test.source +++ b/src/test/regress/input/set_user_defined_variables_test.source @@ -532,6 +532,28 @@ select @v1; set @ v1:=10; select @v1:=10; +--DTS +\c test_set +set @v := 10; +select @v + 666::numeric(10, 2), @v + 20::float; +set @v = @v + 666::numeric(10, 2); +select @v; + +set @v1 := 10, @v2 := 13.3; +drop table if exists test_pro; +create table test_pro(f1 int, f2 float); +create or replace procedure pro_insert() +as +begin + insert into test_pro values(@v1 + 666::numeric(10, 2), @v2 + 20::float); +end; +/ +call pro_insert(); +select * from test_pro; +set @v1 := 11, @v2 := 14.3; +call pro_insert(); +select * from test_pro; + \c test_set show enable_set_variable_b_format; set enable_set_variable_b_format = off; diff --git a/src/test/regress/output/set_user_defined_variables_test.source b/src/test/regress/output/set_user_defined_variables_test.source index 79af682f4..d2813f668 100644 --- a/src/test/regress/output/set_user_defined_variables_test.source +++ b/src/test/regress/output/set_user_defined_variables_test.source @@ -1125,6 +1125,57 @@ LINE 1: set @ v1:=10; ^ select @v1:=10; ERROR: user_defined variables cannot be set, such as @var_name := expr is not supported. +--DTS +\c test_set +set @v := 10; +select @v + 666::numeric(10, 2), @v + 20::float; + ?column? | ?column? +----------+---------- + 676.00 | 30 +(1 row) + +set @v = @v + 666::numeric(10, 2); +select @v; + @v +----- + 676 +(1 row) + +set @v1 := 10, @v2 := 13.3; +drop table if exists test_pro; +create table test_pro(f1 int, f2 float); +create or replace procedure pro_insert() +as +begin + insert into test_pro values(@v1 + 666::numeric(10, 2), @v2 + 20::float); +end; +/ +call pro_insert(); + pro_insert +------------ + +(1 row) + +select * from test_pro; + f1 | f2 +-----+------ + 676 | 33.3 +(1 row) + +set @v1 := 11, @v2 := 14.3; +call pro_insert(); + pro_insert +------------ + +(1 row) + +select * from test_pro; + f1 | f2 +-----+------ + 676 | 33.3 + 677 | 34.3 +(2 rows) + \c test_set show enable_set_variable_b_format; enable_set_variable_b_format