10
10
*
11
11
*
12
12
* IDENTIFICATION
13
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.151 2003/08/04 02:40:00 momjian Exp $
13
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.152 2003/08/07 19:20:22 tgl Exp $
14
14
*
15
15
*-------------------------------------------------------------------------
16
16
*/
@@ -504,52 +504,87 @@ create_unique_plan(Query *root, UniquePath * best_path)
504
504
{
505
505
Plan * plan ;
506
506
Plan * subplan ;
507
- List * sub_targetlist ;
507
+ List * uniq_exprs ;
508
+ int numGroupCols ;
509
+ AttrNumber * groupColIdx ;
510
+ int groupColPos ;
511
+ List * newtlist ;
512
+ int nextresno ;
513
+ bool newitems ;
508
514
List * my_tlist ;
509
515
List * l ;
510
516
511
517
subplan = create_plan (root , best_path -> subpath );
512
518
513
519
/*
514
- * If the subplan came from an IN subselect (currently always the
515
- * case), we need to instantiate the correct output targetlist for the
516
- * subselect, rather than using the flattened tlist.
520
+ * As constructed, the subplan has a "flat" tlist containing just the
521
+ * Vars needed here and at upper levels. The values we are supposed
522
+ * to unique-ify may be expressions in these variables. We have to
523
+ * add any such expressions to the subplan's tlist. We then build
524
+ * control information showing which subplan output columns are to be
525
+ * examined by the grouping step. (Since we do not remove any existing
526
+ * subplan outputs, not all the output columns may be used for grouping.)
527
+ *
528
+ * Note: the reason we don't remove any subplan outputs is that there
529
+ * are scenarios where a Var is needed at higher levels even though it
530
+ * is not one of the nominal outputs of an IN clause. Consider
531
+ * WHERE x IN (SELECT y FROM t1,t2 WHERE y = z)
532
+ * Implied equality deduction will generate an "x = z" clause, which may
533
+ * get used instead of "x = y" in the upper join step. Therefore the
534
+ * sub-select had better deliver both y and z in its targetlist. It is
535
+ * sufficient to unique-ify on y, however.
536
+ *
537
+ * To find the correct list of values to unique-ify, we look in the
538
+ * information saved for IN expressions. If this code is ever used in
539
+ * other scenarios, some other way of finding what to unique-ify will
540
+ * be needed.
517
541
*/
518
- sub_targetlist = NIL ;
542
+ uniq_exprs = NIL ; /* just to keep compiler quiet */
519
543
foreach (l , root -> in_info_list )
520
544
{
521
545
InClauseInfo * ininfo = (InClauseInfo * ) lfirst (l );
522
546
523
547
if (bms_equal (ininfo -> righthand , best_path -> path .parent -> relids ))
524
548
{
525
- sub_targetlist = ininfo -> sub_targetlist ;
549
+ uniq_exprs = ininfo -> sub_targetlist ;
526
550
break ;
527
551
}
528
552
}
529
-
530
- if (sub_targetlist )
553
+ if (l == NIL ) /* fell out of loop? */
554
+ elog (ERROR , "could not find UniquePath in in_info_list" );
555
+
556
+ /* set up to record positions of unique columns */
557
+ numGroupCols = length (uniq_exprs );
558
+ groupColIdx = (AttrNumber * ) palloc (numGroupCols * sizeof (AttrNumber ));
559
+ groupColPos = 0 ;
560
+ /* not sure if tlist might be shared with other nodes, so copy */
561
+ newtlist = copyObject (subplan -> targetlist );
562
+ nextresno = length (newtlist ) + 1 ;
563
+ newitems = false;
564
+
565
+ foreach (l , uniq_exprs )
531
566
{
532
- /*
533
- * Transform list of plain Vars into targetlist
534
- */
535
- List * newtlist = NIL ;
536
- int resno = 1 ;
567
+ Node * uniqexpr = lfirst (l );
568
+ TargetEntry * tle ;
537
569
538
- foreach (l , sub_targetlist )
570
+ tle = tlistentry_member (uniqexpr , newtlist );
571
+ if (!tle )
539
572
{
540
- Node * tlexpr = lfirst (l );
541
- TargetEntry * tle ;
542
-
543
- tle = makeTargetEntry (makeResdom (resno ,
544
- exprType (tlexpr ),
545
- exprTypmod (tlexpr ),
573
+ tle = makeTargetEntry (makeResdom (nextresno ,
574
+ exprType (uniqexpr ),
575
+ exprTypmod (uniqexpr ),
546
576
NULL ,
547
577
false),
548
- (Expr * ) tlexpr );
578
+ (Expr * ) uniqexpr );
549
579
newtlist = lappend (newtlist , tle );
550
- resno ++ ;
580
+ nextresno ++ ;
581
+ newitems = true;
551
582
}
583
+ groupColIdx [groupColPos ++ ] = tle -> resdom -> resno ;
584
+ }
552
585
586
+ if (newitems )
587
+ {
553
588
/*
554
589
* If the top plan node can't do projections, we need to add a
555
590
* Result node to help it along.
@@ -563,21 +598,15 @@ create_unique_plan(Query *root, UniquePath * best_path)
563
598
subplan -> targetlist = newtlist ;
564
599
}
565
600
601
+ /* Copy tlist again to make one we can put sorting labels on */
566
602
my_tlist = copyObject (subplan -> targetlist );
567
603
568
604
if (best_path -> use_hash )
569
605
{
570
- int numGroupCols = length (my_tlist );
571
606
long numGroups ;
572
- AttrNumber * groupColIdx ;
573
- int i ;
574
607
575
608
numGroups = (long ) Min (best_path -> rows , (double ) LONG_MAX );
576
609
577
- groupColIdx = (AttrNumber * ) palloc (numGroupCols * sizeof (AttrNumber ));
578
- for (i = 0 ; i < numGroupCols ; i ++ )
579
- groupColIdx [i ] = i + 1 ;
580
-
581
610
plan = (Plan * ) make_agg (root ,
582
611
my_tlist ,
583
612
NIL ,
@@ -590,9 +619,17 @@ create_unique_plan(Query *root, UniquePath * best_path)
590
619
}
591
620
else
592
621
{
593
- List * sortList ;
622
+ List * sortList = NIL ;
594
623
595
- sortList = addAllTargetsToSortList (NULL , NIL , my_tlist , false);
624
+ for (groupColPos = 0 ; groupColPos < numGroupCols ; groupColPos ++ )
625
+ {
626
+ TargetEntry * tle ;
627
+
628
+ tle = nth (groupColIdx [groupColPos ] - 1 , my_tlist );
629
+ Assert (tle -> resdom -> resno == groupColIdx [groupColPos ]);
630
+ sortList = addTargetToSortList (NULL , tle , sortList ,
631
+ my_tlist , NIL , false);
632
+ }
596
633
plan = (Plan * ) make_sort_from_sortclauses (root , my_tlist ,
597
634
subplan , sortList );
598
635
plan = (Plan * ) make_unique (my_tlist , plan , sortList );
0 commit comments