aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-03-03 16:39:57 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2021-03-03 16:39:57 -0500
commit0a687c8f103d217ff1ca8c34a644b380d89bb0ad (patch)
tree6406e23e84feca1351f879b7ddaaa9edafb4cf6a /src
parent3769e11a31831fc2f3bd4c4a24b4f45c352fb8fb (diff)
downloadpostgresql-0a687c8f103d217ff1ca8c34a644b380d89bb0ad.tar.gz
postgresql-0a687c8f103d217ff1ca8c34a644b380d89bb0ad.zip
Add trim_array() function.
This has been in the SQL spec since 2008. It's a pretty thin wrapper around the array slice functionality, but the spec says we should have it, so here it is. Vik Fearing, reviewed by Dian Fay Discussion: https://postgr.es/m/fc92ce17-9655-8ff1-c62a-4dc4c8ccd815@postgresfriends.org
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/sql_features.txt2
-rw-r--r--src/backend/utils/adt/arrayfuncs.c43
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat3
-rw-r--r--src/test/regress/expected/arrays.out21
-rw-r--r--src/test/regress/sql/arrays.sql13
6 files changed, 82 insertions, 2 deletions
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index ab0895ce3c8..32eed988ab0 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -398,7 +398,7 @@ S301 Enhanced UNNEST YES
S401 Distinct types based on array types NO
S402 Distinct types based on distinct types NO
S403 ARRAY_MAX_CARDINALITY NO
-S404 TRIM_ARRAY NO
+S404 TRIM_ARRAY YES
T011 Timestamp in Information Schema NO
T021 BINARY and VARBINARY data types NO
T022 Advanced support for BINARY and VARBINARY data types NO
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index f7012cc5d98..17a16b4c5cc 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -6631,3 +6631,46 @@ width_bucket_array_variable(Datum operand,
return left;
}
+
+/*
+ * Trim the last N elements from an array by building an appropriate slice.
+ * Only the first dimension is trimmed.
+ */
+Datum
+trim_array(PG_FUNCTION_ARGS)
+{
+ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ int n = PG_GETARG_INT32(1);
+ int array_length = ARR_DIMS(v)[0];
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
+ int lower[MAXDIM];
+ int upper[MAXDIM];
+ bool lowerProvided[MAXDIM];
+ bool upperProvided[MAXDIM];
+ Datum result;
+
+ /* Per spec, throw an error if out of bounds */
+ if (n < 0 || n > array_length)
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+ errmsg("number of elements to trim must be between 0 and %d",
+ array_length)));
+
+ /* Set all the bounds as unprovided except the first upper bound */
+ memset(lowerProvided, false, sizeof(lowerProvided));
+ memset(upperProvided, false, sizeof(upperProvided));
+ upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
+ upperProvided[0] = true;
+
+ /* Fetch the needed information about the element type */
+ get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
+
+ /* Get the slice */
+ result = array_get_slice(PointerGetDatum(v), 1,
+ upper, lower, upperProvided, lowerProvided,
+ -1, elmlen, elmbyval, elmalign);
+
+ PG_RETURN_DATUM(result);
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index b19975c5c89..28b8a32129c 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202103031
+#define CATALOG_VERSION_NO 202103032
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3d3974f4676..59d2b71ca9c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1663,6 +1663,9 @@
proname => 'width_bucket', prorettype => 'int4',
proargtypes => 'anycompatible anycompatiblearray',
prosrc => 'width_bucket_array' },
+{ oid => '8819', descr => 'remove last N elements of array',
+ proname => 'trim_array', prorettype => 'anyarray',
+ proargtypes => 'anyarray int4', prosrc => 'trim_array' },
{ 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 8bc7721e7d5..3e3a1beaab3 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2399,3 +2399,24 @@ SELECT width_bucket(5, ARRAY[3, 4, NULL]);
ERROR: thresholds array must not contain NULLs
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
ERROR: thresholds must be one-dimensional array
+-- trim_array
+SELECT arr, trim_array(arr, 2)
+FROM
+(VALUES ('{1,2,3,4,5,6}'::bigint[]),
+ ('{1,2}'),
+ ('[10:16]={1,2,3,4,5,6,7}'),
+ ('[-15:-10]={1,2,3,4,5,6}'),
+ ('{{1,10},{2,20},{3,30},{4,40}}')) v(arr);
+ arr | trim_array
+-------------------------------+-----------------
+ {1,2,3,4,5,6} | {1,2,3,4}
+ {1,2} | {}
+ [10:16]={1,2,3,4,5,6,7} | {1,2,3,4,5}
+ [-15:-10]={1,2,3,4,5,6} | {1,2,3,4}
+ {{1,10},{2,20},{3,30},{4,40}} | {{1,10},{2,20}}
+(5 rows)
+
+SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
+ERROR: number of elements to trim must be between 0 and 3
+SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail
+ERROR: number of elements to trim must be between 0 and 3
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index c40619a8d5d..912233ef968 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -722,3 +722,16 @@ SELECT width_bucket(5, '{}');
SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
SELECT width_bucket(5, ARRAY[3, 4, NULL]);
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
+
+-- trim_array
+
+SELECT arr, trim_array(arr, 2)
+FROM
+(VALUES ('{1,2,3,4,5,6}'::bigint[]),
+ ('{1,2}'),
+ ('[10:16]={1,2,3,4,5,6,7}'),
+ ('[-15:-10]={1,2,3,4,5,6}'),
+ ('{{1,10},{2,20},{3,30},{4,40}}')) v(arr);
+
+SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
+SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail