@@ -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
18611861JsonbExtractScalar (JsonbContainer * jbc ,JsonbValue * res )
18621862{
18631863JsonbIterator * it ;
18641864JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY ;
18651865JsonbValue tmp ;
18661866
18671867if (!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)
18871891tok = JsonbIteratorNext (& it ,& tmp , true);
18881892Assert (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
18931930Datum
@@ -1897,9 +1934,7 @@ jsonb_bool(PG_FUNCTION_ARGS)
18971934JsonbValue v ;
18981935
18991936if (!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
19041939PG_FREE_IF_COPY (in ,0 );
19051940
@@ -1914,9 +1949,7 @@ jsonb_numeric(PG_FUNCTION_ARGS)
19141949Numeric retValue ;
19151950
19161951if (!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)
19371970Datum retValue ;
19381971
19391972if (!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
19441975retValue = DirectFunctionCall1 (numeric_int2 ,
19451976NumericGetDatum (v .val .numeric ));
@@ -1957,9 +1988,7 @@ jsonb_int4(PG_FUNCTION_ARGS)
19571988Datum retValue ;
19581989
19591990if (!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
19641993retValue = DirectFunctionCall1 (numeric_int4 ,
19651994NumericGetDatum (v .val .numeric ));
@@ -1977,9 +2006,7 @@ jsonb_int8(PG_FUNCTION_ARGS)
19772006Datum retValue ;
19782007
19792008if (!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
19842011retValue = DirectFunctionCall1 (numeric_int8 ,
19852012NumericGetDatum (v .val .numeric ));
@@ -1997,9 +2024,7 @@ jsonb_float4(PG_FUNCTION_ARGS)
19972024Datum retValue ;
19982025
19992026if (!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
20042029retValue = DirectFunctionCall1 (numeric_float4 ,
20052030NumericGetDatum (v .val .numeric ));
@@ -2017,9 +2042,7 @@ jsonb_float8(PG_FUNCTION_ARGS)
20172042Datum retValue ;
20182043
20192044if (!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
20242047retValue = DirectFunctionCall1 (numeric_float8 ,
20252048NumericGetDatum (v .val .numeric ));