<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="cs">
	<id>http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=Iter%C3%A1tor_pole</id>
	<title>Iterátor pole - Historie editací</title>
	<link rel="self" type="application/atom+xml" href="http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=Iter%C3%A1tor_pole"/>
	<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=Iter%C3%A1tor_pole&amp;action=history"/>
	<updated>2026-05-20T17:37:01Z</updated>
	<subtitle>Historie editací této stránky</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>http://postgres.cz/index.php?title=Iter%C3%A1tor_pole&amp;diff=362&amp;oldid=prev</id>
		<title>imported&gt;Pavel v 7. 3. 2012, 22:07</title>
		<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=Iter%C3%A1tor_pole&amp;diff=362&amp;oldid=prev"/>
		<updated>2012-03-07T22:07:39Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nová stránka&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Ukázka tabulkové funkce typu SFRM_Materialize&lt;br /&gt;
&lt;br /&gt;
Funkce vrací celočíselnou řadu odpovídající indexům zadaného pole:&lt;br /&gt;
&amp;lt;pre&amp;gt;Datum array_subscripts(PG_FUNCTION_ARGS);&lt;br /&gt;
PG_FUNCTION_INFO_V1(array_subscripts);&lt;br /&gt;
&lt;br /&gt;
Datum&lt;br /&gt;
array_subscripts(PG_FUNCTION_ARGS)&lt;br /&gt;
{&lt;br /&gt;
        ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo-&amp;gt;resultinfo;&lt;br /&gt;
        ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);&lt;br /&gt;
        TupleDesc       tupdesc;&lt;br /&gt;
        Tuplestorestate *tupstore;&lt;br /&gt;
        MemoryContext per_query_ctx;&lt;br /&gt;
        MemoryContext oldcontext;&lt;br /&gt;
        int reqdim;&lt;br /&gt;
        int     *lb, *dimv;&lt;br /&gt;
        int     lower, upper;&lt;br /&gt;
        bool reverse;&lt;br /&gt;
        int i;&lt;br /&gt;
&lt;br /&gt;
       /* check to see if caller supports us returning a tuplestore */&lt;br /&gt;
        if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))&lt;br /&gt;
                ereport(ERROR,&lt;br /&gt;
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),&lt;br /&gt;
                                 errmsg(&amp;quot;set-valued function called in context that cannot accept a set&amp;quot;)));&lt;br /&gt;
        if (!(rsinfo-&amp;gt;allowedModes &amp;amp; SFRM_Materialize))&lt;br /&gt;
                ereport(ERROR,&lt;br /&gt;
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),&lt;br /&gt;
                                 errmsg(&amp;quot;materialize mode required, but it is not &amp;quot; \&lt;br /&gt;
                                                &amp;quot;allowed in this context&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
        reqdim = (PG_NARGS() &amp;lt; 2) ? 1 : PG_GETARG_INT32(1);&lt;br /&gt;
        reverse = (PG_NARGS() &amp;lt; 3) ? false : PG_GETARG_BOOL(2);&lt;br /&gt;
&lt;br /&gt;
        /* Sanity check: does it look like an array at all? */&lt;br /&gt;
        if (ARR_NDIM(v) &amp;lt;= 0 || ARR_NDIM(v) &amp;gt; MAXDIM)&lt;br /&gt;
                 PG_RETURN_NULL();&lt;br /&gt;
&lt;br /&gt;
        /* Sanity check: was the requested dim valid */&lt;br /&gt;
        if (reqdim &amp;lt;= 0 || reqdim &amp;gt; ARR_NDIM(v))&lt;br /&gt;
                 PG_RETURN_NULL();&lt;br /&gt;
&lt;br /&gt;
        lb = ARR_LBOUND(v);&lt;br /&gt;
        dimv = ARR_DIMS(v);&lt;br /&gt;
&lt;br /&gt;
        lower = lb[reqdim - 1];&lt;br /&gt;
        upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;&lt;br /&gt;
&lt;br /&gt;
        /* need to build tuplestore in query context */&lt;br /&gt;
        per_query_ctx = rsinfo-&amp;gt;econtext-&amp;gt;ecxt_per_query_memory;&lt;br /&gt;
        oldcontext = MemoryContextSwitchTo(per_query_ctx);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        /* note: for 8.4 and higher - tupdesc = CreateTupleDescCopy(rsinfo-&amp;gt;expectedDesc); */&lt;br /&gt;
        tupdesc = rsinfo-&amp;gt;expectedDesc;&lt;br /&gt;
        tupstore = tuplestore_begin_heap(true, false, work_mem);&lt;br /&gt;
&lt;br /&gt;
        for (i = lower; i &amp;lt;= upper; i++)&lt;br /&gt;
        {&lt;br /&gt;
                Datum        value;&lt;br /&gt;
                bool         null = false;&lt;br /&gt;
                HeapTuple       tuple;&lt;br /&gt;
&lt;br /&gt;
                /* generate junk in short-term context */&lt;br /&gt;
                MemoryContextSwitchTo(oldcontext);&lt;br /&gt;
&lt;br /&gt;
                value = !reverse ? Int32GetDatum(i) : Int32GetDatum(upper - i + 1);&lt;br /&gt;
                tuple = heap_form_tuple(tupdesc, &amp;amp;value, &amp;amp;null);&lt;br /&gt;
&lt;br /&gt;
                MemoryContextSwitchTo(per_query_ctx);&lt;br /&gt;
                tuplestore_puttuple(tupstore, tuple);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /* clean up and return the tuplestore */&lt;br /&gt;
        tuplestore_donestoring(tupstore);&lt;br /&gt;
&lt;br /&gt;
        MemoryContextSwitchTo(oldcontext);&lt;br /&gt;
&lt;br /&gt;
        rsinfo-&amp;gt;returnMode = SFRM_Materialize;&lt;br /&gt;
        rsinfo-&amp;gt;setResult = tupstore;&lt;br /&gt;
        rsinfo-&amp;gt;setDesc = tupdesc;&lt;br /&gt;
&lt;br /&gt;
        return (Datum) 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
a její obdoba typu SRFM_by_call (sice o zhruba 10% pomalejší zato paměťově šetrnější (má smysl řešit od 10 000 řádků):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;quot;funcapi.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
typedef struct generate_iterator_fctx&lt;br /&gt;
{&lt;br /&gt;
        int4    lower;&lt;br /&gt;
        int4    upper;&lt;br /&gt;
        bool    reverse;&lt;br /&gt;
} generate_iterator_fctx;&lt;br /&gt;
&lt;br /&gt;
Datum array_subscripts(PG_FUNCTION_ARGS);&lt;br /&gt;
PG_FUNCTION_INFO_V1(array_subscripts);&lt;br /&gt;
&lt;br /&gt;
/* &lt;br /&gt;
 * array_subscripts(array anyarray, dim int, reverse bool)&lt;br /&gt;
 */&lt;br /&gt;
Datum&lt;br /&gt;
array_subscripts(PG_FUNCTION_ARGS)&lt;br /&gt;
{&lt;br /&gt;
        FuncCallContext *funcctx;&lt;br /&gt;
        MemoryContext oldcontext;&lt;br /&gt;
        generate_iterator_fctx *fctx;&lt;br /&gt;
&lt;br /&gt;
        /* stuff done only on the first call of the function */&lt;br /&gt;
        if (SRF_IS_FIRSTCALL())&lt;br /&gt;
        {&lt;br /&gt;
                ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);&lt;br /&gt;
                int reqdim;&lt;br /&gt;
                int     *lb, *dimv;&lt;br /&gt;
&lt;br /&gt;
                /* create a function context for cross-call persistence */&lt;br /&gt;
                funcctx = SRF_FIRSTCALL_INIT();&lt;br /&gt;
&lt;br /&gt;
                reqdim = (PG_NARGS() &amp;lt; 2) ? 1 : PG_GETARG_INT32(1);&lt;br /&gt;
&lt;br /&gt;
                /* Sanity check: does it look like an array at all? */&lt;br /&gt;
                if (ARR_NDIM(v) &amp;lt;= 0 || ARR_NDIM(v) &amp;gt; MAXDIM)&lt;br /&gt;
                        SRF_RETURN_DONE(funcctx);&lt;br /&gt;
&lt;br /&gt;
                /* Sanity check: was the requested dim valid */&lt;br /&gt;
                if (reqdim &amp;lt;= 0 || reqdim &amp;gt; ARR_NDIM(v))&lt;br /&gt;
                        SRF_RETURN_DONE(funcctx);&lt;br /&gt;
&lt;br /&gt;
                /*&lt;br /&gt;
                 * switch to memory context appropriate for multiple function calls&lt;br /&gt;
                 */&lt;br /&gt;
                oldcontext = MemoryContextSwitchTo(funcctx-&amp;gt;multi_call_memory_ctx);&lt;br /&gt;
                fctx = (generate_iterator_fctx *) palloc(sizeof(generate_iterator_fctx));&lt;br /&gt;
&lt;br /&gt;
                lb = ARR_LBOUND(v);&lt;br /&gt;
                dimv = ARR_DIMS(v);&lt;br /&gt;
&lt;br /&gt;
                fctx-&amp;gt;lower = lb[reqdim - 1];&lt;br /&gt;
                fctx-&amp;gt;upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;&lt;br /&gt;
                fctx-&amp;gt;reverse = (PG_NARGS() &amp;lt; 3) ? false : PG_GETARG_BOOL(2);&lt;br /&gt;
&lt;br /&gt;
                funcctx-&amp;gt;user_fctx = fctx;&lt;br /&gt;
&lt;br /&gt;
                MemoryContextSwitchTo(oldcontext);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        funcctx = SRF_PERCALL_SETUP();&lt;br /&gt;
&lt;br /&gt;
        fctx = funcctx-&amp;gt;user_fctx;&lt;br /&gt;
&lt;br /&gt;
        if (fctx-&amp;gt;lower &amp;lt;= fctx-&amp;gt;upper)&lt;br /&gt;
        {&lt;br /&gt;
                if (!fctx-&amp;gt;reverse)&lt;br /&gt;
                        SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx-&amp;gt;lower++));&lt;br /&gt;
                else&lt;br /&gt;
                        SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx-&amp;gt;upper--));&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
                /* do when there is no more left */&lt;br /&gt;
                SRF_RETURN_DONE(funcctx);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Registrace:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE FUNCTION array_subscripts(anyarray)&lt;br /&gt;
RETURNS SETOF int&lt;br /&gt;
AS &amp;#039;MODULE_PATHNAME&amp;#039;&lt;br /&gt;
LANGUAGE C STRICT;&lt;br /&gt;
&lt;br /&gt;
CREATE FUNCTION array_subscripts(anyarray, integer)&lt;br /&gt;
RETURNS SETOF int&lt;br /&gt;
AS &amp;#039;MODULE_PATHNAME&amp;#039;&lt;br /&gt;
LANGUAGE C STRICT;&lt;br /&gt;
&lt;br /&gt;
CREATE FUNCTION array_subscripts(anyarray, integer, bool)&lt;br /&gt;
RETURNS SETOF int&lt;br /&gt;
AS &amp;#039;MODULE_PATHNAME&amp;#039;&lt;br /&gt;
LANGUAGE C STRICT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Použití:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE FUNCTION array_expand(anyarray)&lt;br /&gt;
RETURNS SETOF anyelements&lt;br /&gt;
AS&lt;br /&gt;
$$&lt;br /&gt;
  SELECT $1[i] &lt;br /&gt;
     FROM array_subscripts($1) g(i);&lt;br /&gt;
$$ LANGUAGE SQL;&lt;br /&gt;
&lt;br /&gt;
CREATE FUNCTION array_expand2(anyarray)&lt;br /&gt;
RETURNS SETOF anyelements&lt;br /&gt;
AS&lt;br /&gt;
$$&lt;br /&gt;
  SELECT $1[i][j] &lt;br /&gt;
     FROM array_subscripts($1,1) d1(i),&lt;br /&gt;
          array_subscripts($1,2) d2{j};&lt;br /&gt;
$$ LANGUAGE SQL;&lt;br /&gt;
&lt;br /&gt;
postgres=# select array_expand2(ARRAY[[10,11,12],[13,14,15]]);&lt;br /&gt;
 array_expand2 &lt;br /&gt;
---------------&lt;br /&gt;
            10&lt;br /&gt;
            11&lt;br /&gt;
            12&lt;br /&gt;
            13&lt;br /&gt;
            14&lt;br /&gt;
            15&lt;br /&gt;
(6 rows)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>imported&gt;Pavel</name></author>
	</entry>
</feed>