@@ -33,6 +33,7 @@ typedef struct JsonbInState
33
33
{
34
34
JsonbParseState * parseState ;
35
35
JsonbValue * res ;
36
+ Node * escontext ;
36
37
} JsonbInState ;
37
38
38
39
/* unlike with json categories, we need to treat json and jsonb differently */
@@ -61,8 +62,8 @@ typedef struct JsonbAggState
61
62
Oid val_output_func ;
62
63
} JsonbAggState ;
63
64
64
- static inline Datum jsonb_from_cstring (char * json , int len );
65
- static size_t checkStringLen (size_t len );
65
+ static inline Datum jsonb_from_cstring (char * json , int len , Node * escontext );
66
+ static bool checkStringLen (size_t len , Node * escontext );
66
67
static JsonParseErrorType jsonb_in_object_start (void * pstate );
67
68
static JsonParseErrorType jsonb_in_object_end (void * pstate );
68
69
static JsonParseErrorType jsonb_in_array_start (void * pstate );
@@ -98,7 +99,7 @@ jsonb_in(PG_FUNCTION_ARGS)
98
99
{
99
100
char * json = PG_GETARG_CSTRING (0 );
100
101
101
- return jsonb_from_cstring (json , strlen (json ));
102
+ return jsonb_from_cstring (json , strlen (json ), fcinfo -> context );
102
103
}
103
104
104
105
/*
@@ -122,7 +123,7 @@ jsonb_recv(PG_FUNCTION_ARGS)
122
123
else
123
124
elog (ERROR , "unsupported jsonb version number %d" , version );
124
125
125
- return jsonb_from_cstring (str , nbytes );
126
+ return jsonb_from_cstring (str , nbytes , NULL );
126
127
}
127
128
128
129
/*
@@ -251,9 +252,12 @@ jsonb_typeof(PG_FUNCTION_ARGS)
251
252
* Turns json string into a jsonb Datum.
252
253
*
253
254
* Uses the json parser (with hooks) to construct a jsonb.
255
+ *
256
+ * If escontext points to an ErrorSaveContext, errors are reported there
257
+ * instead of being thrown.
254
258
*/
255
259
static inline Datum
256
- jsonb_from_cstring (char * json , int len )
260
+ jsonb_from_cstring (char * json , int len , Node * escontext )
257
261
{
258
262
JsonLexContext * lex ;
259
263
JsonbInState state ;
@@ -263,6 +267,7 @@ jsonb_from_cstring(char *json, int len)
263
267
memset (& sem , 0 , sizeof (sem ));
264
268
lex = makeJsonLexContextCstringLen (json , len , GetDatabaseEncoding (), true);
265
269
270
+ state .escontext = escontext ;
266
271
sem .semstate = (void * ) & state ;
267
272
268
273
sem .object_start = jsonb_in_object_start ;
@@ -272,23 +277,24 @@ jsonb_from_cstring(char *json, int len)
272
277
sem .scalar = jsonb_in_scalar ;
273
278
sem .object_field_start = jsonb_in_object_field_start ;
274
279
275
- pg_parse_json_or_ereport (lex , & sem );
280
+ if (!pg_parse_json_or_errsave (lex , & sem , escontext ))
281
+ return (Datum ) 0 ;
276
282
277
283
/* after parsing, the item member has the composed jsonb structure */
278
284
PG_RETURN_POINTER (JsonbValueToJsonb (state .res ));
279
285
}
280
286
281
- static size_t
282
- checkStringLen (size_t len )
287
+ static bool
288
+ checkStringLen (size_t len , Node * escontext )
283
289
{
284
290
if (len > JENTRY_OFFLENMASK )
285
- ereport ( ERROR ,
291
+ ereturn ( escontext , false ,
286
292
(errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
287
293
errmsg ("string too long to represent as jsonb string" ),
288
294
errdetail ("Due to an implementation restriction, jsonb strings cannot exceed %d bytes." ,
289
295
JENTRY_OFFLENMASK )));
290
296
291
- return len ;
297
+ return true ;
292
298
}
293
299
294
300
static JsonParseErrorType
@@ -339,7 +345,9 @@ jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
339
345
340
346
Assert (fname != NULL );
341
347
v .type = jbvString ;
342
- v .val .string .len = checkStringLen (strlen (fname ));
348
+ v .val .string .len = strlen (fname );
349
+ if (!checkStringLen (v .val .string .len , _state -> escontext ))
350
+ return JSON_SEM_ACTION_FAILED ;
343
351
v .val .string .val = fname ;
344
352
345
353
_state -> res = pushJsonbValue (& _state -> parseState , WJB_KEY , & v );
@@ -390,7 +398,9 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
390
398
case JSON_TOKEN_STRING :
391
399
Assert (token != NULL );
392
400
v .type = jbvString ;
393
- v .val .string .len = checkStringLen (strlen (token ));
401
+ v .val .string .len = strlen (token );
402
+ if (!checkStringLen (v .val .string .len , _state -> escontext ))
403
+ return JSON_SEM_ACTION_FAILED ;
394
404
v .val .string .val = token ;
395
405
break ;
396
406
case JSON_TOKEN_NUMBER :
@@ -401,10 +411,11 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
401
411
*/
402
412
Assert (token != NULL );
403
413
v .type = jbvNumeric ;
404
- numd = DirectFunctionCall3 (numeric_in ,
405
- CStringGetDatum (token ),
406
- ObjectIdGetDatum (InvalidOid ),
407
- Int32GetDatum (-1 ));
414
+ if (!DirectInputFunctionCallSafe (numeric_in , token ,
415
+ InvalidOid , -1 ,
416
+ _state -> escontext ,
417
+ & numd ))
418
+ return JSON_SEM_ACTION_FAILED ;
408
419
v .val .numeric = DatumGetNumeric (numd );
409
420
break ;
410
421
case JSON_TOKEN_TRUE :
@@ -738,6 +749,9 @@ jsonb_categorize_type(Oid typoid,
738
749
*
739
750
* If key_scalar is true, the value is stored as a key, so insist
740
751
* it's of an acceptable type, and force it to be a jbvString.
752
+ *
753
+ * Note: currently, we assume that result->escontext is NULL and errors
754
+ * will be thrown.
741
755
*/
742
756
static void
743
757
datum_to_jsonb (Datum val , bool is_null , JsonbInState * result ,
@@ -910,7 +924,8 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
910
924
default :
911
925
outputstr = OidOutputFunctionCall (outfuncoid , val );
912
926
jb .type = jbvString ;
913
- jb .val .string .len = checkStringLen (strlen (outputstr ));
927
+ jb .val .string .len = strlen (outputstr );
928
+ (void ) checkStringLen (jb .val .string .len , NULL );
914
929
jb .val .string .val = outputstr ;
915
930
break ;
916
931
}
@@ -1648,6 +1663,7 @@ jsonb_agg_finalfn(PG_FUNCTION_ARGS)
1648
1663
* shallow clone is sufficient as we aren't going to change any of the
1649
1664
* values, just add the final array end marker.
1650
1665
*/
1666
+ memset (& result , 0 , sizeof (JsonbInState ));
1651
1667
1652
1668
result .parseState = clone_parse_state (arg -> res -> parseState );
1653
1669
@@ -1880,6 +1896,7 @@ jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
1880
1896
* going to change any of the values, just add the final object end
1881
1897
* marker.
1882
1898
*/
1899
+ memset (& result , 0 , sizeof (JsonbInState ));
1883
1900
1884
1901
result .parseState = clone_parse_state (arg -> res -> parseState );
1885
1902
0 commit comments