Обсуждение: POC: PLpgSQL FOREACH IN JSON ARRAY

Поиск
Список
Период
Сортировка

POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

I wrote PoC for previously proposed plpgsql statement FOREACH IN JSON ARRAY

It looks like:

do $$
declare x int;
begin
  foreach x in json array '[1,2,3,4]' 
  loop
    raise notice 'x: %', x;
  end loop;
end;
$$

do $$
declare x int; y int;
begin
  foreach x, y in json array '[{"x": 100, "y": 1000}, {"y": 1000, "x": 100}]'
  loop
    raise notice 'x: %, y: %', x, y;
  end loop;
end
$$

My first motivation for this patch is performance. This is faster (3 - 4 x) than using FOR IN SELECT FROM json_array_elements, because there is no overhead of SQL executor. Second motivation is a little bit better readability, because inside plpgsql' statements we have info about used variables and we can use it.

The behavior is very similar to FOREACH IN ARRAY with one significant difference - the values of JSON objects are assigned to the composite variable or lists of variables by names (not by position). It made this decision because jsonb doesn't preserve the position of the field in object, and then assignment based on position cannot work.

The code is relatively short now - about 400 lines +/- and the code is simple without risks.

There are some open questions - mainly if default mode for mapping json fields to plpgsql variables should be in lax or strict mode. Now, it is something between (cast errors are raised) - it is consistent with jsonb_populate_record - but it should not be the final design. I cannot say what is better - currently implemented behavior is consistent with common plpgsql behaviour, but SQL/JSON is different. I can imagine that default behaviour will be lax, and with some optional clauses we can push behave to strict mode. I have no strong opinion about it. Maybe I prefer the current "strict" behaviour a little bit, because it is more "safe", but it is only my personal opinion. But again, I have no strong opinion about this question and I very much invite any discussion about it.

This is proof of concept patch - casting between plpgsql arrays and json arrays is not supported, documentation and regress tests are minimalistic, but it is good enough for testing and good enough for decision, if this feature is wanted or not (or if it needs some modifications).

This is a new feature (and proprietary feature). There should not be any compatibility issues. 

What do you think about this feature? 

Regards

Pavel

Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

small update

Now assignment to plpgsql array variable and json array works. Some minor code cleaning + more regress tests.

Regards

Pavel

Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:


ne 1. 3. 2026 v 6:44 odesílatel Pavel Stehule <pavel.stehule@gmail.com> napsal:
Hi

small update

Now assignment to plpgsql array variable and json array works. Some minor code cleaning + more regress tests.

fix uninitialized argument of  json_populate_type function

regards

Pavel


Regards

Pavel

Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Jim Jones
Дата:
Hi Pavel,

I quickly tested the patch, and I also could observe a ~3x performance
improvement!

A few first impressions:

## in exec_stmt_foreach_json_a the boolean variable found is declared as
false, bit its value is never set to true until exec_set_found() is called:

/*
 * Set the FOUND variable to indicate the result of executing the loop
 * (namely, whether we looped one or more times). This must be set here so
 * that it does not interfere with the value of the FOUND variable inside
 * the loop processing itself.
 */
exec_set_found(estate, found);


Test:


DO $$
DECLARE
  x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3]'
  LOOP
    RAISE NOTICE 'x: %', x;
  END LOOP;

  IF FOUND THEN
    RAISE NOTICE 'FOUND is true';
  ELSE
    RAISE NOTICE 'FOUND is false';
  END IF;
END;
$$;
NOTICE:  x: 1
NOTICE:  x: 2
NOTICE:  x: 3
NOTICE:  FOUND is false


## Suggestion in the plpgsql.sgml

The <literal>FOREACH</literal> loop is much like a
<literal>FOREACH</literal> loop,

to

"much like a regular <literal>FOREACH</literal> loop over arrays"

## Typo in comment

/*
 * We cannot to use fieldnames for tupdescentry, because
 * these names can be suffixed by name of row variable.
...

We cannot to use > We cannot use


## Nit pick

These error messages are not wrong, but IMO a errhint/errdetail could
add some value here:

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("cannot extract elements from a scalar")));

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    errmsg("cannot extract elements from an object")));

Something like this perhaps?

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("cannot extract elements from a scalar"),
     errhint("FOREACH IN JSON ARRAY requires an array value.")));

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("FOREACH expression must evaluate to a JSON array"),
     errdetail("Cannot iterate over a scalar value.")));


Thanks for the patch!

Best, Jim



Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

út 3. 3. 2026 v 8:43 odesílatel Jim Jones <jim.jones@uni-muenster.de> napsal:
Hi Pavel,

I quickly tested the patch, and I also could observe a ~3x performance
improvement!

A few first impressions:

## in exec_stmt_foreach_json_a the boolean variable found is declared as
false, bit its value is never set to true until exec_set_found() is called:

/*
 * Set the FOUND variable to indicate the result of executing the loop
 * (namely, whether we looped one or more times). This must be set here so
 * that it does not interfere with the value of the FOUND variable inside
 * the loop processing itself.
 */
exec_set_found(estate, found);


Test:


DO $$
DECLARE
  x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3]'
  LOOP
    RAISE NOTICE 'x: %', x;
  END LOOP;

  IF FOUND THEN
    RAISE NOTICE 'FOUND is true';
  ELSE
    RAISE NOTICE 'FOUND is false';
  END IF;
END;
$$;
NOTICE:  x: 1
NOTICE:  x: 2
NOTICE:  x: 3
NOTICE:  FOUND is false


fixed + regress tests
 

## Suggestion in the plpgsql.sgml

The <literal>FOREACH</literal> loop is much like a
<literal>FOREACH</literal> loop,

to

"much like a regular <literal>FOREACH</literal> loop over arrays"

done
 

## Typo in comment

/*
 * We cannot to use fieldnames for tupdescentry, because
 * these names can be suffixed by name of row variable.
...

We cannot to use > We cannot use

fixed
 


## Nit pick

These error messages are not wrong, but IMO a errhint/errdetail could
add some value here:

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("cannot extract elements from a scalar")));

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    errmsg("cannot extract elements from an object")));

Something like this perhaps?

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("cannot extract elements from a scalar"),
     errhint("FOREACH IN JSON ARRAY requires an array value.")));

ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     errmsg("FOREACH expression must evaluate to a JSON array"),
     errdetail("Cannot iterate over a scalar value.")));


I rewrote it to

    if (JB_ROOT_IS_SCALAR(jb))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("FOREACH expression must evaluate to a JSON array"),
                 errhint("Cannot iterate over a scalar value.")));
    else if (JB_ROOT_IS_OBJECT(jb))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("FOREACH expression must evaluate to a JSON array"),
                 errdetail("Cannot iterate over a object value.")));
 
    Assert(JB_ROOT_IS_ARRAY(jb));

+ regress tests

 

Thanks for the patch!

Thank you for check

Regards

Pavel
 

Best, Jim
Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Jim Jones
Дата:
I reviewed the code I have nothing to add at this point. LGTM!

The tests touch a lot of different scenarios, but for the sake of
completeness I'd like to suggest adding these three cases:

-- EXIT and CONTINUE can be triggered by LOOP_RC_PROCESSING
DO $$
DECLARE x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
  LOOP
    EXIT WHEN x = 3;
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;

DO $$
DECLARE x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
  LOOP
    CONTINUE WHEN x % 2 = 0;
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;


-- Variable instead of string
DO $$
DECLARE x int; arr jsonb;
BEGIN
  SELECT jsonb_agg(i) INTO arr
  FROM generate_series(1,3) i;

  FOREACH x IN JSON ARRAY arr
  LOOP
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;


Thanks!

Best, Jim



Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

st 4. 3. 2026 v 12:35 odesílatel Jim Jones <jim.jones@uni-muenster.de> napsal:
I reviewed the code I have nothing to add at this point. LGTM!

The tests touch a lot of different scenarios, but for the sake of
completeness I'd like to suggest adding these three cases:

-- EXIT and CONTINUE can be triggered by LOOP_RC_PROCESSING
DO $$
DECLARE x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
  LOOP
    EXIT WHEN x = 3;
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;

DO $$
DECLARE x int;
BEGIN
  FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
  LOOP
    CONTINUE WHEN x % 2 = 0;
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;


-- Variable instead of string
DO $$
DECLARE x int; arr jsonb;
BEGIN
  SELECT jsonb_agg(i) INTO arr
  FROM generate_series(1,3) i;

  FOREACH x IN JSON ARRAY arr
  LOOP
    RAISE NOTICE '%', x;
  END LOOP;
END;
$$;


I merged these examples to tests

Thank you for review

Regards

Pavel
 

Thanks!

Best, Jim
Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Shreeya Sharma
Дата:
Status: SUCCESS
Applied against: /Users/shreeyasharma/postgresql (Current HEAD)
Build status: PASS
Test status: PASS
Notes:
- Compilation passed: True
- Regression tests (make check) passed: True

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Shreeya Sharma
Дата:
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:       tested, passed
Spec compliant:           tested, passed
Documentation:            tested, passed

The changes are good

The new status of this patch is: Ready for Committer

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:


po 9. 3. 2026 v 7:12 odesílatel Shreeya Sharma <shreeya2304@gmail.com> napsal:
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:       tested, passed
Spec compliant:           tested, passed
Documentation:            tested, passed

The changes are good

The new status of this patch is: Ready for Committer

Thank you very much

Regards

Pavel
 

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Peter Eisentraut
Дата:
On 28.02.26 08:10, Pavel Stehule wrote:
> I wrote PoC for previously proposed plpgsql statement FOREACH IN JSON ARRAY

Maybe this could be written in such a way that it doesn't hardcode JSON 
arrays specifically, but a type could have an iteration helper function 
that would feed this feature?




Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Chao Li
Дата:

> On Mar 5, 2026, at 02:50, Pavel Stehule <pavel.stehule@gmail.com> wrote:
>
> Hi
>
> st 4. 3. 2026 v 12:35 odesílatel Jim Jones <jim.jones@uni-muenster.de> napsal:
> I reviewed the code I have nothing to add at this point. LGTM!
>
> The tests touch a lot of different scenarios, but for the sake of
> completeness I'd like to suggest adding these three cases:
>
> -- EXIT and CONTINUE can be triggered by LOOP_RC_PROCESSING
> DO $$
> DECLARE x int;
> BEGIN
>   FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
>   LOOP
>     EXIT WHEN x = 3;
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
> DO $$
> DECLARE x int;
> BEGIN
>   FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
>   LOOP
>     CONTINUE WHEN x % 2 = 0;
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
>
> -- Variable instead of string
> DO $$
> DECLARE x int; arr jsonb;
> BEGIN
>   SELECT jsonb_agg(i) INTO arr
>   FROM generate_series(1,3) i;
>
>   FOREACH x IN JSON ARRAY arr
>   LOOP
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
>
> I merged these examples to tests
>
> Thank you for review
>
> Regards
>
> Pavel
>
> Thanks!
>
> Best, Jim
> <v20260304-5-0001-FOREACH-scalar-IN-JSON-ARRAY.patch>

I just reviewed and tested the patch. Here comes my comments:

1 - pl_gram.y
```
+                                ereport(ERROR,
+                                        (errcode(ERRCODE_SYNTAX_ERROR),
+                                         errmsg("not zero slice is allowed only for arrays"),
+                                                 parser_errposition(@4)));
```

* () around errcode and errmsg are no longer needed. This comment is general, and I saw other ereport() also use () in
thispatch. 
* parser_errposition should have the same indention as errmsg.

2 - pl_exec.c
```
+                 errdetail("Cannot iterate over a object value.")));
```

Typo: a -> an

3 - pl_exec.c
```
+    tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
+                                    "FOREACH IN JSON ARRAY temporary cxt",
+                                    ALLOCSET_DEFAULT_SIZES);
```

Do we need to destroy tmp_cxt after the loop?

4 Looks like record type of loop var is not supported:
```
evantest=# do $$
declare
  r record;
begin
  foreach r in json array '[{"x":1,"y":"hi"},{"x":2,"y":"hello"}]’
  loop
    raise notice 'x: %, y: %', r.x, r.y;
  end loop;
end;
$$;
ERROR:  record type has not been registered
CONTEXT:  PL/pgSQL function inline_code_block line 5 at FOREACH over json array
```

So, I want to check if you intentionally don’t want to support that or just missed that? If it’s not supported, then
maybedocument that. 

5 I tried that composite type of loop var is supported, maybe add a test case for that. What I tested:
```
create type t_foreach_json_row as (
  x int,
  y text,
  z numeric
);

do $$
declare
  r t_foreach_json_row;
begin
  foreach r in json array
    '[{"x":1,"y":"one","z":1.5},
      {"x":2,"y":"two"},
      {"y":"three","z":3.14},
      {}]'
  loop
    raise notice 'x=%, y=%, z=%', r.x, r.y, r.z;
  end loop;
end;
$$;

drop type t_foreach_json_row;
```

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/







Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Tom Lane
Дата:
Peter Eisentraut <peter@eisentraut.org> writes:
> Maybe this could be written in such a way that it doesn't hardcode JSON 
> arrays specifically, but a type could have an iteration helper function 
> that would feed this feature?

+1.  ISTM that this feature would make sense for subscriptable types,
so one way to shoehorn it into the system without a lot of new overhead
could be to extend struct SubscriptRoutines to offer optional support
function(s) for iterating through all the elements of a subscriptable
object.

            regards, tom lane



Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

čt 12. 3. 2026 v 5:30 odesílatel Tom Lane <tgl@sss.pgh.pa.us> napsal:
Peter Eisentraut <peter@eisentraut.org> writes:
> Maybe this could be written in such a way that it doesn't hardcode JSON
> arrays specifically, but a type could have an iteration helper function
> that would feed this feature?

+1.  ISTM that this feature would make sense for subscriptable types,
so one way to shoehorn it into the system without a lot of new overhead
could be to extend struct SubscriptRoutines to offer optional support
function(s) for iterating through all the elements of a subscriptable
object.

I'll try to write second patch in this way

Regards

Pavel
 

                        regards, tom lane

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

čt 12. 3. 2026 v 4:55 odesílatel Chao Li <li.evan.chao@gmail.com> napsal:


> On Mar 5, 2026, at 02:50, Pavel Stehule <pavel.stehule@gmail.com> wrote:
>
> Hi
>
> st 4. 3. 2026 v 12:35 odesílatel Jim Jones <jim.jones@uni-muenster.de> napsal:
> I reviewed the code I have nothing to add at this point. LGTM!
>
> The tests touch a lot of different scenarios, but for the sake of
> completeness I'd like to suggest adding these three cases:
>
> -- EXIT and CONTINUE can be triggered by LOOP_RC_PROCESSING
> DO $$
> DECLARE x int;
> BEGIN
>   FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
>   LOOP
>     EXIT WHEN x = 3;
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
> DO $$
> DECLARE x int;
> BEGIN
>   FOREACH x IN JSON ARRAY '[1,2,3,4,5]'
>   LOOP
>     CONTINUE WHEN x % 2 = 0;
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
>
> -- Variable instead of string
> DO $$
> DECLARE x int; arr jsonb;
> BEGIN
>   SELECT jsonb_agg(i) INTO arr
>   FROM generate_series(1,3) i;
>
>   FOREACH x IN JSON ARRAY arr
>   LOOP
>     RAISE NOTICE '%', x;
>   END LOOP;
> END;
> $$;
>
>
> I merged these examples to tests
>
> Thank you for review
>
> Regards
>
> Pavel

> Thanks!
>
> Best, Jim
> <v20260304-5-0001-FOREACH-scalar-IN-JSON-ARRAY.patch>

I just reviewed and tested the patch. Here comes my comments:

1 - pl_gram.y
```
+                                                               ereport(ERROR,
+                                                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                                                                errmsg("not zero slice is allowed only for arrays"),
+                                                                                                parser_errposition(@4)));
```

* () around errcode and errmsg are no longer needed. This comment is general, and I saw other ereport() also use () in this patch.
* parser_errposition should have the same indention as errmsg.

fixed
 

2 - pl_exec.c
```
+                                errdetail("Cannot iterate over a object value.")));
```

Typo: a -> an

fixed
 

3 - pl_exec.c
```
+       tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
+                                                                       "FOREACH IN JSON ARRAY temporary cxt",
+                                                                       ALLOCSET_DEFAULT_SIZES);
```

Do we need to destroy tmp_cxt after the loop?

no - it is cleaned by MemoryContextReset(stmt_mcontext); 

4 Looks like record type of loop var is not supported:
```
evantest=# do $$
declare
  r record;
begin
  foreach r in json array '[{"x":1,"y":"hi"},{"x":2,"y":"hello"}]’
  loop
    raise notice 'x: %, y: %', r.x, r.y;
  end loop;
end;
$$;
ERROR:  record type has not been registered
CONTEXT:  PL/pgSQL function inline_code_block line 5 at FOREACH over json array
```

So, I want to check if you intentionally don’t want to support that or just missed that? If it’s not supported, then maybe document that.

It is intentional at this moment (and I think so it will be in future too). For reading fields from a json object I use the json_populate_type function, and this function needs a known tupdesc. Generally JSON objects have no fixed structure, and when a record's variable has no assigned type, then we have to create new tupdesc for each value. This can be possibly slow and memory expensive. Probably - I never tested this case. It is valid use case, but it can be solved in later - and the support will be more invasive - requires support in json_populate_type

I enhanced doc

    <para>
     The target variable can be of type RECORD, but the real structure has to be
     assigned before usage in FOREACH statement.
    </para>


 

5 I tried that composite type of loop var is supported, maybe add a test case for that. What I tested:
```
create type t_foreach_json_row as (
  x int,
  y text,
  z numeric
);

do $$
declare
  r t_foreach_json_row;
begin
  foreach r in json array
    '[{"x":1,"y":"one","z":1.5},
      {"x":2,"y":"two"},
      {"y":"three","z":3.14},
      {}]'
  loop
    raise notice 'x=%, y=%, z=%', r.x, r.y, r.z;
  end loop;
end;
$$;

drop type t_foreach_json_row;
```

it is there already

create type t3 as (x int, y numeric, z varchar);

do $$
declare c t3;
begin
  foreach c in json array '[{}, {"z":"Hi"}, {"y": 3.14}, {"z":"Hi", "x":10, "y":3.14}]'
  loop
    raise notice 'x: %, y: %, z: %', c.x, c.y, c.z;
  end loop;
end;
$$;

assigned updated version - 

I'll try to modify this patch like Tom proposed in the next version. But the fundament behavior should be same

Thank you for check and testing

Regards

Pavel


 

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/




Вложения

Re: POC: PLpgSQL FOREACH IN JSON ARRAY

От
Pavel Stehule
Дата:
Hi

čt 12. 3. 2026 v 8:00 odesílatel Pavel Stehule <pavel.stehule@gmail.com> napsal:
Hi

čt 12. 3. 2026 v 5:30 odesílatel Tom Lane <tgl@sss.pgh.pa.us> napsal:
Peter Eisentraut <peter@eisentraut.org> writes:
> Maybe this could be written in such a way that it doesn't hardcode JSON
> arrays specifically, but a type could have an iteration helper function
> that would feed this feature?

+1.  ISTM that this feature would make sense for subscriptable types,
so one way to shoehorn it into the system without a lot of new overhead
could be to extend struct SubscriptRoutines to offer optional support
function(s) for iterating through all the elements of a subscriptable
object.


attached patch do this - new interface has two methods: CreateForeachAIterator and iterate

diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h
index 301f21dac2f..08bfe59ede4 100644
--- a/src/include/nodes/subscripting.h
+++ b/src/include/nodes/subscripting.h
@@ -154,6 +154,32 @@ typedef void (*SubscriptExecSetup) (const SubscriptingRef *sbsref,
                                    SubscriptingRefState *sbsrefstate,
                                    SubscriptExecSteps *methods);
 
+typedef struct _ForeachAIterator ForeachAIterator;
+
+/*
+ * ForeachAIiterator is used by PLpgSQL FOREACH IN ARRAY statement.
+ * Input value should not be null, and inside CreateForeachAIterator
+ * routine must be copied to current (statement) context. "iterate"
+ * routine is called under short life memory context, that is resetted
+ * after any call.
+ */
+struct _ForeachAIterator
+{
+   bool        (*iterate) (ForeachAIterator *self,
+                           Datum *value,
+                           bool *isnull,
+                           Oid *typid,
+                           int32 *typmod);
+   /* Private fields might appear beyond this point... */
+};
+    
+typedef ForeachAIterator * (*CreateForeachAIterator) (Datum value,
+                                                     Oid typid,
+                                                     int32 typmod,
+                                                     int slice,
+                                                     Oid target_typid,
+                                                     int32 target_typmod);
+
 /* Struct returned by the SQL-visible subscript handler function */
 typedef struct SubscriptRoutines
 {
@@ -163,6 +189,9 @@ typedef struct SubscriptRoutines
    bool        fetch_leakproof;    /* is fetch SubscriptingRef leakproof? */
    bool        store_leakproof;    /* is assignment SubscriptingRef
                                     * leakproof? */
+    
+   /* returns iterator used by PL/pgSQL FOREACH statement */
+   CreateForeachAIterator create_foreach_a_iterator;
 } SubscriptRoutines;

 #endif                         /* SUBSCRIPTING_H */

Regards

Pavel
 
 

Regards

Pavel
 

                        regards, tom lane
Вложения