From b8cc8f94730610c0189aa82dfec4ae6ce9b13e34 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 27 May 2014 19:42:08 -0400 Subject: [PATCH] Support BSD and e2fsprogs UUID libraries alongside OSSP UUID library. 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 --- configure | 374 ++++++++++++++++----- configure.in | 81 ++++- contrib/Makefile | 2 +- contrib/uuid-ossp/.gitignore | 6 + contrib/uuid-ossp/Makefile | 16 +- contrib/uuid-ossp/expected/uuid_ossp.out | 91 +++++ contrib/uuid-ossp/sql/uuid_ossp.sql | 22 ++ contrib/uuid-ossp/uuid-ossp.c | 409 +++++++++++++++++++---- doc/src/sgml/installation.sgml | 43 ++- doc/src/sgml/uuid-ossp.sgml | 47 ++- src/Makefile.global.in | 5 +- src/include/pg_config.h.in | 12 + 12 files changed, 927 insertions(+), 181 deletions(-) create mode 100644 contrib/uuid-ossp/.gitignore create mode 100644 contrib/uuid-ossp/expected/uuid_ossp.out create mode 100644 contrib/uuid-ossp/sql/uuid_ossp.sql diff --git a/configure b/configure index 17f3f2654f..3663e50d15 100755 --- 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,8 +5617,37 @@ 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 @@ -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 or is required for OSSP-UUID" "$LINENO" 5 + 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 fi done diff --git a/configure.in b/configure.in index b94db352e1..80df1d7651 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/contrib/Makefile b/contrib/Makefile index 8dc40f7de0..b37d0dd2c3 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -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 index 0000000000..6c989c7872 --- /dev/null +++ b/contrib/uuid-ossp/.gitignore @@ -0,0 +1,6 @@ +/md5.c +/sha1.c +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/uuid-ossp/Makefile b/contrib/uuid-ossp/Makefile index 9b2d2e3ff9..335cc7ef50 100644 --- a/contrib/uuid-ossp/Makefile +++ b/contrib/uuid-ossp/Makefile @@ -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 index 0000000000..986843c897 --- /dev/null +++ b/contrib/uuid-ossp/expected/uuid_ossp.out @@ -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 index 0000000000..29fba21b3f --- /dev/null +++ b/contrib/uuid-ossp/sql/uuid_ossp.sql @@ -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(); diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c index 8f99084df3..f8c33d2b46 100644 --- a/contrib/uuid-ossp/uuid-ossp.c +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -1,40 +1,113 @@ /*------------------------------------------------------------------------- * - * 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 -/* better both be 16 */ -#if (UUID_LEN != UUID_LEN_BIN) +#undef uuid_hash + +/* + * 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,44 +189,9 @@ special_uuid_value(const char *name) return DirectFunctionCall1(uuid_in, CStringGetDatum(str)); } - -Datum -uuid_nil(PG_FUNCTION_ARGS) -{ - return special_uuid_value("nil"); -} - - -Datum -uuid_ns_dns(PG_FUNCTION_ARGS) -{ - return special_uuid_value("ns:DNS"); -} - - -Datum -uuid_ns_url(PG_FUNCTION_ARGS) -{ - return special_uuid_value("ns:URL"); -} - - -Datum -uuid_ns_oid(PG_FUNCTION_ARGS) -{ - return special_uuid_value("ns:OID"); -} - - -Datum -uuid_ns_x500(PG_FUNCTION_ARGS) -{ - return special_uuid_value("ns:X500"); -} - - +/* 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) +uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len) { uuid_t *uuid; char *str; @@ -172,20 +212,6 @@ uuid_generate_internal(int mode, const uuid_t *ns, const char *name) } -Datum -uuid_generate_v1(PG_FUNCTION_ARGS) -{ - return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL); -} - - -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) { @@ -201,7 +227,8 @@ uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name) result = uuid_generate_internal(mode, ns_uuid, - text_to_cstring(name)); + text_to_cstring(name), + 0); rc = uuid_destroy(ns_uuid); if (rc != UUID_RC_OK) @@ -210,6 +237,248 @@ uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name) 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"); +#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, 0); +} + + +Datum +uuid_generate_v1mc(PG_FUNCTION_ARGS) +{ +#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 uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL, + buf, 13); +} + Datum uuid_generate_v3(PG_FUNCTION_ARGS) @@ -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 } diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index b6b582e24c..7353c612b1 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -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: + + + + + + + + + + + + + + + + + + - Build components using the OSSP UUID - library. Specifically, build the - - ]]> module, - which provides functions to generate - UUIDs.UUID + Obsolete equivalent of --with-uuid=ossp. diff --git a/doc/src/sgml/uuid-ossp.sgml b/doc/src/sgml/uuid-ossp.sgml index c48106ba0f..dbbea09313 100644 --- a/doc/src/sgml/uuid-ossp.sgml +++ b/doc/src/sgml/uuid-ossp.sgml @@ -13,20 +13,6 @@ are also functions to produce certain special UUID constants. - - This module depends on the OSSP UUID library, which can be found at - . - - - - - The OSSP UUID library is not well maintained, and is becoming increasingly - difficult to port to newer platforms. If you only need randomly-generated - (version 4) UUIDs, consider using the gen_random_uuid() - function from the module instead. - - - <literal>uuid-ossp</literal> Functions @@ -172,6 +158,39 @@ SELECT uuid_generate_v3(uuid_ns_url(), 'http://www.postgresql.org'); + + Building <filename>uuid-ossp</> + + + Historically this module depended on the OSSP UUID library, which accounts + for the module's name. While the OSSP UUID library can still be found + at , it is not well + maintained, and is becoming increasingly difficult to port to newer + platforms. uuid-ossp can now be built without the OSSP + library on some platforms. On FreeBSD, NetBSD, and some other BSD-derived + platforms, suitable UUID creation functions are included in the + core libc library. On Linux, Mac OS X, and some other + platforms, suitable functions are provided in the libuuid + library, which originally came from the e2fsprogs project + (though on modern Linux it is considered part + of util-linux-ng). When invoking configure, + specify to use the BSD functions, + or to + use e2fsprogs' libuuid, or + to use the OSSP UUID library. + More than one of these libraries might be available on a particular + machine, so configure does not automatically choose one. + + + + + If you only need randomly-generated (version 4) UUIDs, + consider using the gen_random_uuid() function + from the module instead. + + + + Author diff --git a/src/Makefile.global.in b/src/Makefile.global.in index 4b31c0a85e..14119a1511 100644 --- a/src/Makefile.global.in +++ b/src/Makefile.global.in @@ -163,11 +163,11 @@ with_perl = @with_perl@ with_python = @with_python@ with_tcl = @with_tcl@ with_openssl = @with_openssl@ -with_ossp_uuid = @with_ossp_uuid@ with_selinux = @with_selinux@ with_libxml = @with_libxml@ with_libxslt = @with_libxslt@ with_system_tzdata = @with_system_tzdata@ +with_uuid = @with_uuid@ with_zlib = @with_zlib@ enable_rpath = @enable_rpath@ enable_nls = @enable_nls@ @@ -240,7 +240,8 @@ DLLWRAP = @DLLWRAP@ LIBS = @LIBS@ LDAP_LIBS_FE = @LDAP_LIBS_FE@ LDAP_LIBS_BE = @LDAP_LIBS_BE@ -OSSP_UUID_LIBS = @OSSP_UUID_LIBS@ +UUID_LIBS = @UUID_LIBS@ +UUID_EXTRA_OBJS = @UUID_EXTRA_OBJS@ LD = @LD@ with_gnu_ld = @with_gnu_ld@ ld_R_works = @ld_R_works@ diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index db930f5bb0..5ff9e41212 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -602,9 +602,21 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H +/* Define to 1 if you have BSD UUID support. */ +#undef HAVE_UUID_BSD + +/* Define to 1 if you have E2FS UUID support. */ +#undef HAVE_UUID_E2FS + /* Define to 1 if you have the header file. */ #undef HAVE_UUID_H +/* Define to 1 if you have OSSP UUID support. */ +#undef HAVE_UUID_OSSP + +/* Define to 1 if you have the header file. */ +#undef HAVE_UUID_UUID_H + /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF