|
12 | 12 |
|
13 | 13 | #include"pathman.h"
|
14 | 14 |
|
| 15 | +#include"catalog/pg_collation.h" |
| 16 | +#include"miscadmin.h" |
| 17 | +#include"nodes/nodeFuncs.h" |
15 | 18 | #include"optimizer/clauses.h"
|
16 | 19 | #include"optimizer/cost.h"
|
17 | 20 | #include"optimizer/restrictinfo.h"
|
18 | 21 | #include"optimizer/planmain.h"
|
19 | 22 | #include"optimizer/tlist.h"
|
20 | 23 | #include"optimizer/var.h"
|
21 |
| -#include"miscadmin.h" |
| 24 | +#include"utils/builtins.h" |
22 | 25 | #include"utils/lsyscache.h"
|
23 | 26 | #include"utils/memutils.h"
|
| 27 | +#include"utils/ruleutils.h" |
24 | 28 |
|
25 | 29 | #include"lib/binaryheap.h"
|
26 | 30 |
|
@@ -53,6 +57,11 @@ static Sort * make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
|
53 | 57 |
|
54 | 58 | staticvoidcopy_plan_costsize(Plan*dest,Plan*src);
|
55 | 59 |
|
| 60 | +staticvoidshow_sort_group_keys(PlanState*planstate,constchar*qlabel, |
| 61 | +intnkeys,AttrNumber*keycols, |
| 62 | +Oid*sortOperators,Oid*collations,bool*nullsFirst, |
| 63 | +List*ancestors,ExplainState*es); |
| 64 | + |
56 | 65 | /*
|
57 | 66 | * We have one slot for each item in the heap array. We use SlotNumber
|
58 | 67 | * to store slot indexes. This doesn't actually provide any formal
|
@@ -443,6 +452,12 @@ runtimemergeappend_explain(CustomScanState *node, List *ancestors, ExplainState
|
443 | 452 | RuntimeMergeAppendState*scan_state= (RuntimeMergeAppendState*)node;
|
444 | 453 |
|
445 | 454 | explain_append_common(node,scan_state->rstate.children_table,es);
|
| 455 | + |
| 456 | +/* We should print sort keys as well */ |
| 457 | +show_sort_group_keys((PlanState*)&node->ss.ps,"Sort Key", |
| 458 | +scan_state->numCols,scan_state->sortColIdx, |
| 459 | +scan_state->sortOperators,scan_state->collations, |
| 460 | +scan_state->nullsFirst,ancestors,es); |
446 | 461 | }
|
447 | 462 |
|
448 | 463 |
|
@@ -765,3 +780,118 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
|
765 | 780 |
|
766 | 781 | returnlefttree;
|
767 | 782 | }
|
| 783 | + |
| 784 | +/* |
| 785 | + * Append nondefault characteristics of the sort ordering of a column to buf |
| 786 | + * (collation, direction, NULLS FIRST/LAST) |
| 787 | + */ |
| 788 | +staticvoid |
| 789 | +show_sortorder_options(StringInfobuf,Node*sortexpr, |
| 790 | +OidsortOperator,Oidcollation,boolnullsFirst) |
| 791 | +{ |
| 792 | +Oidsortcoltype=exprType(sortexpr); |
| 793 | +boolreverse= false; |
| 794 | +TypeCacheEntry*typentry; |
| 795 | + |
| 796 | +typentry=lookup_type_cache(sortcoltype, |
| 797 | +TYPECACHE_LT_OPR |TYPECACHE_GT_OPR); |
| 798 | + |
| 799 | +/* |
| 800 | + * Print COLLATE if it's not default. There are some cases where this is |
| 801 | + * redundant, eg if expression is a column whose declared collation is |
| 802 | + * that collation, but it's hard to distinguish that here. |
| 803 | + */ |
| 804 | +if (OidIsValid(collation)&&collation!=DEFAULT_COLLATION_OID) |
| 805 | +{ |
| 806 | +char*collname=get_collation_name(collation); |
| 807 | + |
| 808 | +if (collname==NULL) |
| 809 | +elog(ERROR,"cache lookup failed for collation %u",collation); |
| 810 | +appendStringInfo(buf," COLLATE %s",quote_identifier(collname)); |
| 811 | +} |
| 812 | + |
| 813 | +/* Print direction if not ASC, or USING if non-default sort operator */ |
| 814 | +if (sortOperator==typentry->gt_opr) |
| 815 | +{ |
| 816 | +appendStringInfoString(buf," DESC"); |
| 817 | +reverse= true; |
| 818 | +} |
| 819 | +elseif (sortOperator!=typentry->lt_opr) |
| 820 | +{ |
| 821 | +char*opname=get_opname(sortOperator); |
| 822 | + |
| 823 | +if (opname==NULL) |
| 824 | +elog(ERROR,"cache lookup failed for operator %u",sortOperator); |
| 825 | +appendStringInfo(buf," USING %s",opname); |
| 826 | +/* Determine whether operator would be considered ASC or DESC */ |
| 827 | +(void)get_equality_op_for_ordering_op(sortOperator,&reverse); |
| 828 | +} |
| 829 | + |
| 830 | +/* Add NULLS FIRST/LAST only if it wouldn't be default */ |
| 831 | +if (nullsFirst&& !reverse) |
| 832 | +{ |
| 833 | +appendStringInfoString(buf," NULLS FIRST"); |
| 834 | +} |
| 835 | +elseif (!nullsFirst&&reverse) |
| 836 | +{ |
| 837 | +appendStringInfoString(buf," NULLS LAST"); |
| 838 | +} |
| 839 | +} |
| 840 | + |
| 841 | +/* |
| 842 | + * Common code to show sort/group keys, which are represented in plan nodes |
| 843 | + * as arrays of targetlist indexes. If it's a sort key rather than a group |
| 844 | + * key, also pass sort operators/collations/nullsFirst arrays. |
| 845 | + */ |
| 846 | +staticvoid |
| 847 | +show_sort_group_keys(PlanState*planstate,constchar*qlabel, |
| 848 | +intnkeys,AttrNumber*keycols, |
| 849 | +Oid*sortOperators,Oid*collations,bool*nullsFirst, |
| 850 | +List*ancestors,ExplainState*es) |
| 851 | +{ |
| 852 | +Plan*plan=planstate->plan; |
| 853 | +List*context; |
| 854 | +List*result=NIL; |
| 855 | +StringInfoDatasortkeybuf; |
| 856 | +booluseprefix; |
| 857 | +intkeyno; |
| 858 | + |
| 859 | +if (nkeys <=0) |
| 860 | +return; |
| 861 | + |
| 862 | +initStringInfo(&sortkeybuf); |
| 863 | + |
| 864 | +/* Set up deparsing context */ |
| 865 | +context=set_deparse_context_planstate(es->deparse_cxt, |
| 866 | +(Node*)planstate, |
| 867 | +ancestors); |
| 868 | +useprefix= (list_length(es->rtable)>1||es->verbose); |
| 869 | + |
| 870 | +for (keyno=0;keyno<nkeys;keyno++) |
| 871 | +{ |
| 872 | +/* find key expression in tlist */ |
| 873 | +AttrNumberkeyresno=keycols[keyno]; |
| 874 | +TargetEntry*target=get_tle_by_resno(plan->targetlist, |
| 875 | +keyresno); |
| 876 | +char*exprstr; |
| 877 | + |
| 878 | +if (!target) |
| 879 | +elog(ERROR,"no tlist entry for key %d",keyresno); |
| 880 | +/* Deparse the expression, showing any top-level cast */ |
| 881 | +exprstr=deparse_expression((Node*)target->expr,context, |
| 882 | +useprefix, true); |
| 883 | +resetStringInfo(&sortkeybuf); |
| 884 | +appendStringInfoString(&sortkeybuf,exprstr); |
| 885 | +/* Append sort order information, if relevant */ |
| 886 | +if (sortOperators!=NULL) |
| 887 | +show_sortorder_options(&sortkeybuf, |
| 888 | + (Node*)target->expr, |
| 889 | +sortOperators[keyno], |
| 890 | +collations[keyno], |
| 891 | +nullsFirst[keyno]); |
| 892 | +/* Emit one property-list item per sort key */ |
| 893 | +result=lappend(result,pstrdup(sortkeybuf.data)); |
| 894 | +} |
| 895 | + |
| 896 | +ExplainPropertyList(qlabel,result,es); |
| 897 | +} |