Skip to content

Commit f52d998

Browse files
committed
print sort keys for RuntimeMergeAppend
1 parent 1f6ccf7 commit f52d998

File tree

1 file changed

+131
-1
lines changed

1 file changed

+131
-1
lines changed

src/runtime_merge_append.c

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@
1212

1313
#include "pathman.h"
1414

15+
#include "catalog/pg_collation.h"
16+
#include "miscadmin.h"
17+
#include "nodes/nodeFuncs.h"
1518
#include "optimizer/clauses.h"
1619
#include "optimizer/cost.h"
1720
#include "optimizer/restrictinfo.h"
1821
#include "optimizer/planmain.h"
1922
#include "optimizer/tlist.h"
2023
#include "optimizer/var.h"
21-
#include "miscadmin.h"
24+
#include "utils/builtins.h"
2225
#include "utils/lsyscache.h"
2326
#include "utils/memutils.h"
27+
#include "utils/ruleutils.h"
2428

2529
#include "lib/binaryheap.h"
2630

@@ -53,6 +57,11 @@ static Sort * make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
5357

5458
static void copy_plan_costsize(Plan *dest, Plan *src);
5559

60+
static void show_sort_group_keys(PlanState *planstate, const char *qlabel,
61+
int nkeys, AttrNumber *keycols,
62+
Oid *sortOperators, Oid *collations, bool *nullsFirst,
63+
List *ancestors, ExplainState *es);
64+
5665
/*
5766
* We have one slot for each item in the heap array. We use SlotNumber
5867
* to store slot indexes. This doesn't actually provide any formal
@@ -443,6 +452,12 @@ runtimemergeappend_explain(CustomScanState *node, List *ancestors, ExplainState
443452
RuntimeMergeAppendState *scan_state = (RuntimeMergeAppendState *) node;
444453

445454
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);
446461
}
447462

448463

@@ -765,3 +780,118 @@ prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
765780

766781
return lefttree;
767782
}
783+
784+
/*
785+
* Append nondefault characteristics of the sort ordering of a column to buf
786+
* (collation, direction, NULLS FIRST/LAST)
787+
*/
788+
static void
789+
show_sortorder_options(StringInfo buf, Node *sortexpr,
790+
Oid sortOperator, Oid collation, bool nullsFirst)
791+
{
792+
Oid sortcoltype = exprType(sortexpr);
793+
bool reverse = 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+
else if (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+
else if (!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+
static void
847+
show_sort_group_keys(PlanState *planstate, const char *qlabel,
848+
int nkeys, 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+
StringInfoData sortkeybuf;
856+
bool useprefix;
857+
int keyno;
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+
AttrNumber keyresno = 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+
}

0 commit comments

Comments
 (0)