Skip to content

Commit ac7a5a3

Browse files
committed
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.
1 parent a8ab8d0 commit ac7a5a3

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

src/backend/parser/parse_coerce.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,24 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
7979
int location)
8080
{
8181
Node *result;
82+
Node *origexpr;
8283

8384
if (!can_coerce_type(1, &exprtype, &targettype, ccontext))
8485
return NULL;
8586

87+
/*
88+
* If the input has a CollateExpr at the top, strip it off, perform the
89+
* coercion, and put a new one back on. This is annoying since it
90+
* duplicates logic in coerce_type, but if we don't do this then it's too
91+
* hard to tell whether coerce_type actually changed anything, and we
92+
* *must* know that to avoid possibly calling hide_coercion_node on
93+
* something that wasn't generated by coerce_type. Note that if there are
94+
* multiple stacked CollateExprs, we just discard all but the topmost.
95+
*/
96+
origexpr = expr;
97+
while (expr && IsA(expr, CollateExpr))
98+
expr = (Node *) ((CollateExpr *) expr)->arg;
99+
86100
result = coerce_type(pstate, expr, exprtype,
87101
targettype, targettypmod,
88102
ccontext, cformat, location);
@@ -98,6 +112,18 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
98112
(cformat != COERCE_IMPLICIT_CAST),
99113
(result != expr && !IsA(result, Const)));
100114

115+
if (expr != origexpr)
116+
{
117+
/* Reinstall top CollateExpr */
118+
CollateExpr *coll = (CollateExpr *) origexpr;
119+
CollateExpr *newcoll = makeNode(CollateExpr);
120+
121+
newcoll->arg = (Expr *) result;
122+
newcoll->collOid = coll->collOid;
123+
newcoll->location = coll->location;
124+
result = (Node *) newcoll;
125+
}
126+
101127
return result;
102128
}
103129

@@ -318,7 +344,7 @@ coerce_type(ParseState *pstate, Node *node,
318344
* If we have a COLLATE clause, we have to push the coercion
319345
* underneath the COLLATE. This is really ugly, but there is little
320346
* choice because the above hacks on Consts and Params wouldn't happen
321-
* otherwise.
347+
* otherwise. This kluge has consequences in coerce_to_target_type.
322348
*/
323349
CollateExpr *coll = (CollateExpr *) node;
324350
CollateExpr *newcoll = makeNode(CollateExpr);

src/test/regress/expected/collate.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,9 @@ ALTER TABLE collate_test22 ADD FOREIGN KEY (f2) REFERENCES collate_test20;
574574
RESET enable_seqscan;
575575
RESET enable_hashjoin;
576576
RESET enable_nestloop;
577+
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
578+
CREATE TEMP TABLE vctable (f1 varchar(25));
579+
INSERT INTO vctable VALUES ('foo' COLLATE "C");
577580
--
578581
-- Clean up. Many of these table names will be re-used if the user is
579582
-- trying to run any platform-specific collation tests later, so we

src/test/regress/sql/collate.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ RESET enable_seqscan;
214214
RESET enable_hashjoin;
215215
RESET enable_nestloop;
216216

217+
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
218+
219+
CREATE TEMP TABLE vctable (f1 varchar(25));
220+
INSERT INTO vctable VALUES ('foo' COLLATE "C");
221+
217222
--
218223
-- Clean up. Many of these table names will be re-used if the user is
219224
-- trying to run any platform-specific collation tests later, so we

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy