我在Base58中找到了Github Gist编码器的MySQL函数。
DELIMITER $$
CREATE FUNCTION base58_encode (num int) RETURNS varchar(255)
DETERMINISTIC
BEGIN
DECLARE alphabet varchar(255);
DECLARE base_count int DEFAULT 0;
DECLARE encoded varchar(255);
DECLARE divisor DECIMAL(10,4);
DECLARE mode int DEFAULT 0;
SET alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
SET base_count = CHAR_LENGTH(alphabet);
SET encoded = "";
WHILE num >= base_count DO
SET divisor = num / base_count;
SET mode = (num - (base_count* TRUNCATE(divisor,0)));
SET encoded = CONCAT(SUBSTRING(alphabet FROM mode+1 FOR 1), encoded);
SET num = TRUNCATE(divisor,0);
END WHILE;
SET encoded = CONCAT(SUBSTRING(alphabet FROM num+1 FOR 1), encoded);
RETURN (encoded);
END
我是PostgreSQL
的新手,并且难以将上述功能转换为PostgreSQL功能。
对于Base58 Encoder,上述SQL代码段的等效PostgreSQL
函数怎么样?
答案 0 :(得分:1)
我想出的PostgreSQL中的等效函数如下。
CREATE FUNCTION base58_encode(num INT)
RETURNS VARCHAR(255) AS $encoded$
DECLARE
alphabet VARCHAR(255);
base_count INT DEFAULT 0;
encoded VARCHAR(255);
divisor DECIMAL(10, 4);
mod INT DEFAULT 0;
BEGIN
alphabet := '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
base_count := char_length(alphabet);
encoded := '';
WHILE num >= base_count LOOP
divisor := num / base_count;
mod := (num - (base_count * trunc(divisor, 0)));
encoded := concat(substring(alphabet FROM mod + 1 FOR 1), encoded);
num := trunc(divisor, 0);
END LOOP;
encoded = concat(substring(alphabet FROM num + 1 FOR 1), encoded);
RETURN (encoded);
END; $encoded$
LANGUAGE PLPGSQL;
答案 1 :(得分:1)
为了完整起见,这里是对反 base58_decode()
函数的快速而肮脏的滑动:
CREATE OR REPLACE FUNCTION base58_decode(str VARCHAR(255))
RETURNS BIGINT AS $$
DECLARE
alphabet VARCHAR(255);
c CHAR(1);
p INT;
v BIGINT;
BEGIN
alphabet := '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
v := 0;
FOR i IN 1..char_length(str) LOOP
c := substring(str FROM i FOR 1);
-- This is probably wildly inefficient, but we're just using this function for diagnostics...
p := position(c IN alphabet);
IF p = 0 THEN
RAISE 'Illegal base58 character ''%'' in ''%''', c, str;
END IF;
v := (v * 58) + (p - 1);
END LOOP;
RETURN v;
END;$$
LANGUAGE PLPGSQL;
答案 2 :(得分:0)
Postgres 9.x
CREATE OR REPLACE FUNCTION base58_encode (num bigint)
RETURNS text AS
$body$
declare
--alphabet text = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
alphabet text[] = array[
'1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'
];
cnt integer = 58;
dst text = '';
mod integer;
begin
while (num >= cnt) loop
num = num / cnt;
mod = num % cnt + 1;
dst = alphabet[mod] || dst;
end loop;
return alphabet[num] || dst;
end;
$body$
LANGUAGE 'plpgsql'
IMMUTABLE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;
答案 3 :(得分:0)
为了保持完整性,如果您需要解码为 UUID (Int16),我基于 @mike-blackwell 的回答来实现这一点。 Gist
我希望得到一些反馈和改进。我必须想象有一种更好的方法可以将 128 位数字转换为 UUID
代码:
CREATE OR REPLACE FUNCTION base58_decode(encoded_id VARCHAR(22))
RETURNS UUID AS $$
DECLARE
-- Bitcoin base58 alphabet
alphabet CHAR(58) := '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
c CHAR(1) := null;
p INT := null;
raw_num NUMERIC := 0;
uuid_str VARCHAR(32);
BEGIN
/*
Parses a UUID encoded with the Bitcoin base58 standard
Use sparingly, any application connecting to the database should handle decoding the ID itself
*/
-- Decode id to numeric
FOR i IN 1..CHAR_LENGTH(encoded_id) LOOP
c = SUBSTRING(encoded_id FROM i FOR 1);
p = POSITION(c IN alphabet);
raw_num = (raw_num * 58) + (p - 1);
END LOOP;
-- Parse NUMERIC into bytes
-- There must be a better way to go from a NUMERIC -> UUID
uuid_str := '';
FOR i IN 0..31 LOOP
uuid_str = CONCAT(uuid_str, TO_HEX(MOD(raw_num, 16)::INT));
raw_num = DIV(raw_num, 16);
END LOOP;
return REVERSE(uuid_str)::UUID;
END;$$
LANGUAGE PLPGSQL;