@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user