Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cb5d942

Browse files
committed
Improve jsonb cast error message
Initial variant of error message didn't follow style of another casting error messages and wasn't informative. Per gripe from Robert Haas. Reviewer: Tom Lane Discussion: https://www.postgresql.org/message-id/flat/CA%2BTgmob08StTV9yu04D0idRFNMh%2BUoyKax5Otvrix7rEZC8rMw%40mail.gmail.com#CA+Tgmob08StTV9yu04D0idRFNMh+UoyKax5Otvrix7rEZC8rMw@mail.gmail.com
1 parent c63913c commit cb5d942

File tree

2 files changed

+51
-28
lines changed

2 files changed

+51
-28
lines changed

src/backend/utils/adt/jsonb.c

+47-24
Original file line numberDiff line numberDiff line change
@@ -1857,15 +1857,19 @@ jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
18571857
/*
18581858
* Extract scalar value from raw-scalar pseudo-array jsonb.
18591859
*/
1860-
static JsonbValue *
1860+
static bool
18611861
JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
18621862
{
18631863
JsonbIterator *it;
18641864
JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
18651865
JsonbValue tmp;
18661866

18671867
if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
1868-
return NULL;
1868+
{
1869+
/* inform caller about actual type of container */
1870+
res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
1871+
return false;
1872+
}
18691873

18701874
/*
18711875
* A root scalar is stored as an array of one element, so we get the array
@@ -1887,7 +1891,40 @@ JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
18871891
tok = JsonbIteratorNext(&it, &tmp, true);
18881892
Assert(tok == WJB_DONE);
18891893

1890-
return res;
1894+
return true;
1895+
}
1896+
1897+
/*
1898+
* Emit correct, translatable cast error message
1899+
*/
1900+
static void
1901+
cannotCastJsonbValue(enum jbvType type, const char *sqltype)
1902+
{
1903+
static const struct
1904+
{
1905+
enum jbvType type;
1906+
const char *msg;
1907+
}
1908+
messages[] =
1909+
{
1910+
{ jbvNull, gettext_noop("cannot cast jsonb null to type %s") },
1911+
{ jbvString, gettext_noop("cannot cast jsonb string to type %s") },
1912+
{ jbvNumeric, gettext_noop("cannot cast jsonb numeric to type %s") },
1913+
{ jbvBool, gettext_noop("cannot cast jsonb boolean to type %s") },
1914+
{ jbvArray, gettext_noop("cannot cast jsonb array to type %s") },
1915+
{ jbvObject, gettext_noop("cannot cast jsonb object to type %s") },
1916+
{ jbvBinary, gettext_noop("cannot cast jsonb array or object to type %s") }
1917+
};
1918+
int i;
1919+
1920+
for(i=0; i<lengthof(messages); i++)
1921+
if (messages[i].type == type)
1922+
ereport(ERROR,
1923+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1924+
errmsg(messages[i].msg, sqltype)));
1925+
1926+
/* should be unreachable */
1927+
elog(ERROR, "unknown jsonb type: %d", (int)type);
18911928
}
18921929

18931930
Datum
@@ -1897,9 +1934,7 @@ jsonb_bool(PG_FUNCTION_ARGS)
18971934
JsonbValue v;
18981935

18991936
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvBool)
1900-
ereport(ERROR,
1901-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1902-
errmsg("jsonb value must be boolean")));
1937+
cannotCastJsonbValue(v.type, "boolean");
19031938

19041939
PG_FREE_IF_COPY(in, 0);
19051940

@@ -1914,9 +1949,7 @@ jsonb_numeric(PG_FUNCTION_ARGS)
19141949
Numeric retValue;
19151950

19161951
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1917-
ereport(ERROR,
1918-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1919-
errmsg("jsonb value must be numeric")));
1952+
cannotCastJsonbValue(v.type, "numeric");
19201953

19211954
/*
19221955
* v.val.numeric points into jsonb body, so we need to make a copy to
@@ -1937,9 +1970,7 @@ jsonb_int2(PG_FUNCTION_ARGS)
19371970
Datum retValue;
19381971

19391972
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1940-
ereport(ERROR,
1941-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1942-
errmsg("jsonb value must be numeric")));
1973+
cannotCastJsonbValue(v.type, "smallint");
19431974

19441975
retValue = DirectFunctionCall1(numeric_int2,
19451976
NumericGetDatum(v.val.numeric));
@@ -1957,9 +1988,7 @@ jsonb_int4(PG_FUNCTION_ARGS)
19571988
Datum retValue;
19581989

19591990
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1960-
ereport(ERROR,
1961-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1962-
errmsg("jsonb value must be numeric")));
1991+
cannotCastJsonbValue(v.type, "integer");
19631992

19641993
retValue = DirectFunctionCall1(numeric_int4,
19651994
NumericGetDatum(v.val.numeric));
@@ -1977,9 +2006,7 @@ jsonb_int8(PG_FUNCTION_ARGS)
19772006
Datum retValue;
19782007

19792008
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1980-
ereport(ERROR,
1981-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1982-
errmsg("jsonb value must be numeric")));
2009+
cannotCastJsonbValue(v.type, "bigint");
19832010

19842011
retValue = DirectFunctionCall1(numeric_int8,
19852012
NumericGetDatum(v.val.numeric));
@@ -1997,9 +2024,7 @@ jsonb_float4(PG_FUNCTION_ARGS)
19972024
Datum retValue;
19982025

19992026
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2000-
ereport(ERROR,
2001-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2002-
errmsg("jsonb value must be numeric")));
2027+
cannotCastJsonbValue(v.type, "real");
20032028

20042029
retValue = DirectFunctionCall1(numeric_float4,
20052030
NumericGetDatum(v.val.numeric));
@@ -2017,9 +2042,7 @@ jsonb_float8(PG_FUNCTION_ARGS)
20172042
Datum retValue;
20182043

20192044
if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2020-
ereport(ERROR,
2021-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2022-
errmsg("jsonb value must be numeric")));
2045+
cannotCastJsonbValue(v.type, "double precision");
20232046

20242047
retValue = DirectFunctionCall1(numeric_float8,
20252048
NumericGetDatum(v.val.numeric));

src/test/regress/expected/jsonb.out

+4-4
Original file line numberDiff line numberDiff line change
@@ -4321,31 +4321,31 @@ select 'true'::jsonb::bool;
43214321
(1 row)
43224322

43234323
select '[]'::jsonb::bool;
4324-
ERROR: jsonb value must be boolean
4324+
ERROR: cannot cast jsonb array to type boolean
43254325
select '1.0'::jsonb::float;
43264326
float8
43274327
--------
43284328
1
43294329
(1 row)
43304330

43314331
select '[1.0]'::jsonb::float;
4332-
ERROR: jsonb value must be numeric
4332+
ERROR: cannot cast jsonb array to type double precision
43334333
select '12345'::jsonb::int4;
43344334
int4
43354335
-------
43364336
12345
43374337
(1 row)
43384338

43394339
select '"hello"'::jsonb::int4;
4340-
ERROR: jsonb value must be numeric
4340+
ERROR: cannot cast jsonb string to type integer
43414341
select '12345'::jsonb::numeric;
43424342
numeric
43434343
---------
43444344
12345
43454345
(1 row)
43464346

43474347
select '{}'::jsonb::numeric;
4348-
ERROR: jsonb value must be numeric
4348+
ERROR: cannot cast jsonb object to type numeric
43494349
select '12345.05'::jsonb::numeric;
43504350
numeric
43514351
----------

0 commit comments

Comments
 (0)