1414#include "postgres.h"
1515
1616#include "access/xact.h"
17+ #include "catalog/pg_collation.h"
1718#include "catalog/pg_type.h"
1819#include "commands/createas.h"
1920#include "commands/defrem.h"
2021#include "commands/prepare.h"
2122#include "executor/hashjoin.h"
2223#include "foreign/fdwapi.h"
24+ #include "nodes/nodeFuncs.h"
2325#include "optimizer/clauses.h"
2426#include "parser/parsetree.h"
2527#include "rewrite/rewriteHandler.h"
3133#include "utils/ruleutils.h"
3234#include "utils/snapmgr.h"
3335#include "utils/tuplesort.h"
36+ #include "utils/typcache.h"
3437#include "utils/xml.h"
3538
3639
@@ -83,7 +86,10 @@ static void show_group_keys(GroupState *gstate, List *ancestors,
8386 ExplainState * es );
8487static void show_sort_group_keys (PlanState * planstate , const char * qlabel ,
8588 int nkeys , AttrNumber * keycols ,
89+ Oid * sortOperators , Oid * collations , bool * nullsFirst ,
8690 List * ancestors , ExplainState * es );
91+ static void show_sortorder_options (StringInfo buf , Node * sortexpr ,
92+ Oid sortOperator , Oid collation , bool nullsFirst );
8793static void show_sort_info (SortState * sortstate , ExplainState * es );
8894static void show_hash_info (HashState * hashstate , ExplainState * es );
8995static void show_tidbitmap_info (BitmapHeapScanState * planstate ,
@@ -1781,6 +1787,8 @@ show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
17811787
17821788 show_sort_group_keys ((PlanState * ) sortstate , "Sort Key" ,
17831789 plan -> numCols , plan -> sortColIdx ,
1790+ plan -> sortOperators , plan -> collations ,
1791+ plan -> nullsFirst ,
17841792 ancestors , es );
17851793}
17861794
@@ -1795,6 +1803,8 @@ show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
17951803
17961804 show_sort_group_keys ((PlanState * ) mstate , "Sort Key" ,
17971805 plan -> numCols , plan -> sortColIdx ,
1806+ plan -> sortOperators , plan -> collations ,
1807+ plan -> nullsFirst ,
17981808 ancestors , es );
17991809}
18001810
@@ -1813,6 +1823,7 @@ show_agg_keys(AggState *astate, List *ancestors,
18131823 ancestors = lcons (astate , ancestors );
18141824 show_sort_group_keys (outerPlanState (astate ), "Group Key" ,
18151825 plan -> numCols , plan -> grpColIdx ,
1826+ NULL , NULL , NULL ,
18161827 ancestors , es );
18171828 ancestors = list_delete_first (ancestors );
18181829 }
@@ -1831,29 +1842,34 @@ show_group_keys(GroupState *gstate, List *ancestors,
18311842 ancestors = lcons (gstate , ancestors );
18321843 show_sort_group_keys (outerPlanState (gstate ), "Group Key" ,
18331844 plan -> numCols , plan -> grpColIdx ,
1845+ NULL , NULL , NULL ,
18341846 ancestors , es );
18351847 ancestors = list_delete_first (ancestors );
18361848}
18371849
18381850/*
18391851 * Common code to show sort/group keys, which are represented in plan nodes
1840- * as arrays of targetlist indexes
1852+ * as arrays of targetlist indexes. If it's a sort key rather than a group
1853+ * key, also pass sort operators/collations/nullsFirst arrays.
18411854 */
18421855static void
18431856show_sort_group_keys (PlanState * planstate , const char * qlabel ,
18441857 int nkeys , AttrNumber * keycols ,
1858+ Oid * sortOperators , Oid * collations , bool * nullsFirst ,
18451859 List * ancestors , ExplainState * es )
18461860{
18471861 Plan * plan = planstate -> plan ;
18481862 List * context ;
18491863 List * result = NIL ;
1864+ StringInfoData sortkeybuf ;
18501865 bool useprefix ;
18511866 int keyno ;
1852- char * exprstr ;
18531867
18541868 if (nkeys <= 0 )
18551869 return ;
18561870
1871+ initStringInfo (& sortkeybuf );
1872+
18571873 /* Set up deparsing context */
18581874 context = set_deparse_context_planstate (es -> deparse_cxt ,
18591875 (Node * ) planstate ,
@@ -1866,18 +1882,86 @@ show_sort_group_keys(PlanState *planstate, const char *qlabel,
18661882 AttrNumber keyresno = keycols [keyno ];
18671883 TargetEntry * target = get_tle_by_resno (plan -> targetlist ,
18681884 keyresno );
1885+ char * exprstr ;
18691886
18701887 if (!target )
18711888 elog (ERROR , "no tlist entry for key %d" , keyresno );
18721889 /* Deparse the expression, showing any top-level cast */
18731890 exprstr = deparse_expression ((Node * ) target -> expr , context ,
18741891 useprefix , true);
1875- result = lappend (result , exprstr );
1892+ resetStringInfo (& sortkeybuf );
1893+ appendStringInfoString (& sortkeybuf , exprstr );
1894+ /* Append sort order information, if relevant */
1895+ if (sortOperators != NULL )
1896+ show_sortorder_options (& sortkeybuf ,
1897+ (Node * ) target -> expr ,
1898+ sortOperators [keyno ],
1899+ collations [keyno ],
1900+ nullsFirst [keyno ]);
1901+ /* Emit one property-list item per sort key */
1902+ result = lappend (result , pstrdup (sortkeybuf .data ));
18761903 }
18771904
18781905 ExplainPropertyList (qlabel , result , es );
18791906}
18801907
1908+ /*
1909+ * Append nondefault characteristics of the sort ordering of a column to buf
1910+ * (collation, direction, NULLS FIRST/LAST)
1911+ */
1912+ static void
1913+ show_sortorder_options (StringInfo buf , Node * sortexpr ,
1914+ Oid sortOperator , Oid collation , bool nullsFirst )
1915+ {
1916+ Oid sortcoltype = exprType (sortexpr );
1917+ bool reverse = false;
1918+ TypeCacheEntry * typentry ;
1919+
1920+ typentry = lookup_type_cache (sortcoltype ,
1921+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
1922+
1923+ /*
1924+ * Print COLLATE if it's not default. There are some cases where this is
1925+ * redundant, eg if expression is a column whose declared collation is
1926+ * that collation, but it's hard to distinguish that here.
1927+ */
1928+ if (OidIsValid (collation ) && collation != DEFAULT_COLLATION_OID )
1929+ {
1930+ char * collname = get_collation_name (collation );
1931+
1932+ if (collname == NULL )
1933+ elog (ERROR , "cache lookup failed for collation %u" , collation );
1934+ appendStringInfo (buf , " COLLATE %s" , quote_identifier (collname ));
1935+ }
1936+
1937+ /* Print direction if not ASC, or USING if non-default sort operator */
1938+ if (sortOperator == typentry -> gt_opr )
1939+ {
1940+ appendStringInfoString (buf , " DESC" );
1941+ reverse = true;
1942+ }
1943+ else if (sortOperator != typentry -> lt_opr )
1944+ {
1945+ char * opname = get_opname (sortOperator );
1946+
1947+ if (opname == NULL )
1948+ elog (ERROR , "cache lookup failed for operator %u" , sortOperator );
1949+ appendStringInfo (buf , " USING %s" , opname );
1950+ /* Determine whether operator would be considered ASC or DESC */
1951+ (void ) get_equality_op_for_ordering_op (sortOperator , & reverse );
1952+ }
1953+
1954+ /* Add NULLS FIRST/LAST only if it wouldn't be default */
1955+ if (nullsFirst && !reverse )
1956+ {
1957+ appendStringInfoString (buf , " NULLS FIRST" );
1958+ }
1959+ else if (!nullsFirst && reverse )
1960+ {
1961+ appendStringInfoString (buf , " NULLS LAST" );
1962+ }
1963+ }
1964+
18811965/*
18821966 * If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node
18831967 */
0 commit comments