Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)