>From 522fef9c3739d4c4f3c107e574e84db67a0c07a2 Mon Sep 17 00:00:00 2001
From: Oskari Saarenmaa <os@ohmu.fi>
Date: Thu, 9 Jan 2014 22:24:36 +0200
Subject: [PATCH] pgcrypto: implement gen_random_uuid

---
 contrib/pgcrypto/Makefile               |   2 +-
 contrib/pgcrypto/pgcrypto--1.0--1.1.sql |   8 ++
 contrib/pgcrypto/pgcrypto--1.0.sql      | 202 -------------------------------
 contrib/pgcrypto/pgcrypto--1.1.sql      | 207 ++++++++++++++++++++++++++++++++
 contrib/pgcrypto/pgcrypto.c             |  22 ++++
 contrib/pgcrypto/pgcrypto.control       |   2 +-
 contrib/pgcrypto/pgcrypto.h             |   1 +
 doc/src/sgml/pgcrypto.sgml              |  11 ++
 8 files changed, 251 insertions(+), 204 deletions(-)
 create mode 100644 contrib/pgcrypto/pgcrypto--1.0--1.1.sql
 delete mode 100644 contrib/pgcrypto/pgcrypto--1.0.sql
 create mode 100644 contrib/pgcrypto/pgcrypto--1.1.sql

diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index dadec95..1c85c98 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -26,7 +26,7 @@ MODULE_big	= pgcrypto
 OBJS		= $(SRCS:.c=.o)
 
 EXTENSION = pgcrypto
-DATA = pgcrypto--1.0.sql pgcrypto--unpackaged--1.0.sql
+DATA = pgcrypto--1.1.sql pgcrypto--1.0--1.1.sql pgcrypto--unpackaged--1.0.sql
 
 REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
 	$(CF_TESTS) \
diff --git a/contrib/pgcrypto/pgcrypto--1.0--1.1.sql b/contrib/pgcrypto/pgcrypto--1.0--1.1.sql
new file mode 100644
index 0000000..2601669
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto--1.0--1.1.sql
@@ -0,0 +1,8 @@
+/* contrib/pgcrypto/pgcrypto--1.0--1.1.sql */
+
+\echo Use "ALTER EXTENSION pgcrypto UPDATE" to load this file. \quit
+
+CREATE FUNCTION gen_random_uuid()
+RETURNS uuid
+AS 'MODULE_PATHNAME', 'pg_random_uuid'
+LANGUAGE C VOLATILE;
diff --git a/contrib/pgcrypto/pgcrypto--1.0.sql b/contrib/pgcrypto/pgcrypto--1.0.sql
deleted file mode 100644
index 347825e..0000000
--- a/contrib/pgcrypto/pgcrypto--1.0.sql
+++ /dev/null
@@ -1,202 +0,0 @@
-/* contrib/pgcrypto/pgcrypto--1.0.sql */
-
--- complain if script is sourced in psql, rather than via CREATE EXTENSION
-\echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
-
-CREATE FUNCTION digest(text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_digest'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION digest(bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_digest'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION hmac(text, text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_hmac'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION hmac(bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_hmac'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION crypt(text, text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pg_crypt'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION gen_salt(text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pg_gen_salt'
-LANGUAGE C VOLATILE STRICT;
-
-CREATE FUNCTION gen_salt(text, int4)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
-LANGUAGE C VOLATILE STRICT;
-
-CREATE FUNCTION encrypt(bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_encrypt'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION decrypt(bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_decrypt'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION gen_random_bytes(int4)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_random_bytes'
-LANGUAGE C VOLATILE STRICT;
-
---
--- pgp_sym_encrypt(data, key)
---
-CREATE FUNCTION pgp_sym_encrypt(text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
-LANGUAGE C STRICT;
-
-CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
-LANGUAGE C STRICT;
-
---
--- pgp_sym_encrypt(data, key, args)
---
-CREATE FUNCTION pgp_sym_encrypt(text, text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
-LANGUAGE C STRICT;
-
-CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
-LANGUAGE C STRICT;
-
---
--- pgp_sym_decrypt(data, key)
---
-CREATE FUNCTION pgp_sym_decrypt(bytea, text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- pgp_sym_decrypt(data, key, args)
---
-CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- pgp_pub_encrypt(data, key)
---
-CREATE FUNCTION pgp_pub_encrypt(text, bytea)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
-LANGUAGE C STRICT;
-
-CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
-LANGUAGE C STRICT;
-
---
--- pgp_pub_encrypt(data, key, args)
---
-CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
-LANGUAGE C STRICT;
-
-CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
-LANGUAGE C STRICT;
-
---
--- pgp_pub_decrypt(data, key)
---
-CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- pgp_pub_decrypt(data, key, psw)
---
-CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- pgp_pub_decrypt(data, key, psw, arg)
---
-CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- PGP key ID
---
-CREATE FUNCTION pgp_key_id(bytea)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pgp_key_id_w'
-LANGUAGE C IMMUTABLE STRICT;
-
---
--- pgp armor
---
-CREATE FUNCTION armor(bytea)
-RETURNS text
-AS 'MODULE_PATHNAME', 'pg_armor'
-LANGUAGE C IMMUTABLE STRICT;
-
-CREATE FUNCTION dearmor(text)
-RETURNS bytea
-AS 'MODULE_PATHNAME', 'pg_dearmor'
-LANGUAGE C IMMUTABLE STRICT;
diff --git a/contrib/pgcrypto/pgcrypto--1.1.sql b/contrib/pgcrypto/pgcrypto--1.1.sql
new file mode 100644
index 0000000..a260857
--- /dev/null
+++ b/contrib/pgcrypto/pgcrypto--1.1.sql
@@ -0,0 +1,207 @@
+/* contrib/pgcrypto/pgcrypto--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pgcrypto" to load this file. \quit
+
+CREATE FUNCTION digest(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION digest(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_digest'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION hmac(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION hmac(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_hmac'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION crypt(text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_crypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gen_salt(text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE FUNCTION gen_salt(text, int4)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_gen_salt_rounds'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE FUNCTION encrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION decrypt(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION encrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_encrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION decrypt_iv(bytea, bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_decrypt_iv'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gen_random_bytes(int4)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_random_bytes'
+LANGUAGE C VOLATILE STRICT;
+
+CREATE FUNCTION gen_random_uuid()
+RETURNS uuid
+AS 'MODULE_PATHNAME', 'pg_random_uuid'
+LANGUAGE C VOLATILE;
+
+--
+-- pgp_sym_encrypt(data, key)
+--
+CREATE FUNCTION pgp_sym_encrypt(text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_encrypt(data, key, args)
+--
+CREATE FUNCTION pgp_sym_encrypt(text, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pgp_sym_encrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_sym_decrypt(data, key)
+--
+CREATE FUNCTION pgp_sym_decrypt(bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_sym_decrypt(data, key, args)
+--
+CREATE FUNCTION pgp_sym_decrypt(bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION pgp_sym_decrypt_bytea(bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_sym_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_encrypt(data, key)
+--
+CREATE FUNCTION pgp_pub_encrypt(text, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_encrypt(data, key, args)
+--
+CREATE FUNCTION pgp_pub_encrypt(text, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_text'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_encrypt_bytea'
+LANGUAGE C STRICT;
+
+--
+-- pgp_pub_decrypt(data, key)
+--
+CREATE FUNCTION pgp_pub_decrypt(bytea, bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw)
+--
+CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp_pub_decrypt(data, key, psw, arg)
+--
+CREATE FUNCTION pgp_pub_decrypt(bytea, bytea, text, text)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_text'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pgp_pub_decrypt_bytea'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- PGP key ID
+--
+CREATE FUNCTION pgp_key_id(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pgp_key_id_w'
+LANGUAGE C IMMUTABLE STRICT;
+
+--
+-- pgp armor
+--
+CREATE FUNCTION armor(bytea)
+RETURNS text
+AS 'MODULE_PATHNAME', 'pg_armor'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION dearmor(text)
+RETURNS bytea
+AS 'MODULE_PATHNAME', 'pg_dearmor'
+LANGUAGE C IMMUTABLE STRICT;
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
index a441ca7..d440068 100644
--- a/contrib/pgcrypto/pgcrypto.c
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -35,6 +35,7 @@
 
 #include "parser/scansup.h"
 #include "utils/builtins.h"
+#include "utils/uuid.h"
 
 #include "px.h"
 #include "px-crypt.h"
@@ -443,6 +444,27 @@ pg_random_bytes(PG_FUNCTION_ARGS)
 	PG_RETURN_BYTEA_P(res);
 }
 
+/* SQL function: pg_random_uuid() returns uuid */
+PG_FUNCTION_INFO_V1(pg_random_uuid);
+
+Datum
+pg_random_uuid(PG_FUNCTION_ARGS)
+{
+	unsigned char *buf = (unsigned char *) palloc(16);
+	/* get 128 random bits */
+	int err = px_get_random_bytes(buf, 16);
+	if (err < 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
+				 errmsg("Random generator error: %s", px_strerror(err))));
+
+	/* set UUID v4 magic numbers, http://tools.ietf.org/html/rfc4122#section-4.4 */
+	buf[6] = (buf[6] & 0x0f) | 0x40;
+	buf[8] = (buf[8] & 0x3f) | 0x80;
+
+	PG_RETURN_UUID_P(buf);
+}
+
 static void *
 find_provider(text *name,
 			  PFN provider_lookup,
diff --git a/contrib/pgcrypto/pgcrypto.control b/contrib/pgcrypto/pgcrypto.control
index 8375cf9..7f79d04 100644
--- a/contrib/pgcrypto/pgcrypto.control
+++ b/contrib/pgcrypto/pgcrypto.control
@@ -1,5 +1,5 @@
 # pgcrypto extension
 comment = 'cryptographic functions'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/pgcrypto'
 relocatable = true
diff --git a/contrib/pgcrypto/pgcrypto.h b/contrib/pgcrypto/pgcrypto.h
index 6284ba2..04ea696 100644
--- a/contrib/pgcrypto/pgcrypto.h
+++ b/contrib/pgcrypto/pgcrypto.h
@@ -45,5 +45,6 @@ Datum		pg_decrypt(PG_FUNCTION_ARGS);
 Datum		pg_encrypt_iv(PG_FUNCTION_ARGS);
 Datum		pg_decrypt_iv(PG_FUNCTION_ARGS);
 Datum		pg_random_bytes(PG_FUNCTION_ARGS);
+Datum		pg_random_uuid(PG_FUNCTION_ARGS);
 
 #endif
diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml
index b99a75c..31dba8c 100644
--- a/doc/src/sgml/pgcrypto.sgml
+++ b/doc/src/sgml/pgcrypto.sgml
@@ -1084,6 +1084,17 @@ gen_random_bytes(count integer) returns bytea
    At most 1024 bytes can be extracted at a time.  This is to avoid
    draining the randomness generator pool.
   </para>
+
+  <indexterm>
+   <primary>gen_random_uuid</primary>
+  </indexterm>
+
+<synopsis>
+gen_random_uuid() returns uuid
+</synopsis>
+  <para>
+   Returns a version 4 (random) UUID.
+  </para>
  </sect2>
 
  <sect2>
-- 
1.8.4.2

