CREATE FUNCTION uuid_reserved_bits(uuid) RETURNS varbit AS
$$ SELECT ('x' || substr($1::text, 20, 2))::bit(8) & '11000000' $$
LANGUAGE SQL STRICT IMMUTABLE;
-CREATE FUNCTION uuid_multicast_bits(uuid) RETURNS varbit AS
-$$ SELECT ('x' || substr($1::text, 25, 2))::bit(8) & '00000011' $$
+CREATE FUNCTION uuid_multicast_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000001') != '00000000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+CREATE FUNCTION uuid_local_admin_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000010') != '00000000' $$
LANGUAGE SQL STRICT IMMUTABLE;
CREATE FUNCTION uuid_node(uuid) RETURNS text AS
$$ SELECT substr($1::text, 25) $$
LANGUAGE SQL STRICT IMMUTABLE;
+-- Ideally, the multicast bit would never be set in V1 output, but the
+-- UUID library may fall back to MC if it can't get the system MAC address.
+-- Also, the local-admin bit might be set (if so, we're probably inside a VM).
+-- So we can't test either bit here.
SELECT uuid_version_bits(uuid_generate_v1()),
- uuid_reserved_bits(uuid_generate_v1()),
- uuid_multicast_bits(uuid_generate_v1());
- uuid_version_bits | uuid_reserved_bits | uuid_multicast_bits
--------------------+--------------------+---------------------
- 00010000 | 10000000 | 00000000
+ uuid_reserved_bits(uuid_generate_v1());
+ uuid_version_bits | uuid_reserved_bits
+-------------------+--------------------
+ 00010000 | 10000000
(1 row)
+-- Although RFC 4122 only requires the multicast bit to be set in V1MC style
+-- UUIDs, our implementation always sets the local-admin bit as well.
SELECT uuid_version_bits(uuid_generate_v1mc()),
uuid_reserved_bits(uuid_generate_v1mc()),
- uuid_multicast_bits(uuid_generate_v1mc());
- uuid_version_bits | uuid_reserved_bits | uuid_multicast_bits
--------------------+--------------------+---------------------
- 00010000 | 10000000 | 00000011
+ uuid_multicast_bit(uuid_generate_v1mc()),
+ uuid_local_admin_bit(uuid_generate_v1mc());
+ uuid_version_bits | uuid_reserved_bits | uuid_multicast_bit | uuid_local_admin_bit
+-------------------+--------------------+--------------------+----------------------
+ 00010000 | 10000000 | t | t
(1 row)
-- timestamp+clock sequence should be monotonic increasing in v1
t
(1 row)
--- node should be stable in v1, but not v1mc
-SELECT uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1());
- ?column?
-----------
+-- Ideally, the node value is stable in V1 addresses, but OSSP UUID
+-- falls back to V1MC behavior if it can't get the system MAC address.
+SELECT CASE WHEN uuid_multicast_bit(uuid_generate_v1()) AND
+ uuid_local_admin_bit(uuid_generate_v1()) THEN
+ true -- punt, no test
+ ELSE
+ uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1())
+ END;
+ case
+------
t
(1 row)
+-- In any case, V1MC node addresses should be random.
SELECT uuid_node(uuid_generate_v1()) <> uuid_node(uuid_generate_v1mc());
?column?
----------
$$ SELECT ('x' || substr($1::text, 20, 2))::bit(8) & '11000000' $$
LANGUAGE SQL STRICT IMMUTABLE;
-CREATE FUNCTION uuid_multicast_bits(uuid) RETURNS varbit AS
-$$ SELECT ('x' || substr($1::text, 25, 2))::bit(8) & '00000011' $$
+CREATE FUNCTION uuid_multicast_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000001') != '00000000' $$
+LANGUAGE SQL STRICT IMMUTABLE;
+
+CREATE FUNCTION uuid_local_admin_bit(uuid) RETURNS bool AS
+$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000010') != '00000000' $$
LANGUAGE SQL STRICT IMMUTABLE;
CREATE FUNCTION uuid_node(uuid) RETURNS text AS
$$ SELECT substr($1::text, 25) $$
LANGUAGE SQL STRICT IMMUTABLE;
+-- Ideally, the multicast bit would never be set in V1 output, but the
+-- UUID library may fall back to MC if it can't get the system MAC address.
+-- Also, the local-admin bit might be set (if so, we're probably inside a VM).
+-- So we can't test either bit here.
SELECT uuid_version_bits(uuid_generate_v1()),
- uuid_reserved_bits(uuid_generate_v1()),
- uuid_multicast_bits(uuid_generate_v1());
+ uuid_reserved_bits(uuid_generate_v1());
+-- Although RFC 4122 only requires the multicast bit to be set in V1MC style
+-- UUIDs, our implementation always sets the local-admin bit as well.
SELECT uuid_version_bits(uuid_generate_v1mc()),
uuid_reserved_bits(uuid_generate_v1mc()),
- uuid_multicast_bits(uuid_generate_v1mc());
+ uuid_multicast_bit(uuid_generate_v1mc()),
+ uuid_local_admin_bit(uuid_generate_v1mc());
-- timestamp+clock sequence should be monotonic increasing in v1
SELECT uuid_timestamp_bits(uuid_generate_v1()) < uuid_timestamp_bits(uuid_generate_v1());
SELECT uuid_timestamp_bits(uuid_generate_v1mc()) < uuid_timestamp_bits(uuid_generate_v1mc());
--- node should be stable in v1, but not v1mc
-SELECT uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1());
+-- Ideally, the node value is stable in V1 addresses, but OSSP UUID
+-- falls back to V1MC behavior if it can't get the system MAC address.
+SELECT CASE WHEN uuid_multicast_bit(uuid_generate_v1()) AND
+ uuid_local_admin_bit(uuid_generate_v1()) THEN
+ true -- punt, no test
+ ELSE
+ uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1())
+ END;
+
+-- In any case, V1MC node addresses should be random.
SELECT uuid_node(uuid_generate_v1()) <> uuid_node(uuid_generate_v1mc());
SELECT uuid_node(uuid_generate_v1mc()) <> uuid_node(uuid_generate_v1mc());