Skip to content

Commit aff8ccf

Browse files
author
Nikita Glukhov
committed
Fix JSON_VALUE coercion via IO
1 parent 29f710c commit aff8ccf

File tree

3 files changed

+39
-28
lines changed

3 files changed

+39
-28
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4725,26 +4725,44 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
47254725
op->d.jsonexpr.args);
47264726
struct JsonCoercionState *jcstate;
47274727

4728-
if (!jbv)
4728+
if (!jbv) /* NULL or empty */
47294729
break;
47304730

4731+
Assert(!empty);
4732+
47314733
*resnull = false;
47324734

4735+
/* coerce item datum to the output type */
4736+
if (jexpr->returning->typid == JSONOID ||
4737+
jexpr->returning->typid == JSONBOID)
4738+
{
4739+
/* Use result coercion from json[b] to the output type */
4740+
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4741+
break;
4742+
}
4743+
4744+
/* Use coercion from SQL/JSON item type to the output type */
47334745
res = ExecPrepareJsonItemCoercion(jbv,
47344746
op->d.jsonexpr.jsexpr->returning,
47354747
&op->d.jsonexpr.coercions,
47364748
&jcstate);
47374749

4738-
/* coerce item datum to the output type */
4739-
if ((jcstate->coercion &&
4750+
if (jcstate->coercion &&
47404751
(jcstate->coercion->via_io ||
4741-
jcstate->coercion->via_populate)) || /* ignored for scalars jsons */
4742-
jexpr->returning->typid == JSONOID ||
4743-
jexpr->returning->typid == JSONBOID)
4752+
jcstate->coercion->via_populate))
47444753
{
4745-
/* use coercion via I/O from json[b] to the output type */
4746-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4747-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4754+
/*
4755+
* Coercion via I/O means here that the cast to the target
4756+
* type simply does not exist.
4757+
*/
4758+
ereport(ERROR,
4759+
/*
4760+
* XXX Standard says about a separate error code
4761+
* ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE
4762+
* but does not define its number.
4763+
*/
4764+
(errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED),
4765+
errmsg("SQL/JSON item cannot be cast to target type")));
47484766
}
47494767
else if (jcstate->estate)
47504768
{
@@ -4754,17 +4772,16 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
47544772
res = ExecEvalExpr(jcstate->estate, econtext, resnull);
47554773
}
47564774
/* else no coercion */
4775+
4776+
return res;
47574777
}
4758-
break;
47594778

47604779
case IS_JSON_EXISTS:
4761-
res = BoolGetDatum(JsonbPathExists(item, path, op->d.jsonexpr.args));
47624780
*resnull = false;
4763-
break;
4781+
return BoolGetDatum(JsonbPathExists(item, path, op->d.jsonexpr.args));
47644782

47654783
default:
4766-
elog(ERROR, "unrecognized SQL/JSON expression op %d",
4767-
jexpr->op);
4784+
elog(ERROR, "unrecognized SQL/JSON expression op %d", jexpr->op);
47684785
return (Datum) 0;
47694786
}
47704787

@@ -4780,15 +4797,13 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
47804797
/* execute ON EMPTY behavior */
47814798
res = ExecEvalJsonBehavior(econtext, jexpr->on_empty,
47824799
op->d.jsonexpr.default_on_empty, resnull);
4783-
}
47844800

4785-
if (jexpr->op != IS_JSON_EXISTS &&
4786-
(!empty ? jexpr->op != IS_JSON_VALUE :
4787-
/* result is already coerced in DEFAULT behavior case */
4788-
jexpr->on_empty->btype != JSON_BEHAVIOR_DEFAULT))
4789-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4801+
/* result is already coerced in DEFAULT behavior case */
4802+
if (jexpr->on_empty->btype == JSON_BEHAVIOR_DEFAULT)
4803+
return res;
4804+
}
47904805

4791-
return res;
4806+
return ExecEvalJsonExprCoercion(op, econtext, res, resnull);
47924807
}
47934808

47944809
bool

src/test/regress/expected/jsonb_sqljson.out

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,8 @@ SELECT JSON_VALUE(jsonb '123', '$' RETURNING text);
190190
(1 row)
191191

192192
/* jsonb bytea ??? */
193-
SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea);
194-
json_value
195-
------------
196-
\x313233
197-
(1 row)
198-
193+
SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR);
194+
ERROR: SQL/JSON item cannot be cast to target type
199195
SELECT JSON_VALUE(jsonb '1.23', '$');
200196
json_value
201197
------------

src/test/regress/sql/jsonb_sqljson.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ SELECT JSON_VALUE(jsonb '123', '$');
4646
SELECT JSON_VALUE(jsonb '123', '$' RETURNING int) + 234;
4747
SELECT JSON_VALUE(jsonb '123', '$' RETURNING text);
4848
/* jsonb bytea ??? */
49-
SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea);
49+
SELECT JSON_VALUE(jsonb '123', '$' RETURNING bytea ERROR ON ERROR);
5050

5151
SELECT JSON_VALUE(jsonb '1.23', '$');
5252
SELECT JSON_VALUE(jsonb '1.23', '$' RETURNING int);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy