aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-09-12 00:05:07 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-09-12 00:05:07 +0000
commit3a3c2cd59cabb42d07200e3210a772552a9dc856 (patch)
treeca208b0a755749a02bdb642a35dabfa8804a413f /src
parent96ca52dbe80a90d191eafbc656f03a33e85107a8 (diff)
downloadpostgresql-3a3c2cd59cabb42d07200e3210a772552a9dc856.tar.gz
postgresql-3a3c2cd59cabb42d07200e3210a772552a9dc856.zip
Fix assertion failure when a SELECT DISTINCT ON expression is volatile.
In this case we generate two PathKey references to the expression (one for DISTINCT and one for ORDER BY) and they really need to refer to the same EquivalenceClass. However get_eclass_for_sort_expr was being overly paranoid and creating two different EC's. Correct behavior is to use the SortGroupRef index to decide whether two references to volatile expressions that are equal() (ie textually equivalent) should be considered the same. Backpatch to 8.4. Possibly this should be changed in 8.3 as well, but I'll refrain in the absence of evidence of a visible failure in that branch. Per bug #5049.
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/equivclass.c16
-rw-r--r--src/backend/optimizer/path/pathkeys.c11
-rw-r--r--src/test/regress/expected/select_distinct_on.out7
-rw-r--r--src/test/regress/sql/select_distinct_on.sql3
4 files changed, 32 insertions, 5 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 17d24e400f8..5c07a103ad9 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.19 2009/06/11 14:48:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.19.2.1 2009/09/12 00:05:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -357,7 +357,7 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
* EquivalenceClass for it.
*
* sortref is the SortGroupRef of the originating SortGroupClause, if any,
- * or zero if not.
+ * or zero if not. (It should never be zero if the expression is volatile!)
*
* This can be used safely both before and after EquivalenceClass merging;
* since it never causes merging it does not invalidate any existing ECs
@@ -388,8 +388,12 @@ get_eclass_for_sort_expr(PlannerInfo *root,
EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1);
ListCell *lc2;
- /* Never match to a volatile EC */
- if (cur_ec->ec_has_volatile)
+ /*
+ * Never match to a volatile EC, except when we are looking at another
+ * reference to the same volatile SortGroupClause.
+ */
+ if (cur_ec->ec_has_volatile &&
+ (sortref == 0 || sortref != cur_ec->ec_sortref))
continue;
if (!equal(opfamilies, cur_ec->ec_opfamilies))
@@ -433,6 +437,10 @@ get_eclass_for_sort_expr(PlannerInfo *root,
newec->ec_broken = false;
newec->ec_sortref = sortref;
newec->ec_merged = NULL;
+
+ if (newec->ec_has_volatile && sortref == 0) /* should not happen */
+ elog(ERROR, "volatile EquivalenceClass has no sortref");
+
newem = add_eq_member(newec, expr, pull_varnos((Node *) expr),
false, expr_datatype);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 8f7e02c3b2e..215cb7c9240 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.97.2.1 2009/07/17 23:19:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.97.2.2 2009/09/12 00:05:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -635,6 +635,15 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
+
+ /*
+ * Note: it might look funny to be setting sortref = 0 for
+ * a reference to a volatile sub_eclass. However, the
+ * expression is *not* volatile in the outer query: it's
+ * just a Var referencing whatever the subquery emitted.
+ * (IOW, the outer query isn't going to re-execute the
+ * volatile expression itself.) So this is okay.
+ */
outer_ec =
get_eclass_for_sort_expr(root,
outer_expr,
diff --git a/src/test/regress/expected/select_distinct_on.out b/src/test/regress/expected/select_distinct_on.out
index fc6dda7477f..b787b307f69 100644
--- a/src/test/regress/expected/select_distinct_on.out
+++ b/src/test/regress/expected/select_distinct_on.out
@@ -66,3 +66,10 @@ SELECT DISTINCT ON (string4, ten) string4, ten, two
VVVVxx | 0 | 0
(40 rows)
+-- bug #5049: early 8.4.x chokes on volatile DISTINCT ON clauses
+select distinct on (1) floor(random()) as r, f1 from int4_tbl order by 1,2;
+ r | f1
+---+-------------
+ 0 | -2147483647
+(1 row)
+
diff --git a/src/test/regress/sql/select_distinct_on.sql b/src/test/regress/sql/select_distinct_on.sql
index 54d98ca6979..d18733d274c 100644
--- a/src/test/regress/sql/select_distinct_on.sql
+++ b/src/test/regress/sql/select_distinct_on.sql
@@ -14,3 +14,6 @@ SELECT DISTINCT ON (string4, ten) string4, two, ten
SELECT DISTINCT ON (string4, ten) string4, ten, two
FROM tmp
ORDER BY string4 using <, ten using >, two using <;
+
+-- bug #5049: early 8.4.x chokes on volatile DISTINCT ON clauses
+select distinct on (1) floor(random()) as r, f1 from int4_tbl order by 1,2;