From 68222851d5a8d2ca152a97ee69fe18a95970ed20 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Fri, 6 Sep 2024 10:12:16 +0900 Subject: [PATCH] SQL/JSON: Fix JSON_TABLE() column deparsing The deparsing code in get_json_expr_options() unnecessarily emitted the default column-specific ON ERROR / EMPTY behavior when the top-level ON ERROR behavior in JSON_TABLE was set to ERROR. Fix that by not overriding the column-specific default, determined based on the column's JsonExprOp in get_json_table_columns(), with JSON_BEHAVIOR_ERROR when that is the top-level ON ERROR behavior. Note that this only removes redundancy; the current deparsing output is not incorrect, just redundant. Reviewed-by: Jian He Discussion: https://postgr.es/m/CACJufxEo4sUjKCYtda0_qt9tazqqKPmF1cqhW9KBOUeJFqQd2g@mail.gmail.com Backpatch-through: 17 --- src/backend/utils/adt/ruleutils.c | 8 ++++---- .../regress/expected/sqljson_jsontable.out | 18 ++++++++++++++++++ src/test/regress/sql/sqljson_jsontable.sql | 5 +++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index b31be31321d..371b46e7a2d 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -11719,7 +11719,6 @@ get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, bool showimplicit) { StringInfo buf = context->buf; - JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr); ListCell *lc_colname; ListCell *lc_coltype; ListCell *lc_coltypmod; @@ -11772,6 +11771,10 @@ get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, if (ordinality) continue; + /* + * Set default_behavior to guide get_json_expr_options() on whether to + * to emit the ON ERROR / EMPTY clauses. + */ if (colexpr->op == JSON_EXISTS_OP) { appendStringInfoString(buf, " EXISTS"); @@ -11795,9 +11798,6 @@ get_json_table_columns(TableFunc *tf, JsonTablePathScan *scan, default_behavior = JSON_BEHAVIOR_NULL; } - if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR) - default_behavior = JSON_BEHAVIOR_ERROR; - appendStringInfoString(buf, " PATH "); get_json_path_spec(colexpr->path_spec, context, showimplicit); diff --git a/src/test/regress/expected/sqljson_jsontable.out b/src/test/regress/expected/sqljson_jsontable.out index 721e01d6ad0..ebfde38a056 100644 --- a/src/test/regress/expected/sqljson_jsontable.out +++ b/src/test/regress/expected/sqljson_jsontable.out @@ -1132,3 +1132,21 @@ ERROR: invalid ON ERROR behavior for column "a" LINE 1: ...M JSON_TABLE(jsonb '1', '$' COLUMNS (a int exists empty obje... ^ DETAIL: Only ERROR, TRUE, FALSE, or UNKNOWN is allowed in ON ERROR for EXISTS columns. +-- Test JSON_TABLE() column deparsing -- don't emit default ON ERROR / EMPTY +-- behavior +EXPLAIN VERBOSE SELECT * from JSON_TABLE('"a"', '$' COLUMNS (a text PATH '$')); + QUERY PLAN +----------------------------------------------------------------------------------------------------- + Table Function Scan on "json_table" (cost=0.01..1.00 rows=100 width=32) + Output: a + Table Function Call: JSON_TABLE('"a"'::jsonb, '$' AS json_table_path_0 COLUMNS (a text PATH '$')) +(3 rows) + +EXPLAIN VERBOSE SELECT * from JSON_TABLE('"a"', '$' COLUMNS (a text PATH '$') ERROR ON ERROR); + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------- + Table Function Scan on "json_table" (cost=0.01..1.00 rows=100 width=32) + Output: a + Table Function Call: JSON_TABLE('"a"'::jsonb, '$' AS json_table_path_0 COLUMNS (a text PATH '$') ERROR ON ERROR) +(3 rows) + diff --git a/src/test/regress/sql/sqljson_jsontable.sql b/src/test/regress/sql/sqljson_jsontable.sql index 38992316f5a..c9408878926 100644 --- a/src/test/regress/sql/sqljson_jsontable.sql +++ b/src/test/regress/sql/sqljson_jsontable.sql @@ -542,3 +542,8 @@ SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int) NULL ON ERROR); SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int true on empty)); SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int omit quotes true on error)); SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int exists empty object on error)); + +-- Test JSON_TABLE() column deparsing -- don't emit default ON ERROR / EMPTY +-- behavior +EXPLAIN VERBOSE SELECT * from JSON_TABLE('"a"', '$' COLUMNS (a text PATH '$')); +EXPLAIN VERBOSE SELECT * from JSON_TABLE('"a"', '$' COLUMNS (a text PATH '$') ERROR ON ERROR);