!4654 @var在while语句中调用无限循环缺陷

Merge pull request !4654 from 暖阳/varbug2
This commit is contained in:
opengauss_bot
2024-03-18 06:02:40 +00:00
committed by Gitee
4 changed files with 190 additions and 16 deletions

View File

@ -573,6 +573,151 @@ Node* coerce_type(ParseState* pstate, Node* node, Oid inputTypeId, Oid targetTyp
return result;
}
if (inputTypeId == UNKNOWNOID && IsA(node, UserVar) && IsA(((UserVar*)node)->value, Const)) {
/*
* Input is a string constant with previously undetermined type. Apply
* the target type's typinput function to it to produce a constant of
* the target type.
*
* NOTE: this case cannot be folded together with the other
* constant-input case, since the typinput function does not
* necessarily behave the same as a type conversion function. For
* example, int4's typinput function will reject "1.2", whereas
* float-to-int type conversion will round to integer.
*
* XXX if the typinput function is not immutable, we really ought to
* postpone evaluation of the function call until runtime. But there
* is no way to represent a typinput function call as an expression
* tree, because C-string values are not Datums. (XXX This *is*
* possible as of 7.3, do we want to do it?)
*/
Const* con = (Const*)((UserVar*)node)->value;
Const* newcon = makeNode(Const);
Oid baseTypeId;
int32 baseTypeMod;
int32 inputTypeMod;
Type targetType;
ParseCallbackState pcbstate;
/*
* If the target type is a domain, we want to call its base type's
* input routine, not domain_in(). This is to avoid premature failure
* when the domain applies a typmod: existing input routines follow
* implicit-coercion semantics for length checks, which is not always
* what we want here. The needed check will be applied properly
* inside coerce_to_domain().
*/
baseTypeMod = targetTypeMod;
baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
/*
* For most types we pass typmod -1 to the input routine, because
* existing input routines follow implicit-coercion semantics for
* length checks, which is not always what we want here. Any length
* constraint will be applied later by our caller. An exception
* however is the INTERVAL type, for which we *must* pass the typmod
* or it won't be able to obey the bizarre SQL-spec input rules. (Ugly
* as sin, but so is this part of the spec...)
*/
if (baseTypeId == INTERVALOID) {
inputTypeMod = baseTypeMod;
} else {
inputTypeMod = -1;
}
targetType = typeidType(baseTypeId);
newcon->consttype = baseTypeId;
newcon->consttypmod = inputTypeMod;
if (OidIsValid(GetCollationConnection()) &&
IsSupportCharsetType(baseTypeId)) {
newcon->constcollid = GetCollationConnection();
} else {
newcon->constcollid = typeTypeCollation(targetType);
}
newcon->constlen = typeLen(targetType);
newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull;
newcon->cursor_data.cur_dno = -1;
/*
* We use the original literal's location regardless of the position
* of the coercion. This is a change from pre-9.2 behavior, meant to
* simplify life for pg_stat_statements.
*/
newcon->location = con->location;
/*
* Set up to point at the constant's text if the input routine throws
* an error.
*/
setup_parser_errposition_callback(&pcbstate, pstate, con->location);
/*
* We assume here that UNKNOWN's internal representation is the same
* as CSTRING.
*/
if (!con->constisnull) {
newcon->constvalue = stringTypeDatum_with_collation(targetType, DatumGetCString(con->constvalue),
inputTypeMod, pstate != NULL && pstate->p_has_ignore, con->constcollid);
} else {
newcon->constvalue =
stringTypeDatum(targetType, NULL, inputTypeMod, pstate != NULL && pstate->p_has_ignore);
}
cancel_parser_errposition_callback(&pcbstate);
result = (Node*)newcon;
/* If target is a domain, apply constraints. */
if (baseTypeId != targetTypeId) {
result = coerce_to_domain(result, baseTypeId, baseTypeMod, targetTypeId, cformat, location, false, false);
}
ReleaseSysCache(targetType);
UserVar *newus = makeNode(UserVar);
newus->name = ((UserVar*)node)->name;
newus->value = (Expr*)result;
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, &funcId);
switch (pathtype) {
case COERCION_PATH_NONE:
return (Node *)newus;
break;
case COERCION_PATH_RELABELTYPE: {
result = coerce_to_domain((Node *)newus, InvalidOid, -1, targetTypeId, cformat, location, false, false);
if (result == (Node *)newus) {
RelabelType* r = makeRelabelType((Expr*)result, targetTypeId, -1, InvalidOid, cformat);
r->location = location;
result = (Node*)r;
}
return result;
} break;
default: {
Oid baseTypeId;
int32 baseTypeMod;
baseTypeMod = targetTypeMod;
baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
result = build_coercion_expression((Node *)newus, pathtype, funcId, baseTypeId,
baseTypeMod, cformat, location, (cformat != COERCE_IMPLICIT_CAST));
if (targetTypeId != baseTypeId) {
result = coerce_to_domain(result,
baseTypeId,
baseTypeMod,
targetTypeId,
cformat,
location,
true,
exprIsLengthCoercion(result, NULL));
}
} break;
}
}
if (IsA(node, Param) && pstate != NULL && pstate->p_coerce_param_hook != NULL) {
/*
* Allow the CoerceParamHook to decide what happens. It can return a

View File

@ -1095,9 +1095,14 @@ static Datum ExecEvalConst(ExprState* exprstate, ExprContext* econtext, bool* is
/* if not found, return a null const */
if (found) {
if (entry->isParse) {
con = (Const *)uservar->value;
entry->isParse = false;
Oid target_type = InvalidOid;
if (IsA(uservar->value, CoerceViaIO)) {
target_type = ((CoerceViaIO *)uservar->value)->resulttype;
} else {
target_type = ((Const *)uservar->value)->consttype;
}
if (target_type == UNKNOWNOID && ((Const *)uservar->value)->constisnull) {
con = entry->value;
} else {
Node *node = coerce_type(NULL, (Node *)entry->value, entry->value->consttype, ((Const *)uservar->value)->consttype,
-1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
@ -1316,21 +1321,14 @@ static Datum ExecEvalUserSetElm(ExprState* exprstate, ExprContext* econtext, boo
UserVar *uservar = (UserVar*)linitial(elem->name);
entry = (GucUserParamsEntry*)hash_search(u_sess->utils_cxt.set_user_params_htab,
uservar->name, HASH_FIND, &found);
if (found) {
Const* expr = entry->value;
bool if_use = false;
if (expr->consttype != (usestate->xprstate).resultType && is_in_table) {
find_uservar_in_expr(usestate->instate, uservar->name, &if_use);
if (if_use) {
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("Can not change type of user defined variable when use relations.")));
}
}
}
}
Oid atttypid = exprType((Node*)elem->val);
Oid atttypid = InvalidOid;
if (!found) {
atttypid = exprType((Node *)usestate->instate->expr);
} else {
atttypid = exprType((Node *)elem->val);
}
value = CStringFromDatum(atttypid, result);
con = processResToConst(value, atttypid, collid);

View File

@ -728,6 +728,7 @@ SELECT @r, (SELECT @r:= parent_id FROM my_table WHERE id = @r) AS parent_id2,
@l:= @l+ 1 AS lvl FROM
(SELECT @r:= 5, @l:= 0) vars,
my_table h WHERE @r <>0;
-- error, dolphin cast bigint to integer Implicit
SELECT @r, (SELECT @r:= parent_id FROM my_table WHERE id = @r) AS parent_id2 FROM
(SELECT @r:= 5) vars,
my_table h WHERE @r<> 0;
@ -761,6 +762,18 @@ INNER JOIN recursive_query r ON e.col_2 = (r.col_2 + INTERVAL '1year')
SELECT col_1, col_2, col_3
FROM recursive_query
ORDER BY col_2 ASC;
-- 自增-CONCAT-报错
SET @counter := 0;
SET @sequence := '';
begin
label_1:
WHILE @counter < 10 DO
SET @counter := @counter + 1;
SET @sequence := CONCAT(@sequence, @counter, ', ');
END WHILE label_1;
end;
/
SELECT TRIM(TRAILING ', ' FROM @sequence);
\c regression
drop database if exists test_set;

View File

@ -1450,6 +1450,7 @@ my_table h WHERE @r <>0;
1 | | 4
(4 rows)
-- error, dolphin cast bigint to integer Implicit
SELECT @r, (SELECT @r:= parent_id FROM my_table WHERE id = @r) AS parent_id2 FROM
(SELECT @r:= 5) vars,
my_table h WHERE @r<> 0;
@ -1502,6 +1503,23 @@ ORDER BY col_2 ASC;
dddd | 03-23-2023 | default col_3
(2 rows)
-- 自增-CONCAT-报错
SET @counter := 0;
SET @sequence := '';
begin
label_1:
WHILE @counter < 10 DO
SET @counter := @counter + 1;
SET @sequence := CONCAT(@sequence, @counter, ', ');
END WHILE label_1;
end;
/
SELECT TRIM(TRAILING ', ' FROM @sequence);
rtrim
-------------------------------
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1 row)
\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