Skip to content

Commit 1fcb977

Browse files
committed
Add generate_subscripts, a series-generation function which generates an
array's subscripts. Pavel Stehule, some editorialization by me.
1 parent a1d479f commit 1fcb977

File tree

7 files changed

+253
-6
lines changed

7 files changed

+253
-6
lines changed

doc/src/sgml/array.sgml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.65 2008/04/27 04:33:27 alvherre Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.66 2008/04/28 14:48:57 alvherre Exp $ -->
22

33
<sect1 id="arrays">
44
<title>Arrays</title>
@@ -542,6 +542,21 @@ SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);
542542

543543
</para>
544544

545+
<para>
546+
Alternatively, the <function>generate_subscripts</> function can be used.
547+
For example:
548+
549+
<programlisting>
550+
SELECT * FROM
551+
(SELECT pay_by_quarter,
552+
generate_subscripts(pay_by_quarter, 1) AS s
553+
FROM sal_emp) AS foo
554+
WHERE pay_by_quarter[s] = 10000;
555+
</programlisting>
556+
557+
This function is described in <xref linkend="functions-srf-subscripts">.
558+
</para>
559+
545560
<tip>
546561
<para>
547562
Arrays are not sets; searching for specific array elements

doc/src/sgml/func.sgml

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.433 2008/04/17 20:56:41 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.434 2008/04/28 14:48:57 alvherre Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -10613,7 +10613,8 @@ AND
1061310613
<para>
1061410614
This section describes functions that possibly return more than one row.
1061510615
Currently the only functions in this class are series generating functions,
10616-
as detailed in <xref linkend="functions-srf-series">.
10616+
as detailed in <xref linkend="functions-srf-series"> and
10617+
<xref linkend="functions-srf-subscripts">.
1061710618
</para>
1061810619

1061910620
<table id="functions-srf-series">
@@ -10691,6 +10692,99 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
1069110692
(3 rows)
1069210693
</programlisting>
1069310694
</para>
10695+
10696+
<table id="functions-srf-subscripts">
10697+
10698+
<indexterm>
10699+
<primary>generate_subscripts</primary>
10700+
</indexterm>
10701+
10702+
<title>Subscripts Generating Functions</title>
10703+
<tgroup cols="3">
10704+
<thead>
10705+
<row>
10706+
<entry>Function</entry>
10707+
<entry>Return Type</entry>
10708+
<entry>Description</entry>
10709+
</row>
10710+
</thead>
10711+
10712+
<tbody>
10713+
<row>
10714+
<entry><literal><function>generate_subscripts</function>(<parameter>array annyarray</parameter>, <parameter>dim int</parameter>)</literal></entry>
10715+
<entry><type>setof int</type></entry>
10716+
<entry>
10717+
Generate a series comprising the given array's subscripts.
10718+
</entry>
10719+
</row>
10720+
10721+
<row>
10722+
<entry><literal><function>generate_subscripts</function>(<parameter>array annyarray</parameter>, <parameter>dim int</parameter>, <parameter>reverse boolean</parameter>)</literal></entry>
10723+
<entry><type>setof int</type></entry>
10724+
<entry>
10725+
Generate a series comprising the given array's subscripts. When
10726+
<parameter>reverse</parameter> is true, the series is returned in
10727+
reverse order.
10728+
</entry>
10729+
</row>
10730+
10731+
</tbody>
10732+
</tgroup>
10733+
</table>
10734+
10735+
<para>
10736+
Zero rows are returned for arrays that do not have the requested dimension,
10737+
or for NULL arrays (but valid subscripts are returned for NULL array
10738+
elements.) Some examples follow:
10739+
<programlisting>
10740+
-- basic usage
10741+
select generate_subscripts('{NULL,1,NULL,2}'::int[], 1) as s;
10742+
s
10743+
---
10744+
1
10745+
2
10746+
3
10747+
4
10748+
(4 rows)
10749+
10750+
-- presenting an array, the subscript and the subscripted
10751+
-- value requires a subquery
10752+
select * from arrays;
10753+
a
10754+
--------------------
10755+
{-1,-2}
10756+
{100,200}
10757+
(2 rows)
10758+
10759+
select a as array, s as subscript, a[s] as value
10760+
from (select generate_subscripts(a, 1) as s, a from arrays) foo;
10761+
array | subscript | value
10762+
-----------+-----------+-------
10763+
{-1,-2} | 1 | -1
10764+
{-1,-2} | 2 | -2
10765+
{100,200} | 1 | 100
10766+
{100,200} | 2 | 200
10767+
(4 rows)
10768+
10769+
-- unnest a 2D array
10770+
create or replace function unnest2(anyarray)
10771+
returns setof anyelement as $$
10772+
select $1[i][j]
10773+
from generate_subscripts($1,1) g1(i),
10774+
generate_subscripts($1,2) g2(j);
10775+
$$ language sql immutable;
10776+
CREATE FUNCTION
10777+
postgres=# select * from unnest2(array[[1,2],[3,4]]);
10778+
unnest2
10779+
---------
10780+
1
10781+
2
10782+
3
10783+
4
10784+
(4 rows)
10785+
</programlisting>
10786+
</para>
10787+
1069410788
</sect1>
1069510789

1069610790
<sect1 id="functions-info">

src/backend/utils/adt/arrayfuncs.c

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.143 2008/04/11 22:52:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.144 2008/04/28 14:48:57 alvherre Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -17,6 +17,7 @@
1717
#include <ctype.h>
1818

1919
#include "access/tupmacs.h"
20+
#include "funcapi.h"
2021
#include "libpq/pqformat.h"
2122
#include "parser/parse_coerce.h"
2223
#include "utils/array.h"
@@ -4231,3 +4232,86 @@ array_smaller(PG_FUNCTION_ARGS)
42314232

42324233
PG_RETURN_ARRAYTYPE_P(result);
42334234
}
4235+
4236+
4237+
typedef struct generate_subscripts_fctx
4238+
{
4239+
int4 lower;
4240+
int4 upper;
4241+
bool reverse;
4242+
} generate_subscripts_fctx;
4243+
4244+
/*
4245+
* generate_subscripts(array anyarray, dim int [, reverse bool])
4246+
* Returns all subscripts of the array for any dimension
4247+
*/
4248+
Datum
4249+
generate_subscripts(PG_FUNCTION_ARGS)
4250+
{
4251+
FuncCallContext *funcctx;
4252+
MemoryContext oldcontext;
4253+
generate_subscripts_fctx *fctx;
4254+
4255+
/* stuff done only on the first call of the function */
4256+
if (SRF_IS_FIRSTCALL())
4257+
{
4258+
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
4259+
int reqdim = PG_GETARG_INT32(1);
4260+
int *lb,
4261+
*dimv;
4262+
4263+
/* create a function context for cross-call persistence */
4264+
funcctx = SRF_FIRSTCALL_INIT();
4265+
4266+
/* Sanity check: does it look like an array at all? */
4267+
if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
4268+
SRF_RETURN_DONE(funcctx);
4269+
4270+
/* Sanity check: was the requested dim valid */
4271+
if (reqdim <= 0 || reqdim > ARR_NDIM(v))
4272+
SRF_RETURN_DONE(funcctx);
4273+
4274+
/*
4275+
* switch to memory context appropriate for multiple function calls
4276+
*/
4277+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4278+
fctx = (generate_subscripts_fctx *) palloc(sizeof(generate_subscripts_fctx));
4279+
4280+
lb = ARR_LBOUND(v);
4281+
dimv = ARR_DIMS(v);
4282+
4283+
fctx->lower = lb[reqdim - 1];
4284+
fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
4285+
fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
4286+
4287+
funcctx->user_fctx = fctx;
4288+
4289+
MemoryContextSwitchTo(oldcontext);
4290+
}
4291+
4292+
funcctx = SRF_PERCALL_SETUP();
4293+
4294+
fctx = funcctx->user_fctx;
4295+
4296+
if (fctx->lower <= fctx->upper)
4297+
{
4298+
if (!fctx->reverse)
4299+
SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
4300+
else
4301+
SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
4302+
}
4303+
else
4304+
/* done when there are no more elements left */
4305+
SRF_RETURN_DONE(funcctx);
4306+
}
4307+
4308+
/*
4309+
* generate_subscripts_nodir
4310+
* Implements the 2-argument version of generate_subscripts
4311+
*/
4312+
Datum
4313+
generate_subscripts_nodir(PG_FUNCTION_ARGS)
4314+
{
4315+
/* just call the other one -- it can handle both cases */
4316+
return generate_subscripts(fcinfo);
4317+
}

src/include/catalog/pg_proc.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.492 2008/04/17 20:56:41 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.493 2008/04/28 14:48:57 alvherre Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -1010,6 +1010,11 @@ DATA(insert OID = 515 ( array_larger PGNSP PGUID 12 1 0 f f t f i 2 2277 "22
10101010
DESCR("larger of two");
10111011
DATA(insert OID = 516 ( array_smaller PGNSP PGUID 12 1 0 f f t f i 2 2277 "2277 2277" _null_ _null_ _null_ array_smaller - _null_ _null_ ));
10121012
DESCR("smaller of two");
1013+
DATA(insert OID = 1191 ( generate_subscripts PGNSP PGUID 12 1 1000 f f t t v 3 23 "2277 23 16" _null_ _null_ _null_ generate_subscripts - _null_ _null_ ));
1014+
DESCR("array subscripts generator");
1015+
DATA(insert OID = 1192 ( generate_subscripts PGNSP PGUID 12 1 1000 f f t t v 2 23 "2277 23" _null_ _null_ _null_ generate_subscripts_nodir - _null_ _null_ ));
1016+
DESCR("array subscripts generator");
1017+
10131018

10141019
DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 1 0 f f t f s 1 210 "2275" _null_ _null_ _null_ smgrin - _null_ _null_ ));
10151020
DESCR("I/O");

src/include/utils/array.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
5050
* Portions Copyright (c) 1994, Regents of the University of California
5151
*
52-
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.66 2008/01/01 19:45:59 momjian Exp $
52+
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.67 2008/04/28 14:48:57 alvherre Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -200,6 +200,8 @@ extern Datum array_lower(PG_FUNCTION_ARGS);
200200
extern Datum array_upper(PG_FUNCTION_ARGS);
201201
extern Datum array_larger(PG_FUNCTION_ARGS);
202202
extern Datum array_smaller(PG_FUNCTION_ARGS);
203+
extern Datum generate_subscripts(PG_FUNCTION_ARGS);
204+
extern Datum generate_subscripts_nodir(PG_FUNCTION_ARGS);
203205

204206
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
205207
int arraytyplen, int elmlen, bool elmbyval, char elmalign,

src/test/regress/expected/arrays.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,3 +903,33 @@ select c2[2].f2 from comptable;
903903
drop type _comptype;
904904
drop table comptable;
905905
drop type comptype;
906+
create or replace function unnest1(anyarray)
907+
returns setof anyelement as $$
908+
select $1[s] from generate_subscripts($1,1) g(s);
909+
$$ language sql immutable;
910+
create or replace function unnest2(anyarray)
911+
returns setof anyelement as $$
912+
select $1[s1][s2] from generate_subscripts($1,1) g1(s1),
913+
generate_subscripts($1,2) g2(s2);
914+
$$ language sql immutable;
915+
select * from unnest1(array[1,2,3]);
916+
unnest1
917+
---------
918+
1
919+
2
920+
3
921+
(3 rows)
922+
923+
select * from unnest2(array[[1,2,3],[4,5,6]]);
924+
unnest2
925+
---------
926+
1
927+
2
928+
3
929+
4
930+
5
931+
6
932+
(6 rows)
933+
934+
drop function unnest1(anyarray);
935+
drop function unnest2(anyarray);

src/test/regress/sql/arrays.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,20 @@ select c2[2].f2 from comptable;
340340
drop type _comptype;
341341
drop table comptable;
342342
drop type comptype;
343+
344+
create or replace function unnest1(anyarray)
345+
returns setof anyelement as $$
346+
select $1[s] from generate_subscripts($1,1) g(s);
347+
$$ language sql immutable;
348+
349+
create or replace function unnest2(anyarray)
350+
returns setof anyelement as $$
351+
select $1[s1][s2] from generate_subscripts($1,1) g1(s1),
352+
generate_subscripts($1,2) g2(s2);
353+
$$ language sql immutable;
354+
355+
select * from unnest1(array[1,2,3]);
356+
select * from unnest2(array[[1,2,3],[4,5,6]]);
357+
358+
drop function unnest1(anyarray);
359+
drop function unnest2(anyarray);

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