|
11 | 11 | * Portions Copyright (c) 1994, Regents of the University of California
|
12 | 12 | *
|
13 | 13 | * IDENTIFICATION
|
14 |
| - * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.88 2007/11/0819:25:37 tgl Exp $ |
| 14 | + * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.89 2007/11/0821:49:47 tgl Exp $ |
15 | 15 | *
|
16 | 16 | *-------------------------------------------------------------------------
|
17 | 17 | */
|
@@ -46,6 +46,7 @@ static bool pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys);
|
46 | 46 | staticPathKey*make_pathkey_from_sortinfo(PlannerInfo*root,
|
47 | 47 | Expr*expr,Oidordering_op,
|
48 | 48 | boolnulls_first,
|
| 49 | +Indexsortref, |
49 | 50 | boolcanonicalize);
|
50 | 51 | staticVar*find_indexkey_var(PlannerInfo*root,RelOptInfo*rel,
|
51 | 52 | AttrNumbervarattno);
|
@@ -233,13 +234,17 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
|
233 | 234 | * a PathKey. If canonicalize = true, the result is a "canonical"
|
234 | 235 | * PathKey, otherwise not. (But note it might be redundant anyway.)
|
235 | 236 | *
|
| 237 | + * If the PathKey is being generated from a SortClause, sortref should be |
| 238 | + * the SortClause's SortGroupRef; otherwise zero. |
| 239 | + * |
236 | 240 | * canonicalize should always be TRUE after EquivalenceClass merging has
|
237 | 241 | * been performed, but FALSE if we haven't done EquivalenceClass merging yet.
|
238 | 242 | */
|
239 | 243 | staticPathKey*
|
240 | 244 | make_pathkey_from_sortinfo(PlannerInfo*root,
|
241 | 245 | Expr*expr,Oidordering_op,
|
242 | 246 | boolnulls_first,
|
| 247 | +Indexsortref, |
243 | 248 | boolcanonicalize)
|
244 | 249 | {
|
245 | 250 | Oidopfamily,
|
@@ -303,7 +308,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
|
303 | 308 | }
|
304 | 309 |
|
305 | 310 | /* Now find or create a matching EquivalenceClass */
|
306 |
| -eclass=get_eclass_for_sort_expr(root,expr,opcintype,opfamilies); |
| 311 | +eclass=get_eclass_for_sort_expr(root,expr,opcintype,opfamilies, |
| 312 | +sortref); |
307 | 313 |
|
308 | 314 | /* And finally we can find or create a PathKey node */
|
309 | 315 | if (canonicalize)
|
@@ -525,6 +531,7 @@ build_index_pathkeys(PlannerInfo *root,
|
525 | 531 | indexkey,
|
526 | 532 | sortop,
|
527 | 533 | nulls_first,
|
| 534 | +0, |
528 | 535 | true);
|
529 | 536 |
|
530 | 537 | /* Add to list unless redundant */
|
@@ -597,102 +604,161 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
597 | 604 | PathKey*sub_pathkey= (PathKey*)lfirst(i);
|
598 | 605 | EquivalenceClass*sub_eclass=sub_pathkey->pk_eclass;
|
599 | 606 | PathKey*best_pathkey=NULL;
|
600 |
| -intbest_score=-1; |
601 |
| -ListCell*j; |
602 | 607 |
|
603 |
| -/* |
604 |
| - * The sub_pathkey's EquivalenceClass could contain multiple elements |
605 |
| - * (representing knowledge that multiple items are effectively equal). |
606 |
| - * Each element might match none, one, or more of the output columns |
607 |
| - * that are visible to the outer query. This means we may have |
608 |
| - * multiple possible representations of the sub_pathkey in the context |
609 |
| - * of the outer query. Ideally we would generate them all and put |
610 |
| - * them all into an EC of the outer query, thereby propagating |
611 |
| - * equality knowledge up to the outer query. Right now we cannot do |
612 |
| - * so, because the outer query's EquivalenceClasses are already frozen |
613 |
| - * when this is called. Instead we prefer the one that has the highest |
614 |
| - * "score" (number of EC peers, plus one if it matches the outer |
615 |
| - * query_pathkeys). This is the most likely to be useful in the outer |
616 |
| - * query. |
617 |
| - */ |
618 |
| -foreach(j,sub_eclass->ec_members) |
| 608 | +if (sub_eclass->ec_has_volatile) |
619 | 609 | {
|
620 |
| -EquivalenceMember*sub_member= (EquivalenceMember*)lfirst(j); |
621 |
| -Expr*sub_expr=sub_member->em_expr; |
622 |
| -Expr*rtarg; |
623 |
| -ListCell*k; |
624 |
| - |
625 | 610 | /*
|
626 |
| - * We handle two cases: the sub_pathkey key can be either an exact |
627 |
| - * match for a targetlist entry, or a RelabelType of a targetlist |
628 |
| - * entry. (The latter case is worth extra code because it arises |
629 |
| - * frequently in connection with varchar fields.) |
| 611 | + * If the sub_pathkey's EquivalenceClass is volatile, then it must |
| 612 | + * have come from an ORDER BY clause, and we have to match it to |
| 613 | + * that same targetlist entry. |
630 | 614 | */
|
631 |
| -if (IsA(sub_expr,RelabelType)) |
632 |
| -rtarg= ((RelabelType*)sub_expr)->arg; |
633 |
| -else |
634 |
| -rtarg=NULL; |
635 |
| - |
636 |
| -foreach(k,sub_tlist) |
| 615 | +TargetEntry*tle; |
| 616 | + |
| 617 | +if (sub_eclass->ec_sortref==0)/* can't happen */ |
| 618 | +elog(ERROR,"volatile EquivalenceClass has no sortref"); |
| 619 | +tle=get_sortgroupref_tle(sub_eclass->ec_sortref,sub_tlist); |
| 620 | +Assert(tle); |
| 621 | +/* resjunk items aren't visible to outer query */ |
| 622 | +if (!tle->resjunk) |
637 | 623 | {
|
638 |
| -TargetEntry*tle= (TargetEntry*)lfirst(k); |
| 624 | +/* We can represent this sub_pathkey */ |
| 625 | +EquivalenceMember*sub_member; |
639 | 626 | Expr*outer_expr;
|
640 | 627 | EquivalenceClass*outer_ec;
|
641 |
| -PathKey*outer_pk; |
642 |
| -intscore; |
643 | 628 |
|
644 |
| -/* resjunk items aren't visible to outer query */ |
645 |
| -if (tle->resjunk) |
646 |
| -continue; |
| 629 | +Assert(list_length(sub_eclass->ec_members)==1); |
| 630 | +sub_member= (EquivalenceMember*)linitial(sub_eclass->ec_members); |
| 631 | +outer_expr= (Expr*) |
| 632 | +makeVar(rel->relid, |
| 633 | +tle->resno, |
| 634 | +exprType((Node*)tle->expr), |
| 635 | +exprTypmod((Node*)tle->expr), |
| 636 | +0); |
| 637 | +outer_ec= |
| 638 | +get_eclass_for_sort_expr(root, |
| 639 | +outer_expr, |
| 640 | +sub_member->em_datatype, |
| 641 | +sub_eclass->ec_opfamilies, |
| 642 | +0); |
| 643 | +best_pathkey= |
| 644 | +make_canonical_pathkey(root, |
| 645 | +outer_ec, |
| 646 | +sub_pathkey->pk_opfamily, |
| 647 | +sub_pathkey->pk_strategy, |
| 648 | +sub_pathkey->pk_nulls_first); |
| 649 | +} |
| 650 | +} |
| 651 | +else |
| 652 | +{ |
| 653 | +/* |
| 654 | + * Otherwise, the sub_pathkey's EquivalenceClass could contain |
| 655 | + * multiple elements (representing knowledge that multiple items |
| 656 | + * are effectively equal). Each element might match none, one, or |
| 657 | + * more of the output columns that are visible to the outer |
| 658 | + * query. This means we may have multiple possible representations |
| 659 | + * of the sub_pathkey in the context of the outer query. Ideally |
| 660 | + * we would generate them all and put them all into an EC of the |
| 661 | + * outer query, thereby propagating equality knowledge up to the |
| 662 | + * outer query. Right now we cannot do so, because the outer |
| 663 | + * query's EquivalenceClasses are already frozen when this is |
| 664 | + * called. Instead we prefer the one that has the highest "score" |
| 665 | + * (number of EC peers, plus one if it matches the outer |
| 666 | + * query_pathkeys). This is the most likely to be useful in the |
| 667 | + * outer query. |
| 668 | + */ |
| 669 | +intbest_score=-1; |
| 670 | +ListCell*j; |
647 | 671 |
|
648 |
| -if (equal(tle->expr,sub_expr)) |
649 |
| -{ |
650 |
| -/* Exact match */ |
651 |
| -outer_expr= (Expr*) |
652 |
| -makeVar(rel->relid, |
653 |
| -tle->resno, |
654 |
| -exprType((Node*)tle->expr), |
655 |
| -exprTypmod((Node*)tle->expr), |
656 |
| -0); |
657 |
| -} |
658 |
| -elseif (rtarg&&equal(tle->expr,rtarg)) |
| 672 | +foreach(j,sub_eclass->ec_members) |
| 673 | +{ |
| 674 | +EquivalenceMember*sub_member= (EquivalenceMember*)lfirst(j); |
| 675 | +Expr*sub_expr=sub_member->em_expr; |
| 676 | +Expr*sub_stripped; |
| 677 | +ListCell*k; |
| 678 | + |
| 679 | +/* |
| 680 | + * We handle two cases: the sub_pathkey key can be either an |
| 681 | + * exact match for a targetlist entry, or it could match after |
| 682 | + * stripping RelabelType nodes. (We need that case since |
| 683 | + * make_pathkey_from_sortinfo could add or remove RelabelType.) |
| 684 | + */ |
| 685 | +sub_stripped=sub_expr; |
| 686 | +while (sub_stripped&&IsA(sub_stripped,RelabelType)) |
| 687 | +sub_stripped= ((RelabelType*)sub_stripped)->arg; |
| 688 | + |
| 689 | +foreach(k,sub_tlist) |
659 | 690 | {
|
660 |
| -/* Match after discarding RelabelType */ |
661 |
| -outer_expr= (Expr*) |
662 |
| -makeVar(rel->relid, |
663 |
| -tle->resno, |
664 |
| -exprType((Node*)tle->expr), |
665 |
| -exprTypmod((Node*)tle->expr), |
666 |
| -0); |
667 |
| -outer_expr= (Expr*) |
668 |
| -makeRelabelType((Expr*)outer_expr, |
669 |
| -((RelabelType*)sub_expr)->resulttype, |
670 |
| - ((RelabelType*)sub_expr)->resulttypmod, |
671 |
| - ((RelabelType*)sub_expr)->relabelformat); |
672 |
| -} |
673 |
| -else |
674 |
| -continue; |
| 691 | +TargetEntry*tle= (TargetEntry*)lfirst(k); |
| 692 | +Expr*outer_expr; |
| 693 | +EquivalenceClass*outer_ec; |
| 694 | +PathKey*outer_pk; |
| 695 | +intscore; |
675 | 696 |
|
676 |
| -/* Found a representation for this sub_pathkey */ |
677 |
| -outer_ec=get_eclass_for_sort_expr(root, |
678 |
| -outer_expr, |
679 |
| -sub_member->em_datatype, |
680 |
| -sub_eclass->ec_opfamilies); |
681 |
| -outer_pk=make_canonical_pathkey(root, |
682 |
| -outer_ec, |
683 |
| -sub_pathkey->pk_opfamily, |
684 |
| -sub_pathkey->pk_strategy, |
685 |
| -sub_pathkey->pk_nulls_first); |
686 |
| -/* score = # of equivalence peers */ |
687 |
| -score=list_length(outer_ec->ec_members)-1; |
688 |
| -/* +1 if it matches the proper query_pathkeys item */ |
689 |
| -if (retvallen<outer_query_keys&& |
690 |
| -list_nth(root->query_pathkeys,retvallen)==outer_pk) |
691 |
| -score++; |
692 |
| -if (score>best_score) |
693 |
| -{ |
694 |
| -best_pathkey=outer_pk; |
695 |
| -best_score=score; |
| 697 | +/* resjunk items aren't visible to outer query */ |
| 698 | +if (tle->resjunk) |
| 699 | +continue; |
| 700 | + |
| 701 | +if (equal(tle->expr,sub_expr)) |
| 702 | +{ |
| 703 | +/* Exact match */ |
| 704 | +outer_expr= (Expr*) |
| 705 | +makeVar(rel->relid, |
| 706 | +tle->resno, |
| 707 | +exprType((Node*)tle->expr), |
| 708 | +exprTypmod((Node*)tle->expr), |
| 709 | +0); |
| 710 | +} |
| 711 | +else |
| 712 | +{ |
| 713 | +Expr*tle_stripped; |
| 714 | + |
| 715 | +tle_stripped=tle->expr; |
| 716 | +while (tle_stripped&&IsA(tle_stripped,RelabelType)) |
| 717 | +tle_stripped= ((RelabelType*)tle_stripped)->arg; |
| 718 | + |
| 719 | +if (equal(tle_stripped,sub_stripped)) |
| 720 | +{ |
| 721 | +/* Match after discarding RelabelType */ |
| 722 | +outer_expr= (Expr*) |
| 723 | +makeVar(rel->relid, |
| 724 | +tle->resno, |
| 725 | +exprType((Node*)tle->expr), |
| 726 | +exprTypmod((Node*)tle->expr), |
| 727 | +0); |
| 728 | +if (exprType((Node*)outer_expr)!= |
| 729 | +exprType((Node*)sub_expr)) |
| 730 | +outer_expr= (Expr*) |
| 731 | +makeRelabelType(outer_expr, |
| 732 | +exprType((Node*)sub_expr), |
| 733 | +-1, |
| 734 | +COERCE_DONTCARE); |
| 735 | +} |
| 736 | +else |
| 737 | +continue; |
| 738 | +} |
| 739 | + |
| 740 | +/* Found a representation for this sub_pathkey */ |
| 741 | +outer_ec=get_eclass_for_sort_expr(root, |
| 742 | +outer_expr, |
| 743 | +sub_member->em_datatype, |
| 744 | +sub_eclass->ec_opfamilies, |
| 745 | +0); |
| 746 | +outer_pk=make_canonical_pathkey(root, |
| 747 | +outer_ec, |
| 748 | +sub_pathkey->pk_opfamily, |
| 749 | +sub_pathkey->pk_strategy, |
| 750 | +sub_pathkey->pk_nulls_first); |
| 751 | +/* score = # of equivalence peers */ |
| 752 | +score=list_length(outer_ec->ec_members)-1; |
| 753 | +/* +1 if it matches the proper query_pathkeys item */ |
| 754 | +if (retvallen<outer_query_keys&& |
| 755 | +list_nth(root->query_pathkeys,retvallen)==outer_pk) |
| 756 | +score++; |
| 757 | +if (score>best_score) |
| 758 | +{ |
| 759 | +best_pathkey=outer_pk; |
| 760 | +best_score=score; |
| 761 | +} |
696 | 762 | }
|
697 | 763 | }
|
698 | 764 | }
|
@@ -795,6 +861,7 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
|
795 | 861 | sortkey,
|
796 | 862 | sortcl->sortop,
|
797 | 863 | sortcl->nulls_first,
|
| 864 | +sortcl->tleSortGroupRef, |
798 | 865 | canonicalize);
|
799 | 866 |
|
800 | 867 | /* Canonical form eliminates redundant ordering keys */
|
@@ -843,12 +910,14 @@ cache_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
|
843 | 910 | get_eclass_for_sort_expr(root,
|
844 | 911 | (Expr*)get_leftop(clause),
|
845 | 912 | lefttype,
|
846 |
| -restrictinfo->mergeopfamilies); |
| 913 | +restrictinfo->mergeopfamilies, |
| 914 | +0); |
847 | 915 | restrictinfo->right_ec=
|
848 | 916 | get_eclass_for_sort_expr(root,
|
849 | 917 | (Expr*)get_rightop(clause),
|
850 | 918 | righttype,
|
851 |
| -restrictinfo->mergeopfamilies); |
| 919 | +restrictinfo->mergeopfamilies, |
| 920 | +0); |
852 | 921 | }
|
853 | 922 | else
|
854 | 923 | Assert(restrictinfo->right_ec!=NULL);
|
|