postgresql - 如何将 postgres 中的默认值 ksuid 赋予列? postgres 中有 ksuid 的替代品吗?

标签 postgresql

我有一个 char 字段,其默认值应该是一个 ksuid。如何在 postgres 中生成 ksuid?

最佳答案

此函数在 PostgreSQL 上生成 KSUID。它使用 numeric 数据类型将时间和负载转换为 base62。

它使用 native MD5() 函数创建伪随机负载。如果您想使用 pgcrypto,请查看 @ssz 的评论。谢谢@ssz!

函数生成的 KSUID 符合 reference implementation .

最后更新:

  • fn_ksuid() 重命名为 ksuid()
  • 将数值变量更改为声明为 numeric(50) 以避免 floor()
/**
 * Returns a Segment's KSUID.
 *
 * Reference implementation: https://github.com/segmentio/ksuid
 * Also read: https://segment.com/blog/a-brief-history-of-the-uuid/
 */
create or replace function ksuid() returns text as $$
declare
    v_time timestamp with time zone := null;
    v_seconds numeric(50) := null;
    v_payload bytea := null;
    v_numeric numeric(50) := null;
    v_base62 text := '';
    v_epoch numeric(50) = 1400000000; -- 2014-05-13T16:53:20Z
    v_alphabet char array[62] := array[
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 
        'U', 'V', 'W', 'X', 'Y', 'Z', 
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'];
    i integer := 0;
begin

    -- Get the current time
    v_time := clock_timestamp();

    -- Extract seconds from the current time and apply epoch
    v_seconds := EXTRACT(EPOCH FROM v_time) - v_epoch;

    -- Generate a numeric value from the seconds
    v_numeric := v_seconds * pow(2::numeric, 128);

    -- Generate a pseudo-random payload
    -- v_payload := gen_random_bytes(16); -- to be used with `pgcrypto`
    v_payload := decode(md5(v_time::text || random()::text || random()::text), 'hex');
    
    -------------------------------------------------------------------
    -- FOR TEST: the expected result is '0ujtsYcgvSTl8PAuAdqWYSMnLOv'
    -------------------------------------------------------------------
    -- v_numeric := 107608047 * pow(2::numeric, 128);
    -- v_payload := decode('B5A1CD34B5F99D1154FB6853345C9735', 'hex');
    
    -- Add the payload to the numeric value
    while i < 16 loop
        i := i + 1;
        v_numeric := v_numeric + (get_byte(v_payload, i - 1) * pow(2::numeric, (16 - i) * 8));
    end loop;

    -- Encode the numeric value to base62
    while v_numeric <> 0 loop
        v_base62 := v_base62 || v_alphabet[mod(v_numeric, 62) + 1];
        v_numeric := div(v_numeric, 62);
    end loop;
    v_base62 := reverse(v_base62);
    v_base62 := lpad(v_base62, 27, '0');

    return v_base62;
    
end $$ language plpgsql;

请参阅 GitHub Gist 上的更新功能.

关于postgresql - 如何将 postgres 中的默认值 ksuid 赋予列? postgres 中有 ksuid 的替代品吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63152831/

相关文章:

asp.net-mvc - 带有 Postgres 的 ASP.NET MVC; ORM 推荐?

PostgreSQL:从列值将间隔添加到时间戳

python - 多记录上传到postgres

postgresql - 连接 pgbouncer 和使用 docker 运行的 postgres

sql - 我如何从 self 引用表中找到 parent 和 child 。?

PostgreSQL,格式化 float

sql - 依靠 GROUP BY 以及结果总数

python - 如何使用 psycopg2 更新 postgresql 中多行的多列

windows - 如何在 Windows 上手动配置和启动 PostgreSQL?

php - 在 PHP 中使用 PGSQL