Support BSD and e2fsprogs UUID libraries alongside OSSP UUID library.
authorTom Lane
Tue, 27 May 2014 23:42:08 +0000 (19:42 -0400)
committerTom Lane
Tue, 27 May 2014 23:42:08 +0000 (19:42 -0400)
Allow the contrib/uuid-ossp extension to be built atop any one of these
three popular UUID libraries.  (The extension's name is now arguably a
misnomer, but we'll keep it the same so as not to cause unnecessary
compatibility issues for users.)

We would not normally consider a change like this post-beta1, but the issue
has been forced by our upgrade to autoconf 2.69, whose more rigorous header
checks are causing OSSP's header files to be rejected on some platforms.
It's been foreseen for some time that we'd have to move away from depending
on OSSP UUID due to lack of upstream maintenance, so this is a down payment
on that problem.

While at it, add some simple regression tests, in hopes of catching any
major incompatibilities between the three implementations.

Matteo Beccati, with some further hacking by me

12 files changed:
configure
configure.in
contrib/Makefile
contrib/uuid-ossp/.gitignore [new file with mode: 0644]
contrib/uuid-ossp/Makefile
contrib/uuid-ossp/expected/uuid_ossp.out [new file with mode: 0644]
contrib/uuid-ossp/sql/uuid_ossp.sql [new file with mode: 0644]
contrib/uuid-ossp/uuid-ossp.c
doc/src/sgml/installation.sgml
doc/src/sgml/uuid-ossp.sgml
src/Makefile.global.in
src/include/pg_config.h.in

index 17f3f2654f81c3c986b205c0d47e925bacfaccce..3663e50d15005b2cecf43682dc49c4cec1317535 100755 (executable)
--- a/configure
+++ b/configure
@@ -657,7 +657,7 @@ acx_pthread_config
 have_win32_dbghelp
 HAVE_IPV6
 LIBOBJS
-OSSP_UUID_LIBS
+UUID_LIBS
 ZIC
 python_enable_shared
 python_additional_libs
@@ -705,7 +705,8 @@ with_system_tzdata
 with_libxslt
 with_libxml
 XML2_CONFIG
-with_ossp_uuid
+UUID_EXTRA_OBJS
+with_uuid
 with_selinux
 with_openssl
 krb_srvtab
@@ -826,6 +827,7 @@ with_openssl
 with_selinux
 with_readline
 with_libedit_preferred
+with_uuid
 with_ossp_uuid
 with_libxml
 with_libxslt
@@ -1512,7 +1514,8 @@ Optional Packages:
   --without-readline      do not use GNU Readline nor BSD Libedit for editing
   --with-libedit-preferred
                           prefer BSD Libedit over GNU Readline
-  --with-ossp-uuid        build contrib/uuid-ossp, requires OSSP UUID library
+  --with-uuid=LIB         build contrib/uuid-ossp using LIB (bsd,e2fs,ossp)
+  --with-ossp-uuid        obsolete spelling of --with-uuid=ossp
   --with-libxml           build with XML support
   --with-libxslt          use XSLT support when building contrib/xml2
   --with-system-tzdata=DIR
@@ -1737,6 +1740,73 @@ fi
 
 } # ac_fn_c_try_cpp
 
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case  declares $2.
+   For example, HP-UX 11i  declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer  to  if __STDC__ is defined, since
+     exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include 
+#else
+# include 
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
 # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
 # -------------------------------------------------------
 # Tests whether HEADER exists, giving a warning if it cannot be compiled using
@@ -2195,73 +2265,6 @@ rm -f conftest.val
 
 } # ac_fn_c_compute_int
 
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-/* Define $2 to an innocuous variant, in case  declares $2.
-   For example, HP-UX 11i  declares gettimeofday.  */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $2 (); below.
-    Prefer  to  if __STDC__ is defined, since
-     exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include 
-#else
-# include 
-#endif
-
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main ()
-{
-return $2 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-
 # ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
 # ---------------------------------------------
 # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
@@ -5614,11 +5617,40 @@ fi
 
 
 #
-# OSSP UUID library
+# UUID library
+#
+# There are at least three UUID libraries in common use: the FreeBSD/NetBSD
+# library, the e2fsprogs libuuid (now part of util-linux-ng), and the OSSP
+# UUID library.  More than one of these might be present on a given platform,
+# so we make the user say which one she wants.
 #
 
 
 
+# Check whether --with-uuid was given.
+if test "${with_uuid+set}" = set; then :
+  withval=$with_uuid;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-uuid option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-uuid option" "$LINENO" 5
+      ;;
+    *)
+
+      ;;
+  esac
+
+fi
+
+
+if test x"$with_uuid" = x"" ; then
+  with_uuid=no
+fi
+
+
+
 # Check whether --with-ossp-uuid was given.
 if test "${with_ossp_uuid+set}" = set; then :
   withval=$with_ossp_uuid;
@@ -5640,6 +5672,31 @@ else
 fi
 
 
+if test "$with_ossp_uuid" = yes ; then
+  with_uuid=ossp
+fi
+
+if test "$with_uuid" = bsd ; then
+
+$as_echo "#define HAVE_UUID_BSD 1" >>confdefs.h
+
+  UUID_EXTRA_OBJS="md5.o sha1.o"
+elif test "$with_uuid" = e2fs ; then
+
+$as_echo "#define HAVE_UUID_E2FS 1" >>confdefs.h
+
+  UUID_EXTRA_OBJS="md5.o sha1.o"
+elif test "$with_uuid" = ossp ; then
+
+$as_echo "#define HAVE_UUID_OSSP 1" >>confdefs.h
+
+  UUID_EXTRA_OBJS=""
+elif test "$with_uuid" = no ; then
+  UUID_EXTRA_OBJS=""
+else
+  as_fn_error $? "--with-uuid must specify one of bsd, e2fs, or ossp" "$LINENO" 5
+fi
+
 
 
 
@@ -8775,7 +8832,66 @@ fi
 fi
 
 # for contrib/uuid-ossp
-if test "$with_ossp_uuid" = yes ; then
+if test "$with_uuid" = bsd ; then
+  # On BSD, the UUID functions are in libc
+  ac_fn_c_check_func "$LINENO" "uuid_to_string" "ac_cv_func_uuid_to_string"
+if test "x$ac_cv_func_uuid_to_string" = xyes; then :
+  UUID_LIBS=""
+else
+  as_fn_error $? "BSD UUID functions are not present" "$LINENO" 5
+fi
+
+elif test "$with_uuid" = e2fs ; then
+  # On OS X, the UUID functions are in libc
+  ac_fn_c_check_func "$LINENO" "uuid_generate" "ac_cv_func_uuid_generate"
+if test "x$ac_cv_func_uuid_generate" = xyes; then :
+  UUID_LIBS=""
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5
+$as_echo_n "checking for uuid_generate in -luuid... " >&6; }
+if ${ac_cv_lib_uuid_uuid_generate+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-luuid  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char uuid_generate ();
+int
+main ()
+{
+return uuid_generate ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_uuid_uuid_generate=yes
+else
+  ac_cv_lib_uuid_uuid_generate=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5
+$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; }
+if test "x$ac_cv_lib_uuid_uuid_generate" = xyes; then :
+  UUID_LIBS="-luuid"
+else
+  as_fn_error $? "library 'uuid' is required for E2FS UUID" "$LINENO" 5
+fi
+
+fi
+
+elif test "$with_uuid" = ossp ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_export in -lossp-uuid" >&5
 $as_echo_n "checking for uuid_export in -lossp-uuid... " >&6; }
 if ${ac_cv_lib_ossp_uuid_uuid_export+:} false; then :
@@ -8813,7 +8929,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ossp_uuid_uuid_export" >&5
 $as_echo "$ac_cv_lib_ossp_uuid_uuid_export" >&6; }
 if test "x$ac_cv_lib_ossp_uuid_uuid_export" = xyes; then :
-  OSSP_UUID_LIBS="-lossp-uuid"
+  UUID_LIBS="-lossp-uuid"
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_export in -luuid" >&5
 $as_echo_n "checking for uuid_export in -luuid... " >&6; }
@@ -8852,9 +8968,9 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_export" >&5
 $as_echo "$ac_cv_lib_uuid_uuid_export" >&6; }
 if test "x$ac_cv_lib_uuid_uuid_export" = xyes; then :
-  OSSP_UUID_LIBS="-luuid"
+  UUID_LIBS="-luuid"
 else
-  as_fn_error $? "library 'ossp-uuid' or 'uuid' is required for OSSP-UUID" "$LINENO" 5
+  as_fn_error $? "library 'ossp-uuid' or 'uuid' is required for OSSP UUID" "$LINENO" 5
 fi
 
 fi
@@ -9398,7 +9514,86 @@ fi
 fi
 
 # for contrib/uuid-ossp
-if test "$with_ossp_uuid" = yes ; then
+if test "$with_uuid" = bsd ; then
+  for ac_header in uuid.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default"
+if test "x$ac_cv_header_uuid_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_UUID_H 1
+_ACEOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uuid_to_string" >/dev/null 2>&1; then :
+
+else
+  as_fn_error $? "header file  does not match BSD UUID library" "$LINENO" 5
+fi
+rm -f conftest*
+
+else
+  as_fn_error $? "header file  is required for BSD UUID" "$LINENO" 5
+fi
+
+done
+
+elif test "$with_uuid" = e2fs ; then
+  for ac_header in uuid/uuid.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
+if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_UUID_UUID_H 1
+_ACEOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uuid_generate" >/dev/null 2>&1; then :
+
+else
+  as_fn_error $? "header file  does not match E2FS UUID library" "$LINENO" 5
+fi
+rm -f conftest*
+
+else
+  for ac_header in uuid.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default"
+if test "x$ac_cv_header_uuid_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_UUID_H 1
+_ACEOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uuid_generate" >/dev/null 2>&1; then :
+
+else
+  as_fn_error $? "header file  does not match E2FS UUID library" "$LINENO" 5
+fi
+rm -f conftest*
+
+else
+  as_fn_error $? "header file  or  is required for E2FS UUID" "$LINENO" 5
+fi
+
+done
+
+fi
+
+done
+
+elif test "$with_uuid" = ossp ; then
   for ac_header in ossp/uuid.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "ossp/uuid.h" "ac_cv_header_ossp_uuid_h" "$ac_includes_default"
@@ -9406,19 +9601,42 @@ if test "x$ac_cv_header_ossp_uuid_h" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_OSSP_UUID_H 1
 _ACEOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uuid_export" >/dev/null 2>&1; then :
 
 else
+  as_fn_error $? "header file  does not match OSSP UUID library" "$LINENO" 5
+fi
+rm -f conftest*
 
-    for ac_header in uuid.h
+else
+  for ac_header in uuid.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default"
 if test "x$ac_cv_header_uuid_h" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_UUID_H 1
 _ACEOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uuid_export" >/dev/null 2>&1; then :
+
+else
+  as_fn_error $? "header file  does not match OSSP UUID library" "$LINENO" 5
+fi
+rm -f conftest*
 
 else
-  as_fn_error $? "header file  or  is required for OSSP-UUID" "$LINENO" 5
+  as_fn_error $? "header file  or  is required for OSSP UUID" "$LINENO" 5
 fi
 
 done
index b94db352e13dbc3066bb07588eaa040b73a5e5f3..80df1d76510c707009518ef253ecd29d9919b976 100644 (file)
@@ -694,10 +694,38 @@ PGAC_ARG_BOOL(with, libedit-preferred, no,
 
 
 #
-# OSSP UUID library
+# UUID library
 #
-PGAC_ARG_BOOL(with, ossp-uuid, no, [build contrib/uuid-ossp, requires OSSP UUID library])
-AC_SUBST(with_ossp_uuid)
+# There are at least three UUID libraries in common use: the FreeBSD/NetBSD
+# library, the e2fsprogs libuuid (now part of util-linux-ng), and the OSSP
+# UUID library.  More than one of these might be present on a given platform,
+# so we make the user say which one she wants.
+#
+PGAC_ARG_REQ(with, uuid, [LIB], [build contrib/uuid-ossp using LIB (bsd,e2fs,ossp)])
+if test x"$with_uuid" = x"" ; then
+  with_uuid=no
+fi
+PGAC_ARG_BOOL(with, ossp-uuid, no, [obsolete spelling of --with-uuid=ossp])
+if test "$with_ossp_uuid" = yes ; then
+  with_uuid=ossp
+fi
+
+if test "$with_uuid" = bsd ; then
+  AC_DEFINE([HAVE_UUID_BSD], 1, [Define to 1 if you have BSD UUID support.])
+  UUID_EXTRA_OBJS="md5.o sha1.o"
+elif test "$with_uuid" = e2fs ; then
+  AC_DEFINE([HAVE_UUID_E2FS], 1, [Define to 1 if you have E2FS UUID support.])
+  UUID_EXTRA_OBJS="md5.o sha1.o"
+elif test "$with_uuid" = ossp ; then
+  AC_DEFINE([HAVE_UUID_OSSP], 1, [Define to 1 if you have OSSP UUID support.])
+  UUID_EXTRA_OBJS=""
+elif test "$with_uuid" = no ; then
+  UUID_EXTRA_OBJS=""
+else
+  AC_MSG_ERROR([--with-uuid must specify one of bsd, e2fs, or ossp])
+fi
+AC_SUBST(with_uuid)
+AC_SUBST(UUID_EXTRA_OBJS)
 
 
 #
@@ -948,14 +976,26 @@ if test "$with_selinux" = yes; then
 fi
 
 # for contrib/uuid-ossp
-if test "$with_ossp_uuid" = yes ; then
+if test "$with_uuid" = bsd ; then
+  # On BSD, the UUID functions are in libc
+  AC_CHECK_FUNC(uuid_to_string,
+    [UUID_LIBS=""],
+    [AC_MSG_ERROR([BSD UUID functions are not present])])
+elif test "$with_uuid" = e2fs ; then
+  # On OS X, the UUID functions are in libc
+  AC_CHECK_FUNC(uuid_generate,
+    [UUID_LIBS=""],
+    [AC_CHECK_LIB(uuid, uuid_generate,
+      [UUID_LIBS="-luuid"],
+      [AC_MSG_ERROR([library 'uuid' is required for E2FS UUID])])])
+elif test "$with_uuid" = ossp ; then
   AC_CHECK_LIB(ossp-uuid, uuid_export,
-    [OSSP_UUID_LIBS="-lossp-uuid"],
+    [UUID_LIBS="-lossp-uuid"],
     [AC_CHECK_LIB(uuid, uuid_export,
-      [OSSP_UUID_LIBS="-luuid"],
-      [AC_MSG_ERROR([library 'ossp-uuid' or 'uuid' is required for OSSP-UUID])])])
+      [UUID_LIBS="-luuid"],
+      [AC_MSG_ERROR([library 'ossp-uuid' or 'uuid' is required for OSSP UUID])])])
 fi
-AC_SUBST(OSSP_UUID_LIBS)
+AC_SUBST(UUID_LIBS)
 
 
 ##
@@ -1075,10 +1115,27 @@ if test "$with_bonjour" = yes ; then
 fi
 
 # for contrib/uuid-ossp
-if test "$with_ossp_uuid" = yes ; then
-  AC_CHECK_HEADERS(ossp/uuid.h, [], [
-    AC_CHECK_HEADERS(uuid.h, [],
-      [AC_MSG_ERROR([header file  or  is required for OSSP-UUID])])])
+if test "$with_uuid" = bsd ; then
+  AC_CHECK_HEADERS(uuid.h,
+    [AC_EGREP_HEADER([uuid_to_string], uuid.h, [],
+      [AC_MSG_ERROR([header file  does not match BSD UUID library])])],
+    [AC_MSG_ERROR([header file  is required for BSD UUID])])
+elif test "$with_uuid" = e2fs ; then
+  AC_CHECK_HEADERS(uuid/uuid.h,
+    [AC_EGREP_HEADER([uuid_generate], uuid/uuid.h, [],
+      [AC_MSG_ERROR([header file  does not match E2FS UUID library])])],
+    [AC_CHECK_HEADERS(uuid.h,
+      [AC_EGREP_HEADER([uuid_generate], uuid.h, [],
+        [AC_MSG_ERROR([header file  does not match E2FS UUID library])])],
+      [AC_MSG_ERROR([header file  or  is required for E2FS UUID])])])
+elif test "$with_uuid" = ossp ; then
+  AC_CHECK_HEADERS(ossp/uuid.h,
+    [AC_EGREP_HEADER([uuid_export], ossp/uuid.h, [],
+      [AC_MSG_ERROR([header file  does not match OSSP UUID library])])],
+    [AC_CHECK_HEADERS(uuid.h,
+      [AC_EGREP_HEADER([uuid_export], uuid.h, [],
+        [AC_MSG_ERROR([header file  does not match OSSP UUID library])])],
+      [AC_MSG_ERROR([header file  or  is required for OSSP UUID])])])
 fi
 
 if test "$PORTNAME" = "win32" ; then
index 8dc40f7de0033d372995390a7706ca22cf778fdc..b37d0dd2c318f722628caef69c510b2ef99d9044 100644 (file)
@@ -64,7 +64,7 @@ else
 ALWAYS_SUBDIRS += sslinfo
 endif
 
-ifeq ($(with_ossp_uuid),yes)
+ifneq ($(with_uuid),no)
 SUBDIRS += uuid-ossp
 else
 ALWAYS_SUBDIRS += uuid-ossp
diff --git a/contrib/uuid-ossp/.gitignore b/contrib/uuid-ossp/.gitignore
new file mode 100644 (file)
index 0000000..6c989c7
--- /dev/null
@@ -0,0 +1,6 @@
+/md5.c
+/sha1.c
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
index 9b2d2e3ff93c3d50053aa95bf2bac7913ea36537..335cc7ef50a8e9d2fedf9bb434ce0cb5fd1e133f 100644 (file)
@@ -1,12 +1,21 @@
 # contrib/uuid-ossp/Makefile
 
 MODULE_big = uuid-ossp
-OBJS = uuid-ossp.o
+OBJS = uuid-ossp.o $(UUID_EXTRA_OBJS)
 
 EXTENSION = uuid-ossp
 DATA = uuid-ossp--1.0.sql uuid-ossp--unpackaged--1.0.sql
 
-SHLIB_LINK += $(OSSP_UUID_LIBS)
+REGRESS = uuid_ossp
+
+SHLIB_LINK += $(UUID_LIBS)
+
+# We copy some needed files verbatim from pgcrypto
+pgcrypto_src = $(top_srcdir)/contrib/pgcrypto
+
+PG_CPPFLAGS = -I$(pgcrypto_src)
+
+EXTRA_CLEAN = md5.c sha1.c
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
@@ -18,3 +27,6 @@ top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 include $(top_srcdir)/contrib/contrib-global.mk
 endif
+
+md5.c sha1.c: % : $(pgcrypto_src)/%
+   rm -f $@ && $(LN_S) $< .
diff --git a/contrib/uuid-ossp/expected/uuid_ossp.out b/contrib/uuid-ossp/expected/uuid_ossp.out
new file mode 100644 (file)
index 0000000..986843c
--- /dev/null
@@ -0,0 +1,91 @@
+CREATE EXTENSION "uuid-ossp";
+SELECT uuid_nil();
+               uuid_nil               
+--------------------------------------
+ 00000000-0000-0000-0000-000000000000
+(1 row)
+
+SELECT uuid_ns_dns();
+             uuid_ns_dns              
+--------------------------------------
+ 6ba7b810-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_url();
+             uuid_ns_url              
+--------------------------------------
+ 6ba7b811-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_oid();
+             uuid_ns_oid              
+--------------------------------------
+ 6ba7b812-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_ns_x500();
+             uuid_ns_x500             
+--------------------------------------
+ 6ba7b814-9dad-11d1-80b4-00c04fd430c8
+(1 row)
+
+SELECT uuid_generate_v1() < uuid_generate_v1();
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT uuid_generate_v1() < uuid_generate_v1mc();
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT substr(uuid_generate_v1()::text, 25) = substr(uuid_generate_v1()::text, 25);
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT substr(uuid_generate_v1()::text, 25) <> substr(uuid_generate_v1mc()::text, 25);
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT substr(uuid_generate_v1mc()::text, 25) <> substr(uuid_generate_v1mc()::text, 25);
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT ('x' || substr(uuid_generate_v1mc()::text, 25, 2))::bit(8) & '00000011';
+ ?column? 
+----------
+ 00000011
+(1 row)
+
+SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com');
+           uuid_generate_v3           
+--------------------------------------
+ 3d813cbb-47fb-32ba-91df-831e1593ac29
+(1 row)
+
+SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com');
+           uuid_generate_v5           
+--------------------------------------
+ 21f7f8de-8051-5b89-8680-0195ef798b6a
+(1 row)
+
+SELECT uuid_generate_v4()::text ~ '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$';
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT uuid_generate_v4() <> uuid_generate_v4();
+ ?column? 
+----------
+ t
+(1 row)
+
diff --git a/contrib/uuid-ossp/sql/uuid_ossp.sql b/contrib/uuid-ossp/sql/uuid_ossp.sql
new file mode 100644 (file)
index 0000000..29fba21
--- /dev/null
@@ -0,0 +1,22 @@
+CREATE EXTENSION "uuid-ossp";
+
+SELECT uuid_nil();
+SELECT uuid_ns_dns();
+SELECT uuid_ns_url();
+SELECT uuid_ns_oid();
+SELECT uuid_ns_x500();
+
+SELECT uuid_generate_v1() < uuid_generate_v1();
+SELECT uuid_generate_v1() < uuid_generate_v1mc();
+
+SELECT substr(uuid_generate_v1()::text, 25) = substr(uuid_generate_v1()::text, 25);
+SELECT substr(uuid_generate_v1()::text, 25) <> substr(uuid_generate_v1mc()::text, 25);
+SELECT substr(uuid_generate_v1mc()::text, 25) <> substr(uuid_generate_v1mc()::text, 25);
+
+SELECT ('x' || substr(uuid_generate_v1mc()::text, 25, 2))::bit(8) & '00000011';
+
+SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com');
+SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com');
+
+SELECT uuid_generate_v4()::text ~ '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$';
+SELECT uuid_generate_v4() <> uuid_generate_v4();
index 8f99084df3487d48f86291aab45cf10625955639..f8c33d2b4698fb85fd9b05e8810638acd4f2d59f 100644 (file)
 /*-------------------------------------------------------------------------
  *
- * UUID generation functions using the OSSP UUID library
+ * UUID generation functions using the BSD, E2FS or OSSP UUID library
  *
  * Copyright (c) 2007-2014, PostgreSQL Global Development Group
  *
+ * Portions Copyright (c) 2009 Andrew Gierth
+ *
  * contrib/uuid-ossp/uuid-ossp.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
+
 #include "fmgr.h"
 #include "utils/builtins.h"
 #include "utils/uuid.h"
 
 /*
- * There's some confusion over the location of the uuid.h header file.
- * On Debian, it's installed as ossp/uuid.h, while on Fedora, or if you
- * install ossp-uuid from a tarball, it's installed as uuid.h. Don't know
- * what other systems do.
+ * It's possible that there's more than one uuid.h header file present.
+ * We expect configure to set the HAVE_ symbol for only the one we want.
+ *
+ * BSD includes a uuid_hash() function that conflicts with the one in
+ * builtins.h; we #define it out of the way.
  */
-#ifdef HAVE_OSSP_UUID_H
-#include 
-#else
+#define uuid_hash bsd_uuid_hash
+
 #ifdef HAVE_UUID_H
 #include 
-#else
-#error OSSP uuid.h not found
 #endif
+#ifdef HAVE_OSSP_UUID_H
+#include 
 #endif
+#ifdef HAVE_UUID_UUID_H
+#include 
+#endif
+
+#undef uuid_hash
 
-/* better both be 16 */
-#if (UUID_LEN != UUID_LEN_BIN)
+/*
+ * Some BSD variants offer md5 and sha1 implementations but Linux does not,
+ * so we use a copy of the ones from pgcrypto.  Not needed with OSSP, though.
+ */
+#ifndef HAVE_UUID_OSSP
+#include "md5.h"
+#include "sha1.h"
+#endif
+
+
+/* Check our UUID length against OSSP's; better both be 16 */
+#if defined(HAVE_UUID_OSSP) && (UUID_LEN != UUID_LEN_BIN)
 #error UUID length mismatch
 #endif
 
+/* Define some constants like OSSP's, to make the code more readable */
+#ifndef HAVE_UUID_OSSP
+#define UUID_MAKE_MC 0
+#define UUID_MAKE_V1 1
+#define UUID_MAKE_V2 2
+#define UUID_MAKE_V3 3
+#define UUID_MAKE_V4 4
+#define UUID_MAKE_V5 5
+#endif
+
+/*
+ * A DCE 1.1 compatible source representation of UUIDs, derived from
+ * the BSD implementation.  BSD already has this; OSSP doesn't need it.
+ */
+#ifdef HAVE_UUID_E2FS
+typedef struct
+{
+   uint32_t    time_low;
+   uint16_t    time_mid;
+   uint16_t    time_hi_and_version;
+   uint8_t     clock_seq_hi_and_reserved;
+   uint8_t     clock_seq_low;
+   uint8_t     node[6];
+} dce_uuid_t;
+#else
+#define dce_uuid_t uuid_t
+#endif
+
+/* If not OSSP, we need some endianness-manipulation macros */
+#ifndef HAVE_UUID_OSSP
+
+#define UUID_TO_NETWORK(uu) \
+do { \
+   uu.time_low = htonl(uu.time_low); \
+   uu.time_mid = htons(uu.time_mid); \
+   uu.time_hi_and_version = htons(uu.time_hi_and_version); \
+} while (0)
+
+#define UUID_TO_LOCAL(uu) \
+do { \
+   uu.time_low = ntohl(uu.time_low); \
+   uu.time_mid = ntohs(uu.time_mid); \
+   uu.time_hi_and_version = ntohs(uu.time_hi_and_version); \
+} while (0)
+
+#define UUID_V3_OR_V5(uu, v) \
+do { \
+   uu.time_hi_and_version &= 0x0FFF; \
+   uu.time_hi_and_version |= (v << 12); \
+   uu.clock_seq_hi_and_reserved &= 0x3F; \
+   uu.clock_seq_hi_and_reserved |= 0x80; \
+} while(0)
+
+#endif   /* !HAVE_UUID_OSSP */
+
 
 PG_MODULE_MAGIC;
 
@@ -51,6 +124,8 @@ PG_FUNCTION_INFO_V1(uuid_generate_v3);
 PG_FUNCTION_INFO_V1(uuid_generate_v4);
 PG_FUNCTION_INFO_V1(uuid_generate_v5);
 
+#ifdef HAVE_UUID_OSSP
+
 static void
 pguuid_complain(uuid_rc_t rc)
 {
@@ -114,100 +189,294 @@ special_uuid_value(const char *name)
    return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
 }
 
+/* len is unused with OSSP, but we want to have the same number of args */
+static Datum
+uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
+{
+   uuid_t     *uuid;
+   char       *str;
+   uuid_rc_t   rc;
+
+   rc = uuid_create(&uuid);
+   if (rc != UUID_RC_OK)
+       pguuid_complain(rc);
+   rc = uuid_make(uuid, mode, ns, name);
+   if (rc != UUID_RC_OK)
+       pguuid_complain(rc);
+   str = uuid_to_string(uuid);
+   rc = uuid_destroy(uuid);
+   if (rc != UUID_RC_OK)
+       pguuid_complain(rc);
+
+   return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
+}
+
+
+static Datum
+uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
+{
+   uuid_t     *ns_uuid;
+   Datum       result;
+   uuid_rc_t   rc;
+
+   rc = uuid_create(&ns_uuid);
+   if (rc != UUID_RC_OK)
+       pguuid_complain(rc);
+   string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
+                  ns_uuid);
+
+   result = uuid_generate_internal(mode,
+                                   ns_uuid,
+                                   text_to_cstring(name),
+                                   0);
+
+   rc = uuid_destroy(ns_uuid);
+   if (rc != UUID_RC_OK)
+       pguuid_complain(rc);
+
+   return result;
+}
+
+#else                          /* !HAVE_UUID_OSSP */
+
+static Datum
+uuid_generate_internal(int v, unsigned char *ns, char *ptr, int len)
+{
+   char        strbuf[40];
+
+   switch (v)
+   {
+       case 0:         /* constant-value uuids */
+           strlcpy(strbuf, ptr, 37);
+           break;
+
+       case 1:         /* time/node-based uuids */
+           {
+#ifdef HAVE_UUID_E2FS
+               uuid_t      uu;
+
+               uuid_generate_time(uu);
+               uuid_unparse(uu, strbuf);
+
+               /*
+                * PTR, if set, replaces the trailing characters of the uuid;
+                * this is to support v1mc, where a random multicast MAC is
+                * used instead of the physical one
+                */
+               if (ptr && len <= 36)
+                   strcpy(strbuf + (36 - len), ptr);
+#else                          /* BSD */
+               uuid_t      uu;
+               uint32_t    status = uuid_s_ok;
+               char       *str = NULL;
+
+               uuid_create(&uu, &status);
+
+               if (status == uuid_s_ok)
+               {
+                   uuid_to_string(&uu, &str, &status);
+                   if (status == uuid_s_ok)
+                   {
+                       strlcpy(strbuf, str, 37);
+
+                       /*
+                        * PTR, if set, replaces the trailing characters of
+                        * the uuid; this is to support v1mc, where a random
+                        * multicast MAC is used instead of the physical one
+                        */
+                       if (ptr && len <= 36)
+                           strcpy(strbuf + (36 - len), ptr);
+                   }
+                   if (str)
+                       free(str);
+               }
+
+               if (status != uuid_s_ok)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                            errmsg("uuid library failure: %d",
+                                   (int) status)));
+#endif
+               break;
+           }
+
+       case 3:         /* namespace-based MD5 uuids */
+       case 5:         /* namespace-based SHA1 uuids */
+           {
+               dce_uuid_t  uu;
+#ifdef HAVE_UUID_BSD
+               uint32_t    status = uuid_s_ok;
+               char       *str = NULL;
+#endif
+
+               if (v == 3)
+               {
+                   MD5_CTX     ctx;
+
+                   MD5Init(&ctx);
+                   MD5Update(&ctx, ns, sizeof(uu));
+                   MD5Update(&ctx, (unsigned char *) ptr, len);
+                   MD5Final((unsigned char *) &uu, &ctx);
+               }
+               else
+               {
+                   SHA1_CTX    ctx;
+
+                   SHA1Init(&ctx);
+                   SHA1Update(&ctx, ns, sizeof(uu));
+                   SHA1Update(&ctx, (unsigned char *) ptr, len);
+                   SHA1Final((unsigned char *) &uu, &ctx);
+               }
+
+               /* the calculated hash is using local order */
+               UUID_TO_NETWORK(uu);
+               UUID_V3_OR_V5(uu, v);
+
+#ifdef HAVE_UUID_E2FS
+               /* uuid_unparse expects local order */
+               UUID_TO_LOCAL(uu);
+               uuid_unparse((unsigned char *) &uu, strbuf);
+#else                          /* BSD */
+               uuid_to_string(&uu, &str, &status);
+
+               if (status == uuid_s_ok)
+                   strlcpy(strbuf, str, 37);
+
+               if (str)
+                   free(str);
+
+               if (status != uuid_s_ok)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                            errmsg("uuid library failure: %d",
+                                   (int) status)));
+#endif
+               break;
+           }
+
+       case 4:         /* random uuid */
+       default:
+           {
+#ifdef HAVE_UUID_E2FS
+               uuid_t      uu;
+
+               uuid_generate_random(uu);
+               uuid_unparse(uu, strbuf);
+#else                          /* BSD */
+               snprintf(strbuf, sizeof(strbuf),
+                        "%08lx-%04x-%04x-%04x-%04x%08lx",
+                        (unsigned long) arc4random(),
+                        (unsigned) (arc4random() & 0xffff),
+                        (unsigned) ((arc4random() & 0xfff) | 0x4000),
+                        (unsigned) ((arc4random() & 0x3fff) | 0x8000),
+                        (unsigned) (arc4random() & 0xffff),
+                        (unsigned long) arc4random());
+#endif
+               break;
+           }
+   }
+
+   return DirectFunctionCall1(uuid_in, CStringGetDatum(strbuf));
+}
+
+#endif   /* HAVE_UUID_OSSP */
+
 
 Datum
 uuid_nil(PG_FUNCTION_ARGS)
 {
+#ifdef HAVE_UUID_OSSP
    return special_uuid_value("nil");
+#else
+   return uuid_generate_internal(0, NULL,
+                                 "00000000-0000-0000-0000-000000000000", 36);
+#endif
 }
 
 
 Datum
 uuid_ns_dns(PG_FUNCTION_ARGS)
 {
+#ifdef HAVE_UUID_OSSP
    return special_uuid_value("ns:DNS");
+#else
+   return uuid_generate_internal(0, NULL,
+                                 "6ba7b810-9dad-11d1-80b4-00c04fd430c8", 36);
+#endif
 }
 
 
 Datum
 uuid_ns_url(PG_FUNCTION_ARGS)
 {
+#ifdef HAVE_UUID_OSSP
    return special_uuid_value("ns:URL");
+#else
+   return uuid_generate_internal(0, NULL,
+                                 "6ba7b811-9dad-11d1-80b4-00c04fd430c8", 36);
+#endif
 }
 
 
 Datum
 uuid_ns_oid(PG_FUNCTION_ARGS)
 {
+#ifdef HAVE_UUID_OSSP
    return special_uuid_value("ns:OID");
+#else
+   return uuid_generate_internal(0, NULL,
+                                 "6ba7b812-9dad-11d1-80b4-00c04fd430c8", 36);
+#endif
 }
 
 
 Datum
 uuid_ns_x500(PG_FUNCTION_ARGS)
 {
+#ifdef HAVE_UUID_OSSP
    return special_uuid_value("ns:X500");
-}
-
-
-static Datum
-uuid_generate_internal(int mode, const uuid_t *ns, const char *name)
-{
-   uuid_t     *uuid;
-   char       *str;
-   uuid_rc_t   rc;
-
-   rc = uuid_create(&uuid);
-   if (rc != UUID_RC_OK)
-       pguuid_complain(rc);
-   rc = uuid_make(uuid, mode, ns, name);
-   if (rc != UUID_RC_OK)
-       pguuid_complain(rc);
-   str = uuid_to_string(uuid);
-   rc = uuid_destroy(uuid);
-   if (rc != UUID_RC_OK)
-       pguuid_complain(rc);
-
-   return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
+#else
+   return uuid_generate_internal(0, NULL,
+                                 "6ba7b814-9dad-11d1-80b4-00c04fd430c8", 36);
+#endif
 }
 
 
 Datum
 uuid_generate_v1(PG_FUNCTION_ARGS)
 {
-   return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL);
+   return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL, 0);
 }
 
 
 Datum
 uuid_generate_v1mc(PG_FUNCTION_ARGS)
 {
-   return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL, NULL);
-}
-
-
-static Datum
-uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
-{
-   uuid_t     *ns_uuid;
-   Datum       result;
-   uuid_rc_t   rc;
-
-   rc = uuid_create(&ns_uuid);
-   if (rc != UUID_RC_OK)
-       pguuid_complain(rc);
-   string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
-                  ns_uuid);
-
-   result = uuid_generate_internal(mode,
-                                   ns_uuid,
-                                   text_to_cstring(name));
-
-   rc = uuid_destroy(ns_uuid);
-   if (rc != UUID_RC_OK)
-       pguuid_complain(rc);
+#ifdef HAVE_UUID_OSSP
+   char       *buf = NULL;
+#elif defined(HAVE_UUID_E2FS)
+   char        strbuf[40];
+   char       *buf;
+   uuid_t      uu;
+
+   uuid_generate_random(uu);
+
+   /* set IEEE802 multicast and local-admin bits */
+   ((dce_uuid_t *) &uu)->node[0] |= 0x03;
+
+   uuid_unparse(uu, strbuf);
+   buf = strbuf + 24;
+#else                          /* BSD */
+   char        buf[16];
+
+   /* set IEEE802 multicast and local-admin bits */
+   snprintf(buf, sizeof(buf), "-%04x%08lx",
+            (unsigned) ((arc4random() & 0xffff) | 0x0300),
+            (unsigned long) arc4random());
+#endif
 
-   return result;
+   return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL,
+                                 buf, 13);
 }
 
 
@@ -217,14 +486,19 @@ uuid_generate_v3(PG_FUNCTION_ARGS)
    pg_uuid_t  *ns = PG_GETARG_UUID_P(0);
    text       *name = PG_GETARG_TEXT_P(1);
 
+#ifdef HAVE_UUID_OSSP
    return uuid_generate_v35_internal(UUID_MAKE_V3, ns, name);
+#else
+   return uuid_generate_internal(UUID_MAKE_V3, (unsigned char *) ns,
+                                 VARDATA(name), VARSIZE(name) - VARHDRSZ);
+#endif
 }
 
 
 Datum
 uuid_generate_v4(PG_FUNCTION_ARGS)
 {
-   return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL);
+   return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL, 0);
 }
 
 
@@ -234,5 +508,10 @@ uuid_generate_v5(PG_FUNCTION_ARGS)
    pg_uuid_t  *ns = PG_GETARG_UUID_P(0);
    text       *name = PG_GETARG_TEXT_P(1);
 
+#ifdef HAVE_UUID_OSSP
    return uuid_generate_v35_internal(UUID_MAKE_V5, ns, name);
+#else
+   return uuid_generate_internal(UUID_MAKE_V5, (unsigned char *) ns,
+                                 VARDATA(name), VARSIZE(name) - VARHDRSZ);
+#endif
 }
index b6b582e24c28f3cf0e9e486044bb1821ad3f6d97..7353c612b1f6721161c8b7e2c29e4b5955446922 100644 (file)
@@ -869,17 +869,46 @@ su - postgres
        
       
 
+      
+       
+       
+        
+         Build the 
+         ]]> module
+         (which provides functions to generate UUIDs), using the specified
+         UUID library.UUID
+         LIBRARY must be one of:
+        
+        
+         
+          
+           
+           and some other BSD-derived systems
+          
+         
+         
+          
+           
+           the e2fsprogs project; this library is present in most
+           Linux systems and in Mac OS X, and can be obtained for other
+           platforms as well
+          
+         
+         
+          
+