create or replace function uuid_bytespp(howmany integer) returns bytea as $$
declare
	bytes bytea;
begin
	bytes = rpad('', howmany);

	for i in 0 .. howmany-1 loop
		bytes := set_byte(bytes, i, (random()*256)::integer);
	end loop;

	return bytes;
end;
$$ language 'plpgsql';

create or replace function uuid_v1pp() returns uuid as $$
declare
	bytes bytea;
	byte	integer;
	str	text;
	id	uuid;
	tslow	bytea;
	tsmid	bytea;
	tshigh	bytea;
	tsi	bigint;
begin
	-- 122192928000000000

	select extract(epoch from now() - '1582-10-15 00:00:00 UTC'::timestamp with time zone)::bigint * 10000000 +
	extract(microseconds from now() - '1582-10-15 00:00:00 UTC'::timestamp with time zone)::integer % 1000000 * 10
	into tsi
	;

	tslow := decode(lpad(to_hex(tsi & x'ffffffff'::bigint), 8, '0'), 'hex');
	tsmid := decode(lpad(to_hex((tsi>>32) & x'ffff'::bigint), 4, '0'), 'hex');
	tshigh := decode(lpad(to_hex((tsi>>48) & x'ffff'::bigint), 4, '0'), 'hex');

	-- we don't store any state, so the clock sequence is random,
	-- and we don't have any way to get the macaddr, so that's
	-- random too.  though we set the multicast bit (the real one,
	-- not the one in the rfc)
	bytes := tslow || tsmid || tshigh || uuid_bytespp(8);

	byte = get_byte(bytes, 6);
	byte = (byte & 15) | 16;
	bytes = set_byte(bytes, 6, byte);

	byte = get_byte(bytes, 8);
	byte = (byte & 63) | 128;
	bytes = set_byte(bytes, 8, byte);

	byte = get_byte(bytes, 10);
	byte = (byte & 127) | 128;
	bytes = set_byte(bytes, 10, byte);

	str = encode(bytes, 'hex');
	id = str::uuid;
	return id;
end;
$$ language 'plpgsql';

create or replace function uuid_v4pp() returns uuid as $$
declare
	bytes bytea;
	byte	integer;
	str	text;
	id	uuid;
begin
	bytes = uuid_bytespp(16);

	byte = get_byte(bytes, 6);
	byte = (byte & 15) | 64;
	bytes = set_byte(bytes, 6, byte);

	byte = get_byte(bytes, 8);
	byte = (byte & 63) | 128;
	bytes = set_byte(bytes, 8, byte);

	str = encode(bytes, 'hex');
	id = str::uuid;
	return id;
end;
$$ language 'plpgsql';

create or replace function uuid_v3pp(ns uuid, content bytea) returns uuid as $$
declare
	bytes bytea;
	nsbytes	bytea;
	byte	integer;
	str	text;
	id	uuid;
begin
	nsbytes = decode(regexp_replace(ns::text, '-', '', 'g'), 'hex');
	bytes = decode(md5(nsbytes || content), 'hex');

	byte = get_byte(bytes, 6);
	byte = (byte & 15) | 48;
	bytes = set_byte(bytes, 6, byte);

	byte = get_byte(bytes, 8);
	byte = (byte & 63) | 128;
	bytes = set_byte(bytes, 8, byte);

	str = encode(bytes, 'hex');
	id = str::uuid;
	return id;
end;
$$ language 'plpgsql';

create or replace function uuid_v5pp(ns uuid, content bytea) returns uuid as $$
declare
	bytes bytea;
	nsbytes	bytea;
	byte	integer;
	str	text;
	id	uuid;
begin
	nsbytes = decode(regexp_replace(ns::text, '-', '', 'g'), 'hex');
	bytes = substring(decode(sha1(nsbytes || content), 'hex') from 1 for 16);

	byte = get_byte(bytes, 6);
	byte = (byte & 15) | 80;
	bytes = set_byte(bytes, 6, byte);

	byte = get_byte(bytes, 8);
	byte = (byte & 63) | 128;
	bytes = set_byte(bytes, 8, byte);

	str = encode(bytes, 'hex');
	id = str::uuid;
	return id;
end;
$$ language 'plpgsql';
