如何在PostgreSQL中实现bigint的环绕式算术运算(无溢出)?
在PostgreSQL的bigint列上实现64位整数环绕式运算的方法
可以实现标准的64位整数环绕式运算,以下是针对不同场景的具体方案:
一、普通加减乘运算的环绕实现
PostgreSQL默认会检测bigint溢出并抛出错误,但利用bit(64)类型的自动溢出环绕特性,可以高效实现目标行为:
加法环绕
SELECT (9223372036854775807::bit(64) + 1::bit(64))::bigint; -- 输出:-9223372036854775808
乘法环绕
SELECT (9223372036854775807::bit(64) * 2::bit(64))::bigint; -- 输出:-2
这种方法依赖原生位运算实现,性能接近纯64位整数运算,远优于基于numeric或模运算的方案。
二、SUM聚合的环绕实现
PostgreSQL默认的SUM会将bigint转为numeric类型计算以避免溢出,要实现环绕式SUM,需自定义聚合函数:
- 先创建环绕加法的辅助函数:
CREATE OR REPLACE FUNCTION bigint_wrap_add(a bigint, b bigint) RETURNS bigint AS $$ BEGIN RETURN (a::bit(64) + b::bit(64))::bigint; END; $$ LANGUAGE plpgsql IMMUTABLE;
- 基于该函数创建自定义聚合:
CREATE AGGREGATE sum_wrap(bigint) ( SFUNC = bigint_wrap_add, STYPE = bigint, INITCOND = '0' );
- 使用自定义聚合实现环绕求和:
SELECT sum_wrap(id) FROM (VALUES(9223372036854775807), (9223372036854775807)) AS t(id); -- 输出:-2
这个自定义聚合全程基于bigint和位运算,性能与原生聚合接近,完全符合补码溢出环绕的标准行为。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

