mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Fix coerce_to_target_type for coerce_type's klugy handling of COLLATE.
Because coerce_type recurses into the argument of a CollateExpr, coerce_to_target_type's longstanding code for detecting whether coerce_type had actually done anything (to wit, returned a different node than it passed in) was broken in 9.1. This resulted in unexpected failures in hide_coercion_node; which was not the latter's fault, since it's critical that we never call it on anything that wasn't inserted by coerce_type. (Else we might decide to "hide" a user-written function call.) Fix by removing and replacing the CollateExpr in coerce_to_target_type itself. This is all pretty ugly but I don't immediately see a way to make it nicer. Per report from Jean-Yves F. Barbier.
This commit is contained in:
parent
a8ab8d0eaa
commit
ac7a5a3f25
@ -79,10 +79,24 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
|
|||||||
int location)
|
int location)
|
||||||
{
|
{
|
||||||
Node *result;
|
Node *result;
|
||||||
|
Node *origexpr;
|
||||||
|
|
||||||
if (!can_coerce_type(1, &exprtype, &targettype, ccontext))
|
if (!can_coerce_type(1, &exprtype, &targettype, ccontext))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the input has a CollateExpr at the top, strip it off, perform the
|
||||||
|
* coercion, and put a new one back on. This is annoying since it
|
||||||
|
* duplicates logic in coerce_type, but if we don't do this then it's too
|
||||||
|
* hard to tell whether coerce_type actually changed anything, and we
|
||||||
|
* *must* know that to avoid possibly calling hide_coercion_node on
|
||||||
|
* something that wasn't generated by coerce_type. Note that if there are
|
||||||
|
* multiple stacked CollateExprs, we just discard all but the topmost.
|
||||||
|
*/
|
||||||
|
origexpr = expr;
|
||||||
|
while (expr && IsA(expr, CollateExpr))
|
||||||
|
expr = (Node *) ((CollateExpr *) expr)->arg;
|
||||||
|
|
||||||
result = coerce_type(pstate, expr, exprtype,
|
result = coerce_type(pstate, expr, exprtype,
|
||||||
targettype, targettypmod,
|
targettype, targettypmod,
|
||||||
ccontext, cformat, location);
|
ccontext, cformat, location);
|
||||||
@ -98,6 +112,18 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
|
|||||||
(cformat != COERCE_IMPLICIT_CAST),
|
(cformat != COERCE_IMPLICIT_CAST),
|
||||||
(result != expr && !IsA(result, Const)));
|
(result != expr && !IsA(result, Const)));
|
||||||
|
|
||||||
|
if (expr != origexpr)
|
||||||
|
{
|
||||||
|
/* Reinstall top CollateExpr */
|
||||||
|
CollateExpr *coll = (CollateExpr *) origexpr;
|
||||||
|
CollateExpr *newcoll = makeNode(CollateExpr);
|
||||||
|
|
||||||
|
newcoll->arg = (Expr *) result;
|
||||||
|
newcoll->collOid = coll->collOid;
|
||||||
|
newcoll->location = coll->location;
|
||||||
|
result = (Node *) newcoll;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +344,7 @@ coerce_type(ParseState *pstate, Node *node,
|
|||||||
* If we have a COLLATE clause, we have to push the coercion
|
* If we have a COLLATE clause, we have to push the coercion
|
||||||
* underneath the COLLATE. This is really ugly, but there is little
|
* underneath the COLLATE. This is really ugly, but there is little
|
||||||
* choice because the above hacks on Consts and Params wouldn't happen
|
* choice because the above hacks on Consts and Params wouldn't happen
|
||||||
* otherwise.
|
* otherwise. This kluge has consequences in coerce_to_target_type.
|
||||||
*/
|
*/
|
||||||
CollateExpr *coll = (CollateExpr *) node;
|
CollateExpr *coll = (CollateExpr *) node;
|
||||||
CollateExpr *newcoll = makeNode(CollateExpr);
|
CollateExpr *newcoll = makeNode(CollateExpr);
|
||||||
|
@ -574,6 +574,9 @@ ALTER TABLE collate_test22 ADD FOREIGN KEY (f2) REFERENCES collate_test20;
|
|||||||
RESET enable_seqscan;
|
RESET enable_seqscan;
|
||||||
RESET enable_hashjoin;
|
RESET enable_hashjoin;
|
||||||
RESET enable_nestloop;
|
RESET enable_nestloop;
|
||||||
|
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
|
||||||
|
CREATE TEMP TABLE vctable (f1 varchar(25));
|
||||||
|
INSERT INTO vctable VALUES ('foo' COLLATE "C");
|
||||||
--
|
--
|
||||||
-- Clean up. Many of these table names will be re-used if the user is
|
-- Clean up. Many of these table names will be re-used if the user is
|
||||||
-- trying to run any platform-specific collation tests later, so we
|
-- trying to run any platform-specific collation tests later, so we
|
||||||
|
@ -214,6 +214,11 @@ RESET enable_seqscan;
|
|||||||
RESET enable_hashjoin;
|
RESET enable_hashjoin;
|
||||||
RESET enable_nestloop;
|
RESET enable_nestloop;
|
||||||
|
|
||||||
|
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
|
||||||
|
|
||||||
|
CREATE TEMP TABLE vctable (f1 varchar(25));
|
||||||
|
INSERT INTO vctable VALUES ('foo' COLLATE "C");
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Clean up. Many of these table names will be re-used if the user is
|
-- Clean up. Many of these table names will be re-used if the user is
|
||||||
-- trying to run any platform-specific collation tests later, so we
|
-- trying to run any platform-specific collation tests later, so we
|
||||||
|
Loading…
Reference in New Issue
Block a user