I wrote the following, heavily inspired by what you already wrote:
CREATE FUNCTION public.generate_ulid() RETURNS uuid
LANGUAGE plpgsql
AS $$
DECLARE
timestamp BYTEA = E'\\000\\000\\000\\000\\000\\000';
unix_time BIGINT;
BEGIN
unix_time = (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT;
timestamp = SET_BYTE(timestamp, 3, (unix_time >> 40)::BIT(8)::INTEGER);
timestamp = SET_BYTE(timestamp, 2, (unix_time >> 32)::BIT(8)::INTEGER);
timestamp = SET_BYTE(timestamp, 1, (unix_time >> 24)::BIT(8)::INTEGER);
timestamp = SET_BYTE(timestamp, 0, (unix_time >> 16)::BIT(8)::INTEGER);
timestamp = SET_BYTE(timestamp, 5, (unix_time >> 8)::BIT(8)::INTEGER);
timestamp = SET_BYTE(timestamp, 4, unix_time::BIT(8)::INTEGER);
RETURN CAST(substring(CAST((timestamp || gen_random_bytes(10)) AS text) from 3) AS uuid);
END
$$;
It generates a ULID, but in the UUID format. The order of the bytes is a bit unintuitive due to the UUID format/endianness.
This function makes it easier to use the uuid PostGres type to hold ULIDs. This makes for smaller, faster indexes (c.f. indexing on text).
I wrote the following, heavily inspired by what you already wrote:
It generates a ULID, but in the UUID format. The order of the bytes is a bit unintuitive due to the UUID format/endianness.
This function makes it easier to use the
uuidPostGres type to hold ULIDs. This makes for smaller, faster indexes (c.f. indexing ontext).