Skip to content

Commit 0a687c8

Browse files
committed
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
1 parent 3769e11 commit 0a687c8

File tree

7 files changed

+100
-2
lines changed

7 files changed

+100
-2
lines changed

doc/src/sgml/func.sgml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17930,6 +17930,24 @@ SELECT NULLIF(value, '(none)') ...
1793017930
</para></entry>
1793117931
</row>
1793217932

17933+
<row>
17934+
<entry role="func_table_entry"><para role="func_signature">
17935+
<indexterm>
17936+
<primary>trim_array</primary>
17937+
</indexterm>
17938+
<function>trim_array</function> ( <parameter>array</parameter> <type>anyarray</type>, <parameter>n</parameter> <type>integer</type> )
17939+
<returnvalue>anyarray</returnvalue>
17940+
</para>
17941+
<para>
17942+
Trims an array by removing the last <parameter>n</parameter> elements.
17943+
If the array is multidimensional, only the first dimension is trimmed.
17944+
</para>
17945+
<para>
17946+
<literal>trim_array(ARRAY[1,2,3,4,5,6], 2)</literal>
17947+
<returnvalue>{1,2,3,4}</returnvalue>
17948+
</para></entry>
17949+
</row>
17950+
1793317951
<row>
1793417952
<entry role="func_table_entry"><para role="func_signature">
1793517953
<indexterm>

src/backend/catalog/sql_features.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ S301 Enhanced UNNEST YES
398398
S401 Distinct types based on array types NO
399399
S402 Distinct types based on distinct types NO
400400
S403 ARRAY_MAX_CARDINALITY NO
401-
S404 TRIM_ARRAY NO
401+
S404 TRIM_ARRAY YES
402402
T011 Timestamp in Information Schema NO
403403
T021 BINARY and VARBINARY data types NO
404404
T022 Advanced support for BINARY and VARBINARY data types NO

src/backend/utils/adt/arrayfuncs.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6631,3 +6631,46 @@ width_bucket_array_variable(Datum operand,
66316631

66326632
return left;
66336633
}
6634+
6635+
/*
6636+
* Trim the last N elements from an array by building an appropriate slice.
6637+
* Only the first dimension is trimmed.
6638+
*/
6639+
Datum
6640+
trim_array(PG_FUNCTION_ARGS)
6641+
{
6642+
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
6643+
int n = PG_GETARG_INT32(1);
6644+
int array_length = ARR_DIMS(v)[0];
6645+
int16 elmlen;
6646+
bool elmbyval;
6647+
char elmalign;
6648+
int lower[MAXDIM];
6649+
int upper[MAXDIM];
6650+
bool lowerProvided[MAXDIM];
6651+
bool upperProvided[MAXDIM];
6652+
Datum result;
6653+
6654+
/* Per spec, throw an error if out of bounds */
6655+
if (n < 0 || n > array_length)
6656+
ereport(ERROR,
6657+
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
6658+
errmsg("number of elements to trim must be between 0 and %d",
6659+
array_length)));
6660+
6661+
/* Set all the bounds as unprovided except the first upper bound */
6662+
memset(lowerProvided, false, sizeof(lowerProvided));
6663+
memset(upperProvided, false, sizeof(upperProvided));
6664+
upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
6665+
upperProvided[0] = true;
6666+
6667+
/* Fetch the needed information about the element type */
6668+
get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
6669+
6670+
/* Get the slice */
6671+
result = array_get_slice(PointerGetDatum(v), 1,
6672+
upper, lower, upperProvided, lowerProvided,
6673+
-1, elmlen, elmbyval, elmalign);
6674+
6675+
PG_RETURN_DATUM(result);
6676+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 202103031
56+
#define CATALOG_VERSION_NO 202103032
5757

5858
#endif

src/include/catalog/pg_proc.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,9 @@
16631663
proname => 'width_bucket', prorettype => 'int4',
16641664
proargtypes => 'anycompatible anycompatiblearray',
16651665
prosrc => 'width_bucket_array' },
1666+
{ oid => '8819', descr => 'remove last N elements of array',
1667+
proname => 'trim_array', prorettype => 'anyarray',
1668+
proargtypes => 'anyarray int4', prosrc => 'trim_array' },
16661669
{ oid => '3816', descr => 'array typanalyze',
16671670
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
16681671
proargtypes => 'internal', prosrc => 'array_typanalyze' },

src/test/regress/expected/arrays.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,3 +2399,24 @@ SELECT width_bucket(5, ARRAY[3, 4, NULL]);
23992399
ERROR: thresholds array must not contain NULLs
24002400
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
24012401
ERROR: thresholds must be one-dimensional array
2402+
-- trim_array
2403+
SELECT arr, trim_array(arr, 2)
2404+
FROM
2405+
(VALUES ('{1,2,3,4,5,6}'::bigint[]),
2406+
('{1,2}'),
2407+
('[10:16]={1,2,3,4,5,6,7}'),
2408+
('[-15:-10]={1,2,3,4,5,6}'),
2409+
('{{1,10},{2,20},{3,30},{4,40}}')) v(arr);
2410+
arr | trim_array
2411+
-------------------------------+-----------------
2412+
{1,2,3,4,5,6} | {1,2,3,4}
2413+
{1,2} | {}
2414+
[10:16]={1,2,3,4,5,6,7} | {1,2,3,4,5}
2415+
[-15:-10]={1,2,3,4,5,6} | {1,2,3,4}
2416+
{{1,10},{2,20},{3,30},{4,40}} | {{1,10},{2,20}}
2417+
(5 rows)
2418+
2419+
SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
2420+
ERROR: number of elements to trim must be between 0 and 3
2421+
SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail
2422+
ERROR: number of elements to trim must be between 0 and 3

src/test/regress/sql/arrays.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,3 +722,16 @@ SELECT width_bucket(5, '{}');
722722
SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
723723
SELECT width_bucket(5, ARRAY[3, 4, NULL]);
724724
SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
725+
726+
-- trim_array
727+
728+
SELECT arr, trim_array(arr, 2)
729+
FROM
730+
(VALUES ('{1,2,3,4,5,6}'::bigint[]),
731+
('{1,2}'),
732+
('[10:16]={1,2,3,4,5,6,7}'),
733+
('[-15:-10]={1,2,3,4,5,6}'),
734+
('{{1,10},{2,20},{3,30},{4,40}}')) v(arr);
735+
736+
SELECT trim_array(ARRAY[1, 2, 3], -1); -- fail
737+
SELECT trim_array(ARRAY[1, 2, 3], 10); -- fail

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy