-- regression test for the uuid datatype -- creating test tables CREATE TABLE guid1 ( guid_field UUID, text_field TEXT DEFAULT(now()) ); CREATE TABLE guid2 ( guid_field UUID, text_field TEXT DEFAULT(now()) ); CREATE TABLE guid3 ( id SERIAL, guid_field UUID ); -- inserting invalid data tests -- too long INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111F'); ERROR: invalid input syntax for type uuid: "11111111-1111-1111-1111-111111111111F" LINE 1: INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-111... ^ -- too short INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-1111-11111111111}'); ERROR: invalid input syntax for type uuid: "{11111111-1111-1111-1111-11111111111}" LINE 1: INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-11... ^ -- valid data but invalid format INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-1111-111111111111'); ERROR: invalid input syntax for type uuid: "111-11111-1111-1111-1111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-11... ^ INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222 '); ERROR: invalid input syntax for type uuid: "{22222222-2222-2222-2222-222222222222 " LINE 1: INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-22... ^ -- invalid data INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G111-111111111111'); ERROR: invalid input syntax for type uuid: "11111111-1111-1111-G111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G11... ^ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111'); ERROR: invalid input syntax for type uuid: "11+11111-1111-1111-1111-111111111111" LINE 1: INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-111... ^ -- test non-error-throwing API SELECT pg_input_is_valid('11', 'uuid'); pg_input_is_valid ------------------- f (1 row) SELECT * FROM pg_input_error_info('11', 'uuid'); message | detail | hint | sql_error_code ------------------------------------------+--------+------+---------------- invalid input syntax for type uuid: "11" | | | 22P02 (1 row) --inserting three input formats INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111'); INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}'); INSERT INTO guid1(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e'); -- retrieving the inserted data SELECT guid_field FROM guid1; guid_field -------------------------------------- 11111111-1111-1111-1111-111111111111 22222222-2222-2222-2222-222222222222 3f3e3c3b-3a30-3938-3736-353433a2313e (3 rows) -- ordering test SELECT guid_field FROM guid1 ORDER BY guid_field ASC; guid_field -------------------------------------- 11111111-1111-1111-1111-111111111111 22222222-2222-2222-2222-222222222222 3f3e3c3b-3a30-3938-3736-353433a2313e (3 rows) SELECT guid_field FROM guid1 ORDER BY guid_field DESC; guid_field -------------------------------------- 3f3e3c3b-3a30-3938-3736-353433a2313e 22222222-2222-2222-2222-222222222222 11111111-1111-1111-1111-111111111111 (3 rows) -- = operator test SELECT COUNT(*) FROM guid1 WHERE guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e'; count ------- 1 (1 row) -- <> operator test SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111'; count ------- 2 (1 row) -- < operator test SELECT COUNT(*) FROM guid1 WHERE guid_field < '22222222-2222-2222-2222-222222222222'; count ------- 1 (1 row) -- <= operator test SELECT COUNT(*) FROM guid1 WHERE guid_field <= '22222222-2222-2222-2222-222222222222'; count ------- 2 (1 row) -- > operator test SELECT COUNT(*) FROM guid1 WHERE guid_field > '22222222-2222-2222-2222-222222222222'; count ------- 1 (1 row) -- >= operator test SELECT COUNT(*) FROM guid1 WHERE guid_field >= '22222222-2222-2222-2222-222222222222'; count ------- 2 (1 row) -- btree and hash index creation test CREATE INDEX guid1_btree ON guid1 USING BTREE (guid_field); CREATE INDEX guid1_hash ON guid1 USING HASH (guid_field); -- unique index test CREATE UNIQUE INDEX guid1_unique_BTREE ON guid1 USING BTREE (guid_field); EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111' OR guid_field <> '3f3e3c3b-3a30-3938-3736-353433a2313e'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------ Aggregate -> Seq Scan on guid1 Filter: ((guid_field <> '11111111-1111-1111-1111-111111111111'::uuid) OR (guid_field <> '3f3e3c3b-3a30-3938-3736-353433a2313e'::uuid)) (3 rows) EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM guid1 WHERE guid_field <= '22222222-2222-2222-2222-222222222222' OR guid_field <= '11111111111111111111111111111111' OR guid_field <= '3f3e3c3b-3a30-3938-3736-353433a2313e'; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Seq Scan on guid1 Filter: ((guid_field <= '22222222-2222-2222-2222-222222222222'::uuid) OR (guid_field <= '11111111-1111-1111-1111-111111111111'::uuid) OR (guid_field <= '3f3e3c3b-3a30-3938-3736-353433a2313e'::uuid)) (3 rows) EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM guid1 WHERE guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e' OR guid_field = '11111111111111111111111111111111'; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------- Aggregate -> Seq Scan on guid1 Filter: ((guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e'::uuid) OR (guid_field = '11111111-1111-1111-1111-111111111111'::uuid)) (3 rows) -- should fail INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111'); ERROR: duplicate key value violates unique constraint "guid1_unique_btree" DETAIL: Key (guid_field)=(11111111-1111-1111-1111-111111111111) already exists. -- check to see whether the new indexes are actually there SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%'; count ------- 3 (1 row) -- populating the test tables with additional records INSERT INTO guid1(guid_field) VALUES('44444444-4444-4444-4444-444444444444'); INSERT INTO guid2(guid_field) VALUES('11111111-1111-1111-1111-111111111111'); INSERT INTO guid2(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}'); INSERT INTO guid2(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e'); -- join test SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field; count ------- 3 (1 row) SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_field WHERE g2.guid_field IS NULL; count ------- 1 (1 row) -- generation test TRUNCATE guid1; INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid()); INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid()); SELECT count(DISTINCT guid_field) FROM guid1; count ------- 2 (1 row) -- test of uuidv4() alias TRUNCATE guid1; INSERT INTO guid1 (guid_field) VALUES (uuidv4()); INSERT INTO guid1 (guid_field) VALUES (uuidv4()); SELECT count(DISTINCT guid_field) FROM guid1; count ------- 2 (1 row) -- generation test for v7 TRUNCATE guid1; INSERT INTO guid1 (guid_field) VALUES (uuidv7()); INSERT INTO guid1 (guid_field) VALUES (uuidv7()); INSERT INTO guid1 (guid_field) VALUES (uuidv7(INTERVAL '1 day')); SELECT count(DISTINCT guid_field) FROM guid1; count ------- 3 (1 row) -- test sortability of v7 INSERT INTO guid3 (guid_field) SELECT uuidv7() FROM generate_series(1, 10); SELECT array_agg(id ORDER BY guid_field) FROM guid3; array_agg ------------------------ {1,2,3,4,5,6,7,8,9,10} (1 row) -- Check the timestamp offsets for v7. -- -- generate UUIDv7 values with timestamps ranging from 1970 (the Unix epoch year) -- to 10888 (one year before the maximum possible year), and then verify that -- the extracted timestamps from these UUIDv7 values have not overflowed. WITH uuidts AS ( SELECT y, ts as ts, lag(ts) OVER (ORDER BY y) AS prev_ts FROM (SELECT y, uuid_extract_timestamp(uuidv7((y || ' years')::interval)) AS ts FROM generate_series(1970 - extract(year from now())::int, 10888 - extract(year from now())::int) y) ) SELECT y, ts, prev_ts FROM uuidts WHERE ts < prev_ts; y | ts | prev_ts ---+----+--------- (0 rows) -- extract functions -- version SELECT uuid_extract_version('11111111-1111-5111-8111-111111111111'); -- 5 uuid_extract_version ---------------------- 5 (1 row) SELECT uuid_extract_version(gen_random_uuid()); -- 4 uuid_extract_version ---------------------- 4 (1 row) SELECT uuid_extract_version('11111111-1111-1111-1111-111111111111'); -- null uuid_extract_version ---------------------- (1 row) SELECT uuid_extract_version(uuidv4()); -- 4 uuid_extract_version ---------------------- 4 (1 row) SELECT uuid_extract_version(uuidv7()); -- 7 uuid_extract_version ---------------------- 7 (1 row) -- timestamp SELECT uuid_extract_timestamp('C232AB00-9414-11EC-B3C8-9F6BDECED846') = 'Tuesday, February 22, 2022 2:22:22.00 PM GMT+05:00'; -- RFC 9562 test vector for v1 ?column? ---------- t (1 row) SELECT uuid_extract_timestamp('017F22E2-79B0-7CC3-98C4-DC0C0C07398F') = 'Tuesday, February 22, 2022 2:22:22.00 PM GMT+05:00'; -- RFC 9562 test vector for v7 ?column? ---------- t (1 row) SELECT uuid_extract_timestamp(gen_random_uuid()); -- null uuid_extract_timestamp ------------------------ (1 row) SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null uuid_extract_timestamp ------------------------ (1 row) -- clean up DROP TABLE guid1, guid2, guid3 CASCADE;