Skip to content

Commit 91f82de

Browse files
committed
Assign sort keys properly when there are duplicate entries in
pathkey list --- corrects misbehavior seen with multiple mergejoin clauses mentioning same variable.
1 parent 5517938 commit 91f82de

File tree

1 file changed

+63
-35
lines changed

1 file changed

+63
-35
lines changed

src/backend/optimizer/plan/createplan.c

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.71 1999/08/16 02:17:53 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.72 1999/08/16 23:07:20 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -28,7 +28,7 @@
2828

2929

3030
static List *switch_outer(List *clauses);
31-
static List *set_tlist_sort_info(List *tlist, List *pathkeys);
31+
static int set_tlist_sort_info(List *tlist, List *pathkeys);
3232
static Scan *create_scan_node(Path *best_path, List *tlist);
3333
static Join *create_join_node(JoinPath *best_path, List *tlist);
3434
static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
@@ -804,40 +804,65 @@ switch_outer(List *clauses)
804804
* Sets the reskey and reskeyop fields of resdom nodes in a target list
805805
* for a sort node.
806806
*
807-
* 'tlist' is the target list
807+
* 'tlist' is the target list (which is modified in-place).
808+
* tlist's reskey fields must be clear to start with.
808809
* 'pathkeys' is the desired pathkeys for the sort. NIL means no sort.
809810
*
810-
* Returns the modified-in-place target list.
811+
* Returns the number of sort keys assigned (which might be less than
812+
* length(pathkeys)!)
811813
*/
812-
static List *
814+
static int
813815
set_tlist_sort_info(List *tlist, List *pathkeys)
814816
{
815-
int keyno = 1;
817+
int keysassigned = 0;
816818
List *i;
817819

818820
foreach(i, pathkeys)
819821
{
820822
List *keysublist = (List *) lfirst(i);
821-
PathKeyItem *pathkey;
822-
Resdom *resdom;
823+
PathKeyItem *pathkey = NULL;
824+
Resdom *resdom = NULL;
825+
List *j;
823826

824827
/*
825828
* We can sort by any one of the sort key items listed in this
826-
* sublist. For now, we always take the first one --- is there
827-
* any way of figuring out which might be cheapest to execute?
828-
* (For example, int4lt is likely much cheaper to execute than
829-
* numericlt, but both might appear in the same pathkey sublist...)
829+
* sublist. For now, we take the first one that corresponds to
830+
* an available Var in the tlist.
831+
*
832+
* XXX if we have a choice, is there any way of figuring out which
833+
* might be cheapest to execute? (For example, int4lt is likely
834+
* much cheaper to execute than numericlt, but both might appear in
835+
* the same pathkey sublist...) Not clear that we ever will have
836+
* a choice in practice, so it may not matter.
830837
*/
831-
pathkey = lfirst(keysublist);
832-
Assert(IsA(pathkey, PathKeyItem));
833-
resdom = tlist_member((Var *) pathkey->key, tlist);
838+
foreach(j, keysublist)
839+
{
840+
pathkey = lfirst(j);
841+
Assert(IsA(pathkey, PathKeyItem));
842+
resdom = tlist_member((Var *) pathkey->key, tlist);
843+
if (resdom)
844+
break;
845+
}
834846
if (!resdom)
835847
elog(ERROR, "set_tlist_sort_info: cannot find tlist item to sort");
836-
resdom->reskey = keyno;
837-
resdom->reskeyop = get_opcode(pathkey->sortop);
838-
keyno++;
848+
849+
/*
850+
* The resdom might be already marked as a sort key, if the pathkeys
851+
* contain duplicate entries. (This can happen in scenarios where
852+
* multiple mergejoinable clauses mention the same var, for example.)
853+
* In that case the current pathkey is essentially a no-op, because
854+
* only one value can be seen within any subgroup where it would be
855+
* consulted. We can ignore it.
856+
*/
857+
if (resdom->reskey == 0)
858+
{
859+
/* OK, mark it as a sort key and set the sort operator regproc */
860+
resdom->reskey = ++keysassigned;
861+
resdom->reskeyop = get_opcode(pathkey->sortop);
862+
}
839863
}
840-
return tlist;
864+
865+
return keysassigned;
841866
}
842867

843868
/*
@@ -885,34 +910,37 @@ make_noname(List *tlist,
885910
Plan *plan_node)
886911
{
887912
List *noname_tlist;
913+
int numsortkeys;
914+
Plan *tmpplan;
888915
Noname *retval;
889916

890917
/* Create a new target list for the noname, with sort keys set. */
891-
noname_tlist = set_tlist_sort_info(new_unsorted_tlist(tlist),
892-
pathkeys);
918+
noname_tlist = new_unsorted_tlist(tlist);
919+
numsortkeys = set_tlist_sort_info(noname_tlist, pathkeys);
893920

894-
if (pathkeys != NIL)
921+
if (numsortkeys > 0)
895922
{
896923
/* need to sort */
897-
retval = (Noname *) make_seqscan(tlist,
898-
NIL,
899-
_NONAME_RELATION_ID_,
900-
(Plan *) make_sort(noname_tlist,
901-
_NONAME_RELATION_ID_,
902-
plan_node,
903-
length(pathkeys)));
924+
tmpplan = (Plan *) make_sort(noname_tlist,
925+
_NONAME_RELATION_ID_,
926+
plan_node,
927+
numsortkeys);
904928
}
905929
else
906930
{
907931
/* no sort */
908-
retval = (Noname *) make_seqscan(tlist,
909-
NIL,
932+
tmpplan = (Plan *) make_material(noname_tlist,
910933
_NONAME_RELATION_ID_,
911-
(Plan *) make_material(noname_tlist,
912-
_NONAME_RELATION_ID_,
913-
plan_node,
914-
0));
934+
plan_node,
935+
0);
915936
}
937+
938+
/* Return a seqscan using the original tlist */
939+
retval = (Noname *) make_seqscan(tlist,
940+
NIL,
941+
_NONAME_RELATION_ID_,
942+
tmpplan);
943+
916944
return retval;
917945
}
918946

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy