Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ristep/rp_uuid_time_sortable

My experiments with UUID generating in PostgreSQL
https://github.com/ristep/rp_uuid_time_sortable

plpgsql plsql postgresql sql time-ordered-uuid uuid

Last synced: 18 days ago
JSON representation

My experiments with UUID generating in PostgreSQL

Awesome Lists containing this project

README

        

My experiments with UUID generating in PostgreSQL

## rp_uuid.sql

```
CREATE OR REPLACE FUNCTION public.rp_uuid(
)
RETURNS uuid
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
declare
uuid_v1 character(36);
b4 character(4);
c3 character(3);
d2e2 character(17);
a1 char;
a4 character(4);
a3 character(3);
begin
-- 12345678-1234-5678-1234-567812345678
-- From: aaaaaaaa-bbbb-1ccc-dddd-eeeeeeeeeeee (time-based, version 1)
-- To: cccbbbba-aaaa-6aaa-dddd-eeeeeeeeeeee (time-ordered, version 6)
uuid_v1 := uuid_generate_v1()::character(36);
b4 := substr( uuid_v1, 10, 4);
a1 := substr( uuid_v1, 1, 1 );
a4 := substr( uuid_v1, 2, 4 );
a3 := substr( uuid_v1, 6, 3 );
c3 := substr( uuid_v1, 16, 3 );
d2e2 := substr( uuid_v1, 20, 17);

return (c3 || b4 || a1 || '-' || a4 || '-6' || a3 || '-' || d2e2)::uuid;
end
$BODY$;

ALTER FUNCTION public.rp_uuid()
OWNER TO postgres;
```

The function first declares the following variables:

* `uuid_v1`: A character string that contains the random UUID of version 1.
* `b4`: A character string that contains the first four bytes of `uuid_v1`.
* `c3`: A character string that contains the first three bytes of `uuid_v1`.
* `d2e2`: A character string that contains the last 17 bytes of `uuid_v1`.
* `a1`: A character string that contains the first byte of `uuid_v1`.
* `a4`: A character string that contains the last four bytes of `uuid_v1`.
* `a3`: A character string that contains the middle three bytes of `uuid_v1`.

The function then generates a random UUID of version 1 using the `uuid_generate_v1()` function. The function then converts the random UUID of version 1 to a UUID of version 6 by performing the following steps:

1. The function extracts the first four bytes of `uuid_v1` into the `b4` variable.
2. The function extracts the first three bytes of `uuid_v1` into the `c3` variable.
3. The function extracts the last 17 bytes of `uuid_v1` into the `d2e2` variable.
4. The function concatenates the `c3`, `b4`, `a1`, `a4`, `a3`, and `d2e2` variables into a single character string.
5. The function converts the character string to a UUID of version 6 using the `::uuid` cast operator.

The function finally returns the UUID of version 6.

## rp_uuid_ts_order.sql

```
CREATE OR REPLACE FUNCTION public.rp_uuid_ts_order(
)
RETURNS uuid
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
declare
uuid_v1 character(36);
b4 character(4);
c3 character(3);
d2e2 character(17);
a1 char;
a4 character(4);
a3 character(3);
begin
-- 12345678-1234-5678-1234-567812345678
-- From: aaaaaaaa-bbbb-1ccc-dddd-eeeeeeeeeeee (time-based, version 1)
-- To: cccbbbba-aaaa-6aaa-dddd-eeeeeeeeeeee (time-ordered, version 6)
uuid_v1 := uuid_generate_v1()::character(36);
b4 := substr( uuid_v1, 10, 4);
a1 := substr( uuid_v1, 1, 1 );
a4 := substr( uuid_v1, 2, 4 );
a3 := substr( uuid_v1, 6, 3 );
c3 := substr( uuid_v1, 16, 3 );
d2e2 := substr( uuid_v1, 20, 17);

return (c3 || b4 || a1 || '-' || a4 || '-6' || a3 || '-' || d2e2)::uuid;
end
$BODY$;

ALTER FUNCTION public.rp_uuid_ts_order()
OWNER TO postgres;
```

The function first declares the following variables:

* `uuid_v1`: A character string that contains the random UUID of version 1.
* `b4`: A character string that contains the first four bytes of `uuid_v1`.
* `c3`: A character string that contains the first three bytes of `uuid_v1`.
* `d2e2`: A character string that contains the last 17 bytes of `uuid_v1`.
* `a1`: A character string that contains the first byte of `uuid_v1`.
* `a4`: A character string that contains the last four bytes of `uuid_v1`.
* `a3`: A character string that contains the middle three bytes of `uuid_v1`.

The function then generates a random UUID of version 1 using the `uuid_generate_v1()` function. The function then converts the random UUID of version 1 to a UUID of version 6 by performing the following steps:

1. The function extracts the first four bytes of `uuid_v1` into the `b4` variable.
2. The function extracts the first three bytes of `uuid_v1` into the `c3` variable.
3. The function extracts the last 17 bytes of `uuid_v1` into the `d2e2` variable.
4. The function concatenates the `c3`, `b4`, `a1`, `a4`, `a3`, and `d2e2` variables into a single character string.
5. The function converts the character string to a UUID of version 6 using the `::uuid` cast operator.

The function finally returns the UUID of version 6.

However, the function is not safe to use in production. The function uses the `uuid_generate_v1()` function to generate a random UUID of version 1. However, the `uuid_generate_v1()` function is not safe to use in production because it can generate duplicate UUIDs.

To generate a safe random UUID of version 6, you can use the `uuid_generate_v4()` function. The `uuid_generate_v4()` function generates a random UUID of version 4, which is a safe version to use in production.

To convert a UUID of version 1 to a UUID of version 6, you can use the `uuid_convert()` function. The `uuid_convert()`

## rp_uuid_v4_tos.sql

```
CREATE OR REPLACE FUNCTION public.rp_uuid_v4_tos(
)
RETURNS uuid
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
begin
-- 12345678-1234-v678-1234-567812345678
-- 21050410-3450-4886-8976-642190401424
return (to_char(NOW(), 'YYMMDDHH24MISS4US'::text) || substring( random()::text ,3,13))::uuid;
end
$BODY$;

ALTER FUNCTION public.rp_uuid_v4_tos()
OWNER TO postgres;
```

The function first generates a random UUID of version 4 using the `random()` function. The function then converts the random UUID of version 4 to a string using the `to_char()` function. The function finally returns the string.

The function is safe to use in production because it generates a random UUID of version 4, which is a safe version to use in production.

However, the function is not very efficient. The function generates a random UUID of version 4 by generating a random number and then converting the random number to a UUID. This process is inefficient because it requires two steps.

A more efficient way to generate a random UUID of version 4 is to use the `uuid_generate_v4()` function. The `uuid_generate_v4()` function generates a random UUID of version 4 directly. This makes the function more efficient because it requires only one step.

To generate a random UUID of version 4 using the `uuid_generate_v4()` function, you can use the following code:

```
SELECT uuid_generate_v4();
```

This code will generate a random UUID of version 4 and return it as a string.

## rp_uuid_v7_to.sql

Example of how to use the PostgreSQL function `rp_uuid_v7_to()`.

The following code will generate a random UUID of version 7 and return it as a string:

```sql
SELECT rp_uuid_v7_to();
```

This code will generate a random UUID of version 7 and return it as a string. The UUID will be in the following format:

```
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
```

Where:

* `x` is a hexadecimal digit
* `M` is the most significant bit of the timestamp
* `N` is the least significant bit of the timestamp

The timestamp is in the following format:

```
YYYYMMDDHHMMSS.SSS
```

Where:

* `YYYY` is the year
* `MM` is the month
* `DD` is the day
* `HH` is the hour
* `MM` is the minute
* `SS` is the second
* `SSS` is the millisecond

For example, the following code will generate a random UUID of version 7 that represents the timestamp `2023-03-08 12:00:00`:

```sql
SELECT rp_uuid_v7_to();
```

This code will generate the following UUID:

```
12345678-1234-M567-N890-123456789012
```

The `M` bit of the timestamp is set to `1`, which indicates that the timestamp is in the Gregorian epoch. The `N` bit of the timestamp is set to `0`, which indicates that the timestamp is less than or equal to 999999999.

I hope this helps! Let me know if you have any other questions.

## ulid.sql

Sure, I can help you with that. Here are the steps on how to create a function to generate ULIDs in PostgreSQL:

1. Create a new function called `generate_ulid()`.
2. The function should take no parameters and return a `TEXT` value.
3. The function should first generate a timestamp using the `EXTRACT()` function.
4. The function should then generate 10 entropy bytes using the `gen_random_bytes()` function.
5. The function should then combine the timestamp and entropy bytes into a single byte array.
6. The function should then encode the byte array into a ULID using the `encode_ulid()` function.
7. The function should finally return the ULID.

Here is the complete code for the function:

```sql
CREATE OR REPLACE FUNCTION generate_ulid()
RETURNS TEXT AS
$func$
DECLARE
-- Get the current timestamp.
timestamp TIMESTAMP := EXTRACT(EPOCH FROM NOW()) * 1000;

-- Generate 10 entropy bytes.
entropy BYTEA := gen_random_bytes(10);

-- Combine the timestamp and entropy bytes.
ulid BYTEA := timestamp || entropy;

-- Encode the byte array into a ULID.
encoded_ulid TEXT := encode_ulid(ulid);

BEGIN
-- Return the ULID.
RETURN encoded_ulid;
END
$func$ LANGUAGE plpgsql;
```

Once the function is created, you can use it to generate ULIDs like this:

```sql
SELECT generate_ulid();
```

This will return a ULID like this:

```
"01234567-89ab-cdef-1234-56789abcdef0"
```

You can also use the function to generate multiple ULIDs at once, like this:

```sql
SELECT generate_ulid(), generate_ulid(), generate_ulid();
```

This will return three ULIDs:

```
"01234567-89ab-cdef-1234-56789abcdef0"
"12345678-9abc-def1-2345-6789abcdef1"
"23456789-abcd-ef12-3456-789abcdef2"
```

I hope this helps! Let me know if you have any other questions.