1212 */
1313#include "postgres.h"
1414
15+ #include "catalog/pg_operator_d.h"
1516#include "catalog/pg_type.h"
1617#include "common/int.h"
1718#include "common/pg_prng.h"
1819#include "libpq/pqformat.h"
20+ #include "miscadmin.h"
1921#include "nodes/supportnodes.h"
2022#include "port/pg_bitutils.h"
2123#include "utils/array.h"
2224#include "utils/builtins.h"
2325#include "utils/datum.h"
2426#include "utils/lsyscache.h"
27+ #include "utils/tuplesort.h"
2528#include "utils/typcache.h"
2629
2730/*
@@ -43,6 +46,18 @@ typedef struct DeserialIOData
4346 Oid typioparam ;
4447} DeserialIOData ;
4548
49+ /*
50+ * ArraySortCachedInfo
51+ * Used for caching catalog data in array_sort
52+ */
53+ typedef struct ArraySortCachedInfo
54+ {
55+ ArrayMetaState array_meta ; /* metadata for array_create_iterator */
56+ Oid elem_lt_opr ; /* "<" operator for element type */
57+ Oid elem_gt_opr ; /* ">" operator for element type */
58+ Oid array_type ; /* pg_type OID of array type */
59+ } ArraySortCachedInfo ;
60+
4661static Datum array_position_common (FunctionCallInfo fcinfo );
4762
4863
@@ -1858,3 +1873,171 @@ array_reverse(PG_FUNCTION_ARGS)
18581873
18591874 PG_RETURN_ARRAYTYPE_P (result );
18601875}
1876+
1877+ /*
1878+ * array_sort
1879+ *
1880+ * Sorts the first dimension of the array.
1881+ */
1882+ static ArrayType *
1883+ array_sort_internal (ArrayType * array , bool descending , bool nulls_first ,
1884+ FunctionCallInfo fcinfo )
1885+ {
1886+ ArrayType * newarray ;
1887+ Oid collation = PG_GET_COLLATION ();
1888+ int ndim ,
1889+ * dims ,
1890+ * lbs ;
1891+ ArraySortCachedInfo * cache_info ;
1892+ Oid elmtyp ;
1893+ Oid sort_typ ;
1894+ Oid sort_opr ;
1895+ Tuplesortstate * tuplesortstate ;
1896+ ArrayIterator array_iterator ;
1897+ Datum value ;
1898+ bool isnull ;
1899+ ArrayBuildStateAny * astate = NULL ;
1900+
1901+ ndim = ARR_NDIM (array );
1902+ dims = ARR_DIMS (array );
1903+ lbs = ARR_LBOUND (array );
1904+
1905+ /* Quick exit if we don't need to sort */
1906+ if (ndim < 1 || dims [0 ] < 2 )
1907+ return array ;
1908+
1909+ /* Set up cache area if we didn't already */
1910+ cache_info = (ArraySortCachedInfo * ) fcinfo -> flinfo -> fn_extra ;
1911+ if (cache_info == NULL )
1912+ {
1913+ cache_info = (ArraySortCachedInfo * )
1914+ MemoryContextAllocZero (fcinfo -> flinfo -> fn_mcxt ,
1915+ sizeof (ArraySortCachedInfo ));
1916+ fcinfo -> flinfo -> fn_extra = cache_info ;
1917+ }
1918+
1919+ /* Fetch and cache required data if we don't have it */
1920+ elmtyp = ARR_ELEMTYPE (array );
1921+ if (elmtyp != cache_info -> array_meta .element_type )
1922+ {
1923+ TypeCacheEntry * typentry ;
1924+
1925+ typentry = lookup_type_cache (elmtyp ,
1926+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR );
1927+ cache_info -> array_meta .element_type = elmtyp ;
1928+ cache_info -> array_meta .typlen = typentry -> typlen ;
1929+ cache_info -> array_meta .typbyval = typentry -> typbyval ;
1930+ cache_info -> array_meta .typalign = typentry -> typalign ;
1931+ cache_info -> elem_lt_opr = typentry -> lt_opr ;
1932+ cache_info -> elem_gt_opr = typentry -> gt_opr ;
1933+ /* For some reason the typcache doesn't track array type */
1934+ cache_info -> array_type = InvalidOid ;
1935+ }
1936+
1937+ /* Identify the sort operator to use */
1938+ if (ndim == 1 )
1939+ {
1940+ /* Need to sort the element type */
1941+ sort_typ = elmtyp ;
1942+ sort_opr = (descending ? cache_info -> elem_gt_opr : cache_info -> elem_lt_opr );
1943+ }
1944+ else
1945+ {
1946+ /* Otherwise we're sorting arrays */
1947+ if (!OidIsValid (cache_info -> array_type ))
1948+ {
1949+ cache_info -> array_type = get_array_type (elmtyp );
1950+ if (!OidIsValid (cache_info -> array_type ))
1951+ ereport (ERROR ,
1952+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
1953+ errmsg ("could not find array type for data type %s" ,
1954+ format_type_be (elmtyp ))));
1955+ }
1956+ sort_typ = cache_info -> array_type ;
1957+ /* We know what operators to use for arrays */
1958+ sort_opr = (descending ? ARRAY_GT_OP : ARRAY_LT_OP );
1959+ }
1960+
1961+ /*
1962+ * Fail if we don't know how to sort. The error message is chosen to
1963+ * match what array_lt()/array_gt() will say in the multidimensional case.
1964+ */
1965+ if (!OidIsValid (sort_opr ))
1966+ ereport (ERROR ,
1967+ errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1968+ errmsg ("could not identify a comparison function for type %s" ,
1969+ format_type_be (elmtyp )));
1970+
1971+ /* Put the things to be sorted (elements or sub-arrays) into a tuplesort */
1972+ tuplesortstate = tuplesort_begin_datum (sort_typ ,
1973+ sort_opr ,
1974+ collation ,
1975+ nulls_first ,
1976+ work_mem ,
1977+ NULL ,
1978+ TUPLESORT_NONE );
1979+
1980+ array_iterator = array_create_iterator (array , ndim - 1 ,
1981+ & cache_info -> array_meta );
1982+ while (array_iterate (array_iterator , & value , & isnull ))
1983+ {
1984+ tuplesort_putdatum (tuplesortstate , value , isnull );
1985+ }
1986+ array_free_iterator (array_iterator );
1987+
1988+ /* Do the sort */
1989+ tuplesort_performsort (tuplesortstate );
1990+
1991+ /* Extract results into a new array */
1992+ while (tuplesort_getdatum (tuplesortstate , true, false, & value , & isnull , NULL ))
1993+ {
1994+ astate = accumArrayResultAny (astate , value , isnull ,
1995+ sort_typ , CurrentMemoryContext );
1996+ }
1997+ tuplesort_end (tuplesortstate );
1998+
1999+ newarray = DatumGetArrayTypeP (makeArrayResultAny (astate ,
2000+ CurrentMemoryContext ,
2001+ true));
2002+
2003+ /* Adjust lower bound to match the input */
2004+ ARR_LBOUND (newarray )[0 ] = lbs [0 ];
2005+
2006+ return newarray ;
2007+ }
2008+
2009+ Datum
2010+ array_sort (PG_FUNCTION_ARGS )
2011+ {
2012+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2013+
2014+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2015+ false,
2016+ false,
2017+ fcinfo ));
2018+ }
2019+
2020+ Datum
2021+ array_sort_order (PG_FUNCTION_ARGS )
2022+ {
2023+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2024+ bool descending = PG_GETARG_BOOL (1 );
2025+
2026+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2027+ descending ,
2028+ descending ,
2029+ fcinfo ));
2030+ }
2031+
2032+ Datum
2033+ array_sort_order_nulls_first (PG_FUNCTION_ARGS )
2034+ {
2035+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2036+ bool descending = PG_GETARG_BOOL (1 );
2037+ bool nulls_first = PG_GETARG_BOOL (2 );
2038+
2039+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2040+ descending ,
2041+ nulls_first ,
2042+ fcinfo ));
2043+ }
0 commit comments