Last active
April 14, 2023 00:05
-
-
Save fabiolimace/e02a4caba5b19cda5909d8bf8af35385 to your computer and use it in GitHub Desktop.
Function for generating UUIDv1 on PostgreSQL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Returns a time-based UUID (UUIDv1). | |
* | |
* RFC-4122 compliant. | |
* | |
* Tags: uuid guid uuid-generator guid-generator generator time rfc4122 rfc-4122 | |
*/ | |
create or replace function uuid1() returns uuid as $$ | |
declare | |
v_time timestamp with time zone:= null; | |
v_secs bigint := null; | |
v_usec bigint := null; | |
v_timestamp bigint := null; | |
v_timestamp_hex varchar := null; | |
v_clkseq_and_nodeid bigint := null; | |
v_clkseq_and_nodeid_hex varchar := null; | |
v_bytes bytea; | |
c_epoch bigint := -12219292800; -- RFC-4122 epoch: '1582-10-15 00:00:00' | |
c_variant bit(64):= x'8000000000000000'; -- RFC-4122 variant: b'10xx...' | |
begin | |
-- Get seconds and micros | |
v_time := clock_timestamp(); | |
v_secs := EXTRACT(EPOCH FROM v_time); | |
v_usec := mod(EXTRACT(MICROSECONDS FROM v_time)::numeric, 10^6::numeric); | |
-- Generate timestamp hexadecimal (and set version 1) | |
v_timestamp := (((v_secs - c_epoch) * 10^6) + v_usec) * 10; | |
v_timestamp_hex := lpad(to_hex(v_timestamp), 16, '0'); | |
v_timestamp_hex := substr(v_timestamp_hex, 9, 8) || substr(v_timestamp_hex, 5, 4) || '1' || substr(v_timestamp_hex, 2, 3); | |
-- Generate clock sequence and node identifier hexadecimal (and set variant b'10xx') | |
v_clkseq_and_nodeid := ((random()::numeric * 2^62::numeric)::bigint::bit(64) | c_variant)::bigint; | |
v_clkseq_and_nodeid_hex := lpad(to_hex(v_clkseq_and_nodeid), 16, '0'); | |
-- Concat timestemp, clock sequence and node identifier hexadecimal | |
v_bytes := decode(v_timestamp_hex || v_clkseq_and_nodeid_hex, 'hex'); | |
return encode(v_bytes, 'hex')::uuid; | |
end $$ language plpgsql; | |
-- EXAMPLE: | |
-- | |
-- select uuid1() uuid, clock_timestamp()-statement_timestamp() time_taken; | |
-- EXAMPLE OUTPUT: | |
-- | |
-- |uuid |time_taken | | |
-- |--------------------------------------|------------------| | |
-- |7b5ea280-58cb-11ed-992b-e1747b187ecf |00:00:00.000176 | | |
------------------------------------------------------------------- | |
-- FOR TEST: the expected result is an empty result set | |
------------------------------------------------------------------- | |
-- with t as ( | |
-- select uuid1() as id from generate_series(1, 1000) | |
-- ) | |
-- select * from t | |
-- where (id is null or id::text !~ '^[a-f0-9]{8}-[a-f0-9]{4}-1[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment