14
14
#include "postgres.h"
15
15
16
16
#include "access/xact.h"
17
+ #include "catalog/pg_collation.h"
17
18
#include "catalog/pg_type.h"
18
19
#include "commands/createas.h"
19
20
#include "commands/defrem.h"
20
21
#include "commands/prepare.h"
21
22
#include "executor/hashjoin.h"
22
23
#include "foreign/fdwapi.h"
24
+ #include "nodes/nodeFuncs.h"
23
25
#include "optimizer/clauses.h"
24
26
#include "parser/parsetree.h"
25
27
#include "rewrite/rewriteHandler.h"
31
33
#include "utils/ruleutils.h"
32
34
#include "utils/snapmgr.h"
33
35
#include "utils/tuplesort.h"
36
+ #include "utils/typcache.h"
34
37
#include "utils/xml.h"
35
38
36
39
@@ -83,7 +86,10 @@ static void show_group_keys(GroupState *gstate, List *ancestors,
83
86
ExplainState * es );
84
87
static void show_sort_group_keys (PlanState * planstate , const char * qlabel ,
85
88
int nkeys , AttrNumber * keycols ,
89
+ Oid * sortOperators , Oid * collations , bool * nullsFirst ,
86
90
List * ancestors , ExplainState * es );
91
+ static void show_sortorder_options (StringInfo buf , Node * sortexpr ,
92
+ Oid sortOperator , Oid collation , bool nullsFirst );
87
93
static void show_sort_info (SortState * sortstate , ExplainState * es );
88
94
static void show_hash_info (HashState * hashstate , ExplainState * es );
89
95
static void show_tidbitmap_info (BitmapHeapScanState * planstate ,
@@ -1781,6 +1787,8 @@ show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es)
1781
1787
1782
1788
show_sort_group_keys ((PlanState * ) sortstate , "Sort Key" ,
1783
1789
plan -> numCols , plan -> sortColIdx ,
1790
+ plan -> sortOperators , plan -> collations ,
1791
+ plan -> nullsFirst ,
1784
1792
ancestors , es );
1785
1793
}
1786
1794
@@ -1795,6 +1803,8 @@ show_merge_append_keys(MergeAppendState *mstate, List *ancestors,
1795
1803
1796
1804
show_sort_group_keys ((PlanState * ) mstate , "Sort Key" ,
1797
1805
plan -> numCols , plan -> sortColIdx ,
1806
+ plan -> sortOperators , plan -> collations ,
1807
+ plan -> nullsFirst ,
1798
1808
ancestors , es );
1799
1809
}
1800
1810
@@ -1813,6 +1823,7 @@ show_agg_keys(AggState *astate, List *ancestors,
1813
1823
ancestors = lcons (astate , ancestors );
1814
1824
show_sort_group_keys (outerPlanState (astate ), "Group Key" ,
1815
1825
plan -> numCols , plan -> grpColIdx ,
1826
+ NULL , NULL , NULL ,
1816
1827
ancestors , es );
1817
1828
ancestors = list_delete_first (ancestors );
1818
1829
}
@@ -1831,29 +1842,34 @@ show_group_keys(GroupState *gstate, List *ancestors,
1831
1842
ancestors = lcons (gstate , ancestors );
1832
1843
show_sort_group_keys (outerPlanState (gstate ), "Group Key" ,
1833
1844
plan -> numCols , plan -> grpColIdx ,
1845
+ NULL , NULL , NULL ,
1834
1846
ancestors , es );
1835
1847
ancestors = list_delete_first (ancestors );
1836
1848
}
1837
1849
1838
1850
/*
1839
1851
* 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.
1841
1854
*/
1842
1855
static void
1843
1856
show_sort_group_keys (PlanState * planstate , const char * qlabel ,
1844
1857
int nkeys , AttrNumber * keycols ,
1858
+ Oid * sortOperators , Oid * collations , bool * nullsFirst ,
1845
1859
List * ancestors , ExplainState * es )
1846
1860
{
1847
1861
Plan * plan = planstate -> plan ;
1848
1862
List * context ;
1849
1863
List * result = NIL ;
1864
+ StringInfoData sortkeybuf ;
1850
1865
bool useprefix ;
1851
1866
int keyno ;
1852
- char * exprstr ;
1853
1867
1854
1868
if (nkeys <= 0 )
1855
1869
return ;
1856
1870
1871
+ initStringInfo (& sortkeybuf );
1872
+
1857
1873
/* Set up deparsing context */
1858
1874
context = set_deparse_context_planstate (es -> deparse_cxt ,
1859
1875
(Node * ) planstate ,
@@ -1866,18 +1882,86 @@ show_sort_group_keys(PlanState *planstate, const char *qlabel,
1866
1882
AttrNumber keyresno = keycols [keyno ];
1867
1883
TargetEntry * target = get_tle_by_resno (plan -> targetlist ,
1868
1884
keyresno );
1885
+ char * exprstr ;
1869
1886
1870
1887
if (!target )
1871
1888
elog (ERROR , "no tlist entry for key %d" , keyresno );
1872
1889
/* Deparse the expression, showing any top-level cast */
1873
1890
exprstr = deparse_expression ((Node * ) target -> expr , context ,
1874
1891
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 ));
1876
1903
}
1877
1904
1878
1905
ExplainPropertyList (qlabel , result , es );
1879
1906
}
1880
1907
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
+
1881
1965
/*
1882
1966
* If it's EXPLAIN ANALYZE, show tuplesort stats for a sort node
1883
1967
*/
0 commit comments