Обсуждение: pgsql: Add basic JSON_TABLE() functionality

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

pgsql: Add basic JSON_TABLE() functionality

От
Amit Langote
Дата:
Add basic JSON_TABLE() functionality

JSON_TABLE() allows JSON data to be converted into a relational view
and thus used, for example, in a FROM clause, like other tabular
data.  Data to show in the view is selected from a source JSON object
using a JSON path expression to get a sequence of JSON objects that's
called a "row pattern", which becomes the source to compute the
SQL/JSON values that populate the view's output columns.  Column
values themselves are computed using JSON path expressions applied to
each of the JSON objects comprising the "row pattern", for which the
SQL/JSON query functions added in 6185c9737cf4 are used.

To implement JSON_TABLE() as a table function, this augments the
TableFunc and TableFuncScanState nodes that are currently used to
support XMLTABLE() with some JSON_TABLE()-specific fields.

Note that the JSON_TABLE() spec includes NESTED COLUMNS and PLAN
clauses, which are required to provide more flexibility to extract
data out of nested JSON objects, but they are not implemented here
to keep this commit of manageable size.

Author: Nikita Glukhov <n.gluhov@postgrespro.ru>
Author: Teodor Sigaev <teodor@sigaev.ru>
Author: Oleg Bartunov <obartunov@gmail.com>
Author: Alexander Korotkov <aekorotkov@gmail.com>
Author: Andrew Dunstan <andrew@dunslane.net>
Author: Amit Langote <amitlangote09@gmail.com>
Author: Jian He <jian.universality@gmail.com>

Reviewers have included (in no particular order):

Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup,
Erik Rijkers, Zihong Yu, Himanshu Upadhyaya, Daniel Gustafsson,
Justin Pryzby, Álvaro Herrera, Jian He

Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
Discussion: https://postgr.es/m/20220616233130.rparivafipt6doj3@alap3.anarazel.de
Discussion: https://postgr.es/m/abd9b83b-aa66-f230-3d6d-734817f0995d%40postgresql.org
Discussion: https://postgr.es/m/CA+HiwqE4XTdfb1nW=Ojoy_tQSRhYt-q_kb6i5d4xcKyrLC1Nbg@mail.gmail.com

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/de3600452b61d1bc3967e9e37e86db8956c8f577

Modified Files
--------------
doc/src/sgml/func.sgml                             | 334 +++++++++++
src/backend/commands/explain.c                     |  21 +-
src/backend/executor/execExpr.c                    |  11 +-
src/backend/executor/execExprInterp.c              |   2 +
src/backend/executor/nodeTableFuncscan.c           |  41 +-
src/backend/nodes/makefuncs.c                      |  53 ++
src/backend/nodes/nodeFuncs.c                      |  36 ++
src/backend/parser/Makefile                        |   1 +
src/backend/parser/gram.y                          | 173 +++++-
src/backend/parser/meson.build                     |   1 +
src/backend/parser/parse_clause.c                  |  14 +-
src/backend/parser/parse_expr.c                    |  53 +-
src/backend/parser/parse_jsontable.c               | 421 ++++++++++++++
src/backend/parser/parse_relation.c                |   6 +-
src/backend/parser/parse_target.c                  |   1 +
src/backend/utils/adt/jsonpath_exec.c              | 372 ++++++++++++
src/backend/utils/adt/ruleutils.c                  | 185 +++++-
src/include/nodes/execnodes.h                      |   2 +
src/include/nodes/makefuncs.h                      |   5 +
src/include/nodes/parsenodes.h                     |  66 +++
src/include/nodes/primnodes.h                      |  56 +-
src/include/parser/kwlist.h                        |   3 +
src/include/parser/parse_clause.h                  |   3 +
src/include/utils/jsonpath.h                       |   3 +
src/interfaces/ecpg/test/ecpg_schedule             |   1 +
.../ecpg/test/expected/sql-sqljson_jsontable.c     | 143 +++++
.../test/expected/sql-sqljson_jsontable.stderr     |  16 +
.../test/expected/sql-sqljson_jsontable.stdout     |   1 +
src/interfaces/ecpg/test/sql/Makefile              |   1 +
src/interfaces/ecpg/test/sql/meson.build           |   1 +
src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc |  29 +
src/test/regress/expected/sqljson_jsontable.out    | 636 +++++++++++++++++++++
src/test/regress/parallel_schedule                 |   2 +-
src/test/regress/sql/sqljson_jsontable.sql         | 290 ++++++++++
src/tools/pgindent/typedefs.list                   |  12 +
35 files changed, 2943 insertions(+), 52 deletions(-)


Re: pgsql: Add basic JSON_TABLE() functionality

От
Erik Rijkers
Дата:
Op 4/4/24 om 13:21 schreef Amit Langote:
> Add basic JSON_TABLE() functionality
> 

Great that it's now committed. Congrats!


There is one 'uninitialized' muttering during compile (gcc 13.2.0):

In function ‘transformJsonFuncExpr’,
     inlined from ‘transformExprRecurse’ at parse_expr.c:373:13:
parse_expr.c:4317:34: warning: ‘default_format’ may be used 
uninitialized [-Wmaybe-uninitialized]
  4317 |         jsexpr->formatted_expr = transformJsonValueExpr(pstate, 
func_name,
       | 
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4318 | 
                                         func->context_item,
       | 
                                         ~~~~~~~~~~~~~~~~~~~
  4319 | 
                                         default_format,
       | 
                                         ~~~~~~~~~~~~~~~
  4320 | 
                                         JSONBOID,
       | 
                                         ~~~~~~~~~
  4321 | 
                                         false);
       | 
                                         ~~~~~~
parse_expr.c: In function ‘transformExprRecurse’:
parse_expr.c:4257:24: note: ‘default_format’ was declared here
  4257 |         JsonFormatType default_format;
       |                        ^~~~~~~~~~~~~~


Thanks!

Erik



Re: pgsql: Add basic JSON_TABLE() functionality

От
Andrew Dunstan
Дата:


On 2024-04-04 Th 07:21, Amit Langote wrote:
Add basic JSON_TABLE() functionality


Excellent!

But I am getting this:

../../../src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc:23: WARNING: unsupported feature will be passed to server

Is that intended?


cheers


andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

Re: pgsql: Add basic JSON_TABLE() functionality

От
Amit Langote
Дата:
Hi Erik

On Thu, Apr 4, 2024 at 9:30 PM Erik Rijkers <er@xs4all.nl> wrote:
> Op 4/4/24 om 13:21 schreef Amit Langote:
> > Add basic JSON_TABLE() functionality
> >
>
> Great that it's now committed. Congrats!
>
>
> There is one 'uninitialized' muttering during compile (gcc 13.2.0):
>
> In function ‘transformJsonFuncExpr’,
>      inlined from ‘transformExprRecurse’ at parse_expr.c:373:13:
> parse_expr.c:4317:34: warning: ‘default_format’ may be used
> uninitialized [-Wmaybe-uninitialized]
>   4317 |         jsexpr->formatted_expr = transformJsonValueExpr(pstate,
> func_name,
>        |
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   4318 |
>                                          func->context_item,
>        |
>                                          ~~~~~~~~~~~~~~~~~~~
>   4319 |
>                                          default_format,
>        |
>                                          ~~~~~~~~~~~~~~~
>   4320 |
>                                          JSONBOID,
>        |
>                                          ~~~~~~~~~
>   4321 |
>                                          false);
>        |
>                                          ~~~~~~
> parse_expr.c: In function ‘transformExprRecurse’:
> parse_expr.c:4257:24: note: ‘default_format’ was declared here
>   4257 |         JsonFormatType default_format;
>        |                        ^~~~~~~~~~~~~~

Thanks for the report.  Pushed a fix.

--
Thanks, Amit Langote



Re: pgsql: Add basic JSON_TABLE() functionality

От
Amit Langote
Дата:
Hi Andrew,

On Thu, Apr 4, 2024 at 10:06 PM Andrew Dunstan <andrew@dunslane.net> wrote:
> On 2024-04-04 Th 07:21, Amit Langote wrote:
>
> Add basic JSON_TABLE() functionality
>
>
> Excellent!
>
> But I am getting this:
>
> ../../../src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc:23: WARNING: unsupported feature will be passed to server
>
> Is that intended?

I don't get that WARNING here, but I remember seeing it at one point,
which I am supposed to have fixed.

Can you please share more details about where you're seeing it?

--
Thanks, Amit Langote



Re: pgsql: Add basic JSON_TABLE() functionality

От
Andrew Dunstan
Дата:


On 2024-04-04 Th 09:20, Amit Langote wrote:
Hi Andrew,

On Thu, Apr 4, 2024 at 10:06 PM Andrew Dunstan <andrew@dunslane.net> wrote:
On 2024-04-04 Th 07:21, Amit Langote wrote:

Add basic JSON_TABLE() functionality


Excellent!

But I am getting this:

../../../src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc:23: WARNING: unsupported feature will be passed to server

Is that intended?
I don't get that WARNING here, but I remember seeing it at one point,
which I am supposed to have fixed.

Can you please share more details about where you're seeing it?


It's with a meson build:


[2330/2355] /home/andrew/pgl/pg_head/root/HEAD/pgsql.build/src/interfaces/ecpg/preproc/ecpg --regression -I../../../src/interfaces/ecpg/test/sql -I../../../src/interfaces/ecpg/
include/ -o src/interfaces/ecpg/test/sql/sqljson_jsontable.c ../../../src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc
../../../src/interfaces/ecpg/test/sql/sqljson_jsontable.pgc:23: WARNING: unsupported feature will be passed to server


cheers


andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

Re: pgsql: Add basic JSON_TABLE() functionality

От
Tom Lane
Дата:
Andrew Dunstan <andrew@dunslane.net> writes:
> On 2024-04-04 Th 09:20, Amit Langote wrote:
>> I don't get that WARNING here, but I remember seeing it at one point,
>> which I am supposed to have fixed.
>> 
>> Can you please share more details about where you're seeing it?

> It's with a meson build:

I see it with autoconf builds too, both on RHEL8 and macOS.

Looking at parse.pl, I guess it's probably triggered by some
unconventional use of ERRCODE_FEATURE_NOT_SUPPORTED in your
gram.y changes.

            regards, tom lane



Re: pgsql: Add basic JSON_TABLE() functionality

От
Tom Lane
Дата:
I wrote:
> Looking at parse.pl, I guess it's probably triggered by some
> unconventional use of ERRCODE_FEATURE_NOT_SUPPORTED in your
> gram.y changes.

Oh, no, it's parse.pl that is at fault.  It's doing this:

        if (/ERRCODE_FEATURE_NOT_SUPPORTED/)
        {
            $feature_not_supported = 1;
            next line;
        }
        ... later ...
        if ($feature_not_supported == 1)
        {

            # we found an unsupported feature, but we have to
            # filter out ExecuteStmt: CREATE OptTemp TABLE ...
            # because the warning there is only valid in some situations
            if ($flds->[0] ne 'create' || $flds->[2] ne 'table')
            {
                add_to_buffer('rules',
                    'mmerror(PARSE_ERROR, ET_WARNING, "unsupported feature will be passed to server");'
                );
            }
            $feature_not_supported = 0;
        }

In English, if a production in gram.y contains the string
ERRCODE_FEATURE_NOT_SUPPORTED anywhere, then the ecpg parser
will be made to spit out this warning when it reduces that
same production.

This works great for cases like

            | UNENCRYPTED PASSWORD Sconst
                {
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("UNENCRYPTED PASSWORD is no longer supported"),
                             errhint("Remove UNENCRYPTED to store the password in encrypted form instead."),
                             parser_errposition(@1)));
                }

but not well at all if the error is conditional, as it is in the
json_table production.  The cowboy hack for CREATE OptTemp TABLE
was evidently meant to suppress what must have been the only
conditional FEATURE_NOT_SUPPORTED rule at the time, but it doesn't
look like that matches anything at all anymore.  If you look through
the generated preproc.y file you'll find quite a few of these that
are being reported inappropriately; I'm surprised that it hasn't
come up before.

We need to either nuke that ecpg warning entirely, or find a more
robust way of detecting whether the gram.y complaint is conditional.
I'll put a brown paper bag on my head before suggesting that maybe
we could pay attention to how far the errcode is indented.  Perhaps
a slightly nicer way is to assume it's conditional if any earlier
line in the rule starts with "if".

            regards, tom lane



Re: pgsql: Add basic JSON_TABLE() functionality

От
Tom Lane
Дата:
I wrote:
> We need to either nuke that ecpg warning entirely, or find a more
> robust way of detecting whether the gram.y complaint is conditional.
> I'll put a brown paper bag on my head before suggesting that maybe
> we could pay attention to how far the errcode is indented.  Perhaps
> a slightly nicer way is to assume it's conditional if any earlier
> line in the rule starts with "if".

The latter seems considerably safer, so I modified parse.pl along
those lines.  Eyeball comparison of gram.y with preproc.y verifies
that now ecpg will emit the warning only in rules where the backend
unconditionally reports FEATURE_NOT_SUPPORTED.

I suppose this needs to be back-patched.

            regards, tom lane

diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl
index 87b512b2a1..fe8d3e5178 100644
--- a/src/interfaces/ecpg/preproc/parse.pl
+++ b/src/interfaces/ecpg/preproc/parse.pl
@@ -34,7 +34,8 @@ my $brace_indent = 0;
 my $yaccmode = 0;
 my $in_rule = 0;
 my $header_included = 0;
-my $feature_not_supported = 0;
+my $has_feature_not_supported = 0;
+my $has_if_command = 0;
 my $tokenmode = 0;

 my (%buff, $infield, $comment, %tokens, %addons);
@@ -151,12 +152,6 @@ sub main
 {
   line: while (<$parserfh>)
     {
-        if (/ERRCODE_FEATURE_NOT_SUPPORTED/)
-        {
-            $feature_not_supported = 1;
-            next line;
-        }
-
         chomp;

         # comment out the line below to make the result file match (blank line wise)
@@ -182,6 +177,13 @@ sub main
             $infield = 0;
         }

+        if ($yaccmode == 1)
+        {
+            # Check for rules that throw FEATURE_NOT_SUPPORTED
+            $has_feature_not_supported = 1 if /ERRCODE_FEATURE_NOT_SUPPORTED/;
+            $has_if_command = 1 if /^\s*if/;
+        }
+
         my $prec = 0;

         # Make sure any braces are split
@@ -541,20 +543,17 @@ sub dump_fields

         #Normal
         add_to_buffer('rules', $ln);
-        if ($feature_not_supported == 1)
+        if ($has_feature_not_supported and not $has_if_command)
         {
-
-            # we found an unsupported feature, but we have to
-            # filter out ExecuteStmt: CREATE OptTemp TABLE ...
-            # because the warning there is only valid in some situations
-            if ($flds->[0] ne 'create' || $flds->[2] ne 'table')
-            {
-                add_to_buffer('rules',
-                    'mmerror(PARSE_ERROR, ET_WARNING, "unsupported feature will be passed to server");'
-                );
-            }
-            $feature_not_supported = 0;
+            # The backend unconditionally reports
+            # FEATURE_NOT_SUPPORTED in this rule, so let's emit
+            # a warning on the ecpg side.
+            add_to_buffer('rules',
+                'mmerror(PARSE_ERROR, ET_WARNING, "unsupported feature will be passed to server");'
+            );
         }
+        $has_feature_not_supported = 0;
+        $has_if_command = 0;

         if ($len == 0)
         {

Re: pgsql: Add basic JSON_TABLE() functionality

От
Amit Langote
Дата:
On Fri, Apr 5, 2024 at 1:55 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> I wrote:
> > We need to either nuke that ecpg warning entirely, or find a more
> > robust way of detecting whether the gram.y complaint is conditional.
> > I'll put a brown paper bag on my head before suggesting that maybe
> > we could pay attention to how far the errcode is indented.  Perhaps
> > a slightly nicer way is to assume it's conditional if any earlier
> > line in the rule starts with "if".
>
> The latter seems considerably safer, so I modified parse.pl along
> those lines.  Eyeball comparison of gram.y with preproc.y verifies
> that now ecpg will emit the warning only in rules where the backend
> unconditionally reports FEATURE_NOT_SUPPORTED.
>
> I suppose this needs to be back-patched.

Thanks for taking care of this and the missing .gitignore entries as well.

Just to make a correction to what I said upthread in reply to Andrew,
it seems like I did get the WARNING but missed it.

Wonder if, for consistency, I should change the coding so that the
FEATURE_NOT_SUPPORTED is reported in transformJsonTable() or
something?

--
Thanks, Amit Langote



Re: pgsql: Add basic JSON_TABLE() functionality

От
Tom Lane
Дата:
Amit Langote <amitlangote09@gmail.com> writes:
> Wonder if, for consistency, I should change the coding so that the
> FEATURE_NOT_SUPPORTED is reported in transformJsonTable() or
> something?

Consistency with what?  There are plenty of other gram.y productions
that throw FEATURE_NOT_SUPPORTED conditionally.

            regards, tom lane



Re: pgsql: Add basic JSON_TABLE() functionality

От
Amit Langote
Дата:
On Fri, Apr 5, 2024 at 11:56 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Amit Langote <amitlangote09@gmail.com> writes:
> > Wonder if, for consistency, I should change the coding so that the
> > FEATURE_NOT_SUPPORTED is reported in transformJsonTable() or
> > something?
>
> Consistency with what?  There are plenty of other gram.y productions
> that throw FEATURE_NOT_SUPPORTED conditionally.

Ah, yes, I see.  I thought maybe not when I read "unconventional use
of" in your first email.

--
Thanks, Amit Langote



Re: pgsql: Add basic JSON_TABLE() functionality

От
Tom Lane
Дата:
Amit Langote <amitlangote09@gmail.com> writes:
> On Fri, Apr 5, 2024 at 11:56 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Consistency with what?  There are plenty of other gram.y productions
>> that throw FEATURE_NOT_SUPPORTED conditionally.

> Ah, yes, I see.  I thought maybe not when I read "unconventional use
> of" in your first email.

That was my first guess before I'd looked at any of the code,
but really the json_table production isn't doing anything
unusual.

            regards, tom lane