From: Michael Paquier Date: Thu, 14 May 2026 07:02:07 +0000 (+0900) Subject: Fix jsonpath .split_part() to honor silent mode X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=954e57708ea6996e8948ccb820ed03d0262fc2d2;p=thirdparty%2Fpostgresql.git Fix jsonpath .split_part() to honor silent mode The jsonpath .split_part() method passed its field-position argument through numeric_int4(), that can fail hard if called directly. This commit switches the code to use numeric_int4_safe() with an error context for soft reporting, so as the overflow and zero field-position cases can be handled in silent mode. Oversight in bd4f879a9cdd. Author: Chao Li Reviewed-by: Nazir Bilal Yavuz Discussion: https://postgr.es/m/FCF996D0-580B-431C-8DE1-A540C58E444C@gmail.com --- diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 0ec9b4df2ef..6cc2acb4254 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -3017,7 +3017,8 @@ executeStringInternalMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, case jpiStrSplitPart: { char *from_str; - Numeric n; + int32 n; + ErrorSaveContext escontext = {T_ErrorSaveContext}; jspGetLeftArg(jsp, &elem); if (elem.type != jpiString) @@ -3029,13 +3030,25 @@ executeStringInternalMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, if (elem.type != jpiNumeric) elog(ERROR, "invalid jsonpath item type for .split_part()"); - n = jspGetNumeric(&elem); + n = numeric_int4_safe(jspGetNumeric(&elem), + (Node *) &escontext); + if (escontext.error_occurred) + RETURN_ERROR(ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("field position of jsonpath item method .%s() is out of range for type integer", + jspOperationName(jsp->type)))); + + if (n == 0) + RETURN_ERROR(ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("field position of jsonpath item method .%s() must not be zero", + jspOperationName(jsp->type)))); resStr = TextDatumGetCString(DirectFunctionCall3Coll(split_part, DEFAULT_COLLATION_OID, str, CStringGetTextDatum(from_str), - DirectFunctionCall1(numeric_int4, NumericGetDatum(n)))); + Int32GetDatum(n))); break; } default: diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index afa6c4cb529..81efebc3d0f 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -3073,6 +3073,20 @@ select jsonb_path_query('"abc,def,ghi,jkl"', '$.split_part(",", -2)'); "ghi" (1 row) +select jsonb_path_query('"a,b"', '$.split_part(",", 0)'); +ERROR: field position of jsonpath item method .split_part() must not be zero +select jsonb_path_query('"a,b"', '$.split_part(",", 0)', silent => true); + jsonb_path_query +------------------ +(0 rows) + +select jsonb_path_query('"a,b"', '$.split_part(",", 2147483648)'); +ERROR: field position of jsonpath item method .split_part() is out of range for type integer +select jsonb_path_query('"a,b"', '$.split_part(",", 2147483648)', silent => true); + jsonb_path_query +------------------ +(0 rows) + -- Test string methods play nicely together select jsonb_path_query('"hello world"', '$.replace("hello","bye").upper()'); jsonb_path_query diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index d3a38c57791..c1f4ab5422e 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -721,6 +721,10 @@ select jsonb_path_query('"hello world"', '$.replace("hello","bye") starts with " -- Test .split_part() select jsonb_path_query('"abc~@~def~@~ghi"', '$.split_part("~@~", 2)'); select jsonb_path_query('"abc,def,ghi,jkl"', '$.split_part(",", -2)'); +select jsonb_path_query('"a,b"', '$.split_part(",", 0)'); +select jsonb_path_query('"a,b"', '$.split_part(",", 0)', silent => true); +select jsonb_path_query('"a,b"', '$.split_part(",", 2147483648)'); +select jsonb_path_query('"a,b"', '$.split_part(",", 2147483648)', silent => true); -- Test string methods play nicely together select jsonb_path_query('"hello world"', '$.replace("hello","bye").upper()');