In-built MySQL CONV() function works with 64-bit precision only. It makes it useless if you want to convert UUID or MD5 hash to base-36 number for example.
The only solution I’ve figured out is to code own custom function, which converts from base-16 to base-10, and then from base-10 to base-36.
DROP FUNCTION IF EXISTS conv_hex_to_base36;
DELIMITER $$
CREATE FUNCTION conv_hex_to_base36(_hex TEXT)
RETURNS TEXT
BEGIN
DECLARE _hex_len TINYINT;
DECLARE _dec DECIMAL(65);
DECLARE _chars CHAR(36);
DECLARE _base36 TEXT;
DECLARE _mod TINYINT;
SET _hex_len = LENGTH(_hex);
IF (_hex_len > 32) THEN
SIGNAL SQLSTATE '40001' \
SET MESSAGE_TEXT = \
'Hex is out of range (max 32 chars)';
END IF;
-- convert from base-16 to base-10
SET _dec = CAST(
CONV(
SUBSTRING(_hex, -LEAST(16, _hex_len)
), 16, 10)
AS DECIMAL(65)
);
IF _hex_len > 16 THEN
SET _dec = _dec + CAST(
CONV(
SUBSTRING(_hex, 1, _hex_len - 16), 16, 10)
AS DECIMAL(65)
) * 18446744073709551616;
END IF;
-- convert from base-10 to base-36
SET _chars = "0123456789abcdefghijklmnopqrstuvwxyz";
SET _base36 = "";
WHILE _dec > 0 DO
SET _mod = _dec % 36;
SET _base36 = CONCAT(
SUBSTRING(_chars, _mod + 1, 1),
_base36
);
SET _dec = FLOOR(_dec / 36);
END WHILE;
return _base36;
END;
$$
DELIMITER ;
If you know any better (and smarter) way, please let me know!
A few additional notes:
DECIMAL(65) must be used (and not DOUBLE PRECISION for example), otherwise it generates false results without any notice.shared.conv_hex_to_base36.base_convert. It returns false values for big numbers.ruby -e 'print "ffff".to_i(16).to_s(36)').