diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 17d24e400f87b78c8a4a8808b6a4c5cd2228b781..ff3af5ee102460d2cf2dad03487f5042bbdb3028 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.20 2009/09/12 00:04:58 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 2693cc154d534a20091b3da98c68c6e7eac9738d..aae3fc950457fe5410cbfbe913fcef5b2793aae2 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.98 2009/07/17 23:19:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.99 2009/09/12 00:04:59 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 fc6dda7477f4c68c6b175acea9a19233f97ae564..b787b307f6950204036482f2d9566ff71a5666f9 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 54d98ca6979baf89afef1c132d425b5499c597b7..d18733d274c3b783bec57e25442b6d642551a0bc 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;