|
7 | 7 | * |
8 | 8 | * |
9 | 9 | * IDENTIFICATION |
10 | | - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.71 1999/08/1602:17:53 tgl Exp $ |
| 10 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.72 1999/08/1623:07:20 tgl Exp $ |
11 | 11 | * |
12 | 12 | *------------------------------------------------------------------------- |
13 | 13 | */ |
|
28 | 28 |
|
29 | 29 |
|
30 | 30 | staticList*switch_outer(List*clauses); |
31 | | -staticList*set_tlist_sort_info(List*tlist,List*pathkeys); |
| 31 | +staticintset_tlist_sort_info(List*tlist,List*pathkeys); |
32 | 32 | staticScan*create_scan_node(Path*best_path,List*tlist); |
33 | 33 | staticJoin*create_join_node(JoinPath*best_path,List*tlist); |
34 | 34 | staticSeqScan*create_seqscan_node(Path*best_path,List*tlist, |
@@ -804,40 +804,65 @@ switch_outer(List *clauses) |
804 | 804 | * Sets the reskey and reskeyop fields of resdom nodes in a target list |
805 | 805 | * for a sort node. |
806 | 806 | * |
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. |
808 | 809 | * 'pathkeys' is the desired pathkeys for the sort. NIL means no sort. |
809 | 810 | * |
810 | | - * Returns the modified-in-place target list. |
| 811 | + * Returns the number of sort keys assigned (which might be less than |
| 812 | + * length(pathkeys)!) |
811 | 813 | */ |
812 | | -staticList* |
| 814 | +staticint |
813 | 815 | set_tlist_sort_info(List*tlist,List*pathkeys) |
814 | 816 | { |
815 | | -intkeyno=1; |
| 817 | +intkeysassigned=0; |
816 | 818 | List*i; |
817 | 819 |
|
818 | 820 | foreach(i,pathkeys) |
819 | 821 | { |
820 | 822 | List*keysublist= (List*)lfirst(i); |
821 | | -PathKeyItem*pathkey; |
822 | | -Resdom*resdom; |
| 823 | +PathKeyItem*pathkey=NULL; |
| 824 | +Resdom*resdom=NULL; |
| 825 | +List*j; |
823 | 826 |
|
824 | 827 | /* |
825 | 828 | * 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. |
830 | 837 | */ |
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 | +} |
834 | 846 | if (!resdom) |
835 | 847 | 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 | +} |
839 | 863 | } |
840 | | -returntlist; |
| 864 | + |
| 865 | +returnkeysassigned; |
841 | 866 | } |
842 | 867 |
|
843 | 868 | /* |
@@ -885,34 +910,37 @@ make_noname(List *tlist, |
885 | 910 | Plan*plan_node) |
886 | 911 | { |
887 | 912 | List*noname_tlist; |
| 913 | +intnumsortkeys; |
| 914 | +Plan*tmpplan; |
888 | 915 | Noname*retval; |
889 | 916 |
|
890 | 917 | /* 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); |
893 | 920 |
|
894 | | -if (pathkeys!=NIL) |
| 921 | +if (numsortkeys>0) |
895 | 922 | { |
896 | 923 | /* 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); |
904 | 928 | } |
905 | 929 | else |
906 | 930 | { |
907 | 931 | /* no sort */ |
908 | | -retval= (Noname*)make_seqscan(tlist, |
909 | | -NIL, |
| 932 | +tmpplan= (Plan*)make_material(noname_tlist, |
910 | 933 | _NONAME_RELATION_ID_, |
911 | | - (Plan*)make_material(noname_tlist, |
912 | | -_NONAME_RELATION_ID_, |
913 | | -plan_node, |
914 | | -0)); |
| 934 | +plan_node, |
| 935 | +0); |
915 | 936 | } |
| 937 | + |
| 938 | +/* Return a seqscan using the original tlist */ |
| 939 | +retval= (Noname*)make_seqscan(tlist, |
| 940 | +NIL, |
| 941 | +_NONAME_RELATION_ID_, |
| 942 | +tmpplan); |
| 943 | + |
916 | 944 | returnretval; |
917 | 945 | } |
918 | 946 |
|
|