|
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); |
|