Skip to content

Scalar functions fail or return wrong results on BIGINT argument overflow #30803

Description

@SEPURI-SAI-KRISHNA

Four scalar functions perform unchecked 64-bit arithmetic on their user-supplied BIGINT arguments. When a value near the BIGINT bounds is passed, the arithmetic overflows and the function either returns a wrong result or fails with a raw ArithmeticException instead of the documented NULL / 0.

Query Actual Expected
SELECT slice(ARRAY[1, 2, 3, 4], 1, 9223372036854775807) [] [1, 2, 3, 4]
SELECT element_at(ARRAY[1, 2, 3], -9223372036854775808) ArithmeticException: integer overflow NULL
SELECT split_part('abc', '', 3000000000) ArithmeticException: integer overflow NULL
SELECT strpos('abc/xyz', '/', -9223372036854775808) 'instance' must be a positive or negative number. 0

The slice case is the most serious: it returns a wrong result silently rather than failing, so a query asking for "everything from position N onwards" via a large sentinel length quietly loses all its rows.

Details

slice computes its end index as fromIndex + length without an overflow check. A large length wraps the sum negative, which then loses the min(..., size + 1) comparison, so the fromIndex >= toIndex guard treats a fully in-range slice as empty.

element_at guards its bounds with Math.abs(index) > arrayLength. Math.abs(Long.MIN_VALUE) is negative, so the guard does not fire and execution falls through to toIntExact(arrayLength + index), which throws.

split_part converts its index with toIntExact when the delimiter is empty, so any index above Integer.MAX_VALUE throws — even though such an index is simply past the end of the string, a case the function already handles by returning NULL (split_part('abc', '', 99)NULL).

strpos negates a negative instance with Math.abs before searching from the end. Math.abs(Long.MIN_VALUE) is negative, so stringPositionFromEnd rejects it as non-negative and reports "'instance' must be a positive or negative number" for a value that is in fact negative. The @ScalarFunction(value = "strpos", neverFails = false /* for instance==0 */) annotation documents instance == 0 as the only failure mode, so this is an unintended second one.

Related existing handling

This class of input is already guarded elsewhere in the same code:

  • substring uses Ints.saturatedCast
  • overlay uses LongMath.saturatedAdd
  • json_array_get special-cases Long.MIN_VALUE and returns NULL

These four functions appear to have been missed.

Environment

Reproduced on master.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions