Fix jsonpath .split_part() to Honor Silent Mode
Core Problem
PostgreSQL's jsonpath execution engine has a well-established contract: when silent => true is passed to jsonpath query functions (jsonb_path_query, jsonb_path_exists, jsonb_path_match, etc.), errors from invalid inputs or out-of-range arguments should be suppressed, returning empty results instead of throwing exceptions. This is architecturally critical because jsonpath is defined by the SQL/JSON standard, and the silent/lax mode semantics dictate that type errors and argument errors are treated as "no match" rather than hard failures — enabling robust querying over heterogeneous JSON data without requiring the caller to pre-validate every value.
The bug reported here is that the split_part() jsonpath method, newly introduced in PostgreSQL v19, violates this contract. Two specific failure modes are identified:
- Zero field position:
$.split_part(",", 0)raisesERROR: field position must not be zeroeven in silent mode. - Integer overflow:
$.split_part(",", 2147483648)raisesERROR: integer out of rangeeven in silent mode.
Both cases should return zero rows when silent => true.
Root Cause Analysis
The issue traces to how integer arguments are parsed from jsonpath numeric literals inside the executor. The jsonpath executor processes method arguments as Numeric values internally (since jsonpath literals are parsed as numeric), and these must be converted to int4 for methods that require integer parameters.
PostgreSQL provides two conversion paths:
numeric_int4(): The standard conversion function. It raises anERRORon overflow or invalid input viaereport(). Once this error fires, there is no way for the jsonpath executor to catch and suppress it — the transaction is already in an error state.numeric_int4_safe(): A "safe" variant (introduced as part of the broader push for non-throwing conversion functions) that returns a boolean success indicator and writes the result to an output parameter, allowing the caller to handle failure gracefully without raising an error.
The existing .decimal() method already correctly uses numeric_int4_safe() to parse its precision and scale arguments, then routes any conversion failure through the jsonpath error reporting mechanism (RETURN_ERROR()), which respects the silent flag. The .split_part() implementation, being newer code, missed this pattern and called numeric_int4() directly — a classic oversight when adding new methods to an existing framework.
Proposed Fix
The patch makes a targeted change in executeStringInternalMethod() (likely in src/backend/utils/adt/jsonpath_exec.c):
- Replace the call to
numeric_int4()withnumeric_int4_safe()for parsing the field position argument of.split_part(). - Check the boolean return value of
numeric_int4_safe(). - On failure (overflow), route the error through the jsonpath error reporting infrastructure (
RETURN_ERROR()macro or equivalent), which checks whether silent mode is active and either suppresses the error (returning empty) or re-raises it as appropriate. - Similarly handle the zero-position check through the same error reporting path rather than a direct
ereport(ERROR, ...).
This is a minimal, low-risk fix that aligns .split_part() with the established pattern used by .decimal() and other methods.
Architectural Implications
This bug highlights an important maintainability concern in the jsonpath executor: every new method added must carefully use the "safe" variants of type conversion functions and route all errors through the jsonpath error handling mechanism. There is no compile-time enforcement of this — it relies entirely on developer discipline and code review. As more jsonpath methods are added (v19 appears to have added several string methods), this class of bug becomes increasingly likely.
A potential future improvement would be to centralize argument parsing into a shared helper (e.g., jspGetIntArg()) that always uses safe conversion and always routes errors through the jsonpath error handler, making it impossible for individual method implementations to accidentally bypass silent mode.
Assessment
This is a clear, well-diagnosed bug with a straightforward fix. The reporter correctly identified not just the symptom but the exact root cause (the difference between numeric_int4() and numeric_int4_safe()), provided a clean reproduction case, and submitted a patch. The confirming review validates both the diagnosis and the fix. This should be a quick commit for v19 before release or in an early minor release.