mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
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
This commit is contained in:
@ -20379,6 +20379,23 @@ SELECT NULLIF(value, '(none)') ...
|
|||||||
</para></entry>
|
</para></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
|
<indexterm>
|
||||||
|
<primary>array_reverse</primary>
|
||||||
|
</indexterm>
|
||||||
|
<function>array_reverse</function> ( <type>anyarray</type> )
|
||||||
|
<returnvalue>anyarray</returnvalue>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Reverses the first dimension of the array.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<literal>array_reverse(ARRAY[[1,2],[3,4],[5,6]])</literal>
|
||||||
|
<returnvalue>{{5,6},{3,4},{1,2}}</returnvalue>
|
||||||
|
</para></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry role="func_table_entry"><para role="func_signature">
|
<entry role="func_table_entry"><para role="func_signature">
|
||||||
<indexterm>
|
<indexterm>
|
||||||
|
@ -1685,3 +1685,115 @@ array_sample(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_ARRAYTYPE_P(result);
|
PG_RETURN_ARRAYTYPE_P(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* array_reverse_n
|
||||||
|
* Return a copy of array with reversed items.
|
||||||
|
*
|
||||||
|
* NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
|
||||||
|
* from the system catalogs, given only the elmtyp. However, the caller is
|
||||||
|
* in a better position to cache this info across multiple calls.
|
||||||
|
*/
|
||||||
|
static ArrayType *
|
||||||
|
array_reverse_n(ArrayType *array, Oid elmtyp, TypeCacheEntry *typentry)
|
||||||
|
{
|
||||||
|
ArrayType *result;
|
||||||
|
int ndim,
|
||||||
|
*dims,
|
||||||
|
*lbs,
|
||||||
|
nelm,
|
||||||
|
nitem,
|
||||||
|
rdims[MAXDIM],
|
||||||
|
rlbs[MAXDIM];
|
||||||
|
int16 elmlen;
|
||||||
|
bool elmbyval;
|
||||||
|
char elmalign;
|
||||||
|
Datum *elms,
|
||||||
|
*ielms;
|
||||||
|
bool *nuls,
|
||||||
|
*inuls;
|
||||||
|
|
||||||
|
ndim = ARR_NDIM(array);
|
||||||
|
dims = ARR_DIMS(array);
|
||||||
|
lbs = ARR_LBOUND(array);
|
||||||
|
|
||||||
|
elmlen = typentry->typlen;
|
||||||
|
elmbyval = typentry->typbyval;
|
||||||
|
elmalign = typentry->typalign;
|
||||||
|
|
||||||
|
deconstruct_array(array, elmtyp, elmlen, elmbyval, elmalign,
|
||||||
|
&elms, &nuls, &nelm);
|
||||||
|
|
||||||
|
nitem = dims[0]; /* total number of items */
|
||||||
|
nelm /= nitem; /* number of elements per item */
|
||||||
|
|
||||||
|
/* Reverse the array */
|
||||||
|
ielms = elms;
|
||||||
|
inuls = nuls;
|
||||||
|
for (int i = 0; i < nitem / 2; i++)
|
||||||
|
{
|
||||||
|
int j = (nitem - i - 1) * nelm;
|
||||||
|
Datum *jelms = elms + j;
|
||||||
|
bool *jnuls = nuls + j;
|
||||||
|
|
||||||
|
/* Swap i'th and j'th items; advance ielms/inuls to next item */
|
||||||
|
for (int k = 0; k < nelm; k++)
|
||||||
|
{
|
||||||
|
Datum elm = *ielms;
|
||||||
|
bool nul = *inuls;
|
||||||
|
|
||||||
|
*ielms++ = *jelms;
|
||||||
|
*inuls++ = *jnuls;
|
||||||
|
*jelms++ = elm;
|
||||||
|
*jnuls++ = nul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up dimensions of the result */
|
||||||
|
memcpy(rdims, dims, ndim * sizeof(int));
|
||||||
|
memcpy(rlbs, lbs, ndim * sizeof(int));
|
||||||
|
rdims[0] = nitem;
|
||||||
|
|
||||||
|
result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
|
||||||
|
elmtyp, elmlen, elmbyval, elmalign);
|
||||||
|
|
||||||
|
pfree(elms);
|
||||||
|
pfree(nuls);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* array_reverse
|
||||||
|
*
|
||||||
|
* Returns an array with the same dimensions as the input array, with its
|
||||||
|
* first-dimension elements in reverse order.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
array_reverse(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
|
||||||
|
ArrayType *result;
|
||||||
|
Oid elmtyp;
|
||||||
|
TypeCacheEntry *typentry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no point in reversing empty arrays or arrays with less than
|
||||||
|
* two items.
|
||||||
|
*/
|
||||||
|
if (ARR_NDIM(array) < 1 || ARR_DIMS(array)[0] < 2)
|
||||||
|
PG_RETURN_ARRAYTYPE_P(array);
|
||||||
|
|
||||||
|
elmtyp = ARR_ELEMTYPE(array);
|
||||||
|
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
||||||
|
if (typentry == NULL || typentry->type_id != elmtyp)
|
||||||
|
{
|
||||||
|
typentry = lookup_type_cache(elmtyp, 0);
|
||||||
|
fcinfo->flinfo->fn_extra = (void *) typentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = array_reverse_n(array, elmtyp, typentry);
|
||||||
|
|
||||||
|
PG_RETURN_ARRAYTYPE_P(result);
|
||||||
|
}
|
||||||
|
@ -57,6 +57,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202410311
|
#define CATALOG_VERSION_NO 202411011
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1741,6 +1741,9 @@
|
|||||||
{ oid => '6216', descr => 'take samples from array',
|
{ oid => '6216', descr => 'take samples from array',
|
||||||
proname => 'array_sample', provolatile => 'v', prorettype => 'anyarray',
|
proname => 'array_sample', provolatile => 'v', prorettype => 'anyarray',
|
||||||
proargtypes => 'anyarray int4', prosrc => 'array_sample' },
|
proargtypes => 'anyarray int4', prosrc => 'array_sample' },
|
||||||
|
{ oid => '8686', descr => 'reverse array',
|
||||||
|
proname => 'array_reverse', prorettype => 'anyarray',
|
||||||
|
proargtypes => 'anyarray', prosrc => 'array_reverse' },
|
||||||
{ oid => '3816', descr => 'array typanalyze',
|
{ oid => '3816', descr => 'array typanalyze',
|
||||||
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
|
proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool',
|
||||||
proargtypes => 'internal', prosrc => 'array_typanalyze' },
|
proargtypes => 'internal', prosrc => 'array_typanalyze' },
|
||||||
|
@ -2703,3 +2703,34 @@ SELECT array_sample('{1,2,3,4,5,6}'::int[], -1); -- fail
|
|||||||
ERROR: sample size must be between 0 and 6
|
ERROR: sample size must be between 0 and 6
|
||||||
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
|
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
|
||||||
ERROR: sample size must be between 0 and 6
|
ERROR: sample size must be between 0 and 6
|
||||||
|
-- array_reverse
|
||||||
|
SELECT array_reverse('{}'::int[]);
|
||||||
|
array_reverse
|
||||||
|
---------------
|
||||||
|
{}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT array_reverse('{1}'::int[]);
|
||||||
|
array_reverse
|
||||||
|
---------------
|
||||||
|
{1}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT array_reverse('{1,2}'::int[]);
|
||||||
|
array_reverse
|
||||||
|
---------------
|
||||||
|
{2,1}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT array_reverse('{1,2,3,NULL,4,5,6}'::int[]);
|
||||||
|
array_reverse
|
||||||
|
--------------------
|
||||||
|
{6,5,4,NULL,3,2,1}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT array_reverse('{{1,2},{3,4},{5,6},{7,8}}'::int[]);
|
||||||
|
array_reverse
|
||||||
|
---------------------------
|
||||||
|
{{7,8},{5,6},{3,4},{1,2}}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -827,3 +827,10 @@ SELECT array_dims(array_sample('[-1:2][2:3]={{1,2},{3,NULL},{5,6},{7,8}}'::int[]
|
|||||||
SELECT array_dims(array_sample('{{{1,2},{3,NULL}},{{5,6},{7,8}},{{9,10},{11,12}}}'::int[], 2));
|
SELECT array_dims(array_sample('{{{1,2},{3,NULL}},{{5,6},{7,8}},{{9,10},{11,12}}}'::int[], 2));
|
||||||
SELECT array_sample('{1,2,3,4,5,6}'::int[], -1); -- fail
|
SELECT array_sample('{1,2,3,4,5,6}'::int[], -1); -- fail
|
||||||
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
|
SELECT array_sample('{1,2,3,4,5,6}'::int[], 7); --fail
|
||||||
|
|
||||||
|
-- array_reverse
|
||||||
|
SELECT array_reverse('{}'::int[]);
|
||||||
|
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[]);
|
Reference in New Issue
Block a user