postgresql xxhash64 哈希函数实现

由于业务需求,只支持 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$;
相关推荐
SelectDB技术团队2 分钟前
日志场景 Elasticsearch 替换实操:建表、索引、写入链路与查询改写的完整参数
大数据·数据库·数据仓库·elasticsearch·全文检索·日志分析·apache doris
百数平台9 分钟前
低代码安全技术实践:表单 / 流程 / 报表三级权限体系设计解析
java·大数据·数据库
驭渊的小故事13 分钟前
MyBatis-Plus 实战指南:从基础 CRUD 到条件构造器与自定义 SQL(二)
数据库·sql·mybatis
小小AK16 分钟前
销售订单从 CRM 推到 ERP:一条策略的完整同步实战
数据库
木雷坞18 分钟前
Docker Compose部署Docmost:数据库、附件持久化与首次协作
数据库·docker·容器
VidDown20 分钟前
上线三个月后的第一次事故:一个 Django 服务的日志、监控与故障复盘
数据库·python·django·wpf·音视频·视频编解码
小蒜学长26 分钟前
基于Springboot+Vue的高校教师教学业绩综合管理系统的设计与开发(代码+数据库+LW)
java·数据库·spring boot·后端·教学业绩管理·三级权限
达梦数据30 分钟前
DMDDB如何兼容 MongoDB
数据库·mongodb
蓝胖的四次元口袋40 分钟前
Redis知识梳理(5)
数据库·redis·缓存