@@ -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{
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
18931930Datum
@@ -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 ));
0 commit comments