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;
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');
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;
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;
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),
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 $$
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 $$
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 $$
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;