1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Redesign DISTINCT ON as discussed in pgsql-sql 1/25/00: syntax is now

SELECT DISTINCT ON (expr [, expr ...]) targetlist ...
and there is a check to make sure that the user didn't specify an ORDER BY
that's incompatible with the DISTINCT operation.
Reimplement nodeUnique and nodeGroup to use the proper datatype-specific
equality function for each column being compared --- they used to do
bitwise comparisons or convert the data to text strings and strcmp().
(To add insult to injury, they'd look up the conversion functions once
for each tuple...)  Parse/plan representation of DISTINCT is now a list
of SortClause nodes.
initdb forced by querytree change...
This commit is contained in:
Tom Lane
2000-01-27 18:11:50 +00:00
parent 3f0074e403
commit dd979f66be
32 changed files with 638 additions and 576 deletions

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.81 2000/01/26 05:56:37 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.82 2000/01/27 18:11:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1342,16 +1342,19 @@ make_group(List *tlist,
}
/*
* The uniqueAttr argument must be a null-terminated string,
* either the name of the attribute to select unique on
* or "*"
* distinctList is a list of SortClauses, identifying the targetlist items
* that should be considered by the Unique filter.
*/
Unique *
make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
make_unique(List *tlist, Plan *lefttree, List *distinctList)
{
Unique *node = makeNode(Unique);
Plan *plan = &node->plan;
int numCols = length(distinctList);
int keyno = 0;
AttrNumber *uniqColIdx;
List *slitem;
copy_plan_costsize(plan, lefttree);
plan->state = (EState *) NULL;
@@ -1361,10 +1364,22 @@ make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
plan->righttree = NULL;
node->nonameid = _NONAME_RELATION_ID_;
node->keycount = 0;
if (strcmp(uniqueAttr, "*") == 0)
node->uniqueAttr = NULL;
else
node->uniqueAttr = pstrdup(uniqueAttr);
/* convert SortClause list into array of attr indexes, as wanted by exec */
Assert(numCols > 0);
uniqColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
foreach(slitem, distinctList)
{
SortClause *sortcl = (SortClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
uniqColIdx[keyno++] = tle->resdom->resno;
}
node->numCols = numCols;
node->uniqColIdx = uniqColIdx;
return node;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.73 2000/01/26 05:56:37 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.74 2000/01/27 18:11:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -381,12 +381,12 @@ union_planner(Query *parse)
}
/*
* Finally, if there is a UNIQUE clause, add the UNIQUE node.
* Finally, if there is a DISTINCT clause, add the UNIQUE node.
*/
if (parse->uniqueFlag)
if (parse->distinctClause)
{
result_plan = (Plan *) make_unique(tlist, result_plan,
parse->uniqueFlag);
parse->distinctClause);
}
return result_plan;
@@ -583,20 +583,8 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode)
foreach(i, sortcls)
{
SortClause *sortcl = (SortClause *) lfirst(i);
Index refnumber = sortcl->tleSortGroupRef;
TargetEntry *tle = NULL;
Resdom *resdom;
List *l;
foreach(l, temp_tlist)
{
tle = (TargetEntry *) lfirst(l);
if (tle->resdom->ressortgroupref == refnumber)
break;
}
if (l == NIL)
elog(ERROR, "make_sortplan: ORDER BY expression not found in targetlist");
resdom = tle->resdom;
TargetEntry *tle = get_sortgroupclause_tle(sortcl, temp_tlist);
Resdom *resdom = tle->resdom;
/*
* Check for the possibility of duplicate order-by clauses --- the

View File

@@ -104,9 +104,7 @@ transformKeySetQuery(Query *origNode)
unionNode->isPortal = origNode->isPortal;
unionNode->isBinary = origNode->isBinary;
if (origNode->uniqueFlag)
unionNode->uniqueFlag = pstrdup(origNode->uniqueFlag);
Node_Copy(origNode, unionNode, distinctClause);
Node_Copy(origNode, unionNode, sortClause);
Node_Copy(origNode, unionNode, rtable);
Node_Copy(origNode, unionNode, targetList);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.41 2000/01/26 05:56:39 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.42 2000/01/27 18:11:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "parser/parse_clause.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
@@ -131,7 +132,7 @@ plan_union_queries(Query *parse)
!last_union_all_flag)
{
parse->sortClause = NIL;
parse->uniqueFlag = NULL;
parse->distinctClause = NIL;
}
parse->unionClause = NIL; /* prevent recursion */
@@ -183,17 +184,28 @@ plan_union_queries(Query *parse)
if (!last_union_all_flag)
{
/* Need SELECT DISTINCT behavior to implement UNION.
* Set uniqueFlag properly, put back the held sortClause,
* and add any missing columns to the sort clause.
* Put back the held sortClause, add any missing columns to the
* sort clause, and set distinctClause properly.
*/
parse->uniqueFlag = "*";
List *slitem;
parse->sortClause = addAllTargetsToSortList(hold_sortClause,
parse->targetList);
parse->distinctClause = NIL;
foreach(slitem, parse->sortClause)
{
SortClause *scl = (SortClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(scl, parse->targetList);
if (! tle->resdom->resjunk)
parse->distinctClause = lappend(parse->distinctClause,
copyObject(scl));
}
}
else
{
/* needed so we don't take the flag from the first query */
parse->uniqueFlag = NULL;
/* needed so we don't take SELECT DISTINCT from the first query */
parse->distinctClause = NIL;
}
/* Make sure we don't try to apply the first query's grouping stuff
@@ -314,9 +326,9 @@ plan_inherit_query(Relids relids,
* Clear the sorting and grouping qualifications in the subquery,
* so that sorting will only be done once after append
*/
new_root->uniqueFlag = NULL;
new_root->sortClause = NULL;
new_root->groupClause = NULL;
new_root->distinctClause = NIL;
new_root->sortClause = NIL;
new_root->groupClause = NIL;
new_root->havingQual = NULL;
new_root->hasAggs = false; /* shouldn't be any left ... */

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.42 2000/01/26 05:56:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.43 2000/01/27 18:11:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -216,6 +216,33 @@ get_expr(TargetEntry *tle)
return (Var *) tle->expr;
}
/*
* get_sortgroupclause_tle
* Find the targetlist entry matching the given SortClause
* (or GroupClause) by ressortgroupref, and return it.
*
* Because GroupClause is typedef'd as SortClause, either kind of
* node can be passed without casting.
*/
TargetEntry *
get_sortgroupclause_tle(SortClause *sortClause,
List *targetList)
{
Index refnumber = sortClause->tleSortGroupRef;
List *l;
foreach(l, targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->resdom->ressortgroupref == refnumber)
return tle;
}
elog(ERROR, "get_sortgroupclause_tle: ORDER/GROUP BY expression not found in targetlist");
return NULL; /* keep compiler quiet */
}
/*
* get_sortgroupclause_expr
* Find the targetlist entry matching the given SortClause
@@ -227,17 +254,7 @@ get_expr(TargetEntry *tle)
Node *
get_sortgroupclause_expr(SortClause *sortClause, List *targetList)
{
Index refnumber = sortClause->tleSortGroupRef;
List *l;
TargetEntry *tle = get_sortgroupclause_tle(sortClause, targetList);
foreach(l, targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->resdom->ressortgroupref == refnumber)
return tle->expr;
}
elog(ERROR, "get_sortgroupclause_expr: ORDER/GROUP BY expression not found in targetlist");
return NULL; /* keep compiler quiet */
return tle->expr;
}