diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index c3c7aa29720..f1003e57fb2 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -3826,6 +3826,7 @@ transformJsonArrayQueryConstructor(ParseState *pstate, CoalesceExpr *coalesce; Const *empty_const; Oid result_type; + int32 result_typmod; Oid typinput; Oid typioparam; int16 typlen; @@ -3904,19 +3905,22 @@ transformJsonArrayQueryConstructor(ParseState *pstate, /* * Wrap in COALESCE so that an empty result set produces '[]' rather than - * NULL. The empty-array constant is created in the output type so that - * the COALESCE arguments have consistent types. + * NULL. The empty-array constant is created in the output type and + * typmod, so that the COALESCE arguments have consistent types and any + * length restriction from the RETURNING clause is enforced uniformly + * across the empty and non-empty paths. */ result_type = exprType(exec_expr); + result_typmod = exprTypmod(exec_expr); getTypeInputInfo(result_type, &typinput, &typioparam); get_typlenbyval(result_type, &typlen, &typbyval); empty_const = makeConst(result_type, - -1, + result_typmod, exprCollation(exec_expr), (int) typlen, OidInputFunctionCall(typinput, "[]", - typioparam, -1), + typioparam, result_typmod), false, typbyval); diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out index a14936a4e6e..143d961c077 100644 --- a/src/test/regress/expected/sqljson.out +++ b/src/test/regress/expected/sqljson.out @@ -783,6 +783,25 @@ WHERE JSON_ARRAY( 4 (2 rows) +-- JSON_ARRAY(subquery) RETURNING with a length-restricted output type +-- Should fail +SELECT JSON_ARRAY(SELECT 1 RETURNING varchar(1)); +ERROR: value too long for type character varying(1) +SELECT JSON_ARRAY(SELECT 1 WHERE FALSE RETURNING varchar(1)); +ERROR: value too long for type character varying(1) +-- Should work +SELECT JSON_ARRAY(SELECT 1 RETURNING varchar(3)); + json_array +------------ + [1] +(1 row) + +SELECT JSON_ARRAY(SELECT 1 WHERE FALSE RETURNING varchar(2)); + json_array +------------ + [] +(1 row) + -- Should fail SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); ERROR: subquery must return only one column diff --git a/src/test/regress/sql/sqljson.sql b/src/test/regress/sql/sqljson.sql index 00ecf6161bf..ed044d81fdd 100644 --- a/src/test/regress/sql/sqljson.sql +++ b/src/test/regress/sql/sqljson.sql @@ -213,6 +213,14 @@ WHERE JSON_ARRAY( RETURNING jsonb ) = '[]'::jsonb; +-- JSON_ARRAY(subquery) RETURNING with a length-restricted output type +-- Should fail +SELECT JSON_ARRAY(SELECT 1 RETURNING varchar(1)); +SELECT JSON_ARRAY(SELECT 1 WHERE FALSE RETURNING varchar(1)); +-- Should work +SELECT JSON_ARRAY(SELECT 1 RETURNING varchar(3)); +SELECT JSON_ARRAY(SELECT 1 WHERE FALSE RETURNING varchar(2)); + -- Should fail SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i)); SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));