PostgreSQL:将 UUID 转换为 OID
PostgreSQL: Convert UUID into OID
PostgreSQL 中是否有将 UUID (RFC 4122) 转换为 OID (ISO 8824) 的函数?
“2.25”之后的值。是作为整数的 UUID 的直接十进制编码。它必须是单个整数的直接十进制编码,所有 128 位。它不能被分解成多个部分。
例如,该函数将采用 UUID "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
和 return OID "2.25.329800735698586629295641978511506172918"
。
参考:
理想情况下,我们会有一个无符号的 16 字节整数 (uint16
) 和一个已注册的转换 uuid --> uint16
(可能是也可能不是二进制内部兼容,使其超级便宜)。 None 这是在 PostgreSQL 中实现的。
您可能会查看(非官方!)附加模块 pg_bignum
or Evan Caroll's (even more unofficial) fork 以直接接受十六进制输入。 (免责声明:未经测试。)
这些模块在大多数托管安装中不可用。这是使用标准 PostgreSQL:
内置工具的 穷人实现
CREATE OR REPLACE FUNCTION f_uuid2oid(_uuid uuid)
RETURNS text
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
SELECT '2.25.' ||
('x0' || left(hex, 15) )::bit(64)::int8 * numeric '295147905179352825856' -- 1.
+ ('x0' || right(left(hex, 30), 15))::bit(64)::int8 * numeric '256' -- 2.
+ ('x000000' || right(hex, 2) )::bit(32)::int4 -- 3.
FROM translate(_uuid::text, '-', '') t(hex)
$func$;
COMMENT ON FUNCTION public.f_uuid2oid(uuid) IS '
Convert UUID (RFC 4122) into a OID (ISO 8824) ?
First, get text representation of UUID without hyphens:
translate(_uuid::text, '-', '')`
Then:
1.
- take the first 15 hex digits
- prefix with x0
- cast to bit(64)
- cast to int8
- multiply with numeric 295147905179352825856 (= 2^68), which is the same as left-shift the binary representation by 68 bits.
68 bits because: 1 hex digit represents 4 bit; uuid has 128; 128 - 15*4 = 68; so shift by 68
2.
- take the next 15 hex digits
- prefix with x0
- cast to bit(64)
- cast to int8
- multiply with numeric 256 (= 2^8) shift by the remaining 2 hex digits / 8 bit
3.
- take the remaining, rightmost 2 hex digits
- prefix with x000000
- cast to bit(32)
- cast to int4
Add 1. + 2. + 3., convert to text, prefix "2.25." Voila.
No leading zeros, according to https://www.rfc-editor.org/rfc/rfc3061
More explanation:
-
- https://dba.stackexchange.com/questions/115271/what-is-the-optimal-data-type-for-an-md5-field/115316#115316
';
致电:
SELECT f_uuid2oid('f81d4fae-7dec-11d0-a765-00a0c91e6bf6');
生成请求的 OID 2.25.329800735698586629295641978511506172918
db<>fiddle here
无前导零,根据 https://www.rfc-editor.org/rfc/rfc3061。
我没有通读各种标准:http://www.oid-info.com/faq.htm#1
据我所知,我优化了性能,利用了从 bit(n)
到 bigint
/integer
的内置(非常快)二进制强制转换。要了解我在那里做什么,请先阅读:
- Convert hex in text representation to decimal number
- What is the optimal data type for an MD5 field?
Postgres 整数类型有符号。所以 - 为避免溢出为负数 - 我们不能使用完整的 64 位(8 字节/16 位十六进制数字),我们必须将 32 位十六进制数字转换为三个垃圾而不是两个。我任意地将它分成 15 + 15 + 2 个十六进制数字。
使用 left()
和 right()
,因为这通常比 substring()
.
快一点点
还要考虑对函数的注释。
PostgreSQL 中是否有将 UUID (RFC 4122) 转换为 OID (ISO 8824) 的函数?
“2.25”之后的值。是作为整数的 UUID 的直接十进制编码。它必须是单个整数的直接十进制编码,所有 128 位。它不能被分解成多个部分。
例如,该函数将采用 UUID "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
和 return OID "2.25.329800735698586629295641978511506172918"
。
参考:
理想情况下,我们会有一个无符号的 16 字节整数 (uint16
) 和一个已注册的转换 uuid --> uint16
(可能是也可能不是二进制内部兼容,使其超级便宜)。 None 这是在 PostgreSQL 中实现的。
您可能会查看(非官方!)附加模块 pg_bignum
or Evan Caroll's (even more unofficial) fork 以直接接受十六进制输入。 (免责声明:未经测试。)
这些模块在大多数托管安装中不可用。这是使用标准 PostgreSQL:
内置工具的 穷人实现CREATE OR REPLACE FUNCTION f_uuid2oid(_uuid uuid)
RETURNS text
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE AS
$func$
SELECT '2.25.' ||
('x0' || left(hex, 15) )::bit(64)::int8 * numeric '295147905179352825856' -- 1.
+ ('x0' || right(left(hex, 30), 15))::bit(64)::int8 * numeric '256' -- 2.
+ ('x000000' || right(hex, 2) )::bit(32)::int4 -- 3.
FROM translate(_uuid::text, '-', '') t(hex)
$func$;
COMMENT ON FUNCTION public.f_uuid2oid(uuid) IS '
Convert UUID (RFC 4122) into a OID (ISO 8824) ?
First, get text representation of UUID without hyphens:
translate(_uuid::text, '-', '')`
Then:
1.
- take the first 15 hex digits
- prefix with x0
- cast to bit(64)
- cast to int8
- multiply with numeric 295147905179352825856 (= 2^68), which is the same as left-shift the binary representation by 68 bits.
68 bits because: 1 hex digit represents 4 bit; uuid has 128; 128 - 15*4 = 68; so shift by 68
2.
- take the next 15 hex digits
- prefix with x0
- cast to bit(64)
- cast to int8
- multiply with numeric 256 (= 2^8) shift by the remaining 2 hex digits / 8 bit
3.
- take the remaining, rightmost 2 hex digits
- prefix with x000000
- cast to bit(32)
- cast to int4
Add 1. + 2. + 3., convert to text, prefix "2.25." Voila.
No leading zeros, according to https://www.rfc-editor.org/rfc/rfc3061
More explanation:
-
- https://dba.stackexchange.com/questions/115271/what-is-the-optimal-data-type-for-an-md5-field/115316#115316
';
致电:
SELECT f_uuid2oid('f81d4fae-7dec-11d0-a765-00a0c91e6bf6');
生成请求的 OID 2.25.329800735698586629295641978511506172918
db<>fiddle here
无前导零,根据 https://www.rfc-editor.org/rfc/rfc3061。
我没有通读各种标准:http://www.oid-info.com/faq.htm#1
据我所知,我优化了性能,利用了从 bit(n)
到 bigint
/integer
的内置(非常快)二进制强制转换。要了解我在那里做什么,请先阅读:
- Convert hex in text representation to decimal number
- What is the optimal data type for an MD5 field?
Postgres 整数类型有符号。所以 - 为避免溢出为负数 - 我们不能使用完整的 64 位(8 字节/16 位十六进制数字),我们必须将 32 位十六进制数字转换为三个垃圾而不是两个。我任意地将它分成 15 + 15 + 2 个十六进制数字。
使用 left()
和 right()
,因为这通常比 substring()
.
还要考虑对函数的注释。