mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +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)
|
||||
{
|
||||
Node *result;
|
||||
Node *origexpr;
|
||||
|
||||
if (!can_coerce_type(1, &exprtype, &targettype, ccontext))
|
||||
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,
|
||||
targettype, targettypmod,
|
||||
ccontext, cformat, location);
|
||||
@ -98,6 +112,18 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
|
||||
(cformat != COERCE_IMPLICIT_CAST),
|
||||
(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;
|
||||
}
|
||||
|
||||
@ -318,7 +344,7 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
* If we have a COLLATE clause, we have to push the coercion
|
||||
* underneath the COLLATE. This is really ugly, but there is little
|
||||
* 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 *newcoll = makeNode(CollateExpr);
|
||||
|
@ -574,6 +574,9 @@ ALTER TABLE collate_test22 ADD FOREIGN KEY (f2) REFERENCES collate_test20;
|
||||
RESET enable_seqscan;
|
||||
RESET enable_hashjoin;
|
||||
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
|
||||
-- trying to run any platform-specific collation tests later, so we
|
||||
|
@ -214,6 +214,11 @@ RESET enable_seqscan;
|
||||
RESET enable_hashjoin;
|
||||
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
|
||||
-- trying to run any platform-specific collation tests later, so we
|
||||
|
Loading…
Reference in New Issue
Block a user