/** * Returns a Time Sortable ID with millisecond precision. * * Time component: 42 bits (2^42 = ~69 years) * * Random component: 22 bits (2^22 = 4,194,304) * * The time component is the count of milliseconds since 2020-01-01T00:00:00Z. * * Tags: tsid ulid snowflake id-generator generator time sortable sort order id */ create or replace function public.fn_tsid_milli() returns bigint as $$ declare -- Milliseconds precision C_MILLI_PREC bigint := 10^3; -- Random component bit length: 22 bits C_RANDOM_LEN bigint := 2^22; -- TSID epoch: seconds since 2020-01-01Z -- extract(epoch from '2020-01-01'::date) C_TSID_EPOCH bigint := 1577836800; begin return ((floor((extract('epoch' from clock_timestamp()) - C_TSID_EPOCH) * C_MILLI_PREC) * C_RANDOM_LEN)::bigint) + (floor(random() * C_RANDOM_LEN)::bigint); end $$ language plpgsql; -- EXAMPLE 1: -- select fn_tsid_milli(); -- EXAMPLE 1 OUTPUT: -- 52930646021833201 ---------------------------------------------------------- /* --------------------- -- LOOP TEST --------------------- -- Insert many into a test table. -- FIXME: -- It fails when the same TSID is inserted more than once. -- It's necessary to figure out a solution, maybe an auxiliar state table with exclusive lock. -- The function 'fn_tsid_MICRO()' is less prone to this fail since it has microsecond precision. --------------------- do $$ declare i int := 0; lim int := 1000000; begin WHILE i < lim LOOP insert into public.tb_tsid_test(id) values (public.fn_tsid_milli()); i := i + 1; END LOOP; end $$ language plpgsql; */ -- CREATE TEST TABLE -- create table public.tb_tsid_test (id bigint unique); -- CHECK RECORDS -- select * from public.tb_tsid_test; -- CLEAR RECORDS -- delete from public.tb_tsid_test;