1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Revert cascading of JSON_TABLE's ON ERROR

86ab7f4c72 commit made the table-level ON ERROR clause serve as the default
ON ERROR for columns lacking their own, so that a top-level ERROR ON ERROR
turned per-column evaluation errors into hard errors.

The SQL standard does mandate this cascade, but introducing it should be
a deliberate, separately-documented change, so restore the previous
behavior for now.  This also reverts the paired ruleutils.c logic that
deparsed a column's behavior against an ERROR default: that dropped an
explicit ERROR ON EMPTY from a dumped view, and otherwise emitted a
redundant NULL ON EMPTY.

Reported-by: Thom Brown <thom@linux.com>
Discussion: https://postgr.es/m/CAA-aLv7aZGSExnbjJRw8eKkoXbu34TdoKLLA2gPye3aHjO5OSA@mail.gmail.com
This commit is contained in:
Alexander Korotkov
2026-07-15 00:46:40 +03:00
parent d15a6bc2e1
commit af6fad879f
4 changed files with 44 additions and 15 deletions

View File

@@ -49,8 +49,7 @@ static JsonTablePlan *transformJsonTableNestedColumns(JsonTableParseContext *cxt
List *columns);
static JsonFuncExpr *transformJsonTableColumn(JsonTableColumn *jtc,
Node *contextItemExpr,
List *passingArgs,
bool errorOnError);
List *passingArgs);
static bool isCompositeType(Oid typid);
static JsonTablePlan *makeJsonTablePathScan(JsonTableParseContext *cxt,
JsonTablePathSpec *pathspec,
@@ -363,12 +362,8 @@ appendJsonTableColumns(JsonTableParseContext *cxt, List *columns, List *passingA
{
ListCell *col;
ParseState *pstate = cxt->pstate;
JsonTable *jt = cxt->jt;
TableFunc *tf = cxt->tf;
bool ordinality_found = false;
JsonBehavior *on_error = jt->on_error;
bool errorOnError = on_error &&
on_error->btype == JSON_BEHAVIOR_ERROR;
Oid contextItemTypid = exprType(tf->docexpr);
foreach(col, columns)
@@ -427,7 +422,7 @@ appendJsonTableColumns(JsonTableParseContext *cxt, List *columns, List *passingA
param->typeMod = -1;
jfe = transformJsonTableColumn(rawc, (Node *) param,
passingArgs, errorOnError);
passingArgs);
colexpr = transformExpr(pstate, (Node *) jfe,
EXPR_KIND_FROM_FUNCTION);
@@ -482,7 +477,7 @@ isCompositeType(Oid typid)
*/
static JsonFuncExpr *
transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
List *passingArgs, bool errorOnError)
List *passingArgs)
{
Node *pathspec;
JsonFuncExpr *jfexpr = makeNode(JsonFuncExpr);
@@ -524,8 +519,6 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
jfexpr->output->returning->format = jtc->format;
jfexpr->on_empty = jtc->on_empty;
jfexpr->on_error = jtc->on_error;
if (jfexpr->on_error == NULL && errorOnError)
jfexpr->on_error = makeJsonBehavior(JSON_BEHAVIOR_ERROR, NULL, -1);
jfexpr->quotes = jtc->quotes;
jfexpr->wrapper = jtc->wrapper;
jfexpr->location = jtc->location;

View File

@@ -12799,7 +12799,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;
@@ -12879,9 +12878,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);

View File

@@ -547,6 +547,15 @@ SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR O
ERROR: jsonpath member accessor can only be applied to an object
SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
ERROR: no SQL/JSON item found for specified path of column "a"
-- Table-level ERROR ON ERROR is not propagated to a column lacking its own
-- ON ERROR clause: the column keeps the default NULL ON ERROR behavior, so a
-- conversion failure yields NULL rather than raising an error.
SELECT * FROM JSON_TABLE(jsonb '"err"', '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt;
a
---
(1 row)
SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
a
---
@@ -1821,7 +1830,7 @@ CREATE OR REPLACE VIEW public.json_table_view9 AS
FROM JSON_TABLE(
'"a"'::text, '$' AS json_table_path_0
COLUMNS (
a text PATH '$' NULL ON EMPTY
a text PATH '$'
) ERROR ON ERROR
)
DROP VIEW json_table_view8, json_table_view9;
@@ -1847,3 +1856,19 @@ CREATE OR REPLACE VIEW public.json_table_view9 AS
)
)
DROP VIEW json_table_view8, json_table_view9;
-- Test JSON_TABLE() column deparsing -- a non-default ON EMPTY behavior of a
-- column must be preserved
CREATE VIEW json_table_view_on_empty AS
SELECT * FROM JSON_TABLE(jsonb '{}', '$' AS p0
COLUMNS (a int PATH '$.nosuch' ERROR ON EMPTY)
ERROR ON ERROR);
\sv json_table_view_on_empty;
CREATE OR REPLACE VIEW public.json_table_view_on_empty AS
SELECT a
FROM JSON_TABLE(
'{}'::jsonb, '$' AS p0
COLUMNS (
a integer PATH '$."nosuch"' ERROR ON EMPTY
) ERROR ON ERROR
)
DROP VIEW json_table_view_on_empty;

View File

@@ -266,6 +266,11 @@ SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH '$.a' ERROR ON EMPTY
SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'strict $.a' ERROR ON ERROR) ERROR ON ERROR) jt;
SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (a int PATH 'lax $.a' ERROR ON EMPTY) ERROR ON ERROR) jt;
-- Table-level ERROR ON ERROR is not propagated to a column lacking its own
-- ON ERROR clause: the column keeps the default NULL ON ERROR behavior, so a
-- conversion failure yields NULL rather than raising an error.
SELECT * FROM JSON_TABLE(jsonb '"err"', '$' COLUMNS (a int PATH '$') ERROR ON ERROR) jt;
SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH '$' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'strict $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
SELECT * FROM JSON_TABLE(jsonb '"a"', '$' COLUMNS (a int PATH 'lax $.a' DEFAULT 1 ON EMPTY DEFAULT 2 ON ERROR)) jt;
@@ -1004,3 +1009,13 @@ CREATE VIEW json_table_view9 AS SELECT * from JSON_TABLE('"a"', '$' COLUMNS (a t
\sv json_table_view9;
DROP VIEW json_table_view8, json_table_view9;
-- Test JSON_TABLE() column deparsing -- a non-default ON EMPTY behavior of a
-- column must be preserved
CREATE VIEW json_table_view_on_empty AS
SELECT * FROM JSON_TABLE(jsonb '{}', '$' AS p0
COLUMNS (a int PATH '$.nosuch' ERROR ON EMPTY)
ERROR ON ERROR);
\sv json_table_view_on_empty;
DROP VIEW json_table_view_on_empty;