On Mon, Nov 4, 2024 at 7:34 PM Dean Rasheed <[email protected]> wrote:
>
> Testing this with an array with non-default lower bounds, it fails to
> preserve the array bounds, which I think it should (note:
> array_reverse() and array_shuffle() do preserve the bounds):
>
> SELECT array_reverse(a), array_shuffle(a), array_sort(a)
> FROM (VALUES ('[10:12][20:21]={{1,2},{10,20},{3,4}}'::int[])) v(a);
>
> -[ RECORD 1 ]-+-------------------------------------
> array_reverse | [10:12][20:21]={{3,4},{10,20},{1,2}}
> array_shuffle | [10:12][20:21]={{10,20},{3,4},{1,2}}
> array_sort | [1:3][20:21]={{1,2},{3,4},{10,20}}
>
if i understand it correctly,
array_create_iterator cannot cope with top dimension bound information.
since input array arguments already have dims, lbs information.
so at the end of array_sort directly copy
from the input array argument to astate.
tuplesort_performsort won't need array bounds, we should be safe?
v12-0001 same as v11-0001-general-purpose-array_sort.patch, only
resolve git conflict
v12-0002 preserve array bound information.
v12-0003 cache ArrayMetaState.
after v12-0003 now
typedef struct ArraySortCachedInfo
{
TypeCacheEntry *typentry;
TypeCacheEntry *array_typentry;
ArrayMetaState array_meta;
} ArraySortCachedInfo;
function array_create_iterator, get_typlenbyvalalign
will do cache search, we can cache ArrayMetaState.
so multiple array_create_iterator calls won't need to call get_typlenbyvalalign.
every time.
0002, I also have a 3 dimensional array test.
create table t(a int[]);
insert into t values ('[-1:-0]={7,1}'::int[]),
('[-2:-0][20:21]={{1,2},{10,20},{1,-4}}'),
('[-2:-0][20:22]={{-11,2,-1},{-11,2, 1},{-11,-4, 10}}'),
('[-13:-10][0:1][20:22]={
{{1,2,112},{1,2,-123}},
{{10,-20,1},{11,123,3}},
{{10,-20,1},{11,-123,-9}},
{{1,2,-11},{1,2,211}}}'::int[]);
SELECT array_sort(t.a) from t;
SELECT array_sort((t.a) [-13:-10][0:1][21:22]) from t where array_ndims(a) = 3;
SELECT array_sort((t.a) [-13:-11][0:1][21:22]) from t where array_ndims(a) = 3;
SELECT array_sort((t.a) [-13:-11][0:0][20:21]) from t where array_ndims(a) = 3;
The test output is ok to me.
From caa24ca549c01e99b3873860dcffe0d8161345d4 Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Tue, 5 Nov 2024 14:34:02 +0800
Subject: [PATCH v12 3/3] array_sort cache ArrayMetaState
---
src/backend/utils/adt/array_userfuncs.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 436f761614..c14ef1ed90 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -1804,6 +1804,7 @@ typedef struct ArraySortCachedInfo
{
TypeCacheEntry *typentry;
TypeCacheEntry *array_typentry;
+ ArrayMetaState array_meta;
} ArraySortCachedInfo;
/*
@@ -1848,6 +1849,7 @@ array_sort(PG_FUNCTION_ARGS)
sizeof(ArraySortCachedInfo));
cache_info->typentry = NULL;
cache_info->array_typentry = NULL;
+ memset(&cache_info->array_meta, 0, sizeof(ArrayMetaState));
fcinfo->flinfo->fn_extra = (void *) cache_info;
}
@@ -1864,6 +1866,10 @@ array_sort(PG_FUNCTION_ARGS)
errmsg("could not identify ordering operator for type %s",
format_type_be(elmtyp))));
cache_info->typentry = typentry;
+ cache_info->array_meta.element_type = elmtyp;
+ cache_info->array_meta.typlen = typentry->typlen;
+ cache_info->array_meta.typbyval = typentry->typbyval;
+ cache_info->array_meta.typalign = typentry->typalign;
}
}
else
@@ -1886,6 +1892,11 @@ array_sort(PG_FUNCTION_ARGS)
format_type_be(array_type))));
cache_info->array_typentry = typentry;
}
+ cache_info->array_meta.element_type = elmtyp;
+ get_typlenbyvalalign(elmtyp,
+ &cache_info->array_meta.typlen,
+ &cache_info->array_meta.typbyval,
+ &cache_info->array_meta.typalign);
}
tuplesortstate = tuplesort_begin_datum(typentry->type_id,
@@ -1893,7 +1904,7 @@ array_sort(PG_FUNCTION_ARGS)
collation,
false, work_mem, NULL, false);
- array_iterator = array_create_iterator(array, ndim - 1, NULL);
+ array_iterator = array_create_iterator(array, ndim - 1, &cache_info->array_meta);
while (array_iterate(array_iterator, &value, &isnull))
{
tuplesort_putdatum(tuplesortstate, value, isnull);
--
2.34.1
From d7c2956893222bb025822810860a01539ca3ec85 Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Tue, 5 Nov 2024 14:53:42 +0800
Subject: [PATCH v12 2/3] array_sort preserve array dimenion and bound info
---
src/backend/utils/adt/array_userfuncs.c | 30 +++++++++++++--
src/backend/utils/adt/arrayfuncs.c | 3 +-
src/include/utils/array.h | 1 +
src/test/regress/expected/arrays.out | 49 +++++++++++++++++++++++++
src/test/regress/sql/arrays.sql | 18 ++++++++-
5 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index a45586c892..436f761614 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -1826,8 +1826,18 @@ array_sort(PG_FUNCTION_ARGS)
Datum value;
bool isnull;
ArrayBuildStateAny *astate = NULL;
+ int ndim,
+ *dims,
+ *lbs;
- if (ARR_NDIM(array) < 1)
+ ndim = ARR_NDIM(array);
+ dims = ARR_DIMS(array);
+ lbs = ARR_LBOUND(array);
+
+ if (ndim < 1)
+ PG_RETURN_ARRAYTYPE_P(array);
+
+ if(dims[0] < 2)
PG_RETURN_ARRAYTYPE_P(array);
elmtyp = ARR_ELEMTYPE(array);
@@ -1841,7 +1851,7 @@ array_sort(PG_FUNCTION_ARGS)
fcinfo->flinfo->fn_extra = (void *) cache_info;
}
- if (ARR_NDIM(array) == 1)
+ if (ndim == 1)
{
/* Finds the ordering operator for the type for 1-D arrays */
typentry = cache_info->typentry;
@@ -1883,7 +1893,7 @@ array_sort(PG_FUNCTION_ARGS)
collation,
false, work_mem, NULL, false);
- array_iterator = array_create_iterator(array, ARR_NDIM(array) - 1, NULL);
+ array_iterator = array_create_iterator(array, ndim - 1, NULL);
while (array_iterate(array_iterator, &value, &isnull))
{
tuplesort_putdatum(tuplesortstate, value, isnull);
@@ -1903,6 +1913,20 @@ array_sort(PG_FUNCTION_ARGS)
tuplesort_end(tuplesortstate);
+ if (astate->arraystate != NULL)
+ {
+ memcpy(astate->arraystate->dims, dims, ndim * sizeof(int));
+ memcpy(astate->arraystate->lbs, lbs, ndim * sizeof(int));
+ Assert(ndim == astate->arraystate->ndims);
+ }
+ else
+ {
+ astate->scalarstate->lbs = lbs[0];
+
+ /* zero dimension won't reach here */
+ Assert(ndim == 1);
+ }
+
/* Avoid leaking memory when handed toasted input */
PG_FREE_IF_COPY(array, 0);
PG_RETURN_DATUM(makeArrayResultAny(astate, CurrentMemoryContext, true));
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index a715e7e0b8..ffdf3449e9 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -5335,6 +5335,7 @@ initArrayResultWithSize(Oid element_type, MemoryContext rcontext,
&astate->typbyval,
&astate->typalign);
+ astate->lbs = 1; /* default lower-bound value set to 1, see array_in also */
return astate;
}
@@ -5867,7 +5868,7 @@ makeArrayResultAny(ArrayBuildStateAny *astate,
/* If no elements were presented, we want to create an empty array */
ndims = (astate->scalarstate->nelems > 0) ? 1 : 0;
dims[0] = astate->scalarstate->nelems;
- lbs[0] = 1;
+ lbs[0] = astate->scalarstate->lbs;
result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
rcontext, release);
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index 157cc0e4c6..7b7937d494 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -193,6 +193,7 @@ typedef struct ArrayBuildState
int nelems; /* number of valid entries in above arrays */
Oid element_type; /* data type of the Datums */
int16 typlen; /* needed info about datatype */
+ int lbs; /* one dimension, one lower-bound is OK*/
bool typbyval;
char typalign;
bool private_cxt; /* use private memory context */
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 846d6acd85..9e371902d3 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2735,6 +2735,18 @@ SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
(1 row)
-- array_sort
+SELECT array_sort('{1}'::int[]);
+ array_sort
+------------
+ {1}
+(1 row)
+
+SELECT array_sort('{{2,1}}'::int[]);
+ array_sort
+------------
+ {{2,1}}
+(1 row)
+
SELECT array_sort('{}'::int[]);
array_sort
------------
@@ -2772,3 +2784,40 @@ SELECT array_sort(ARRAY[[2,4],[2,1],[6,5]]);
{{2,1},{2,4},{6,5}}
(1 row)
+create table t(a int[]);
+insert into t values ('[-1:-0]={7,1}'::int[]),
+('[-2:-0][20:21]={{1,2},{10,20},{1,-4}}'),
+('[-2:-0][20:22]={{-11,2,-1},{-11,2, 1},{-11,-4, 10}}'),
+('[-13:-10][0:1][20:22]={
+{{1,2,112},{1,2,-123}},
+{{10,-20,1},{11,123,3}},
+{{10,-20,1},{11,-123,-9}},
+{{1,2,-11},{1,2,211}}}'::int[]);
+SELECT array_sort(t.a) from t;
+ array_sort
+------------------------------------------------------------------------------------------------------------------------
+ [-1:0]={1,7}
+ [-2:0][20:21]={{1,-4},{1,2},{10,20}}
+ [-2:0][20:22]={{-11,-4,10},{-11,2,-1},{-11,2,1}}
+ [-13:-10][0:1][20:22]={{{1,2,-11},{1,2,211}},{{1,2,112},{1,2,-123}},{{10,-20,1},{11,-123,-9}},{{10,-20,1},{11,123,3}}}
+(4 rows)
+
+SELECT array_sort((t.a) [-13:-10][0:1][21:22]) from t where array_ndims(a) = 3;
+ array_sort
+------------------------------------------------------------------------------
+ {{{-20,1},{-123,-9}},{{-20,1},{123,3}},{{2,-11},{2,211}},{{2,112},{2,-123}}}
+(1 row)
+
+SELECT array_sort((t.a) [-13:-11][0:1][21:22]) from t where array_ndims(a) = 3;
+ array_sort
+------------------------------------------------------------
+ {{{-20,1},{-123,-9}},{{-20,1},{123,3}},{{2,112},{2,-123}}}
+(1 row)
+
+SELECT array_sort((t.a) [-13:-11][0:0][20:21]) from t where array_ndims(a) = 3;
+ array_sort
+---------------------------------
+ {{{1,2}},{{10,-20}},{{10,-20}}}
+(1 row)
+
+drop table t;
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 17205f483b..2a40c401b5 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -836,6 +836,8 @@ SELECT array_reverse('{1,2,3,NULL,4,5,6}'::int[]);
SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
-- array_sort
+SELECT array_sort('{1}'::int[]);
+SELECT array_sort('{{2,1}}'::int[]);
SELECT array_sort('{}'::int[]);
SELECT array_sort('{1,3,5,2,4,6}'::int[]);
SELECT array_sort('{1.1,3.3,5.5,2.2,4.4,6.6}'::numeric[]);
@@ -843,4 +845,18 @@ SELECT array_sort('{foo,bar,CCC,Abc,bbc}'::text[] COLLATE "C");
SELECT array_sort('{foo,bar,null,CCC,Abc,bbc}'::text[] COLLATE "C");
-- multidimensional array tests
-SELECT array_sort(ARRAY[[2,4],[2,1],[6,5]]);
\ No newline at end of file
+SELECT array_sort(ARRAY[[2,4],[2,1],[6,5]]);
+create table t(a int[]);
+insert into t values ('[-1:-0]={7,1}'::int[]),
+('[-2:-0][20:21]={{1,2},{10,20},{1,-4}}'),
+('[-2:-0][20:22]={{-11,2,-1},{-11,2, 1},{-11,-4, 10}}'),
+('[-13:-10][0:1][20:22]={
+{{1,2,112},{1,2,-123}},
+{{10,-20,1},{11,123,3}},
+{{10,-20,1},{11,-123,-9}},
+{{1,2,-11},{1,2,211}}}'::int[]);
+SELECT array_sort(t.a) from t;
+SELECT array_sort((t.a) [-13:-10][0:1][21:22]) from t where array_ndims(a) = 3;
+SELECT array_sort((t.a) [-13:-11][0:1][21:22]) from t where array_ndims(a) = 3;
+SELECT array_sort((t.a) [-13:-11][0:0][20:21]) from t where array_ndims(a) = 3;
+drop table t;
\ No newline at end of file
--
2.34.1
From ea85acab5039ef8d23e1e994c9d1d4ae79bdb29e Mon Sep 17 00:00:00 2001
From: jian he <[email protected]>
Date: Tue, 5 Nov 2024 14:40:56 +0800
Subject: [PATCH v12 1/3] general purpose array_sort
Sorts anyarray on its first dimension.
The sort order is determined by the "<" operator.
Signed-off-by: Junwang Zhao <[email protected]>
---
doc/src/sgml/func.sgml | 18 +++
src/backend/utils/adt/array_userfuncs.c | 110 ++++++++++++++++++
src/include/catalog/pg_proc.dat | 3 +
src/test/regress/expected/arrays.out | 38 ++++++
.../regress/expected/collate.icu.utf8.out | 13 +++
src/test/regress/sql/arrays.sql | 10 ++
src/test/regress/sql/collate.icu.utf8.sql | 4 +
src/tools/pgindent/typedefs.list | 1 +
8 files changed, 197 insertions(+)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 73979f20ff..748611dee5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -20438,6 +20438,24 @@ SELECT NULLIF(value, '(none)') ...
</para></entry>
</row>
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>array_sort</primary>
+ </indexterm>
+ <function>array_sort</function> ( <type>anyarray</type> )
+ <returnvalue>anyarray</returnvalue>
+ </para>
+ <para>
+ Sorts the first dimension of the array. The sort order is determined by the <literal><</literal> operator of the element type, nulls will appear after non-null values.
+ The collation to use can be forced by adding a <literal>COLLATE</literal> clause to any of the arguments.
+ </para>
+ <para>
+ <literal>array_sort(ARRAY[[2,4],[2,1],[6,5]])</literal>
+ <returnvalue>{{2,1},{2,4},{6,5}}</returnvalue>
+ </para></entry>
+ </row>
+
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm id="function-array-to-string">
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index d053808f6e..a45586c892 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -16,11 +16,13 @@
#include "common/int.h"
#include "common/pg_prng.h"
#include "libpq/pqformat.h"
+#include "miscadmin.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
+#include "utils/tuplesort.h"
#include "utils/typcache.h"
/*
@@ -1797,3 +1799,111 @@ array_reverse(PG_FUNCTION_ARGS)
PG_RETURN_ARRAYTYPE_P(result);
}
+
+typedef struct ArraySortCachedInfo
+{
+ TypeCacheEntry *typentry;
+ TypeCacheEntry *array_typentry;
+} ArraySortCachedInfo;
+
+/*
+ * array_sort
+ *
+ * Sorts the first dimension of the array.
+ * The sort order is determined by the "<" operator of the element type.
+ */
+Datum
+array_sort(PG_FUNCTION_ARGS)
+{
+ ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
+ Oid elmtyp;
+ Oid array_type;
+ Oid collation = PG_GET_COLLATION();
+ ArraySortCachedInfo *cache_info;
+ TypeCacheEntry *typentry;
+ Tuplesortstate *tuplesortstate;
+ ArrayIterator array_iterator;
+ Datum value;
+ bool isnull;
+ ArrayBuildStateAny *astate = NULL;
+
+ if (ARR_NDIM(array) < 1)
+ PG_RETURN_ARRAYTYPE_P(array);
+
+ elmtyp = ARR_ELEMTYPE(array);
+ cache_info = (ArraySortCachedInfo *) fcinfo->flinfo->fn_extra;
+ if (cache_info == NULL)
+ {
+ cache_info = (ArraySortCachedInfo *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ sizeof(ArraySortCachedInfo));
+ cache_info->typentry = NULL;
+ cache_info->array_typentry = NULL;
+ fcinfo->flinfo->fn_extra = (void *) cache_info;
+ }
+
+ if (ARR_NDIM(array) == 1)
+ {
+ /* Finds the ordering operator for the type for 1-D arrays */
+ typentry = cache_info->typentry;
+ if (typentry == NULL || typentry->type_id != elmtyp)
+ {
+ typentry = lookup_type_cache(elmtyp, TYPECACHE_LT_OPR);
+ if (!OidIsValid(typentry->lt_opr))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify ordering operator for type %s",
+ format_type_be(elmtyp))));
+ cache_info->typentry = typentry;
+ }
+ }
+ else
+ {
+ /* Finds the ordering operator for the array type for multi-D arrays */
+ typentry = cache_info->array_typentry;
+ if (typentry == NULL || typentry->typelem != elmtyp)
+ {
+ array_type = get_array_type(elmtyp);
+ if (!OidIsValid(array_type))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(elmtyp))));
+ typentry = lookup_type_cache(array_type, TYPECACHE_LT_OPR);
+ if (!OidIsValid(typentry->lt_opr))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify ordering operator for type %s",
+ format_type_be(array_type))));
+ cache_info->array_typentry = typentry;
+ }
+ }
+
+ tuplesortstate = tuplesort_begin_datum(typentry->type_id,
+ typentry->lt_opr,
+ collation,
+ false, work_mem, NULL, false);
+
+ array_iterator = array_create_iterator(array, ARR_NDIM(array) - 1, NULL);
+ while (array_iterate(array_iterator, &value, &isnull))
+ {
+ tuplesort_putdatum(tuplesortstate, value, isnull);
+ }
+ array_free_iterator(array_iterator);
+
+ /*
+ * Do the sort.
+ */
+ tuplesort_performsort(tuplesortstate);
+
+ while (tuplesort_getdatum(tuplesortstate, true, false, &value, &isnull, NULL))
+ {
+ astate = accumArrayResultAny(astate, value, isnull,
+ typentry->type_id, CurrentMemoryContext);
+ }
+
+ tuplesort_end(tuplesortstate);
+
+ /* Avoid leaking memory when handed toasted input */
+ PG_FREE_IF_COPY(array, 0);
+ PG_RETURN_DATUM(makeArrayResultAny(astate, CurrentMemoryContext, true));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f23321a41f..54ebbbd135 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1744,6 +1744,9 @@
{ oid => '8686', descr => 'reverse array',
proname => 'array_reverse', prorettype => 'anyarray',
proargtypes => 'anyarray', prosrc => 'array_reverse' },
+{ oid => '8810', descr => 'sort array',
+ proname => 'array_sort', prorettype => 'anyarray',
+ proargtypes => 'anyarray', prosrc => 'array_sort'},
{ oid => '3816', descr => 'array typanalyze',
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
proargtypes => 'internal', prosrc => 'array_typanalyze' },
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 0b61fb5bb7..846d6acd85 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2734,3 +2734,41 @@ SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
{{7,8},{5,6},{3,4},{1,2}}
(1 row)
+-- array_sort
+SELECT array_sort('{}'::int[]);
+ array_sort
+------------
+ {}
+(1 row)
+
+SELECT array_sort('{1,3,5,2,4,6}'::int[]);
+ array_sort
+---------------
+ {1,2,3,4,5,6}
+(1 row)
+
+SELECT array_sort('{1.1,3.3,5.5,2.2,4.4,6.6}'::numeric[]);
+ array_sort
+---------------------------
+ {1.1,2.2,3.3,4.4,5.5,6.6}
+(1 row)
+
+SELECT array_sort('{foo,bar,CCC,Abc,bbc}'::text[] COLLATE "C");
+ array_sort
+-----------------------
+ {Abc,CCC,bar,bbc,foo}
+(1 row)
+
+SELECT array_sort('{foo,bar,null,CCC,Abc,bbc}'::text[] COLLATE "C");
+ array_sort
+----------------------------
+ {Abc,CCC,bar,bbc,foo,NULL}
+(1 row)
+
+-- multidimensional array tests
+SELECT array_sort(ARRAY[[2,4],[2,1],[6,5]]);
+ array_sort
+---------------------
+ {{2,1},{2,4},{6,5}}
+(1 row)
+
diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out
index faa376e060..aa5fd75e6e 100644
--- a/src/test/regress/expected/collate.icu.utf8.out
+++ b/src/test/regress/expected/collate.icu.utf8.out
@@ -1338,6 +1338,19 @@ SELECT 'abc' <= 'ABC' COLLATE case_insensitive, 'abc' >= 'ABC' COLLATE case_inse
t | t
(1 row)
+-- tests with array_sort
+SELECT array_sort('{a,B}'::text[] COLLATE case_insensitive);
+ array_sort
+------------
+ {a,B}
+(1 row)
+
+SELECT array_sort('{a,B}'::text[] COLLATE "C");
+ array_sort
+------------
+ {B,a}
+(1 row)
+
-- test language tags
CREATE COLLATION lt_insensitive (provider = icu, locale = 'en-u-ks-level1', deterministic = false);
SELECT 'aBcD' COLLATE lt_insensitive = 'AbCd' COLLATE lt_insensitive;
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 03cc8cfcd9..17205f483b 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -834,3 +834,13 @@ SELECT array_reverse('{1}'::int[]);
SELECT array_reverse('{1,2}'::int[]);
SELECT array_reverse('{1,2,3,NULL,4,5,6}'::int[]);
SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
+
+-- array_sort
+SELECT array_sort('{}'::int[]);
+SELECT array_sort('{1,3,5,2,4,6}'::int[]);
+SELECT array_sort('{1.1,3.3,5.5,2.2,4.4,6.6}'::numeric[]);
+SELECT array_sort('{foo,bar,CCC,Abc,bbc}'::text[] COLLATE "C");
+SELECT array_sort('{foo,bar,null,CCC,Abc,bbc}'::text[] COLLATE "C");
+
+-- multidimensional array tests
+SELECT array_sort(ARRAY[[2,4],[2,1],[6,5]]);
\ No newline at end of file
diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql
index 80f28a97d7..3c739d332b 100644
--- a/src/test/regress/sql/collate.icu.utf8.sql
+++ b/src/test/regress/sql/collate.icu.utf8.sql
@@ -536,6 +536,10 @@ CREATE COLLATION case_insensitive (provider = icu, locale = '@colStrength=second
SELECT 'abc' <= 'ABC' COLLATE case_sensitive, 'abc' >= 'ABC' COLLATE case_sensitive;
SELECT 'abc' <= 'ABC' COLLATE case_insensitive, 'abc' >= 'ABC' COLLATE case_insensitive;
+-- tests with array_sort
+SELECT array_sort('{a,B}'::text[] COLLATE case_insensitive);
+SELECT array_sort('{a,B}'::text[] COLLATE "C");
+
-- test language tags
CREATE COLLATION lt_insensitive (provider = icu, locale = 'en-u-ks-level1', deterministic = false);
SELECT 'aBcD' COLLATE lt_insensitive = 'AbCd' COLLATE lt_insensitive;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 1847bbfa95..e740e449f5 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -150,6 +150,7 @@ ArrayIOData
ArrayIterator
ArrayMapState
ArrayMetaState
+ArraySortCachedInfo
ArraySubWorkspace
ArrayToken
ArrayType
--
2.34.1