我有一个Java应用程序,通过将加密随机字节编码为base32(RFC4648)来生成主键的id。
如何在SQL脚本中使用PostgreSQL实现相同的功能?
gen_random_bytes
似乎可以生成随机字节,但似乎没有可用于将它们编码为base32的任何内容。
我有一个Java应用程序,通过将加密随机字节编码为base32(RFC4648)来生成主键的id。
如何在SQL脚本中使用PostgreSQL实现相同的功能?
gen_random_bytes
似乎可以生成随机字节,但似乎没有可用于将它们编码为base32的任何内容。
select base32.encode('foo');
-- MZXW6===
select base32.decode('MZXW6===');
-- foo
bytea
转换为 base32
。以下是带有几个辅助函数以便于理解的 SQL 代码。所有使用的内置函数似乎都被标记为 immutable
,因此这些辅助函数应该很容易地内联。
在 Postgres 14 上进行了测试:
create or replace function public.bytea_to_varbit(p_bytes bytea)
returns varbit as $$
-- https://dev59.com/9bPma4cB1Zd3GeqPua_C#56008861
select right(p_bytes::text, -1)::varbit;
$$ language sql immutable;
create or replace function public.varbit40_to_base32(p_num varbit(40))
returns text as $$
-- https://www.rfc-editor.org/rfc/rfc4648#section-6
select string_agg(('{"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","2","3","4","5","6","7"}'::text[])
-- shift right to 5 lsb and mask off the rest
[(p_num >> s & 31::bit(40))::bigint::int + 1]
-- concatenate resulting characters in order from left to right
, '' order by o)
-- generate bit-shifts to move all five-bit positions to the right
from generate_series(35, 0, -5) with ordinality m(s, o)
$$ language sql immutable;
create or replace function public.bytea_to_base32(p_val bytea, p_omit_padding bool = true)
returns text as $$
with v(val, padding, trm) as (
select string_agg(varbit40_to_base32(bytea_to_varbit(substring (padded from b for 5))), '' order by o)
-- https://www.rfc-editor.org/rfc/rfc4648#section-6 (1)-(5):
, ('{"","======","====","===","="}'::text[])[rem + 1]
, ('{0,6,4,3,1}'::int[])[rem + 1]
from (values(length(p_val), length(p_val) % 5
-- pad length to be divisible by 5
, p_val || substring(bytea '\x0000000000' from 1 for (5 - length(p_val) % 5) % 5))
) v(len, rem, padded)
-- rfc 4648 6: breakpoints for breaking the byte string into 40-bit groups
, generate_series(1, len + (5 - rem) % 5, 5) with ordinality c(b,o)
group by p_val, rem
)
-- rfc4648 3.2
select case when p_omit_padding then
case when trm > 0 then left(val, -trm) else val end
else
case when trm > 0 then overlay(val placing padding from length(val)-trm+1) else val end
end
from v
union all
-- https://www.rfc-editor.org/rfc/rfc4648#section-10: empty input returns empty string
select ''
limit 1;
$$ language sql immutable strict;
/*
https://www.rfc-editor.org/rfc/rfc4648#section-10
select inp, expected, bytea_to_base32(inp::bytea, omit_padding)
from (values
('', '', true)
, ('f', 'MY', true)
, ('fo', 'MZXQ', true)
, ('foo', 'MZXW6', true)
, ('foob', 'MZXW6YQ', true)
, ('fooba', 'MZXW6YTB', true)
, ('foobar', 'MZXW6YTBOI', true)
, ('', '', false)
, ('f', 'MY======', false)
, ('fo', 'MZXQ====', false)
, ('foo', 'MZXW6===', false)
, ('foob', 'MZXW6YQ=', false)
, ('fooba', 'MZXW6YTB', false)
, ('foobar', 'MZXW6YTBOI======', false)
) t(inp, expected, omit_padding)
where bytea_to_base32(inp::bytea, omit_padding) <> expected
;
*/
bytea
的类似于encode(gen_random_bytes(30), 'base64')
但使用base32的东西。使用您扩展中的函数,我必须将随机字节转换为文本,然后进行编码,这样就可以正常工作了。有没有一种直接对字节进行编码的方法? - b0gusb