Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions regress/expected/agtype.out
Original file line number Diff line number Diff line change
Expand Up @@ -3906,6 +3906,54 @@ SELECT * FROM cypher('issue_2243', $$
0::numeric
(1 row)

--
-- Integer overflow tests (issue #2471)
--
SELECT create_graph('integer_overflow');
NOTICE: graph "integer_overflow" has been created
create_graph
--------------

(1 row)

-- Addition overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN 9223372036854775807 + 1 AS r
$$) AS (r agtype);
ERROR: integer addition overflow
-- Subtraction overflow (underflow)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 - 1 AS r
$$) AS (r agtype);
ERROR: integer subtraction overflow
-- Multiplication overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN 9223372036854775807 * 2 AS r
$$) AS (r agtype);
ERROR: integer multiplication overflow
-- Negation overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN -(-9223372036854775808) AS r
$$) AS (r agtype);
ERROR: integer negation overflow
-- Division overflow (INT64_MIN / -1)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 / -1 AS r
$$) AS (r agtype);
ERROR: integer division overflow
-- Modulo overflow (INT64_MIN % -1)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 % -1 AS r
$$) AS (r agtype);
ERROR: integer modulo overflow
-- Cleanup overflow tests
SELECT drop_graph('integer_overflow', true);
NOTICE: graph "integer_overflow" has been dropped
drop_graph
------------

(1 row)

--
-- Cleanup
--
Expand Down
38 changes: 38 additions & 0 deletions regress/sql/agtype.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,44 @@ SELECT * FROM cypher('issue_2243', $$
RETURN 9223372036854775807::integer % 9223372036854775807::numeric
$$ ) as (result agtype);

--
-- Integer overflow tests (issue #2471)
--
SELECT create_graph('integer_overflow');

-- Addition overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN 9223372036854775807 + 1 AS r
$$) AS (r agtype);

-- Subtraction overflow (underflow)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 - 1 AS r
$$) AS (r agtype);

-- Multiplication overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN 9223372036854775807 * 2 AS r
$$) AS (r agtype);

-- Negation overflow
SELECT * FROM cypher('integer_overflow', $$
RETURN -(-9223372036854775808) AS r
$$) AS (r agtype);

-- Division overflow (INT64_MIN / -1)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 / -1 AS r
$$) AS (r agtype);

-- Modulo overflow (INT64_MIN % -1)
SELECT * FROM cypher('integer_overflow', $$
RETURN -9223372036854775808 % -1 AS r
$$) AS (r agtype);

-- Cleanup overflow tests
SELECT drop_graph('integer_overflow', true);

--
-- Cleanup
--
Expand Down
78 changes: 71 additions & 7 deletions src/backend/utils/adt/agtype_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,21 @@ Datum agtype_add(PG_FUNCTION_ARGS)

concat_to_agtype_string(&agtv_result, lhs, llen, rhs, rlen);
}
/* Both are integers - regular addition */
/* Both are integers - addition with overflow check */
else if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
{
int64 result;

if (__builtin_add_overflow(agtv_lhs->val.int_value,
agtv_rhs->val.int_value, &result))
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer addition overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value +
agtv_rhs->val.int_value;
agtv_result.val.int_value = result;
}
/* Both are floats - regular addition */
else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_FLOAT)
Expand Down Expand Up @@ -539,9 +548,18 @@ Datum agtype_sub(PG_FUNCTION_ARGS)

if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
{
int64 result;

if (__builtin_sub_overflow(agtv_lhs->val.int_value,
agtv_rhs->val.int_value, &result))
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer subtraction overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value -
agtv_rhs->val.int_value;
agtv_result.val.int_value = result;
}
else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_FLOAT)
{
Expand Down Expand Up @@ -635,11 +653,25 @@ Datum agtype_neg(PG_FUNCTION_ARGS)

if (agtv_value->type == AGTV_INTEGER)
{
if (agtv_value->val.int_value == PG_INT64_MIN)
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer negation overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = -agtv_value->val.int_value;
}
else if (agtv_value->type == AGTV_FLOAT)
{
if (agtv_value->val.float_value == -(double)PG_INT64_MIN)
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer negation overflow")));
}

agtv_result.type = AGTV_FLOAT;
agtv_result.val.float_value = -agtv_value->val.float_value;
}
Expand Down Expand Up @@ -692,9 +724,18 @@ Datum agtype_mul(PG_FUNCTION_ARGS)

if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
{
int64 result;

if (__builtin_mul_overflow(agtv_lhs->val.int_value,
agtv_rhs->val.int_value, &result))
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer multiplication overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value *
agtv_rhs->val.int_value;
agtv_result.val.int_value = result;
}
else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_FLOAT)
{
Expand Down Expand Up @@ -795,6 +836,14 @@ Datum agtype_div(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}

if (agtv_lhs->val.int_value == PG_INT64_MIN &&
agtv_rhs->val.int_value == -1)
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer division overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value /
agtv_rhs->val.int_value;
Expand Down Expand Up @@ -912,6 +961,21 @@ Datum agtype_mod(PG_FUNCTION_ARGS)

if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
{
if (agtv_rhs->val.int_value == 0)
{
ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
PG_RETURN_NULL();
}

if (agtv_lhs->val.int_value == PG_INT64_MIN &&
agtv_rhs->val.int_value == -1)
{
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer modulo overflow")));
}

agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value %
agtv_rhs->val.int_value;
Expand Down