DROP DOMAIN hexdigit CASCADE; DROP DOMAIN hexstr_int8 CASCADE; DROP DOMAIN hexstr_int4 CASCADE; DROP DOMAIN hexstr_int2 CASCADE; DROP DOMAIN hexstr_internal CASCADE; DROP DOMAIN hexstr CASCADE; -- input validation for user-called hex2int[248] CREATE DOMAIN hexstr AS text CONSTRAINT hexstr_valid_format CHECK (lower(VALUE) ~ $re$^\s*(?:0x)?([0-9a-f]+)\s*$$re$); CREATE DOMAIN hexstr_internal AS text CONSTRAINT hexstr_preproc_assertion CHECK (VALUE ~ '^[0-9a-f]+$'); CREATE DOMAIN hexstr_int2 AS text CONSTRAINT int2_max_hex_digits CHECK (length(VALUE) <= 4); CREATE DOMAIN hexstr_int4 AS text CONSTRAINT int4_max_hex_digits CHECK (length(VALUE) <= 8); CREATE DOMAIN hexstr_int8 AS text CONSTRAINT int8_max_hex_digits CHECK (length(VALUE) <= 16); CREATE DOMAIN hexdigit AS "char" CONSTRAINT hexdigit_format_assertion CHECK (VALUE BETWEEN '0' AND '9' OR VALUE BETWEEN 'a' AND 'f'); -- given a hex string from the user, permute it into a more strict internal -- format CREATE OR REPLACE FUNCTION hexstr_preproc(hexstr) RETURNS hexstr_internal AS $func$ SELECT CAST(regexp_replace( lower($1), $re$^\s*(?:0x)?([0-9a-f]+)\s*$$re$, E'\\1' ) AS hexstr_internal); $func$ LANGUAGE sql IMMUTABLE STRICT; -- split out for readability - given a single char [0-9a-f], convert to -- integer of that hex digit (0 - 15) CREATE OR REPLACE FUNCTION hexdigit_to_decimal(hexdigit) RETURNS int AS $$ SELECT CASE WHEN $1 BETWEEN '0' AND '9' THEN CAST($1 AS int4) - CAST('0'::"char" AS int4) ELSE CAST($1 AS int4) - CAST('a'::"char" AS int4) + 10 END; $$ LANGUAGE sql IMMUTABLE STRICT; -- given a hex string in internal format, return each hex digit and the number -- of bits to left-shift it by to be in the proper position in the resulting -- integer CREATE OR REPLACE FUNCTION hexdigit_factor_pairs(hexstr_internal, length int, OUT hexdigit hexdigit, OUT shiftfactor int) RETURNS SETOF record AS $$ SELECT CAST(substr($1, i, 1) AS hexdigit), -- times 4 because each hex digit is 4 bits 4 * ($2 - i) FROM generate_series($2, 1, -1) AS series(i) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int8_internal(hexstr_int8) RETURNS int8 AS $$ -- bitwise or each digit shifted to its proper place to get the answer SELECT bit_or(hexdigit_to_decimal(hexdigit)::int8 << shiftfactor) FROM hexdigit_factor_pairs($1, length($1)) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int4_internal(hexstr_int4) RETURNS int4 AS $$ -- bitwise or each digit shifted to its proper place to get the answer SELECT bit_or(hexdigit_to_decimal(hexdigit)::int4 << shiftfactor) FROM hexdigit_factor_pairs($1, length($1)) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int2_internal(hexstr_int2) RETURNS int2 AS $$ -- bitwise or each digit shifted to its proper place to get the answer SELECT bit_or(hexdigit_to_decimal(hexdigit)::int2 << shiftfactor) FROM hexdigit_factor_pairs($1, length($1)) $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int8(hexstr) RETURNS int8 AS $$ SELECT hex2int8_internal(hexstr_preproc($1)); $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int4(hexstr) RETURNS int4 AS $$ SELECT hex2int4_internal(hexstr_preproc($1)); $$ LANGUAGE sql IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION hex2int2(hexstr) RETURNS int2 AS $$ SELECT hex2int2_internal(hexstr_preproc($1)); $$ LANGUAGE sql IMMUTABLE STRICT; -- vim: set ft=psql ts=2 sw=2 expandtab :