Skip to content

Commit 49d6c7d

Browse files
committed
Add SQL function array_reverse()
This function takes in input an array, and reverses the position of all its elements. This operation only affects the first dimension of the array, like array_shuffle(). The implementation structure is inspired by array_shuffle(), with a subroutine called array_reverse_n() that may come in handy in the future, should more functions able to reverse portions of arrays be introduced. Bump catalog version. Author: Aleksander Alekseev Reviewed-by: Ashutosh Bapat, Tom Lane, Vladlen Popolitov Discussion: https://postgr.es/m/CAJ7c6TMpeO_ke+QGOaAx9xdJuxa7r=49-anMh3G5476e3CX1CA@mail.gmail.com
1 parent 2d8bff6 commit 49d6c7d

File tree

6 files changed

+171
-1
lines changed

6 files changed

+171
-1
lines changed

doc/src/sgml/func.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20379,6 +20379,23 @@ SELECT NULLIF(value, '(none)') ...
2037920379
</para></entry>
2038020380
</row>
2038120381

20382+
<row>
20383+
<entry role="func_table_entry"><para role="func_signature">
20384+
<indexterm>
20385+
<primary>array_reverse</primary>
20386+
</indexterm>
20387+
<function>array_reverse</function> ( <type>anyarray</type> )
20388+
<returnvalue>anyarray</returnvalue>
20389+
</para>
20390+
<para>
20391+
Reverses the first dimension of the array.
20392+
</para>
20393+
<para>
20394+
<literal>array_reverse(ARRAY[[1,2],[3,4],[5,6]])</literal>
20395+
<returnvalue>{{5,6},{3,4},{1,2}}</returnvalue>
20396+
</para></entry>
20397+
</row>
20398+
2038220399
<row>
2038320400
<entry role="func_table_entry"><para role="func_signature">
2038420401
<indexterm>

src/backend/utils/adt/array_userfuncs.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,3 +1685,115 @@ array_sample(PG_FUNCTION_ARGS)
16851685

16861686
PG_RETURN_ARRAYTYPE_P(result);
16871687
}
1688+
1689+
1690+
/*
1691+
* array_reverse_n
1692+
* Return a copy of array with reversed items.
1693+
*
1694+
* NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
1695+
* from the system catalogs, given only the elmtyp. However, the caller is
1696+
* in a better position to cache this info across multiple calls.
1697+
*/
1698+
static ArrayType *
1699+
array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)
1700+
{
1701+
ArrayType *result;
1702+
int ndim,
1703+
*dims,
1704+
*lbs,
1705+
nelm,
1706+
nitem,
1707+
rdims[MAXDIM],
1708+
rlbs[MAXDIM];
1709+
int16 elmlen;
1710+
bool elmbyval;
1711+
char elmalign;
1712+
Datum *elms,
1713+
*ielms;
1714+
bool *nuls,
1715+
*inuls;
1716+
1717+
ndim = ARR_NDIM(array);
1718+
dims = ARR_DIMS(array);
1719+
lbs = ARR_LBOUND(array);
1720+
1721+
elmlen = typentry->typlen;
1722+
elmbyval = typentry->typbyval;
1723+
elmalign = typentry->typalign;
1724+
1725+
deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
1726+
&elms, &nuls, &nelm);
1727+
1728+
nitem = dims[0]; /* total number of items */
1729+
nelm /= nitem; /* number of elements per item */
1730+
1731+
/* Reverse the array */
1732+
ielms = elms;
1733+
inuls = nuls;
1734+
for (int i = 0; i < nitem / 2; i++)
1735+
{
1736+
int j = (nitem - i - 1) * nelm;
1737+
Datum *jelms = elms + j;
1738+
bool *jnuls = nuls + j;
1739+
1740+
/* Swap i'th and j'th items; advance ielms/inuls to next item */
1741+
for (int k = 0; k < nelm; k++)
1742+
{
1743+
Datum elm = *ielms;
1744+
bool nul = *inuls;
1745+
1746+
*ielms++ = *jelms;
1747+
*inuls++ = *jnuls;
1748+
*jelms++ = elm;
1749+
*jnuls++ = nul;
1750+
}
1751+
}
1752+
1753+
/* Set up dimensions of the result */
1754+
memcpy(rdims, dims, ndim * sizeof(int));
1755+
memcpy(rlbs, lbs, ndim * sizeof(int));
1756+
rdims[0] = nitem;
1757+
1758+
result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
1759+
elmtyp, elmlen, elmbyval, elmalign);
1760+
1761+
pfree(elms);
1762+
pfree(nuls);
1763+
1764+
return result;
1765+
}
1766+
1767+
/*
1768+
* array_reverse
1769+
*
1770+
* Returns an array with the same dimensions as the input array, with its
1771+
* first-dimension elements in reverse order.
1772+
*/
1773+
Datum
1774+
array_reverse(PG_FUNCTION_ARGS)
1775+
{
1776+
ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
1777+
ArrayType *result;
1778+
Oid elmtyp;
1779+
TypeCacheEntry *typentry;
1780+
1781+
/*
1782+
* There is no point in reversing empty arrays or arrays with less than
1783+
* two items.
1784+
*/
1785+
if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
1786+
PG_RETURN_ARRAYTYPE_P(array);
1787+
1788+
elmtyp = ARR_ELEMTYPE(array);
1789+
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
1790+
if (typentry == NULL || typentry->type_id != elmtyp)
1791+
{
1792+
typentry = lookup_type_cache(elmtyp, 0);
1793+
fcinfo->flinfo->fn_extra = (void *) typentry;
1794+
}
1795+
1796+
result = array_reverse_n(array, elmtyp, typentry);
1797+
1798+
PG_RETURN_ARRAYTYPE_P(result);
1799+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202410311
60+
#define CATALOG_VERSION_NO 202411011
6161

6262
#endif

src/include/catalog/pg_proc.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,9 @@
17411741
{ oid => '6216', descr => 'take samples from array',
17421742
proname => 'array_sample', provolatile => 'v', prorettype => 'anyarray',
17431743
proargtypes => 'anyarray int4', prosrc => 'array_sample' },
1744+
{ oid => '8686', descr => 'reverse array',
1745+
proname => 'array_reverse', prorettype => 'anyarray',
1746+
proargtypes => 'anyarray', prosrc => 'array_reverse' },
17441747
{ oid => '3816', descr => 'array typanalyze',
17451748
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
17461749
proargtypes => 'internal', prosrc => 'array_typanalyze' },

src/test/regress/expected/arrays.out

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2703,3 +2703,34 @@ SELECT array_sample('{1,2,3,4,5,6}'::int[], -1); -- fail
27032703
ERROR: sample size must be between 0 and 6
27042704
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
27052705
ERROR: sample size must be between 0 and 6
2706+
-- array_reverse
2707+
SELECT array_reverse('{}'::int[]);
2708+
array_reverse
2709+
---------------
2710+
{}
2711+
(1 row)
2712+
2713+
SELECT array_reverse('{1}'::int[]);
2714+
array_reverse
2715+
---------------
2716+
{1}
2717+
(1 row)
2718+
2719+
SELECT array_reverse('{1,2}'::int[]);
2720+
array_reverse
2721+
---------------
2722+
{2,1}
2723+
(1 row)
2724+
2725+
SELECT array_reverse('{1,2,3,NULL,4,5,6}'::int[]);
2726+
array_reverse
2727+
--------------------
2728+
{6,5,4,NULL,3,2,1}
2729+
(1 row)
2730+
2731+
SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
2732+
array_reverse
2733+
---------------------------
2734+
{{7,8},{5,6},{3,4},{1,2}}
2735+
(1 row)
2736+

src/test/regress/sql/arrays.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,3 +827,10 @@ SELECT array_dims(array_sample('[-1:2][2:3]={{1,2},{3,NULL},{5,6},{7,8}}'::int[]
827827
SELECT array_dims(array_sample('{{{1,2},{3,NULL}},{{5,6},{7,8}},{{9,10},{11,12}}}'::int[], 2));
828828
SELECT array_sample('{1,2,3,4,5,6}'::int[], -1); -- fail
829829
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
830+
831+
-- array_reverse
832+
SELECT array_reverse('{}'::int[]);
833+
SELECT array_reverse('{1}'::int[]);
834+
SELECT array_reverse('{1,2}'::int[]);
835+
SELECT array_reverse('{1,2,3,NULL,4,5,6}'::int[]);
836+
SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);

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