由于业务需求,只支持 int8 -> int8,如果需要改类型,可以让 AI 改下
sql
CREATE OR REPLACE FUNCTION public.xxhash64(p_input bigint)
RETURNS bigint
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $xxh$
DECLARE
-- xxHash64 的 5 个 64 位素数(超出 int8 有符号范围,用 numeric 无损保存)
c_p1 numeric := 11400714785074694791;
c_p2 numeric := 14029467366897019727;
c_p3 numeric := 1609587929392839161;
c_p4 numeric := 9650029242287828579;
c_p5 numeric := 2870177450012600261;
c_mod numeric := 18446744073709551616; -- 2^64,无符号回绕模数
c_half numeric := 9223372036854775808; -- 2^63,无符号<->有符号转换分界
c_len numeric := 8; -- 输入字节数(int8 固定 8 字节)
c_byte_mask bigint := 255; -- 提取单字节用掩码(& 要求整型)
c_shift_33 numeric := 8589934592; -- 2^33,avalanche 逻辑右移量
c_shift_29 numeric := 536870912; -- 2^29
c_shift_32 numeric := 4294967296; -- 2^32
v_le numeric; -- 无符号 64 位输入值(小端展开)
v_h numeric; -- 无符号 64 位哈希累加器
v_acc numeric; -- round 中间累积值
v_bits bit(64); -- 供 按位(XOR/循环左移) 运算中转
v_byte numeric;
v_shift integer;
BEGIN
-- 将 int8 输入按小端展开为无符号 64 位数(符号位视为 2^63)
v_le := 0;
FOR v_shift IN 0..7 LOOP
-- power 必须显式 numeric,否则 PG 会解析为 double 导致 2^56 以上丢失精度
v_byte := (p_input >> (8 * v_shift)) & c_byte_mask;
v_le := v_le + v_byte * power(256::numeric, v_shift);
END LOOP;
-- xxHash64(seed=0),输入固定 8 字节,走 len<32 短路径
v_h := mod(c_p5, c_mod);
v_h := mod(v_h + c_len, c_mod);
-- finalize 中处理第一个 8 字节组:k1 = XXH64_round(0, le64)
v_acc := mod(v_le * c_p2, c_mod);
-- rotl64(v_acc, 31):无符号值转 bit(64) 后做循环左移再转回无符号
v_bits := (CASE WHEN v_acc >= c_half THEN v_acc - c_mod ELSE v_acc END)::bigint::bit(64);
v_bits := (v_bits << 31) | (v_bits >> 33);
v_acc := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
v_acc := mod(v_acc * c_p1, c_mod);
-- h ^= k1
v_bits := (CASE WHEN v_h >= c_half THEN v_h - c_mod ELSE v_h END)::bigint::bit(64)
# (CASE WHEN v_acc >= c_half THEN v_acc - c_mod ELSE v_acc END)::bigint::bit(64);
v_h := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
-- rotl64(v_h, 27),再 h = h*P1 + P4
v_bits := (CASE WHEN v_h >= c_half THEN v_h - c_mod ELSE v_h END)::bigint::bit(64);
v_bits := (v_bits << 27) | (v_bits >> 37);
v_h := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
v_h := mod(mod(v_h * c_p1, c_mod) + c_p4, c_mod);
-- 8 字节已耗尽,无 4 字节/单字节尾部
-- avalanche 归约:逻辑右移用 floor(v/2^n) 在无符号 numeric 域等价
-- h ^= h >> 33
v_bits := (CASE WHEN v_h >= c_half THEN v_h - c_mod ELSE v_h END)::bigint::bit(64)
# (floor(v_h / c_shift_33))::bigint::bit(64);
v_h := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
v_h := mod(v_h * c_p2, c_mod);
-- h ^= h >> 29
v_bits := (CASE WHEN v_h >= c_half THEN v_h - c_mod ELSE v_h END)::bigint::bit(64)
# (floor(v_h / c_shift_29))::bigint::bit(64);
v_h := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
v_h := mod(v_h * c_p3, c_mod);
-- h ^= h >> 32
v_bits := (CASE WHEN v_h >= c_half THEN v_h - c_mod ELSE v_h END)::bigint::bit(64)
# (floor(v_h / c_shift_32))::bigint::bit(64);
v_h := CASE WHEN (v_bits::bigint)::numeric < 0 THEN (v_bits::bigint)::numeric + c_mod
ELSE (v_bits::bigint)::numeric END;
-- 无符号值转有符号 int8 返回
IF v_h >= c_half THEN
v_h := v_h - c_mod;
END IF;
RETURN v_h::bigint;
END;
$xxh$;