From c88047f7fb45363e836aef0eb2422099106e544b Mon Sep 17 00:00:00 2001 From: Alexandra Wang Date: Mon, 10 Mar 2025 07:00:03 -0500 Subject: [PATCH v11 8/8] Add "**" as a new token in scanners DOUBLE_ASTERISK is now recognized but not yet implemented. This change improves error message readability, as "**" is supported in jsonpath_scan.l as ANY_P. However, the SQL standard for simplified JSON accessors does not specify "**", so it is not supported in that context. --- src/backend/parser/gram.y | 9 ++++++++- src/backend/parser/scan.l | 6 ++++++ src/include/parser/scanner.h | 2 +- src/interfaces/ecpg/preproc/pgc.l | 5 +++++ src/interfaces/ecpg/test/expected/sql-sqljson.c | 12 +++++++++++- src/interfaces/ecpg/test/expected/sql-sqljson.stderr | 11 +++++++++++ src/interfaces/ecpg/test/sql/sqljson.pgc | 3 +++ src/pl/plpgsql/src/pl_gram.y | 2 +- src/test/regress/expected/jsonb.out | 2 +- 9 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 44840bc1b25..4635616d93a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -687,7 +687,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %token IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op %token ICONST PARAM -%token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER +%token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER DOUBLE_ASTERISK %token LESS_EQUALS GREATER_EQUALS NOT_EQUALS /* @@ -16969,6 +16969,13 @@ indirection_el: { $$ = (Node *) makeNode(A_Star); } + | '.' DOUBLE_ASTERISK + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("arbitrary depth wild card in simple json accessor not supported"), + parser_errposition(@2))); + } | '[' a_expr ']' { A_Indices *ai = makeNode(A_Indices); diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index 08990831fe8..c58ba233153 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -338,6 +338,7 @@ identifier {ident_start}{ident_cont}* typecast "::" dot_dot \.\. colon_equals ":=" +double_asterisk "**" /* * These operator-like tokens (unlike the above ones) also match the {operator} @@ -851,6 +852,11 @@ other . return COLON_EQUALS; } +{double_asterisk} { + SET_YYLLOC(); + return DOUBLE_ASTERISK; + } + {equals_greater} { SET_YYLLOC(); return EQUALS_GREATER; diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index 74ad86698ac..2f9b7baa1a9 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -50,7 +50,7 @@ typedef union core_YYSTYPE * the ASCII characters plus these: * %token IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op * %token ICONST PARAM - * %token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER + * %token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER DOUBLE_ASTERISK * %token LESS_EQUALS GREATER_EQUALS NOT_EQUALS * The above token definitions *must* be the first ones declared in any * bison parser built atop this scanner, so that they will have consistent diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 63283a4a1e5..1415cbe2808 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -321,6 +321,7 @@ array ({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])* typecast "::" dot_dot \.\. colon_equals ":=" +double_asterisk "**" /* * These operator-like tokens (unlike the above ones) also match the {operator} @@ -832,6 +833,10 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ return COLON_EQUALS; } +{double_asterisk} { + return DOUBLE_ASTERISK; + } + {equals_greater} { return EQUALS_GREATER; } diff --git a/src/interfaces/ecpg/test/expected/sql-sqljson.c b/src/interfaces/ecpg/test/expected/sql-sqljson.c index 748b2e2bee6..f772305c209 100644 --- a/src/interfaces/ecpg/test/expected/sql-sqljson.c +++ b/src/interfaces/ecpg/test/expected/sql-sqljson.c @@ -527,12 +527,22 @@ if (sqlca.sqlcode < 0) sqlprint();} printf("Found json=%s\n", json); - { ECPGdisconnect(__LINE__, "CURRENT"); + { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select json ( ( '{\"a\": {\"b\": 1, \"c\": 2}, \"b\": [{\"x\": 1}, {\"x\": [12, {\"y\":1}]}]}' :: jsonb ) . ** . b )", ECPGt_EOIT, + ECPGt_char,(json),(long)1024,(long)1,(1024)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); #line 151 "sqljson.pgc" if (sqlca.sqlcode < 0) sqlprint();} #line 151 "sqljson.pgc" + // error + + { ECPGdisconnect(__LINE__, "CURRENT"); +#line 154 "sqljson.pgc" + +if (sqlca.sqlcode < 0) sqlprint();} +#line 154 "sqljson.pgc" + return 0; } diff --git a/src/interfaces/ecpg/test/expected/sql-sqljson.stderr b/src/interfaces/ecpg/test/expected/sql-sqljson.stderr index 92c5d1520c4..d9a2fe21915 100644 --- a/src/interfaces/ecpg/test/expected/sql-sqljson.stderr +++ b/src/interfaces/ecpg/test/expected/sql-sqljson.stderr @@ -359,5 +359,16 @@ SQL error: schema "jsonb" does not exist on line 121 [NO_PID]: sqlca: code: 0, state: 00000 [NO_PID]: ecpg_get_data on line 148: RESULT: [1, [12, {"y": 1}]] offset: -1; array: no [NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 151: query: select json ( ( '{"a": {"b": 1, "c": 2}, "b": [{"x": 1}, {"x": [12, {"y":1}]}]}' :: jsonb ) . ** . b ); with 0 parameter(s) on connection ecpg1_regression +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_execute on line 151: using PQexec +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: ecpg_check_PQresult on line 151: bad response - ERROR: arbitrary depth wild card in simple json accessor not supported +LINE 1: ...b": [{"x": 1}, {"x": [12, {"y":1}]}]}' :: jsonb ) . ** . b ) + ^ +[NO_PID]: sqlca: code: 0, state: 00000 +[NO_PID]: raising sqlstate 0A000 (sqlcode -400): arbitrary depth wild card in simple json accessor not supported on line 151 +[NO_PID]: sqlca: code: -400, state: 0A000 +SQL error: arbitrary depth wild card in simple json accessor not supported on line 151 [NO_PID]: ecpg_finish: connection ecpg1_regression closed [NO_PID]: sqlca: code: 0, state: 00000 diff --git a/src/interfaces/ecpg/test/sql/sqljson.pgc b/src/interfaces/ecpg/test/sql/sqljson.pgc index 4e7427d237d..65443d30055 100644 --- a/src/interfaces/ecpg/test/sql/sqljson.pgc +++ b/src/interfaces/ecpg/test/sql/sqljson.pgc @@ -148,6 +148,9 @@ EXEC SQL END DECLARE SECTION; EXEC SQL SELECT JSON(('{"a": {"b": 1, "c": 2}, "b": [{"x": 1}, {"x": [12, {"y":1}]}]}'::jsonb).*.x) INTO :json; printf("Found json=%s\n", json); + EXEC SQL SELECT JSON(('{"a": {"b": 1, "c": 2}, "b": [{"x": 1}, {"x": [12, {"y":1}]}]}'::jsonb).**.b) INTO :json; + // error + EXEC SQL DISCONNECT; return 0; diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 5612e66d023..13e06ad5b0b 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -245,7 +245,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); */ %token IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op %token ICONST PARAM -%token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER +%token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER DOUBLE_ASTERISK %token LESS_EQUALS GREATER_EQUALS NOT_EQUALS /* diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 1a9452937d5..0729d7251c6 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -6181,7 +6181,7 @@ SELECT (jb).a.b.c.* FROM test_jsonb_dot_notation; (1 row) SELECT (jb).a.**.x FROM test_jsonb_dot_notation; -- not supported -ERROR: syntax error at or near "**" +ERROR: arbitrary depth wild card in simple json accessor not supported LINE 1: SELECT (jb).a.**.x FROM test_jsonb_dot_notation; ^ -- explains should work -- 2.39.5 (Apple Git-154)