aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-01-02 14:43:45 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2012-01-02 14:43:45 -0500
commitac7a5a3f25708c03242edc301ad008236fc36c7e (patch)
tree79c6cac10152d29a11cdf532fc7fc49660876e91 /src
parenta8ab8d0eaa96dbaebb646971f8988a3edc28e52c (diff)
downloadpostgresql-ac7a5a3f25708c03242edc301ad008236fc36c7e.tar.gz
postgresql-ac7a5a3f25708c03242edc301ad008236fc36c7e.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_coerce.c28
-rw-r--r--src/test/regress/expected/collate.out3
-rw-r--r--src/test/regress/sql/collate.sql5
3 files changed, 35 insertions, 1 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index e7278374544..6661a3d8a1d 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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);
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index dc17feaefe4..a15e6911b0a 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -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
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index 52d830d58a9..f72f3edb9d2 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -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