88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.87 2001/07/3117:56:31 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.88 2001/07/3120:16:33 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
@@ -736,9 +736,31 @@ pull_constant_clauses(List *quals, List **constantQual)
736736 * think of a better place for it...
737737 *****************************************************************************/
738738
739+ /*
740+ * Test whether a sort/group reference value appears in the given list of
741+ * SortClause (or GroupClause) nodes.
742+ *
743+ * Because GroupClause is typedef'd as SortClause, either kind of
744+ * node list can be passed without casting.
745+ */
746+ static bool
747+ sortgroupref_is_present (Index sortgroupref ,List * clauselist )
748+ {
749+ List * clause ;
750+
751+ foreach (clause ,clauselist )
752+ {
753+ SortClause * scl = (SortClause * )lfirst (clause );
754+
755+ if (scl -> tleSortGroupRef == sortgroupref )
756+ return true;
757+ }
758+ return false;
759+ }
760+
739761/*
740762 * Test whether a query uses DISTINCT ON, ie, has a distinct-list that is
741- *just a subset of the output columns.
763+ *not the same as the set of output columns.
742764 */
743765bool
744766has_distinct_on_clause (Query * query )
@@ -750,30 +772,43 @@ has_distinct_on_clause(Query *query)
750772return false;
751773/*
752774 * If the DISTINCT list contains all the nonjunk targetlist items,
753- * then it's a simple DISTINCT, else it's DISTINCT ON. We do not
754- * require the lists to be in the same order (since the parser may
755- * have adjusted the DISTINCT clause ordering to agree with ORDER BY).
775+ * and nothing else (ie, no junk tlist items), then it's a simple
776+ * DISTINCT, else it's DISTINCT ON. We do not require the lists to be
777+ * in the same order (since the parser may have adjusted the DISTINCT
778+ * clause ordering to agree with ORDER BY). Furthermore, a non-DISTINCT
779+ * junk tlist item that is in the sortClause is also evidence of
780+ * DISTINCT ON, since we don't allow ORDER BY on junk tlist items when
781+ * plain DISTINCT is used.
782+ *
783+ * This code assumes that the DISTINCT list is valid, ie, all its entries
784+ * match some entry of the tlist.
756785 */
757786foreach (targetList ,query -> targetList )
758787{
759788TargetEntry * tle = (TargetEntry * )lfirst (targetList );
760- Index ressortgroupref ;
761- List * distinctClause ;
789+ Index ressortgroupref = tle -> resdom -> ressortgroupref ;
762790
763- if (tle -> resdom -> resjunk )
764- continue ;
765- ressortgroupref = tle -> resdom -> ressortgroupref ;
766791if (ressortgroupref == 0 )
792+ {
793+ if (tle -> resdom -> resjunk )
794+ continue ;/* we can ignore unsorted junk cols */
767795return true;/* definitely not in DISTINCT list */
768- foreach (distinctClause ,query -> distinctClause )
796+ }
797+ if (sortgroupref_is_present (ressortgroupref ,query -> distinctClause ))
769798{
770- SortClause * scl = (SortClause * )lfirst (distinctClause );
771-
772- if (scl -> tleSortGroupRef == ressortgroupref )
773- break ;/* found TLE in DISTINCT */
799+ if (tle -> resdom -> resjunk )
800+ return true;/* junk TLE in DISTINCT means DISTINCT ON */
801+ /* else this TLE is okay, keep looking */
802+ }
803+ else
804+ {
805+ /* This TLE is not in DISTINCT list */
806+ if (!tle -> resdom -> resjunk )
807+ return true;/* non-junk, non-DISTINCT, so DISTINCT ON */
808+ if (sortgroupref_is_present (ressortgroupref ,query -> sortClause ))
809+ return true;/* sorted, non-distinct junk */
810+ /* unsorted junk is okay, keep looking */
774811}
775- if (distinctClause == NIL )
776- return true;/* this TLE is not in DISTINCT list */
777812}
778813/* It's a simple DISTINCT */
779814return false;