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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy