12
12
*/
13
13
#include "postgres.h"
14
14
15
+ #include "catalog/pg_operator_d.h"
15
16
#include "catalog/pg_type.h"
16
17
#include "common/int.h"
17
18
#include "common/pg_prng.h"
18
19
#include "libpq/pqformat.h"
20
+ #include "miscadmin.h"
19
21
#include "nodes/supportnodes.h"
20
22
#include "port/pg_bitutils.h"
21
23
#include "utils/array.h"
22
24
#include "utils/builtins.h"
23
25
#include "utils/datum.h"
24
26
#include "utils/lsyscache.h"
27
+ #include "utils/tuplesort.h"
25
28
#include "utils/typcache.h"
26
29
27
30
/*
@@ -43,6 +46,18 @@ typedef struct DeserialIOData
43
46
Oid typioparam ;
44
47
} DeserialIOData ;
45
48
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
+
46
61
static Datum array_position_common (FunctionCallInfo fcinfo );
47
62
48
63
@@ -1858,3 +1873,166 @@ array_reverse(PG_FUNCTION_ARGS)
1858
1873
1859
1874
PG_RETURN_ARRAYTYPE_P (result );
1860
1875
}
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
+ cache_info -> array_type = typentry -> typarray ;
1934
+ }
1935
+
1936
+ /* Identify the sort operator to use */
1937
+ if (ndim == 1 )
1938
+ {
1939
+ /* Need to sort the element type */
1940
+ sort_typ = elmtyp ;
1941
+ sort_opr = (descending ? cache_info -> elem_gt_opr : cache_info -> elem_lt_opr );
1942
+ }
1943
+ else
1944
+ {
1945
+ /* Otherwise we're sorting arrays */
1946
+ sort_typ = cache_info -> array_type ;
1947
+ if (!OidIsValid (sort_typ ))
1948
+ ereport (ERROR ,
1949
+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
1950
+ errmsg ("could not find array type for data type %s" ,
1951
+ format_type_be (elmtyp ))));
1952
+ /* We know what operators to use for arrays */
1953
+ sort_opr = (descending ? ARRAY_GT_OP : ARRAY_LT_OP );
1954
+ }
1955
+
1956
+ /*
1957
+ * Fail if we don't know how to sort. The error message is chosen to
1958
+ * match what array_lt()/array_gt() will say in the multidimensional case.
1959
+ */
1960
+ if (!OidIsValid (sort_opr ))
1961
+ ereport (ERROR ,
1962
+ errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1963
+ errmsg ("could not identify a comparison function for type %s" ,
1964
+ format_type_be (elmtyp )));
1965
+
1966
+ /* Put the things to be sorted (elements or sub-arrays) into a tuplesort */
1967
+ tuplesortstate = tuplesort_begin_datum (sort_typ ,
1968
+ sort_opr ,
1969
+ collation ,
1970
+ nulls_first ,
1971
+ work_mem ,
1972
+ NULL ,
1973
+ TUPLESORT_NONE );
1974
+
1975
+ array_iterator = array_create_iterator (array , ndim - 1 ,
1976
+ & cache_info -> array_meta );
1977
+ while (array_iterate (array_iterator , & value , & isnull ))
1978
+ {
1979
+ tuplesort_putdatum (tuplesortstate , value , isnull );
1980
+ }
1981
+ array_free_iterator (array_iterator );
1982
+
1983
+ /* Do the sort */
1984
+ tuplesort_performsort (tuplesortstate );
1985
+
1986
+ /* Extract results into a new array */
1987
+ while (tuplesort_getdatum (tuplesortstate , true, false, & value , & isnull , NULL ))
1988
+ {
1989
+ astate = accumArrayResultAny (astate , value , isnull ,
1990
+ sort_typ , CurrentMemoryContext );
1991
+ }
1992
+ tuplesort_end (tuplesortstate );
1993
+
1994
+ newarray = DatumGetArrayTypeP (makeArrayResultAny (astate ,
1995
+ CurrentMemoryContext ,
1996
+ true));
1997
+
1998
+ /* Adjust lower bound to match the input */
1999
+ ARR_LBOUND (newarray )[0 ] = lbs [0 ];
2000
+
2001
+ return newarray ;
2002
+ }
2003
+
2004
+ Datum
2005
+ array_sort (PG_FUNCTION_ARGS )
2006
+ {
2007
+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2008
+
2009
+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2010
+ false,
2011
+ false,
2012
+ fcinfo ));
2013
+ }
2014
+
2015
+ Datum
2016
+ array_sort_order (PG_FUNCTION_ARGS )
2017
+ {
2018
+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2019
+ bool descending = PG_GETARG_BOOL (1 );
2020
+
2021
+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2022
+ descending ,
2023
+ descending ,
2024
+ fcinfo ));
2025
+ }
2026
+
2027
+ Datum
2028
+ array_sort_order_nulls_first (PG_FUNCTION_ARGS )
2029
+ {
2030
+ ArrayType * array = PG_GETARG_ARRAYTYPE_P (0 );
2031
+ bool descending = PG_GETARG_BOOL (1 );
2032
+ bool nulls_first = PG_GETARG_BOOL (2 );
2033
+
2034
+ PG_RETURN_ARRAYTYPE_P (array_sort_internal (array ,
2035
+ descending ,
2036
+ nulls_first ,
2037
+ fcinfo ));
2038
+ }
0 commit comments