From f1f39911e0d2d88c98eae96a3eb14a53c664206f Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 30 Nov 2019 22:37:25 +0300 Subject: Upgrade to 12.1 --- libpq/.gitignore | 20 +- libpq/COPYRIGHT | 1 + libpq/INSTALL | 7 + libpq/README | 20 + libpq/README-DEV | 77 + libpq/build/.gitignore | 3 + libpq/build/bootstrap.build | 40 + libpq/build/export.build | 10 + libpq/build/root.build | 19 + libpq/buildfile | 188 +- libpq/chklocale.c | 445 -- libpq/encnames.c | 553 --- libpq/fe-auth.c | 841 ---- libpq/fe-auth.h | 24 - libpq/fe-connect.c | 6002 -------------------------- libpq/fe-exec.c | 3764 ---------------- libpq/fe-lobj.c | 1103 ----- libpq/fe-misc.c | 1267 ------ libpq/fe-print.c | 761 ---- libpq/fe-protocol2.c | 1623 ------- libpq/fe-protocol3.c | 2204 ---------- libpq/fe-secure.c | 505 --- libpq/getpeereid.c | 80 - libpq/inet_net_ntop.c | 298 -- libpq/ip.c | 819 ---- libpq/libpq-events.c | 209 - libpq/libpq-events.h | 94 - libpq/libpq-fe.h | 607 --- libpq/libpq-int.h | 675 --- libpq/libpq/.gitignore | 3 + libpq/libpq/buildfile | 233 + libpq/libpq/common/base64.c | 1 + libpq/libpq/common/ip.c | 1 + libpq/libpq/common/link-canary.c | 1 + libpq/libpq/common/md5.c | 1 + libpq/libpq/common/saslprep.c | 1 + libpq/libpq/common/scram-common.c | 1 + libpq/libpq/common/sha2_openssl.c | 1 + libpq/libpq/common/unicode_norm.c | 1 + libpq/libpq/include/c.h | 1 + libpq/libpq/include/common | 1 + libpq/libpq/include/getaddrinfo.h | 1 + libpq/libpq/include/libpq/libpq-fs.h | 1 + libpq/libpq/include/libpq/pqcomm.h | 1 + libpq/libpq/include/mb/pg_wchar.h | 1 + libpq/libpq/include/pg_config_manual.h | 1 + libpq/libpq/include/port.h | 1 + libpq/libpq/include/port/darwin.h | 1 + libpq/libpq/include/port/freebsd.h | 1 + libpq/libpq/include/port/linux.h | 1 + libpq/libpq/include/port/pg_bswap.h | 1 + libpq/libpq/include/port/win32 | 1 + libpq/libpq/include/port/win32.h | 1 + libpq/libpq/include/port/win32_msvc | 1 + libpq/libpq/include/port/win32_port.h | 1 + libpq/libpq/include/postgres_ext.h | 1 + libpq/libpq/include/postgres_fe.h | 1 + libpq/libpq/libpqdll.def | 178 + libpq/libpq/libpqdll.map | 178 + libpq/libpq/mb/encnames.c | 1 + libpq/libpq/mb/wchar.c | 1 + libpq/libpq/pg_config.h | 369 ++ libpq/libpq/pg_config.h.in.orig | 1 + libpq/libpq/pg_config.h.win32.orig | 1 + libpq/libpq/pg_config_ext.h | 19 + libpq/libpq/pg_config_ext.h.in.orig | 1 + libpq/libpq/pg_config_ext.h.win32.orig | 1 + libpq/libpq/pg_config_os.h | 21 + libpq/libpq/pg_config_paths.h | 11 + libpq/libpq/port/chklocale.c | 1 + libpq/libpq/port/getaddrinfo.c | 1 + libpq/libpq/port/getpeereid.c | 1 + libpq/libpq/port/inet_aton.c | 1 + libpq/libpq/port/inet_net_ntop.c | 1 + libpq/libpq/port/noblock.c | 1 + libpq/libpq/port/open.c | 1 + libpq/libpq/port/pg_strong_random.c | 1 + libpq/libpq/port/pgsleep.c | 1 + libpq/libpq/port/pgstrcasecmp.c | 1 + libpq/libpq/port/pthread-win32.h | 1 + libpq/libpq/port/snprintf.c | 1 + libpq/libpq/port/strerror.c | 1 + libpq/libpq/port/strlcpy.c | 1 + libpq/libpq/port/system.c | 1 + libpq/libpq/port/thread.c | 1 + libpq/libpq/port/win32error.c | 1 + libpq/libpq/port/win32setlocale.c | 1 + libpq/libpq/pq | 1 + libpq/libpq/version.h.in | 17 + libpq/manifest | 25 + libpq/md5.c | 345 -- libpq/noblock.c | 66 - libpq/non-bsd/strlcpy.c | 71 - libpq/pg_service.conf.sample | 17 - libpq/pgstrcasecmp.c | 151 - libpq/postgresql/c.h | 1107 ----- libpq/postgresql/common/fe_memutils.h | 44 - libpq/postgresql/getaddrinfo.h | 164 - libpq/postgresql/libpq/ip.h | 51 - libpq/postgresql/libpq/libpq-fs.h | 24 - libpq/postgresql/libpq/md5.h | 30 - libpq/postgresql/libpq/pqcomm.h | 206 - libpq/postgresql/mb/pg_wchar.h | 561 --- libpq/postgresql/pg_config.h | 280 -- libpq/postgresql/pg_config.h.in.orig | 931 ---- libpq/postgresql/pg_config.h.win32.orig | 682 --- libpq/postgresql/pg_config_ext.h | 20 - libpq/postgresql/pg_config_ext.h.in.orig | 7 - libpq/postgresql/pg_config_ext.h.win32.orig | 7 - libpq/postgresql/pg_config_manual.h | 327 -- libpq/postgresql/pg_config_paths.h | 1 - libpq/postgresql/port.h | 477 -- libpq/postgresql/port/bsd/pg_config_os.h | 0 libpq/postgresql/port/darwin/pg_config_os.h | 8 - libpq/postgresql/port/linux/pg_config_os.h | 22 - libpq/postgresql/port/win32/arpa/inet.h | 3 - libpq/postgresql/port/win32/netdb.h | 1 - libpq/postgresql/port/win32/netinet/in.h | 3 - libpq/postgresql/port/win32/pg_config_os.h | 486 --- libpq/postgresql/port/win32/pthread-win32.h | 22 - libpq/postgresql/port/win32/pwd.h | 3 - libpq/postgresql/port/win32/sys/socket.h | 33 - libpq/postgresql/port/win32/sys/wait.h | 3 - libpq/postgresql/port/win32_msvc/sys/file.h | 1 - libpq/postgresql/port/win32_msvc/sys/param.h | 1 - libpq/postgresql/port/win32_msvc/sys/time.h | 1 - libpq/postgresql/port/win32_msvc/unistd.h | 1 - libpq/postgresql/postgres_ext.h | 70 - libpq/postgresql/postgres_fe.h | 29 - libpq/pqexpbuffer.c | 430 -- libpq/pqexpbuffer.h | 182 - libpq/pqsignal.c | 90 - libpq/tests/.gitignore | 3 + libpq/tests/build/.gitignore | 3 + libpq/tests/build/bootstrap.build | 9 + libpq/tests/build/root.build | 22 + libpq/tests/buildfile | 5 + libpq/tests/conninfo/buildfile | 13 + libpq/tests/conninfo/driver.c | 74 + libpq/tests/conninfo/expected.out | 171 + libpq/tests/conninfo/postgres_fe.h | 19 + libpq/tests/conninfo/regress.in | 57 + libpq/tests/conninfo/testscript | 5 + libpq/tests/conninfo/uri-regress.c | 1 + libpq/thread.c | 146 - libpq/version.h.in | 26 - libpq/wchar.c | 2054 --------- libpq/win32/crypt.c | 1085 ----- libpq/win32/getaddrinfo.c | 412 -- libpq/win32/inet_aton.c | 147 - libpq/win32/libpq.rc.in | 31 - libpq/win32/libpqdll.def | 174 - libpq/win32/libpqdll.def.orig | 174 - libpq/win32/open.c | 167 - libpq/win32/pgsleep.c | 63 - libpq/win32/pthread-win32.c | 61 - libpq/win32/pthread-win32.h | 22 - libpq/win32/snprintf.c | 1141 ----- libpq/win32/system.c | 119 - libpq/win32/win32.c | 327 -- libpq/win32/win32.h | 40 - libpq/win32/win32error.c | 206 - libpq/win32/win32setlocale.c | 189 - 163 files changed, 1687 insertions(+), 35601 deletions(-) create mode 120000 libpq/COPYRIGHT create mode 100644 libpq/INSTALL create mode 100644 libpq/README create mode 100644 libpq/README-DEV create mode 100644 libpq/build/.gitignore create mode 100644 libpq/build/bootstrap.build create mode 100644 libpq/build/export.build create mode 100644 libpq/build/root.build delete mode 100644 libpq/chklocale.c delete mode 100644 libpq/encnames.c delete mode 100644 libpq/fe-auth.c delete mode 100644 libpq/fe-auth.h delete mode 100644 libpq/fe-connect.c delete mode 100644 libpq/fe-exec.c delete mode 100644 libpq/fe-lobj.c delete mode 100644 libpq/fe-misc.c delete mode 100644 libpq/fe-print.c delete mode 100644 libpq/fe-protocol2.c delete mode 100644 libpq/fe-protocol3.c delete mode 100644 libpq/fe-secure.c delete mode 100644 libpq/getpeereid.c delete mode 100644 libpq/inet_net_ntop.c delete mode 100644 libpq/ip.c delete mode 100644 libpq/libpq-events.c delete mode 100644 libpq/libpq-events.h delete mode 100644 libpq/libpq-fe.h delete mode 100644 libpq/libpq-int.h create mode 100644 libpq/libpq/.gitignore create mode 100644 libpq/libpq/buildfile create mode 120000 libpq/libpq/common/base64.c create mode 120000 libpq/libpq/common/ip.c create mode 120000 libpq/libpq/common/link-canary.c create mode 120000 libpq/libpq/common/md5.c create mode 120000 libpq/libpq/common/saslprep.c create mode 120000 libpq/libpq/common/scram-common.c create mode 120000 libpq/libpq/common/sha2_openssl.c create mode 120000 libpq/libpq/common/unicode_norm.c create mode 120000 libpq/libpq/include/c.h create mode 120000 libpq/libpq/include/common create mode 120000 libpq/libpq/include/getaddrinfo.h create mode 120000 libpq/libpq/include/libpq/libpq-fs.h create mode 120000 libpq/libpq/include/libpq/pqcomm.h create mode 120000 libpq/libpq/include/mb/pg_wchar.h create mode 120000 libpq/libpq/include/pg_config_manual.h create mode 120000 libpq/libpq/include/port.h create mode 120000 libpq/libpq/include/port/darwin.h create mode 120000 libpq/libpq/include/port/freebsd.h create mode 120000 libpq/libpq/include/port/linux.h create mode 120000 libpq/libpq/include/port/pg_bswap.h create mode 120000 libpq/libpq/include/port/win32 create mode 120000 libpq/libpq/include/port/win32.h create mode 120000 libpq/libpq/include/port/win32_msvc create mode 120000 libpq/libpq/include/port/win32_port.h create mode 120000 libpq/libpq/include/postgres_ext.h create mode 120000 libpq/libpq/include/postgres_fe.h create mode 100644 libpq/libpq/libpqdll.def create mode 100644 libpq/libpq/libpqdll.map create mode 120000 libpq/libpq/mb/encnames.c create mode 120000 libpq/libpq/mb/wchar.c create mode 100644 libpq/libpq/pg_config.h create mode 120000 libpq/libpq/pg_config.h.in.orig create mode 120000 libpq/libpq/pg_config.h.win32.orig create mode 100644 libpq/libpq/pg_config_ext.h create mode 120000 libpq/libpq/pg_config_ext.h.in.orig create mode 120000 libpq/libpq/pg_config_ext.h.win32.orig create mode 100644 libpq/libpq/pg_config_os.h create mode 100644 libpq/libpq/pg_config_paths.h create mode 120000 libpq/libpq/port/chklocale.c create mode 120000 libpq/libpq/port/getaddrinfo.c create mode 120000 libpq/libpq/port/getpeereid.c create mode 120000 libpq/libpq/port/inet_aton.c create mode 120000 libpq/libpq/port/inet_net_ntop.c create mode 120000 libpq/libpq/port/noblock.c create mode 120000 libpq/libpq/port/open.c create mode 120000 libpq/libpq/port/pg_strong_random.c create mode 120000 libpq/libpq/port/pgsleep.c create mode 120000 libpq/libpq/port/pgstrcasecmp.c create mode 120000 libpq/libpq/port/pthread-win32.h create mode 120000 libpq/libpq/port/snprintf.c create mode 120000 libpq/libpq/port/strerror.c create mode 120000 libpq/libpq/port/strlcpy.c create mode 120000 libpq/libpq/port/system.c create mode 120000 libpq/libpq/port/thread.c create mode 120000 libpq/libpq/port/win32error.c create mode 120000 libpq/libpq/port/win32setlocale.c create mode 120000 libpq/libpq/pq create mode 100644 libpq/libpq/version.h.in create mode 100644 libpq/manifest delete mode 100644 libpq/md5.c delete mode 100644 libpq/noblock.c delete mode 100644 libpq/non-bsd/strlcpy.c delete mode 100644 libpq/pg_service.conf.sample delete mode 100644 libpq/pgstrcasecmp.c delete mode 100644 libpq/postgresql/c.h delete mode 100644 libpq/postgresql/common/fe_memutils.h delete mode 100644 libpq/postgresql/getaddrinfo.h delete mode 100644 libpq/postgresql/libpq/ip.h delete mode 100644 libpq/postgresql/libpq/libpq-fs.h delete mode 100644 libpq/postgresql/libpq/md5.h delete mode 100644 libpq/postgresql/libpq/pqcomm.h delete mode 100644 libpq/postgresql/mb/pg_wchar.h delete mode 100644 libpq/postgresql/pg_config.h delete mode 100644 libpq/postgresql/pg_config.h.in.orig delete mode 100644 libpq/postgresql/pg_config.h.win32.orig delete mode 100644 libpq/postgresql/pg_config_ext.h delete mode 100644 libpq/postgresql/pg_config_ext.h.in.orig delete mode 100644 libpq/postgresql/pg_config_ext.h.win32.orig delete mode 100644 libpq/postgresql/pg_config_manual.h delete mode 100644 libpq/postgresql/pg_config_paths.h delete mode 100644 libpq/postgresql/port.h delete mode 100644 libpq/postgresql/port/bsd/pg_config_os.h delete mode 100644 libpq/postgresql/port/darwin/pg_config_os.h delete mode 100644 libpq/postgresql/port/linux/pg_config_os.h delete mode 100644 libpq/postgresql/port/win32/arpa/inet.h delete mode 100644 libpq/postgresql/port/win32/netdb.h delete mode 100644 libpq/postgresql/port/win32/netinet/in.h delete mode 100644 libpq/postgresql/port/win32/pg_config_os.h delete mode 100644 libpq/postgresql/port/win32/pthread-win32.h delete mode 100644 libpq/postgresql/port/win32/pwd.h delete mode 100644 libpq/postgresql/port/win32/sys/socket.h delete mode 100644 libpq/postgresql/port/win32/sys/wait.h delete mode 100644 libpq/postgresql/port/win32_msvc/sys/file.h delete mode 100644 libpq/postgresql/port/win32_msvc/sys/param.h delete mode 100644 libpq/postgresql/port/win32_msvc/sys/time.h delete mode 100644 libpq/postgresql/port/win32_msvc/unistd.h delete mode 100644 libpq/postgresql/postgres_ext.h delete mode 100644 libpq/postgresql/postgres_fe.h delete mode 100644 libpq/pqexpbuffer.c delete mode 100644 libpq/pqexpbuffer.h delete mode 100644 libpq/pqsignal.c create mode 100644 libpq/tests/.gitignore create mode 100644 libpq/tests/build/.gitignore create mode 100644 libpq/tests/build/bootstrap.build create mode 100644 libpq/tests/build/root.build create mode 100644 libpq/tests/buildfile create mode 100644 libpq/tests/conninfo/buildfile create mode 100644 libpq/tests/conninfo/driver.c create mode 100644 libpq/tests/conninfo/expected.out create mode 100644 libpq/tests/conninfo/postgres_fe.h create mode 100644 libpq/tests/conninfo/regress.in create mode 100644 libpq/tests/conninfo/testscript create mode 120000 libpq/tests/conninfo/uri-regress.c delete mode 100644 libpq/thread.c delete mode 100644 libpq/version.h.in delete mode 100644 libpq/wchar.c delete mode 100644 libpq/win32/crypt.c delete mode 100644 libpq/win32/getaddrinfo.c delete mode 100644 libpq/win32/inet_aton.c delete mode 100644 libpq/win32/libpq.rc.in delete mode 100644 libpq/win32/libpqdll.def delete mode 100644 libpq/win32/libpqdll.def.orig delete mode 100644 libpq/win32/open.c delete mode 100644 libpq/win32/pgsleep.c delete mode 100644 libpq/win32/pthread-win32.c delete mode 100644 libpq/win32/pthread-win32.h delete mode 100644 libpq/win32/snprintf.c delete mode 100644 libpq/win32/system.c delete mode 100644 libpq/win32/win32.c delete mode 100644 libpq/win32/win32.h delete mode 100644 libpq/win32/win32error.c delete mode 100644 libpq/win32/win32setlocale.c (limited to 'libpq') diff --git a/libpq/.gitignore b/libpq/.gitignore index 620b4c8..cece09c 100644 --- a/libpq/.gitignore +++ b/libpq/.gitignore @@ -1,3 +1,19 @@ -# Generated version.h. +# Compiler/linker output. # -version.h +*.d +*.t +*.i +*.ii +*.o +*.obj +*.so +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc diff --git a/libpq/COPYRIGHT b/libpq/COPYRIGHT new file mode 120000 index 0000000..945f098 --- /dev/null +++ b/libpq/COPYRIGHT @@ -0,0 +1 @@ +../upstream/COPYRIGHT \ No newline at end of file diff --git a/libpq/INSTALL b/libpq/INSTALL new file mode 100644 index 0000000..61ec557 --- /dev/null +++ b/libpq/INSTALL @@ -0,0 +1,7 @@ +The aim of this package is to make reading the INSTALL file unnecessary. So +next time try running: + +$ bpkg build libpq + +But if you don't want to use the package manager, then you can also build this +package manually using the standard build2 build system. diff --git a/libpq/README b/libpq/README new file mode 100644 index 0000000..f57e7a7 --- /dev/null +++ b/libpq/README @@ -0,0 +1,20 @@ +PostgreSQL is an object-relational SQL database management system with libpq +being its C client library. Applications can use this library to pass queries +to the PostgreSQL backend server and to receive the results of those queries +using the C programming language. For more information see: + +https://www.postgresql.org/ + +This package contains the original libpq library source code overlaid with the +build2-based build system and packaged for the build2 package manager (bpkg). + +See the INSTALL file for the prerequisites and installation instructions. + +Send questions, bug reports, or any other feedback about the library itself to +the PostgreSQL mailing lists. Send build system and packaging-related feedback +to the packaging@build2.org mailing list (see https://lists.build2.org for +posting guidelines, etc). + +The packaging of PostgreSQL for build2 is tracked in a Git repository at: + +https://git.build2.org/cgit/packaging/postgresql/ diff --git a/libpq/README-DEV b/libpq/README-DEV new file mode 100644 index 0000000..cadfe63 --- /dev/null +++ b/libpq/README-DEV @@ -0,0 +1,77 @@ +This document describes how libpq was packaged for build2. In particular, this +understanding will be useful when upgrading to a new upstream version. See +../README-DEV for general notes on PostgreSQL packaging. + +The upstream package builds the common and ports static libraries and links +them to the libpq library. These static libraries are generic enough to fit +all the binaries built by the package. We will build libpq selecting only the +required static libraries source files, relying on the linker diagnostics +(unresolved symbol errors, etc). + +Symlink the required upstream components and provide our own implementations +for auto-generated headers: + +$ ln -s ../upstream/COPYRIGHT + +Note that we symlink the libpq directory under the different name not to +confuse the headers auto-generating machinery while it maps the header +directory prefixes. + +$ ln -s ../../upstream/src/interfaces/libpq libpq/pq + +Note that while we could symlink the upstream's top source directories, this +would potentially bloat the distribution, uglify the buildfile, and complicate +pg_config.h change tracking on upgrade (see below). Thus, we selectively +symlink only the required files. + +$ mkdir libpq/mb +$ ln -s ../../../upstream/src/backend/utils/mb/{encnames,wchar}.c libpq/mb + +$ mkdir -p libpq/include/libpq libpq/include/mb libpq/include/port +$ ln -s ../../../upstream/src/include/{c,getaddrinfo,pg_config_manual,port,postgres_ext,postgres_fe}.h libpq/include +$ ln -s ../../../../upstream/src/include/libpq/{libpq-fs,pqcomm}.h libpq/include/libpq +$ ln -s ../../../../upstream/src/include/mb/pg_wchar.h libpq/include/mb +$ ln -s ../../../../upstream/src/include/port/{linux,freebsd,darwin,win32,win32_port,pg_bswap}.h libpq/include/port +$ ln -s ../../../../upstream/src/include/port/{win32,win32_msvc} libpq/include/port + +$ mkdir libpq/common +$ ln -s ../../../upstream/src/common/{md5,scram-common,ip,sha2_openssl,link-canary,base64,saslprep,unicode_norm}.c \ + libpq/common + +$ mkdir libpq/port +$ ln -s ../../../upstream/src/port/{pgstrcasecmp,snprintf,getpeereid,pg_strong_random,thread,strerror,chklocale,noblock,inet_net_ntop,strlcpy,win32setlocale,getaddrinfo,open,inet_aton,pgsleep,win32error,system}.c libpq/port +$ ln -s ../../../upstream/src/port/pthread-win32.h libpq/port + +$ ln -s ../../upstream/src/include/pg_config_ext.h.in libpq/pg_config_ext.h.in.orig +$ ln -s ../../upstream/src/include/pg_config_ext.h.win32 libpq/pg_config_ext.h.win32.orig +$ ln -s ../../upstream/src/include/pg_config.h.in libpq/pg_config.h.in.orig +$ ln -s ../../upstream/src/include/pg_config.h.win32 libpq/pg_config.h.win32.orig + +$ ln -s ../../../upstream/src/interfaces/libpq/test/uri-regress.c tests/conninfo + +Create libpq/{pg_config,pg_config_ext,pg_config_os,pg_config_paths}.h using as +a base the upstream's auto-generated headers and/or the corresponding +templates, makefiles, and perl/batch/shell scripts. + +Note that re-creating libpq/pg_config.h from scratch every time we upgrade to +a new upstream version would be a real pain. Instead we can only (un)define +the newly introduced macros, comparing the already defined and currently used +macro sets: + +$ for m in `cat libpq/pg_config.h.in.orig libpq/pg_config.h.win32.orig | \ + sed -n 's/.*#\s*\(define\|undef\)\s\{1,\}\([_A-Z0-9]\{1,\}\)\(\s.*\)\{0,1\}$/\2/p' | \ + sort -u`; do + if grep -q -e "\b$m\b" `find -L . -name '*.h' -a ! -name 'pg_config.h' -o -name '*.c'`; then + echo "$m" + fi + done >used-macros + +$ cat libpq/pg_config.h | \ + sed -n 's/#\s*\(define\|undef\)\s\{1,\}\([_A-Z0-9]\{1,\}\)\(\s.*\)\{0,1\}$/\2/p' | \ + sort -u >defined-macros + +$ diff defined-macros used-macros + +Copy upstream's auto-generated src/interfaces/libpq/{exports.list,libpqdll.def} +to libpq/{libpqdll.map,libpqdll.def} or create them manually based on +pq/exports.txt. Comment out the "LIBRARY LIBPQ" line in libpqdll.def. diff --git a/libpq/build/.gitignore b/libpq/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/libpq/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/libpq/build/bootstrap.build b/libpq/build/bootstrap.build new file mode 100644 index 0000000..22b180f --- /dev/null +++ b/libpq/build/bootstrap.build @@ -0,0 +1,40 @@ +# file : build/bootstrap.build +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +project = libpq + +using version +using config +using dist +using test +using install + +# PostgreSQL releases (for quite a long time) had the 3-component versions, +# where the first 2 components denoted a major version and the third one -- +# the minor version. This has changed starting from version 10, with the major +# version represented by a single component. Minor releases are guaranteed to +# be backwards-compatible and contain only bug fixes. See also: +# +# https://www.postgresql.org/support/versioning/ +# +# Note that the release version is not a semantic version and we will map it to +# the standard version as ..0. +# +# There is no document that describes libpq ABI versioning and compatibility +# rules, so everything that follows is implied from +# src/interfaces/libpq/Makefile. +# +# The library naming schema on Linux is libpq.so.. +# (SO_MAJOR_VERSION and SO_MINOR_VERSION in the Makefile) So presumably +# so_major is incremented on backwards-incompatible ABI changes (it hasn't +# been for the several last major version releases). And so_minor is equal to +# the package major version. +# +if ($version.major == 12 && $version.minor == 1) +{ + abi_major = 5 + abi_minor = 12 +} +else + fail "increment the ABI version?" diff --git a/libpq/build/export.build b/libpq/build/export.build new file mode 100644 index 0000000..748c3ea --- /dev/null +++ b/libpq/build/export.build @@ -0,0 +1,10 @@ +# file : build/export.build +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +$out_root/ +{ + include libpq/ +} + +export $out_root/libpq/lib{pq} diff --git a/libpq/build/root.build b/libpq/build/root.build new file mode 100644 index 0000000..76b1aa3 --- /dev/null +++ b/libpq/build/root.build @@ -0,0 +1,19 @@ +# file : build/root.build +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +# We rely on this in macros/options deduction (see +# libpq/{buildfile,pg_config.h} for details). +# +c.std = 99 + +using c + +h{*}: extension = h +c{*}: extension = c + +if ($c.target.system == 'win32-msvc') + c.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($c.class == 'msvc') + c.coptions += /wd4251 /wd4275 /wd4800 diff --git a/libpq/buildfile b/libpq/buildfile index 5a1732b..e2ceea2 100644 --- a/libpq/buildfile +++ b/libpq/buildfile @@ -1,188 +1,10 @@ -# file : libpq/buildfile +# file : buildfile # copyright : Copyright (c) 2016-2019 Code Synthesis Ltd # license : PostgreSQL Licenes; see accompanying COPYRIGHT file -# Headers other than these are not installed so treat them as files. -# -# @@ Make it postgresql/{postgres_ext.h pg_config_ext.h} when name pattern can -# be represented with a reversible name. -# -# @@ TODO: we should be able to redo it with install=true/false -# -h = version.h libpq-fe.h libpq-events.h \ - postgresql/postgres_ext.h postgresql/pg_config_ext.h - -lib{pq}: c{*} h{$h} file{**.h -{$h}} def{win32/libpqdll} \ - file{pg_service.conf.sample} - -tclass = $c.target.class - -bsd = ($tclass == 'bsd') -macos = ($tclass == 'macos') -windows = ($tclass == 'windows') - -msvc_runtime = ($c.target.system == 'win32-msvc') - -gcc = ($c.class == 'gcc') -msvc = ($c.class == 'msvc') - -lib{pq}: win32/c{*}: include = $windows -lib{pq}: non-bsd/c{*}: include = (($bsd || $macos) == false) +./: {*/ -build/} doc{COPYRIGHT INSTALL README} manifest -# The version file is an internal one (it is only included from -# postgresql/pg_config.h) so we don't distribute nor install it (see below). +# Don't install tests or the INSTALL file. # -h{version}: in{version} $src_root/manifest - -# Build options. -# -c.poptions += -DFRONTEND -DUNSAFE_STAT_OK -DSO_MAJOR_VERSION=$abi_major - -if! $windows - # Note that the original package uses -pthread compiler/linker option. It is - # currently unsupported by build2, so we use -D_REENTRANT and -lpthread - # preprocessor/linker options instead. We also omit -D_THREAD_SAFE (synonym - # for -D_REENTRANT) and Solaris-specific -D_POSIX_PTHREAD_SEMANTICS. - # - # @@ Maybe makes sense to support -pthread in build2, adding -lpthread - # to pkg-config's Libs.private and to cc.export.libs? - # - c.poptions += -D_REENTRANT -D_GNU_SOURCE -else - # Note that the original package defines the WIN32 macro for VC only, relying - # on the fact that MinGW GCC defines it by default. However, the macro - # disappears from the default ones if to compile with -std=c9x (as we do). So - # we define it for both VC and MinGW GCC. - # - # It's tempting to move this definition to libpq/postgresql/pg_config.h. - # However this header is not included into all files that use the macro, for - # example, libpq/win32/open.c. - # - c.poptions += -DWIN32 - -port_dir = ($windows ? "win32" : \ - $macos ? "darwin" : \ - $tclass) - -# Note that we add "-I$src_root" for the headers auto-generating machinery to -# work properly. -# -c.poptions =+ "-I$out_root" "-I$src_root" "-I$src_base" \ - "-I$src_base/postgresql/port/$port_dir" \ - "-I$src_base/postgresql" - -if $windows - c.poptions =+ "-I$src_base/win32" - -if $msvc_runtime -{ - c.poptions =+ "-I$src_base/postgresql/port/win32_msvc" - - c.poptions += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE - - # Disable warnings that pop up with /W3. - # - if $msvc - c.coptions += /wd4018 /wd4244 /wd4267 -} -elif $gcc -{ - # Omit -fexcess-precision=standard as -std=9x implies it. - # - c.coptions += -fno-strict-aliasing -fwrapv - - # Disable warnings that pop up with -Wall -Wextra. Upstream doesn't seem to - # care about these and it is not easy to disable specific warnings in a way - # that works across compilers/version (some -Wno-* options are only - # recognized in newer versions). - # - c.coptions += -Wno-all -Wno-extra -} - -# Define SYSCONFDIR macro. This path is used as a last resort for the -# pg_service.conf file search (see libpq/fe-connect.c for details). -# -# The whole idea feels utterly broken (hello cross-compilation) so we will -# just do bare minimum and wait and see. -# -# @@ We should probably allow to configure this macros via configuration -# variable config.libpq.sysconfdir. -# -if! $windows -{ - # For the original package if the resulted sysconfdir path doesn't contain - # the 'postgres' or 'pgsql' substring then the '/postgresql' suffix is - # automatically appended (see the original INSTALL file for details). Note - # that the same rule is applied for the datadir and docdir paths. Also if - # the root directory is /usr, then the resulting sysconfdir path is - # /etc/postgresql (rather than /usr/etc/postgresql). - # - # Let's do the same for the sysconfdir to increase the chance that libpq - # will find the configuration file. Note that we don't install anything at - # this path and don't amend the install.data and install.doc path variables. - # We also use the same default path as the original package. - # - if ($install.root != [null]) - { - root = $install.resolve($install.root) - sysconfdir = ($root != /usr ? $root/etc : /etc) - - if! $regex.match("$sysconfdir", '.*(pgsql|postgresql).*') - sysconfdir = $sysconfdir/postgresql - } - else - sysconfdir = /usr/local/pgsql/etc -} -else -{ - # win32.mak from the original package does this. - # - sysconfdir = "" -} - -# If we ever enable National Language Support (ENABLE_NLS macro) then we will -# need to define the LOCALEDIR macro as well. It refers to the locale data -# directory and should be $install.data/locale by default. We will also need -# to install this directory (see configure script --enable-nls options and the -# src/interfaces/libpq/po directory in the original package for details). -# -obj{fe-connect}: c.poptions += -DSYSCONFDIR="\"$sysconfdir\"" - -if! $windows - c.libs += -lpthread -else - # The original package also adds the resource file to the library. The file - # contains only the version information. First, libpq.rc is produced from - # libpq.rc.in with the following command: - # - # sed -e 's/\(VERSION.*\),0 *$/\1,'`date '+%y%j' | \ - # sed 's/^0*//'`'/' libpq.rc.in >libpq.rc - # - # Then libpq.rc is compiled with: - # - # windres -i libpq.rc -o libpqrc.o - # - # Afterwards libpqrc.o is linked to the library. - # - # @@ Currently we don't have support for the first two steps. - # - c.libs += $regex.apply(secur32 ws2_32 advapi32, \ - '(.+)', \ - $msvc_runtime ? '\1.lib' : '-l\1') - -# Export options. -# -lib{pq}: cc.export.poptions = "-I$src_base" "-I$src_base/postgresql" - -# See bootstrap.build for details. -# -if $version.pre_release - lib{pq}: bin.lib.version = @"-$version.project_id" -else - lib{pq}: bin.lib.version = @"-$abi_version" - -# Internal header (see above). -# -h{version}: install = false - -file{pg_service.conf.sample}@./: install = data/ +tests/: install = false +doc{INSTALL}@./: install = false diff --git a/libpq/chklocale.c b/libpq/chklocale.c deleted file mode 100644 index 3c0ef6a..0000000 --- a/libpq/chklocale.c +++ /dev/null @@ -1,445 +0,0 @@ -/*------------------------------------------------------------------------- - * - * chklocale.c - * Functions for handling locale-related info - * - * - * Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * - * IDENTIFICATION - * src/port/chklocale.c - * - *------------------------------------------------------------------------- - */ - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#if defined(WIN32) && (_MSC_VER >= 1900) -#include -#endif - -#include -#ifdef HAVE_LANGINFO_H -#include -#endif - -#include "mb/pg_wchar.h" - - -/* - * This table needs to recognize all the CODESET spellings for supported - * backend encodings, as well as frontend-only encodings where possible - * (the latter case is currently only needed for initdb to recognize - * error situations). On Windows, we rely on entries for codepage - * numbers (CPnnn). - * - * Note that we search the table with pg_strcasecmp(), so variant - * capitalizations don't need their own entries. - */ -struct encoding_match -{ - enum pg_enc pg_enc_code; - const char *system_enc_name; -}; - -static const struct encoding_match encoding_match_list[] = { - {PG_EUC_JP, "EUC-JP"}, - {PG_EUC_JP, "eucJP"}, - {PG_EUC_JP, "IBM-eucJP"}, - {PG_EUC_JP, "sdeckanji"}, - {PG_EUC_JP, "CP20932"}, - - {PG_EUC_CN, "EUC-CN"}, - {PG_EUC_CN, "eucCN"}, - {PG_EUC_CN, "IBM-eucCN"}, - {PG_EUC_CN, "GB2312"}, - {PG_EUC_CN, "dechanzi"}, - {PG_EUC_CN, "CP20936"}, - - {PG_EUC_KR, "EUC-KR"}, - {PG_EUC_KR, "eucKR"}, - {PG_EUC_KR, "IBM-eucKR"}, - {PG_EUC_KR, "deckorean"}, - {PG_EUC_KR, "5601"}, - {PG_EUC_KR, "CP51949"}, - - {PG_EUC_TW, "EUC-TW"}, - {PG_EUC_TW, "eucTW"}, - {PG_EUC_TW, "IBM-eucTW"}, - {PG_EUC_TW, "cns11643"}, - /* No codepage for EUC-TW ? */ - - {PG_UTF8, "UTF-8"}, - {PG_UTF8, "utf8"}, - {PG_UTF8, "CP65001"}, - - {PG_LATIN1, "ISO-8859-1"}, - {PG_LATIN1, "ISO8859-1"}, - {PG_LATIN1, "iso88591"}, - {PG_LATIN1, "CP28591"}, - - {PG_LATIN2, "ISO-8859-2"}, - {PG_LATIN2, "ISO8859-2"}, - {PG_LATIN2, "iso88592"}, - {PG_LATIN2, "CP28592"}, - - {PG_LATIN3, "ISO-8859-3"}, - {PG_LATIN3, "ISO8859-3"}, - {PG_LATIN3, "iso88593"}, - {PG_LATIN3, "CP28593"}, - - {PG_LATIN4, "ISO-8859-4"}, - {PG_LATIN4, "ISO8859-4"}, - {PG_LATIN4, "iso88594"}, - {PG_LATIN4, "CP28594"}, - - {PG_LATIN5, "ISO-8859-9"}, - {PG_LATIN5, "ISO8859-9"}, - {PG_LATIN5, "iso88599"}, - {PG_LATIN5, "CP28599"}, - - {PG_LATIN6, "ISO-8859-10"}, - {PG_LATIN6, "ISO8859-10"}, - {PG_LATIN6, "iso885910"}, - - {PG_LATIN7, "ISO-8859-13"}, - {PG_LATIN7, "ISO8859-13"}, - {PG_LATIN7, "iso885913"}, - - {PG_LATIN8, "ISO-8859-14"}, - {PG_LATIN8, "ISO8859-14"}, - {PG_LATIN8, "iso885914"}, - - {PG_LATIN9, "ISO-8859-15"}, - {PG_LATIN9, "ISO8859-15"}, - {PG_LATIN9, "iso885915"}, - {PG_LATIN9, "CP28605"}, - - {PG_LATIN10, "ISO-8859-16"}, - {PG_LATIN10, "ISO8859-16"}, - {PG_LATIN10, "iso885916"}, - - {PG_KOI8R, "KOI8-R"}, - {PG_KOI8R, "CP20866"}, - - {PG_KOI8U, "KOI8-U"}, - {PG_KOI8U, "CP21866"}, - - {PG_WIN866, "CP866"}, - {PG_WIN874, "CP874"}, - {PG_WIN1250, "CP1250"}, - {PG_WIN1251, "CP1251"}, - {PG_WIN1251, "ansi-1251"}, - {PG_WIN1252, "CP1252"}, - {PG_WIN1253, "CP1253"}, - {PG_WIN1254, "CP1254"}, - {PG_WIN1255, "CP1255"}, - {PG_WIN1256, "CP1256"}, - {PG_WIN1257, "CP1257"}, - {PG_WIN1258, "CP1258"}, - - {PG_ISO_8859_5, "ISO-8859-5"}, - {PG_ISO_8859_5, "ISO8859-5"}, - {PG_ISO_8859_5, "iso88595"}, - {PG_ISO_8859_5, "CP28595"}, - - {PG_ISO_8859_6, "ISO-8859-6"}, - {PG_ISO_8859_6, "ISO8859-6"}, - {PG_ISO_8859_6, "iso88596"}, - {PG_ISO_8859_6, "CP28596"}, - - {PG_ISO_8859_7, "ISO-8859-7"}, - {PG_ISO_8859_7, "ISO8859-7"}, - {PG_ISO_8859_7, "iso88597"}, - {PG_ISO_8859_7, "CP28597"}, - - {PG_ISO_8859_8, "ISO-8859-8"}, - {PG_ISO_8859_8, "ISO8859-8"}, - {PG_ISO_8859_8, "iso88598"}, - {PG_ISO_8859_8, "CP28598"}, - - {PG_SJIS, "SJIS"}, - {PG_SJIS, "PCK"}, - {PG_SJIS, "CP932"}, - {PG_SJIS, "SHIFT_JIS"}, - - {PG_BIG5, "BIG5"}, - {PG_BIG5, "BIG5HKSCS"}, - {PG_BIG5, "Big5-HKSCS"}, - {PG_BIG5, "CP950"}, - - {PG_GBK, "GBK"}, - {PG_GBK, "CP936"}, - - {PG_UHC, "UHC"}, - {PG_UHC, "CP949"}, - - {PG_JOHAB, "JOHAB"}, - {PG_JOHAB, "CP1361"}, - - {PG_GB18030, "GB18030"}, - {PG_GB18030, "CP54936"}, - - {PG_SHIFT_JIS_2004, "SJIS_2004"}, - - {PG_SQL_ASCII, "US-ASCII"}, - - {PG_SQL_ASCII, NULL} /* end marker */ -}; - -#ifdef WIN32 -/* - * On Windows, use CP instead of the nl_langinfo() result - * - * Visual Studio 2012 expanded the set of valid LC_CTYPE values, so have its - * locale machinery determine the code page. See comments at IsoLocaleName(). - * For other compilers, follow the locale's predictable format. - * - * Visual Studio 2015 should still be able to do the same, but the declaration - * of lc_codepage is missing in _locale_t, causing this code compilation to - * fail, hence this falls back instead on GetLocaleInfoEx. VS 2015 may be an - * exception and post-VS2015 versions should be able to handle properly the - * codepage number using _create_locale(). So, instead of the same logic as - * VS 2012 and VS 2013, this routine uses GetLocaleInfoEx to parse short - * locale names like "de-DE", "fr-FR", etc. If those cannot be parsed correctly - * process falls back to the pre-VS-2010 manual parsing done with - * using _. as a base. - * - * Returns a malloc()'d string for the caller to free. - */ -static char * -win32_langinfo(const char *ctype) -{ - char *r = NULL; - -#if (_MSC_VER >= 1700) && (_MSC_VER < 1900) - _locale_t loct = NULL; - - loct = _create_locale(LC_CTYPE, ctype); - if (loct != NULL) - { - r = malloc(16); /* excess */ - if (r != NULL) - sprintf(r, "CP%u", loct->locinfo->lc_codepage); - _free_locale(loct); - } -#else - char *codepage; - -#if (_MSC_VER >= 1900) - uint32 cp; - WCHAR wctype[LOCALE_NAME_MAX_LENGTH]; - - memset(wctype, 0, sizeof(wctype)); - MultiByteToWideChar(CP_ACP, 0, ctype, -1, wctype, LOCALE_NAME_MAX_LENGTH); - - if (GetLocaleInfoEx(wctype, - LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, - (LPWSTR) &cp, sizeof(cp) / sizeof(WCHAR)) > 0) - { - r = malloc(16); /* excess */ - if (r != NULL) - sprintf(r, "CP%u", cp); - } - else -#endif - { - /* - * Locale format on Win32 is _. . For - * example, English_United States.1252. - */ - codepage = strrchr(ctype, '.'); - if (codepage != NULL) - { - int ln; - - codepage++; - ln = strlen(codepage); - r = malloc(ln + 3); - if (r != NULL) - sprintf(r, "CP%s", codepage); - } - - } -#endif - - return r; -} - -#ifndef FRONTEND -/* - * Given a Windows code page identifier, find the corresponding PostgreSQL - * encoding. Issue a warning and return -1 if none found. - */ -int -pg_codepage_to_encoding(UINT cp) -{ - char sys[16]; - int i; - - sprintf(sys, "CP%u", cp); - - /* Check the table */ - for (i = 0; encoding_match_list[i].system_enc_name; i++) - if (pg_strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0) - return encoding_match_list[i].pg_enc_code; - - ereport(WARNING, - (errmsg("could not determine encoding for codeset \"%s\"", sys), - errdetail("Please report this to ."))); - - return -1; -} -#endif -#endif /* WIN32 */ - -#if (defined(HAVE_LANGINFO_H) && defined(CODESET)) || defined(WIN32) - -/* - * Given a setting for LC_CTYPE, return the Postgres ID of the associated - * encoding, if we can determine it. Return -1 if we can't determine it. - * - * Pass in NULL to get the encoding for the current locale setting. - * Pass "" to get the encoding selected by the server's environment. - * - * If the result is PG_SQL_ASCII, callers should treat it as being compatible - * with any desired encoding. - * - * If running in the backend and write_message is false, this function must - * cope with the possibility that elog() and palloc() are not yet usable. - */ -int -pg_get_encoding_from_locale(const char *ctype, bool write_message) -{ - char *sys; - int i; - - /* Get the CODESET property, and also LC_CTYPE if not passed in */ - if (ctype) - { - char *save; - char *name; - - /* If locale is C or POSIX, we can allow all encodings */ - if (pg_strcasecmp(ctype, "C") == 0 || - pg_strcasecmp(ctype, "POSIX") == 0) - return PG_SQL_ASCII; - - save = setlocale(LC_CTYPE, NULL); - if (!save) - return -1; /* setlocale() broken? */ - /* must copy result, or it might change after setlocale */ - save = strdup(save); - if (!save) - return -1; /* out of memory; unlikely */ - - name = setlocale(LC_CTYPE, ctype); - if (!name) - { - free(save); - return -1; /* bogus ctype passed in? */ - } - -#ifndef WIN32 - sys = nl_langinfo(CODESET); - if (sys) - sys = strdup(sys); -#else - sys = win32_langinfo(name); -#endif - - setlocale(LC_CTYPE, save); - free(save); - } - else - { - /* much easier... */ - ctype = setlocale(LC_CTYPE, NULL); - if (!ctype) - return -1; /* setlocale() broken? */ - - /* If locale is C or POSIX, we can allow all encodings */ - if (pg_strcasecmp(ctype, "C") == 0 || - pg_strcasecmp(ctype, "POSIX") == 0) - return PG_SQL_ASCII; - -#ifndef WIN32 - sys = nl_langinfo(CODESET); - if (sys) - sys = strdup(sys); -#else - sys = win32_langinfo(ctype); -#endif - } - - if (!sys) - return -1; /* out of memory; unlikely */ - - /* Check the table */ - for (i = 0; encoding_match_list[i].system_enc_name; i++) - { - if (pg_strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0) - { - free(sys); - return encoding_match_list[i].pg_enc_code; - } - } - - /* Special-case kluges for particular platforms go here */ - -#ifdef __darwin__ - - /* - * Current OS X has many locales that report an empty string for CODESET, - * but they all seem to actually use UTF-8. - */ - if (strlen(sys) == 0) - { - free(sys); - return PG_UTF8; - } -#endif - - /* - * We print a warning if we got a CODESET string but couldn't recognize - * it. This means we need another entry in the table. - */ - if (write_message) - { -#ifdef FRONTEND - fprintf(stderr, _("could not determine encoding for locale \"%s\": codeset is \"%s\""), - ctype, sys); - /* keep newline separate so there's only one translatable string */ - fputc('\n', stderr); -#else - ereport(WARNING, - (errmsg("could not determine encoding for locale \"%s\": codeset is \"%s\"", - ctype, sys), - errdetail("Please report this to ."))); -#endif - } - - free(sys); - return -1; -} -#else /* (HAVE_LANGINFO_H && CODESET) || WIN32 */ - -/* - * stub if no multi-language platform support - * - * Note: we could return -1 here, but that would have the effect of - * forcing users to specify an encoding to initdb on such platforms. - * It seems better to silently default to SQL_ASCII. - */ -int -pg_get_encoding_from_locale(const char *ctype, bool write_message) -{ - return PG_SQL_ASCII; -} - -#endif /* (HAVE_LANGINFO_H && CODESET) || WIN32 */ diff --git a/libpq/encnames.c b/libpq/encnames.c deleted file mode 100644 index 11099b8..0000000 --- a/libpq/encnames.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * Encoding names and routines for work with it. All - * in this file is shared between FE and BE. - * - * src/backend/utils/mb/encnames.c - */ -#ifdef FRONTEND -#include "postgres_fe.h" -#else -#include "postgres.h" -#include "utils/builtins.h" -#endif - -#include -#include - -#include "mb/pg_wchar.h" - - -/* ---------- - * All encoding names, sorted: *** A L P H A B E T I C *** - * - * All names must be without irrelevant chars, search routines use - * isalnum() chars only. It means ISO-8859-1, iso_8859-1 and Iso8859_1 - * are always converted to 'iso88591'. All must be lower case. - * - * The table doesn't contain 'cs' aliases (like csISOLatin1). It's needed? - * - * Karel Zak, Aug 2001 - * ---------- - */ -typedef struct pg_encname -{ - const char *name; - pg_enc encoding; -} pg_encname; - -static const pg_encname pg_encname_tbl[] = -{ - { - "abc", PG_WIN1258 - }, /* alias for WIN1258 */ - { - "alt", PG_WIN866 - }, /* IBM866 */ - { - "big5", PG_BIG5 - }, /* Big5; Chinese for Taiwan multibyte set */ - { - "euccn", PG_EUC_CN - }, /* EUC-CN; Extended Unix Code for simplified - * Chinese */ - { - "eucjis2004", PG_EUC_JIS_2004 - }, /* EUC-JIS-2004; Extended UNIX Code fixed - * Width for Japanese, standard JIS X 0213 */ - { - "eucjp", PG_EUC_JP - }, /* EUC-JP; Extended UNIX Code fixed Width for - * Japanese, standard OSF */ - { - "euckr", PG_EUC_KR - }, /* EUC-KR; Extended Unix Code for Korean , KS - * X 1001 standard */ - { - "euctw", PG_EUC_TW - }, /* EUC-TW; Extended Unix Code for - * - * traditional Chinese */ - { - "gb18030", PG_GB18030 - }, /* GB18030;GB18030 */ - { - "gbk", PG_GBK - }, /* GBK; Chinese Windows CodePage 936 - * simplified Chinese */ - { - "iso88591", PG_LATIN1 - }, /* ISO-8859-1; RFC1345,KXS2 */ - { - "iso885910", PG_LATIN6 - }, /* ISO-8859-10; RFC1345,KXS2 */ - { - "iso885913", PG_LATIN7 - }, /* ISO-8859-13; RFC1345,KXS2 */ - { - "iso885914", PG_LATIN8 - }, /* ISO-8859-14; RFC1345,KXS2 */ - { - "iso885915", PG_LATIN9 - }, /* ISO-8859-15; RFC1345,KXS2 */ - { - "iso885916", PG_LATIN10 - }, /* ISO-8859-16; RFC1345,KXS2 */ - { - "iso88592", PG_LATIN2 - }, /* ISO-8859-2; RFC1345,KXS2 */ - { - "iso88593", PG_LATIN3 - }, /* ISO-8859-3; RFC1345,KXS2 */ - { - "iso88594", PG_LATIN4 - }, /* ISO-8859-4; RFC1345,KXS2 */ - { - "iso88595", PG_ISO_8859_5 - }, /* ISO-8859-5; RFC1345,KXS2 */ - { - "iso88596", PG_ISO_8859_6 - }, /* ISO-8859-6; RFC1345,KXS2 */ - { - "iso88597", PG_ISO_8859_7 - }, /* ISO-8859-7; RFC1345,KXS2 */ - { - "iso88598", PG_ISO_8859_8 - }, /* ISO-8859-8; RFC1345,KXS2 */ - { - "iso88599", PG_LATIN5 - }, /* ISO-8859-9; RFC1345,KXS2 */ - { - "johab", PG_JOHAB - }, /* JOHAB; Extended Unix Code for simplified - * Chinese */ - { - "koi8", PG_KOI8R - }, /* _dirty_ alias for KOI8-R (backward - * compatibility) */ - { - "koi8r", PG_KOI8R - }, /* KOI8-R; RFC1489 */ - { - "koi8u", PG_KOI8U - }, /* KOI8-U; RFC2319 */ - { - "latin1", PG_LATIN1 - }, /* alias for ISO-8859-1 */ - { - "latin10", PG_LATIN10 - }, /* alias for ISO-8859-16 */ - { - "latin2", PG_LATIN2 - }, /* alias for ISO-8859-2 */ - { - "latin3", PG_LATIN3 - }, /* alias for ISO-8859-3 */ - { - "latin4", PG_LATIN4 - }, /* alias for ISO-8859-4 */ - { - "latin5", PG_LATIN5 - }, /* alias for ISO-8859-9 */ - { - "latin6", PG_LATIN6 - }, /* alias for ISO-8859-10 */ - { - "latin7", PG_LATIN7 - }, /* alias for ISO-8859-13 */ - { - "latin8", PG_LATIN8 - }, /* alias for ISO-8859-14 */ - { - "latin9", PG_LATIN9 - }, /* alias for ISO-8859-15 */ - { - "mskanji", PG_SJIS - }, /* alias for Shift_JIS */ - { - "muleinternal", PG_MULE_INTERNAL - }, - { - "shiftjis", PG_SJIS - }, /* Shift_JIS; JIS X 0202-1991 */ - - { - "shiftjis2004", PG_SHIFT_JIS_2004 - }, /* SHIFT-JIS-2004; Shift JIS for Japanese, - * standard JIS X 0213 */ - { - "sjis", PG_SJIS - }, /* alias for Shift_JIS */ - { - "sqlascii", PG_SQL_ASCII - }, - { - "tcvn", PG_WIN1258 - }, /* alias for WIN1258 */ - { - "tcvn5712", PG_WIN1258 - }, /* alias for WIN1258 */ - { - "uhc", PG_UHC - }, /* UHC; Korean Windows CodePage 949 */ - { - "unicode", PG_UTF8 - }, /* alias for UTF8 */ - { - "utf8", PG_UTF8 - }, /* alias for UTF8 */ - { - "vscii", PG_WIN1258 - }, /* alias for WIN1258 */ - { - "win", PG_WIN1251 - }, /* _dirty_ alias for windows-1251 (backward - * compatibility) */ - { - "win1250", PG_WIN1250 - }, /* alias for Windows-1250 */ - { - "win1251", PG_WIN1251 - }, /* alias for Windows-1251 */ - { - "win1252", PG_WIN1252 - }, /* alias for Windows-1252 */ - { - "win1253", PG_WIN1253 - }, /* alias for Windows-1253 */ - { - "win1254", PG_WIN1254 - }, /* alias for Windows-1254 */ - { - "win1255", PG_WIN1255 - }, /* alias for Windows-1255 */ - { - "win1256", PG_WIN1256 - }, /* alias for Windows-1256 */ - { - "win1257", PG_WIN1257 - }, /* alias for Windows-1257 */ - { - "win1258", PG_WIN1258 - }, /* alias for Windows-1258 */ - { - "win866", PG_WIN866 - }, /* IBM866 */ - { - "win874", PG_WIN874 - }, /* alias for Windows-874 */ - { - "win932", PG_SJIS - }, /* alias for Shift_JIS */ - { - "win936", PG_GBK - }, /* alias for GBK */ - { - "win949", PG_UHC - }, /* alias for UHC */ - { - "win950", PG_BIG5 - }, /* alias for BIG5 */ - { - "windows1250", PG_WIN1250 - }, /* Windows-1251; Microsoft */ - { - "windows1251", PG_WIN1251 - }, /* Windows-1251; Microsoft */ - { - "windows1252", PG_WIN1252 - }, /* Windows-1252; Microsoft */ - { - "windows1253", PG_WIN1253 - }, /* Windows-1253; Microsoft */ - { - "windows1254", PG_WIN1254 - }, /* Windows-1254; Microsoft */ - { - "windows1255", PG_WIN1255 - }, /* Windows-1255; Microsoft */ - { - "windows1256", PG_WIN1256 - }, /* Windows-1256; Microsoft */ - { - "windows1257", PG_WIN1257 - }, /* Windows-1257; Microsoft */ - { - "windows1258", PG_WIN1258 - }, /* Windows-1258; Microsoft */ - { - "windows866", PG_WIN866 - }, /* IBM866 */ - { - "windows874", PG_WIN874 - }, /* Windows-874; Microsoft */ - { - "windows932", PG_SJIS - }, /* alias for Shift_JIS */ - { - "windows936", PG_GBK - }, /* alias for GBK */ - { - "windows949", PG_UHC - }, /* alias for UHC */ - { - "windows950", PG_BIG5 - } /* alias for BIG5 */ -}; - -/* ---------- - * These are "official" encoding names. - * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) - * ---------- - */ -#ifndef WIN32 -#define DEF_ENC2NAME(name, codepage) { #name, PG_##name } -#else -#define DEF_ENC2NAME(name, codepage) { #name, PG_##name, codepage } -#endif -const pg_enc2name pg_enc2name_tbl[] = -{ - DEF_ENC2NAME(SQL_ASCII, 0), - DEF_ENC2NAME(EUC_JP, 20932), - DEF_ENC2NAME(EUC_CN, 20936), - DEF_ENC2NAME(EUC_KR, 51949), - DEF_ENC2NAME(EUC_TW, 0), - DEF_ENC2NAME(EUC_JIS_2004, 20932), - DEF_ENC2NAME(UTF8, 65001), - DEF_ENC2NAME(MULE_INTERNAL, 0), - DEF_ENC2NAME(LATIN1, 28591), - DEF_ENC2NAME(LATIN2, 28592), - DEF_ENC2NAME(LATIN3, 28593), - DEF_ENC2NAME(LATIN4, 28594), - DEF_ENC2NAME(LATIN5, 28599), - DEF_ENC2NAME(LATIN6, 0), - DEF_ENC2NAME(LATIN7, 0), - DEF_ENC2NAME(LATIN8, 0), - DEF_ENC2NAME(LATIN9, 28605), - DEF_ENC2NAME(LATIN10, 0), - DEF_ENC2NAME(WIN1256, 1256), - DEF_ENC2NAME(WIN1258, 1258), - DEF_ENC2NAME(WIN866, 866), - DEF_ENC2NAME(WIN874, 874), - DEF_ENC2NAME(KOI8R, 20866), - DEF_ENC2NAME(WIN1251, 1251), - DEF_ENC2NAME(WIN1252, 1252), - DEF_ENC2NAME(ISO_8859_5, 28595), - DEF_ENC2NAME(ISO_8859_6, 28596), - DEF_ENC2NAME(ISO_8859_7, 28597), - DEF_ENC2NAME(ISO_8859_8, 28598), - DEF_ENC2NAME(WIN1250, 1250), - DEF_ENC2NAME(WIN1253, 1253), - DEF_ENC2NAME(WIN1254, 1254), - DEF_ENC2NAME(WIN1255, 1255), - DEF_ENC2NAME(WIN1257, 1257), - DEF_ENC2NAME(KOI8U, 21866), - DEF_ENC2NAME(SJIS, 932), - DEF_ENC2NAME(BIG5, 950), - DEF_ENC2NAME(GBK, 936), - DEF_ENC2NAME(UHC, 949), - DEF_ENC2NAME(GB18030, 54936), - DEF_ENC2NAME(JOHAB, 0), - DEF_ENC2NAME(SHIFT_JIS_2004, 932) -}; - -/* ---------- - * These are encoding names for gettext. - * - * This covers all encodings except MULE_INTERNAL, which is alien to gettext. - * ---------- - */ -const pg_enc2gettext pg_enc2gettext_tbl[] = -{ - {PG_SQL_ASCII, "US-ASCII"}, - {PG_UTF8, "UTF-8"}, - {PG_LATIN1, "LATIN1"}, - {PG_LATIN2, "LATIN2"}, - {PG_LATIN3, "LATIN3"}, - {PG_LATIN4, "LATIN4"}, - {PG_ISO_8859_5, "ISO-8859-5"}, - {PG_ISO_8859_6, "ISO_8859-6"}, - {PG_ISO_8859_7, "ISO-8859-7"}, - {PG_ISO_8859_8, "ISO-8859-8"}, - {PG_LATIN5, "LATIN5"}, - {PG_LATIN6, "LATIN6"}, - {PG_LATIN7, "LATIN7"}, - {PG_LATIN8, "LATIN8"}, - {PG_LATIN9, "LATIN-9"}, - {PG_LATIN10, "LATIN10"}, - {PG_KOI8R, "KOI8-R"}, - {PG_KOI8U, "KOI8-U"}, - {PG_WIN1250, "CP1250"}, - {PG_WIN1251, "CP1251"}, - {PG_WIN1252, "CP1252"}, - {PG_WIN1253, "CP1253"}, - {PG_WIN1254, "CP1254"}, - {PG_WIN1255, "CP1255"}, - {PG_WIN1256, "CP1256"}, - {PG_WIN1257, "CP1257"}, - {PG_WIN1258, "CP1258"}, - {PG_WIN866, "CP866"}, - {PG_WIN874, "CP874"}, - {PG_EUC_CN, "EUC-CN"}, - {PG_EUC_JP, "EUC-JP"}, - {PG_EUC_KR, "EUC-KR"}, - {PG_EUC_TW, "EUC-TW"}, - {PG_EUC_JIS_2004, "EUC-JP"}, - {PG_SJIS, "SHIFT-JIS"}, - {PG_BIG5, "BIG5"}, - {PG_GBK, "GBK"}, - {PG_UHC, "UHC"}, - {PG_GB18030, "GB18030"}, - {PG_JOHAB, "JOHAB"}, - {PG_SHIFT_JIS_2004, "SHIFT_JISX0213"}, - {0, NULL} -}; - - -/* ---------- - * Encoding checks, for error returns -1 else encoding id - * ---------- - */ -int -pg_valid_client_encoding(const char *name) -{ - int enc; - - if ((enc = pg_char_to_encoding(name)) < 0) - return -1; - - if (!PG_VALID_FE_ENCODING(enc)) - return -1; - - return enc; -} - -int -pg_valid_server_encoding(const char *name) -{ - int enc; - - if ((enc = pg_char_to_encoding(name)) < 0) - return -1; - - if (!PG_VALID_BE_ENCODING(enc)) - return -1; - - return enc; -} - -int -pg_valid_server_encoding_id(int encoding) -{ - return PG_VALID_BE_ENCODING(encoding); -} - -/* ---------- - * Remove irrelevant chars from encoding name - * ---------- - */ -static char * -clean_encoding_name(const char *key, char *newkey) -{ - const char *p; - char *np; - - for (p = key, np = newkey; *p != '\0'; p++) - { - if (isalnum((unsigned char) *p)) - { - if (*p >= 'A' && *p <= 'Z') - *np++ = *p + 'a' - 'A'; - else - *np++ = *p; - } - } - *np = '\0'; - return newkey; -} - -/* ---------- - * Search encoding by encoding name - * - * Returns encoding ID, or -1 for error - * ---------- - */ -int -pg_char_to_encoding(const char *name) -{ - unsigned int nel = lengthof(pg_encname_tbl); - const pg_encname *base = pg_encname_tbl, - *last = base + nel - 1, - *position; - int result; - char buff[NAMEDATALEN], - *key; - - if (name == NULL || *name == '\0') - return -1; - - if (strlen(name) >= NAMEDATALEN) - { -#ifdef FRONTEND - fprintf(stderr, "encoding name too long\n"); - return -1; -#else - ereport(ERROR, - (errcode(ERRCODE_NAME_TOO_LONG), - errmsg("encoding name too long"))); -#endif - } - key = clean_encoding_name(name, buff); - - while (last >= base) - { - position = base + ((last - base) >> 1); - result = key[0] - position->name[0]; - - if (result == 0) - { - result = strcmp(key, position->name); - if (result == 0) - return position->encoding; - } - if (result < 0) - last = position - 1; - else - base = position + 1; - } - return -1; -} - -#ifndef FRONTEND -Datum -PG_char_to_encoding(PG_FUNCTION_ARGS) -{ - Name s = PG_GETARG_NAME(0); - - PG_RETURN_INT32(pg_char_to_encoding(NameStr(*s))); -} -#endif - -const char * -pg_encoding_to_char(int encoding) -{ - if (PG_VALID_ENCODING(encoding)) - { - const pg_enc2name *p = &pg_enc2name_tbl[encoding]; - - Assert(encoding == p->encoding); - return p->name; - } - return ""; -} - -#ifndef FRONTEND -Datum -PG_encoding_to_char(PG_FUNCTION_ARGS) -{ - int32 encoding = PG_GETARG_INT32(0); - const char *encoding_name = pg_encoding_to_char(encoding); - - return DirectFunctionCall1(namein, CStringGetDatum(encoding_name)); -} - -#endif diff --git a/libpq/fe-auth.c b/libpq/fe-auth.c deleted file mode 100644 index ab057e9..0000000 --- a/libpq/fe-auth.c +++ /dev/null @@ -1,841 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-auth.c - * The front-end (client) authorization routines - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * src/interfaces/libpq/fe-auth.c - * - *------------------------------------------------------------------------- - */ - -/* - * INTERFACE ROUTINES - * frontend (client) routines: - * pg_fe_sendauth send authentication information - * pg_fe_getauthname get user's name according to the client side - * of the authentication system - */ - -#include "postgres_fe.h" - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#include /* for MAXHOSTNAMELEN on most */ -#include -#ifdef HAVE_SYS_UCRED_H -#include -#endif -#ifndef MAXHOSTNAMELEN -#include /* for MAXHOSTNAMELEN on some */ -#endif -#include -#endif - -#include "libpq-fe.h" -#include "fe-auth.h" -#include "libpq/md5.h" - - -#ifdef ENABLE_GSS -/* - * GSSAPI authentication system. - */ - -#if defined(WIN32) && !defined(WIN32_ONLY_COMPILER) -/* - * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW - * that contain the OIDs required. Redefine here, values copied - * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c - */ -static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc = -{10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"}; -static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc; -#endif - -/* - * Fetch all errors of a specific type and append to "str". - */ -static void -pg_GSS_error_int(PQExpBuffer str, const char *mprefix, - OM_uint32 stat, int type) -{ - OM_uint32 lmin_s; - gss_buffer_desc lmsg; - OM_uint32 msg_ctx = 0; - - do - { - gss_display_status(&lmin_s, stat, type, - GSS_C_NO_OID, &msg_ctx, &lmsg); - appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value); - gss_release_buffer(&lmin_s, &lmsg); - } while (msg_ctx); -} - -/* - * GSSAPI errors contain two parts; put both into conn->errorMessage. - */ -static void -pg_GSS_error(const char *mprefix, PGconn *conn, - OM_uint32 maj_stat, OM_uint32 min_stat) -{ - resetPQExpBuffer(&conn->errorMessage); - - /* Fetch major error codes */ - pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE); - - /* Add the minor codes as well */ - pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE); -} - -/* - * Continue GSS authentication with next token as needed. - */ -static int -pg_GSS_continue(PGconn *conn) -{ - OM_uint32 maj_stat, - min_stat, - lmin_s; - - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &conn->gctx, - conn->gtarg_nam, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - (conn->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &conn->ginbuf, - NULL, - &conn->goutbuf, - NULL, - NULL); - - if (conn->gctx != GSS_C_NO_CONTEXT) - { - free(conn->ginbuf.value); - conn->ginbuf.value = NULL; - conn->ginbuf.length = 0; - } - - if (conn->goutbuf.length != 0) - { - /* - * GSS generated data to send to the server. We don't care if it's the - * first or subsequent packet, just send the same kind of password - * packet. - */ - if (pqPacketSend(conn, 'p', - conn->goutbuf.value, conn->goutbuf.length) - != STATUS_OK) - { - gss_release_buffer(&lmin_s, &conn->goutbuf); - return STATUS_ERROR; - } - } - gss_release_buffer(&lmin_s, &conn->goutbuf); - - if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) - { - pg_GSS_error(libpq_gettext("GSSAPI continuation error"), - conn, - maj_stat, min_stat); - gss_release_name(&lmin_s, &conn->gtarg_nam); - if (conn->gctx) - gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER); - return STATUS_ERROR; - } - - if (maj_stat == GSS_S_COMPLETE) - gss_release_name(&lmin_s, &conn->gtarg_nam); - - return STATUS_OK; -} - -/* - * Send initial GSS authentication token - */ -static int -pg_GSS_startup(PGconn *conn) -{ - OM_uint32 maj_stat, - min_stat; - int maxlen; - gss_buffer_desc temp_gbuf; - - if (!(conn->pghost && conn->pghost[0] != '\0')) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); - return STATUS_ERROR; - } - - if (conn->gctx) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate GSS authentication request\n")); - return STATUS_ERROR; - } - - /* - * Import service principal name so the proper ticket can be acquired by - * the GSSAPI system. - */ - maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2; - temp_gbuf.value = (char *) malloc(maxlen); - if (!temp_gbuf.value) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return STATUS_ERROR; - } - snprintf(temp_gbuf.value, maxlen, "%s@%s", - conn->krbsrvname, conn->pghost); - temp_gbuf.length = strlen(temp_gbuf.value); - - maj_stat = gss_import_name(&min_stat, &temp_gbuf, - GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam); - free(temp_gbuf.value); - - if (maj_stat != GSS_S_COMPLETE) - { - pg_GSS_error(libpq_gettext("GSSAPI name import error"), - conn, - maj_stat, min_stat); - return STATUS_ERROR; - } - - /* - * Initial packet is the same as a continuation packet with no initial - * context. - */ - conn->gctx = GSS_C_NO_CONTEXT; - - return pg_GSS_continue(conn); -} -#endif /* ENABLE_GSS */ - - -#ifdef ENABLE_SSPI -/* - * SSPI authentication system (Windows only) - */ - -static void -pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r) -{ - char sysmsg[256]; - - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, r, 0, - sysmsg, sizeof(sysmsg), NULL) == 0) - printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n", - mprefix, (unsigned int) r); - else - printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n", - mprefix, sysmsg, (unsigned int) r); -} - -/* - * Continue SSPI authentication with next token as needed. - */ -static int -pg_SSPI_continue(PGconn *conn) -{ - SECURITY_STATUS r; - CtxtHandle newContext; - ULONG contextAttr; - SecBufferDesc inbuf; - SecBufferDesc outbuf; - SecBuffer OutBuffers[1]; - SecBuffer InBuffers[1]; - - if (conn->sspictx != NULL) - { - /* - * On runs other than the first we have some data to send. Put this - * data in a SecBuffer type structure. - */ - inbuf.ulVersion = SECBUFFER_VERSION; - inbuf.cBuffers = 1; - inbuf.pBuffers = InBuffers; - InBuffers[0].pvBuffer = conn->ginbuf.value; - InBuffers[0].cbBuffer = conn->ginbuf.length; - InBuffers[0].BufferType = SECBUFFER_TOKEN; - } - - OutBuffers[0].pvBuffer = NULL; - OutBuffers[0].BufferType = SECBUFFER_TOKEN; - OutBuffers[0].cbBuffer = 0; - outbuf.cBuffers = 1; - outbuf.pBuffers = OutBuffers; - outbuf.ulVersion = SECBUFFER_VERSION; - - r = InitializeSecurityContext(conn->sspicred, - conn->sspictx, - conn->sspitarget, - ISC_REQ_ALLOCATE_MEMORY, - 0, - SECURITY_NETWORK_DREP, - (conn->sspictx == NULL) ? NULL : &inbuf, - 0, - &newContext, - &outbuf, - &contextAttr, - NULL); - - if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED) - { - pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r); - - return STATUS_ERROR; - } - - if (conn->sspictx == NULL) - { - /* On first run, transfer retrieved context handle */ - conn->sspictx = malloc(sizeof(CtxtHandle)); - if (conn->sspictx == NULL) - { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); - return STATUS_ERROR; - } - memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); - } - else - { - /* - * On subsequent runs when we had data to send, free buffers that - * contained this data. - */ - free(conn->ginbuf.value); - conn->ginbuf.value = NULL; - conn->ginbuf.length = 0; - } - - /* - * If SSPI returned any data to be sent to the server (as it normally - * would), send this data as a password packet. - */ - if (outbuf.cBuffers > 0) - { - if (outbuf.cBuffers != 1) - { - /* - * This should never happen, at least not for Kerberos - * authentication. Keep check in case it shows up with other - * authentication methods later. - */ - printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n"); - return STATUS_ERROR; - } - - /* - * If the negotiation is complete, there may be zero bytes to send. - * The server is at this point not expecting any more data, so don't - * send it. - */ - if (outbuf.pBuffers[0].cbBuffer > 0) - { - if (pqPacketSend(conn, 'p', - outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer)) - { - FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); - return STATUS_ERROR; - } - } - FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); - } - - /* Cleanup is handled by the code in freePGconn() */ - return STATUS_OK; -} - -/* - * Send initial SSPI authentication token. - * If use_negotiate is 0, use kerberos authentication package which is - * compatible with Unix. If use_negotiate is 1, use the negotiate package - * which supports both kerberos and NTLM, but is not compatible with Unix. - */ -static int -pg_SSPI_startup(PGconn *conn, int use_negotiate) -{ - SECURITY_STATUS r; - TimeStamp expire; - - if (conn->sspictx) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("duplicate SSPI authentication request\n")); - return STATUS_ERROR; - } - - /* - * Retrieve credentials handle - */ - conn->sspicred = malloc(sizeof(CredHandle)); - if (conn->sspicred == NULL) - { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); - return STATUS_ERROR; - } - - r = AcquireCredentialsHandle(NULL, - use_negotiate ? "negotiate" : "kerberos", - SECPKG_CRED_OUTBOUND, - NULL, - NULL, - NULL, - NULL, - conn->sspicred, - &expire); - if (r != SEC_E_OK) - { - pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r); - free(conn->sspicred); - conn->sspicred = NULL; - return STATUS_ERROR; - } - - /* - * Compute target principal name. SSPI has a different format from GSSAPI, - * but not more complex. We can skip the @REALM part, because Windows will - * fill that in for us automatically. - */ - if (!(conn->pghost && conn->pghost[0] != '\0')) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("host name must be specified\n")); - return STATUS_ERROR; - } - conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(conn->pghost) + 2); - if (!conn->sspitarget) - { - printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); - return STATUS_ERROR; - } - sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, conn->pghost); - - /* - * Indicate that we're in SSPI authentication mode to make sure that - * pg_SSPI_continue is called next time in the negotiation. - */ - conn->usesspi = 1; - - return pg_SSPI_continue(conn); -} -#endif /* ENABLE_SSPI */ - -/* - * Respond to AUTH_REQ_SCM_CREDS challenge. - * - * Note: this is dead code as of Postgres 9.1, because current backends will - * never send this challenge. But we must keep it as long as libpq needs to - * interoperate with pre-9.1 servers. It is believed to be needed only on - * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the - * getpeereid() function isn't provided by libc). - */ -static int -pg_local_sendauth(PGconn *conn) -{ -#ifdef HAVE_STRUCT_CMSGCRED - char buf; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - union - { - struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))]; - } cmsgbuf; - - /* - * The backend doesn't care what we send here, but it wants exactly one - * character to force recvmsg() to block and wait for us. - */ - buf = '\0'; - iov.iov_base = &buf; - iov.iov_len = 1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - /* We must set up a message that will be filled in by kernel */ - memset(&cmsgbuf, 0, sizeof(cmsgbuf)); - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDS; - - if (sendmsg(conn->sock, &msg, 0) == -1) - { - char sebuf[256]; - - printfPQExpBuffer(&conn->errorMessage, - "pg_local_sendauth: sendmsg: %s\n", - pqStrerror(errno, sebuf, sizeof(sebuf))); - return STATUS_ERROR; - } - return STATUS_OK; -#else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SCM_CRED authentication method not supported\n")); - return STATUS_ERROR; -#endif -} - -static int -pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) -{ - int ret; - char *crypt_pwd = NULL; - const char *pwd_to_send; - - /* Encrypt the password if needed. */ - - switch (areq) - { - case AUTH_REQ_MD5: - { - char *crypt_pwd2; - - /* Allocate enough space for two MD5 hashes */ - crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); - if (!crypt_pwd) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return STATUS_ERROR; - } - - crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1; - if (!pg_md5_encrypt(password, conn->pguser, - strlen(conn->pguser), crypt_pwd2)) - { - free(crypt_pwd); - return STATUS_ERROR; - } - if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt, - sizeof(conn->md5Salt), crypt_pwd)) - { - free(crypt_pwd); - return STATUS_ERROR; - } - - pwd_to_send = crypt_pwd; - break; - } - case AUTH_REQ_PASSWORD: - pwd_to_send = password; - break; - default: - return STATUS_ERROR; - } - /* Packet has a message type as of protocol 3.0 */ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1); - else - ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1); - if (crypt_pwd) - free(crypt_pwd); - return ret; -} - -/* - * pg_fe_sendauth - * client demux routine for outgoing authentication information - */ -int -pg_fe_sendauth(AuthRequest areq, PGconn *conn) -{ - switch (areq) - { - case AUTH_REQ_OK: - break; - - case AUTH_REQ_KRB4: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 4 authentication not supported\n")); - return STATUS_ERROR; - - case AUTH_REQ_KRB5: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Kerberos 5 authentication not supported\n")); - return STATUS_ERROR; - -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - case AUTH_REQ_GSS: -#if !defined(ENABLE_SSPI) - /* no native SSPI, so use GSSAPI library for it */ - case AUTH_REQ_SSPI: -#endif - { - int r; - - pglock_thread(); - - /* - * If we have both GSS and SSPI support compiled in, use SSPI - * support by default. This is overridable by a connection - * string parameter. Note that when using SSPI we still leave - * the negotiate parameter off, since we want SSPI to use the - * GSSAPI kerberos protocol. For actual SSPI negotiate - * protocol, we use AUTH_REQ_SSPI. - */ -#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) - if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0)) - r = pg_GSS_startup(conn); - else - r = pg_SSPI_startup(conn, 0); -#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) - r = pg_GSS_startup(conn); -#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) - r = pg_SSPI_startup(conn, 0); -#endif - if (r != STATUS_OK) - { - /* Error message already filled in. */ - pgunlock_thread(); - return STATUS_ERROR; - } - pgunlock_thread(); - } - break; - - case AUTH_REQ_GSS_CONT: - { - int r; - - pglock_thread(); -#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) - if (conn->usesspi) - r = pg_SSPI_continue(conn); - else - r = pg_GSS_continue(conn); -#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) - r = pg_GSS_continue(conn); -#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) - r = pg_SSPI_continue(conn); -#endif - if (r != STATUS_OK) - { - /* Error message already filled in. */ - pgunlock_thread(); - return STATUS_ERROR; - } - pgunlock_thread(); - } - break; -#else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ - /* No GSSAPI *or* SSPI support */ - case AUTH_REQ_GSS: - case AUTH_REQ_GSS_CONT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("GSSAPI authentication not supported\n")); - return STATUS_ERROR; -#endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ - -#ifdef ENABLE_SSPI - case AUTH_REQ_SSPI: - - /* - * SSPI has it's own startup message so libpq can decide which - * method to use. Indicate to pg_SSPI_startup that we want SSPI - * negotiation instead of Kerberos. - */ - pglock_thread(); - if (pg_SSPI_startup(conn, 1) != STATUS_OK) - { - /* Error message already filled in. */ - pgunlock_thread(); - return STATUS_ERROR; - } - pgunlock_thread(); - break; -#else - - /* - * No SSPI support. However, if we have GSSAPI but not SSPI - * support, AUTH_REQ_SSPI will have been handled in the codepath - * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in - * that case. - */ -#if !defined(ENABLE_GSS) - case AUTH_REQ_SSPI: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SSPI authentication not supported\n")); - return STATUS_ERROR; -#endif /* !define(ENABLE_GSSAPI) */ -#endif /* ENABLE_SSPI */ - - - case AUTH_REQ_CRYPT: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("Crypt authentication not supported\n")); - return STATUS_ERROR; - - case AUTH_REQ_MD5: - case AUTH_REQ_PASSWORD: - conn->password_needed = true; - if (conn->pgpass == NULL || conn->pgpass[0] == '\0') - { - printfPQExpBuffer(&conn->errorMessage, - PQnoPasswordSupplied); - return STATUS_ERROR; - } - if (pg_password_sendauth(conn, conn->pgpass, areq) != STATUS_OK) - { - printfPQExpBuffer(&conn->errorMessage, - "fe_sendauth: error sending password authentication\n"); - return STATUS_ERROR; - } - break; - - case AUTH_REQ_SCM_CREDS: - if (pg_local_sendauth(conn) != STATUS_OK) - return STATUS_ERROR; - break; - - /* - * SASL authentication was introduced in version 10. Older - * versions recognize the request only to give a nicer error - * message. We call it "SCRAM authentication" in the error, rather - * than SASL, because SCRAM is more familiar to users, and it's - * the only SASL authentication mechanism that has been - * implemented as of this writing, anyway. - */ - case AUTH_REQ_SASL: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("SCRAM authentication requires libpq version 10 or above\n")); - return STATUS_ERROR; - - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("authentication method %u not supported\n"), areq); - return STATUS_ERROR; - } - - return STATUS_OK; -} - - -/* - * pg_fe_getauthname - * - * Returns a pointer to malloc'd space containing whatever name the user - * has authenticated to the system. If there is an error, return NULL, - * and put a suitable error message in *errorMessage if that's not NULL. - */ -char * -pg_fe_getauthname(PQExpBuffer errorMessage) -{ - char *result = NULL; - const char *name = NULL; - -#ifdef WIN32 - /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */ - char username[256 + 1]; - DWORD namesize = sizeof(username); -#else - uid_t user_id = geteuid(); - char pwdbuf[BUFSIZ]; - struct passwd pwdstr; - struct passwd *pw = NULL; - int pwerr; -#endif - - /* - * Some users are using configure --enable-thread-safety-force, so we - * might as well do the locking within our library to protect - * pqGetpwuid(). In fact, application developers can use getpwuid() in - * their application if they use the locking call we provide, or install - * their own locking function using PQregisterThreadLock(). - */ - pglock_thread(); - -#ifdef WIN32 - if (GetUserName(username, &namesize)) - name = username; - else if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("user name lookup failure: error code %lu\n"), - GetLastError()); -#else - pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw); - if (pw != NULL) - name = pw->pw_name; - else if (errorMessage) - { - if (pwerr != 0) - printfPQExpBuffer(errorMessage, - libpq_gettext("could not look up local user ID %d: %s\n"), - (int) user_id, - pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf))); - else - printfPQExpBuffer(errorMessage, - libpq_gettext("local user with ID %d does not exist\n"), - (int) user_id); - } -#endif - - if (name) - { - result = strdup(name); - if (result == NULL && errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - } - - pgunlock_thread(); - - return result; -} - - -/* - * PQencryptPassword -- exported routine to encrypt a password - * - * This is intended to be used by client applications that wish to send - * commands like ALTER USER joe PASSWORD 'pwd'. The password need not - * be sent in cleartext if it is encrypted on the client side. This is - * good because it ensures the cleartext password won't end up in logs, - * pg_stat displays, etc. We export the function so that clients won't - * be dependent on low-level details like whether the encryption is MD5 - * or something else. - * - * Arguments are the cleartext password, and the SQL name of the user it - * is for. - * - * Return value is a malloc'd string, or NULL if out-of-memory. The client - * may assume the string doesn't contain any special characters that would - * require escaping. - */ -char * -PQencryptPassword(const char *passwd, const char *user) -{ - char *crypt_pwd; - - crypt_pwd = malloc(MD5_PASSWD_LEN + 1); - if (!crypt_pwd) - return NULL; - - if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd)) - { - free(crypt_pwd); - return NULL; - } - - return crypt_pwd; -} diff --git a/libpq/fe-auth.h b/libpq/fe-auth.h deleted file mode 100644 index 9d11654..0000000 --- a/libpq/fe-auth.h +++ /dev/null @@ -1,24 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-auth.h - * - * Definitions for network authentication routines - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/fe-auth.h - * - *------------------------------------------------------------------------- - */ -#ifndef FE_AUTH_H -#define FE_AUTH_H - -#include "libpq-fe.h" -#include "libpq-int.h" - - -extern int pg_fe_sendauth(AuthRequest areq, PGconn *conn); -extern char *pg_fe_getauthname(PQExpBuffer errorMessage); - -#endif /* FE_AUTH_H */ diff --git a/libpq/fe-connect.c b/libpq/fe-connect.c deleted file mode 100644 index e61ed7d..0000000 --- a/libpq/fe-connect.c +++ /dev/null @@ -1,6002 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-connect.c - * functions related to setting up a connection to the backend - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-connect.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres_fe.h" - -#include -#include -#include -#include -#include -#include - -#include "libpq-fe.h" -#include "libpq-int.h" -#include "fe-auth.h" -#include "pg_config_paths.h" - -#ifdef WIN32 -#include "win32.h" -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0500 -#ifdef near -#undef near -#endif -#define near -#include -#ifdef WIN32_ONLY_COMPILER /* mstcpip.h is missing on mingw */ -#include -#endif -#else -#include -#include -#include -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#include -#endif - -#ifdef ENABLE_THREAD_SAFETY -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include -#endif -#endif - -#ifdef USE_LDAP -#ifdef WIN32 -#include -#else -/* OpenLDAP deprecates RFC 1823, but we want standard conformance */ -#define LDAP_DEPRECATED 1 -#include -typedef struct timeval LDAP_TIMEVAL; -#endif -static int ldapServiceLookup(const char *purl, PQconninfoOption *options, - PQExpBuffer errorMessage); -#endif - -#include "libpq/ip.h" -#include "mb/pg_wchar.h" - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - - -#ifndef WIN32 -#define PGPASSFILE ".pgpass" -#else -#define PGPASSFILE "pgpass.conf" -#endif - -/* - * Pre-9.0 servers will return this SQLSTATE if asked to set - * application_name in a startup packet. We hard-wire the value rather - * than looking into errcodes.h since it reflects historical behavior - * rather than that of the current code. - */ -#define ERRCODE_APPNAME_UNKNOWN "42704" - -/* This is part of the protocol so just define it */ -#define ERRCODE_INVALID_PASSWORD "28P01" -/* This too */ -#define ERRCODE_CANNOT_CONNECT_NOW "57P03" - -/* - * Cope with the various platform-specific ways to spell TCP keepalive socket - * options. This doesn't cover Windows, which as usual does its own thing. - */ -#if defined(TCP_KEEPIDLE) -/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ -#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE -#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE" -#elif defined(TCP_KEEPALIVE_THRESHOLD) -/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */ -#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD -#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD" -#elif defined(TCP_KEEPALIVE) && defined(__darwin__) -/* TCP_KEEPALIVE is the name of this option on macOS */ -/* Caution: Solaris has this symbol but it means something different */ -#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE -#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE" -#endif - -/* - * fall back options if they are not specified by arguments or defined - * by environment variables - */ -#define DefaultHost "localhost" -#define DefaultTty "" -#define DefaultOption "" -#define DefaultAuthtype "" -#define DefaultPassword "" -#ifdef USE_SSL -#define DefaultSSLMode "prefer" -#else -#define DefaultSSLMode "disable" -#endif - -/* ---------- - * Definition of the conninfo parameters and their fallback resources. - * - * If Environment-Var and Compiled-in are specified as NULL, no - * fallback is available. If after all no value can be determined - * for an option, an error is returned. - * - * The value for the username is treated specially in conninfo_add_defaults. - * If the value is not obtained any other way, the username is determined - * by pg_fe_getauthname(). - * - * The Label and Disp-Char entries are provided for applications that - * want to use PQconndefaults() to create a generic database connection - * dialog. Disp-Char is defined as follows: - * "" Normal input field - * "*" Password field - hide value - * "D" Debug option - don't show by default - * - * PQconninfoOptions[] is a constant static array that we use to initialize - * a dynamically allocated working copy. All the "val" fields in - * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val" - * fields point to malloc'd strings that should be freed when the working - * array is freed (see PQconninfoFree). - * - * The first part of each struct is identical to the one in libpq-fe.h, - * which is required since we memcpy() data between the two! - * ---------- - */ -typedef struct _internalPQconninfoOption -{ - char *keyword; /* The keyword of the option */ - char *envvar; /* Fallback environment variable name */ - char *compiled; /* Fallback compiled in default value */ - char *val; /* Option's current value, or NULL */ - char *label; /* Label for field in connect dialog */ - char *dispchar; /* Indicates how to display this field in a - * connect dialog. Values are: "" Display - * entered value as is "*" Password field - - * hide value "D" Debug option - don't show - * by default */ - int dispsize; /* Field size in characters for dialog */ - /* --- - * Anything above this comment must be synchronized with - * PQconninfoOption in libpq-fe.h, since we memcpy() data - * between them! - * --- - */ - off_t connofs; /* Offset into PGconn struct, -1 if not there */ -} internalPQconninfoOption; - -static const internalPQconninfoOption PQconninfoOptions[] = { - /* - * "authtype" is no longer used, so mark it "don't show". We keep it in - * the array so as not to reject conninfo strings from old apps that might - * still try to set it. - */ - {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL, - "Database-Authtype", "D", 20, -1}, - - {"service", "PGSERVICE", NULL, NULL, - "Database-Service", "", 20, -1}, - - {"user", "PGUSER", NULL, NULL, - "Database-User", "", 20, - offsetof(struct pg_conn, pguser)}, - - {"password", "PGPASSWORD", NULL, NULL, - "Database-Password", "*", 20, - offsetof(struct pg_conn, pgpass)}, - - {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL, - "Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, connect_timeout)}, - - {"dbname", "PGDATABASE", NULL, NULL, - "Database-Name", "", 20, - offsetof(struct pg_conn, dbName)}, - - {"host", "PGHOST", NULL, NULL, - "Database-Host", "", 40, - offsetof(struct pg_conn, pghost)}, - - {"hostaddr", "PGHOSTADDR", NULL, NULL, - "Database-Host-IP-Address", "", 45, - offsetof(struct pg_conn, pghostaddr)}, - - {"port", "PGPORT", DEF_PGPORT_STR, NULL, - "Database-Port", "", 6, - offsetof(struct pg_conn, pgport)}, - - {"client_encoding", "PGCLIENTENCODING", NULL, NULL, - "Client-Encoding", "", 10, - offsetof(struct pg_conn, client_encoding_initial)}, - - /* - * "tty" is no longer used either, but keep it present for backwards - * compatibility. - */ - {"tty", "PGTTY", DefaultTty, NULL, - "Backend-Debug-TTY", "D", 40, - offsetof(struct pg_conn, pgtty)}, - - {"options", "PGOPTIONS", DefaultOption, NULL, - "Backend-Debug-Options", "D", 40, - offsetof(struct pg_conn, pgoptions)}, - - {"application_name", "PGAPPNAME", NULL, NULL, - "Application-Name", "", 64, - offsetof(struct pg_conn, appname)}, - - {"fallback_application_name", NULL, NULL, NULL, - "Fallback-Application-Name", "", 64, - offsetof(struct pg_conn, fbappname)}, - - {"keepalives", NULL, NULL, NULL, - "TCP-Keepalives", "", 1, /* should be just '0' or '1' */ - offsetof(struct pg_conn, keepalives)}, - - {"keepalives_idle", NULL, NULL, NULL, - "TCP-Keepalives-Idle", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, keepalives_idle)}, - - {"keepalives_interval", NULL, NULL, NULL, - "TCP-Keepalives-Interval", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, keepalives_interval)}, - - {"keepalives_count", NULL, NULL, NULL, - "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ - offsetof(struct pg_conn, keepalives_count)}, - - /* - * ssl options are allowed even without client SSL support because the - * client can still handle SSL modes "disable" and "allow". Other - * parameters have no effect on non-SSL connections, so there is no reason - * to exclude them since none of them are mandatory. - */ - {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL, - "SSL-Mode", "", 12, /* sizeof("verify-full") == 12 */ - offsetof(struct pg_conn, sslmode)}, - - {"sslcompression", "PGSSLCOMPRESSION", "1", NULL, - "SSL-Compression", "", 1, - offsetof(struct pg_conn, sslcompression)}, - - {"sslcert", "PGSSLCERT", NULL, NULL, - "SSL-Client-Cert", "", 64, - offsetof(struct pg_conn, sslcert)}, - - {"sslkey", "PGSSLKEY", NULL, NULL, - "SSL-Client-Key", "", 64, - offsetof(struct pg_conn, sslkey)}, - - {"sslrootcert", "PGSSLROOTCERT", NULL, NULL, - "SSL-Root-Certificate", "", 64, - offsetof(struct pg_conn, sslrootcert)}, - - {"sslcrl", "PGSSLCRL", NULL, NULL, - "SSL-Revocation-List", "", 64, - offsetof(struct pg_conn, sslcrl)}, - - {"requirepeer", "PGREQUIREPEER", NULL, NULL, - "Require-Peer", "", 10, - offsetof(struct pg_conn, requirepeer)}, - -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - /* Kerberos and GSSAPI authentication support specifying the service name */ - {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, - "Kerberos-service-name", "", 20, - offsetof(struct pg_conn, krbsrvname)}, -#endif - -#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) - - /* - * GSSAPI and SSPI both enabled, give a way to override which is used by - * default - */ - {"gsslib", "PGGSSLIB", NULL, NULL, - "GSS-library", "", 7, /* sizeof("gssapi") = 7 */ - offsetof(struct pg_conn, gsslib)}, -#endif - - {"replication", NULL, NULL, NULL, - "Replication", "D", 5, - offsetof(struct pg_conn, replication)}, - - /* Terminating entry --- MUST BE LAST */ - {NULL, NULL, NULL, NULL, - NULL, NULL, 0} -}; - -static const PQEnvironmentOption EnvironmentOptions[] = -{ - /* common user-interface settings */ - { - "PGDATESTYLE", "datestyle" - }, - { - "PGTZ", "timezone" - }, - /* internal performance-related settings */ - { - "PGGEQO", "geqo" - }, - { - NULL, NULL - } -}; - -/* The connection URI must start with either of the following designators: */ -static const char uri_designator[] = "postgresql://"; -static const char short_uri_designator[] = "postgres://"; - -static bool connectOptions1(PGconn *conn, const char *conninfo); -static bool connectOptions2(PGconn *conn); -static int connectDBStart(PGconn *conn); -static int connectDBComplete(PGconn *conn); -static PGPing internal_ping(PGconn *conn); -static PGconn *makeEmptyPGconn(void); -static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions); -static void freePGconn(PGconn *conn); -static void closePGconn(PGconn *conn); -static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage); -static PQconninfoOption *parse_connection_string(const char *conninfo, - PQExpBuffer errorMessage, bool use_defaults); -static int uri_prefix_length(const char *connstr); -static bool recognized_connection_string(const char *connstr); -static PQconninfoOption *conninfo_parse(const char *conninfo, - PQExpBuffer errorMessage, bool use_defaults); -static PQconninfoOption *conninfo_array_parse(const char *const * keywords, - const char *const * values, PQExpBuffer errorMessage, - bool use_defaults, int expand_dbname); -static bool conninfo_add_defaults(PQconninfoOption *options, - PQExpBuffer errorMessage); -static PQconninfoOption *conninfo_uri_parse(const char *uri, - PQExpBuffer errorMessage, bool use_defaults); -static bool conninfo_uri_parse_options(PQconninfoOption *options, - const char *uri, PQExpBuffer errorMessage); -static bool conninfo_uri_parse_params(char *params, - PQconninfoOption *connOptions, - PQExpBuffer errorMessage); -static char *conninfo_uri_decode(const char *str, PQExpBuffer errorMessage); -static bool get_hexdigit(char digit, int *value); -static const char *conninfo_getval(PQconninfoOption *connOptions, - const char *keyword); -static PQconninfoOption *conninfo_storeval(PQconninfoOption *connOptions, - const char *keyword, const char *value, - PQExpBuffer errorMessage, bool ignoreMissing, bool uri_decode); -static PQconninfoOption *conninfo_find(PQconninfoOption *connOptions, - const char *keyword); -static void defaultNoticeReceiver(void *arg, const PGresult *res); -static void defaultNoticeProcessor(void *arg, const char *message); -static int parseServiceInfo(PQconninfoOption *options, - PQExpBuffer errorMessage); -static int parseServiceFile(const char *serviceFile, - const char *service, - PQconninfoOption *options, - PQExpBuffer errorMessage, - bool *group_found); -static char *pwdfMatchesString(char *buf, char *token); -static char *PasswordFromFile(char *hostname, char *port, char *dbname, - char *username); -static bool getPgPassFilename(char *pgpassfile); -static void dot_pg_pass_warning(PGconn *conn); -static void default_threadlock(int acquire); - - -/* global variable because fe-auth.c needs to access it */ -pgthreadlock_t pg_g_threadlock = default_threadlock; - - -/* - * pqDropConnection - * - * Close any physical connection to the server, and reset associated - * state inside the connection object. We don't release state that - * would be needed to reconnect, though. - * - * We can always flush the output buffer, since there's no longer any hope - * of sending that data. However, unprocessed input data might still be - * valuable, so the caller must tell us whether to flush that or not. - */ -void -pqDropConnection(PGconn *conn, bool flushInput) -{ - /* Drop any SSL state */ - pqsecure_close(conn); - - /* Close the socket itself */ - if (conn->sock != PGINVALID_SOCKET) - closesocket(conn->sock); - conn->sock = PGINVALID_SOCKET; - - /* Optionally discard any unread data */ - if (flushInput) - conn->inStart = conn->inCursor = conn->inEnd = 0; - - /* Always discard any unsent data */ - conn->outCount = 0; - - /* Free authentication state */ -#ifdef ENABLE_GSS - { - OM_uint32 min_s; - - if (conn->gctx) - gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER); - if (conn->gtarg_nam) - gss_release_name(&min_s, &conn->gtarg_nam); - if (conn->ginbuf.length) - gss_release_buffer(&min_s, &conn->ginbuf); - if (conn->goutbuf.length) - gss_release_buffer(&min_s, &conn->goutbuf); - } -#endif -#ifdef ENABLE_SSPI - if (conn->ginbuf.length) - free(conn->ginbuf.value); - conn->ginbuf.length = 0; - conn->ginbuf.value = NULL; - if (conn->sspitarget) - free(conn->sspitarget); - conn->sspitarget = NULL; - if (conn->sspicred) - { - FreeCredentialsHandle(conn->sspicred); - free(conn->sspicred); - conn->sspicred = NULL; - } - if (conn->sspictx) - { - DeleteSecurityContext(conn->sspictx); - free(conn->sspictx); - conn->sspictx = NULL; - } - conn->usesspi = 0; -#endif -} - - -/* - * Connecting to a Database - * - * There are now six different ways a user of this API can connect to the - * database. Two are not recommended for use in new code, because of their - * lack of extensibility with respect to the passing of options to the - * backend. These are PQsetdb and PQsetdbLogin (the former now being a macro - * to the latter). - * - * If it is desired to connect in a synchronous (blocking) manner, use the - * function PQconnectdb or PQconnectdbParams. The former accepts a string of - * option = value pairs (or a URI) which must be parsed; the latter takes two - * NULL terminated arrays instead. - * - * To connect in an asynchronous (non-blocking) manner, use the functions - * PQconnectStart or PQconnectStartParams (which differ in the same way as - * PQconnectdb and PQconnectdbParams) and PQconnectPoll. - * - * Internally, the static functions connectDBStart, connectDBComplete - * are part of the connection procedure. - */ - -/* - * PQconnectdbParams - * - * establishes a connection to a postgres backend through the postmaster - * using connection information in two arrays. - * - * The keywords array is defined as - * - * const char *params[] = {"option1", "option2", NULL} - * - * The values array is defined as - * - * const char *values[] = {"value1", "value2", NULL} - * - * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL - * if a memory allocation failed. - * If the status field of the connection returned is CONNECTION_BAD, - * then some fields may be null'ed out instead of having valid values. - * - * You should call PQfinish (if conn is not NULL) regardless of whether this - * call succeeded. - */ -PGconn * -PQconnectdbParams(const char *const * keywords, - const char *const * values, - int expand_dbname) -{ - PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname); - - if (conn && conn->status != CONNECTION_BAD) - (void) connectDBComplete(conn); - - return conn; - -} - -/* - * PQpingParams - * - * check server status, accepting parameters identical to PQconnectdbParams - */ -PGPing -PQpingParams(const char *const * keywords, - const char *const * values, - int expand_dbname) -{ - PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname); - PGPing ret; - - ret = internal_ping(conn); - PQfinish(conn); - - return ret; -} - -/* - * PQconnectdb - * - * establishes a connection to a postgres backend through the postmaster - * using connection information in a string. - * - * The conninfo string is either a whitespace-separated list of - * - * option = value - * - * definitions or a URI (refer to the documentation for details.) Value - * might be a single value containing no whitespaces or a single quoted - * string. If a single quote should appear anywhere in the value, it must be - * escaped with a backslash like \' - * - * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL - * if a memory allocation failed. - * If the status field of the connection returned is CONNECTION_BAD, - * then some fields may be null'ed out instead of having valid values. - * - * You should call PQfinish (if conn is not NULL) regardless of whether this - * call succeeded. - */ -PGconn * -PQconnectdb(const char *conninfo) -{ - PGconn *conn = PQconnectStart(conninfo); - - if (conn && conn->status != CONNECTION_BAD) - (void) connectDBComplete(conn); - - return conn; -} - -/* - * PQping - * - * check server status, accepting parameters identical to PQconnectdb - */ -PGPing -PQping(const char *conninfo) -{ - PGconn *conn = PQconnectStart(conninfo); - PGPing ret; - - ret = internal_ping(conn); - PQfinish(conn); - - return ret; -} - -/* - * PQconnectStartParams - * - * Begins the establishment of a connection to a postgres backend through the - * postmaster using connection information in a struct. - * - * See comment for PQconnectdbParams for the definition of the string format. - * - * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and - * you should not attempt to proceed with this connection. If the status - * field of the connection returned is CONNECTION_BAD, an error has - * occurred. In this case you should call PQfinish on the result, (perhaps - * inspecting the error message first). Other fields of the structure may not - * be valid if that occurs. If the status field is not CONNECTION_BAD, then - * this stage has succeeded - call PQconnectPoll, using select(2) to see when - * this is necessary. - * - * See PQconnectPoll for more info. - */ -PGconn * -PQconnectStartParams(const char *const * keywords, - const char *const * values, - int expand_dbname) -{ - PGconn *conn; - PQconninfoOption *connOptions; - - /* - * Allocate memory for the conn structure - */ - conn = makeEmptyPGconn(); - if (conn == NULL) - return NULL; - - /* - * Parse the conninfo arrays - */ - connOptions = conninfo_array_parse(keywords, values, - &conn->errorMessage, - true, expand_dbname); - if (connOptions == NULL) - { - conn->status = CONNECTION_BAD; - /* errorMessage is already set */ - return conn; - } - - /* - * Move option values into conn structure - */ - if (!fillPGconn(conn, connOptions)) - { - PQconninfoFree(connOptions); - return conn; - } - - /* - * Free the option info - all is in conn now - */ - PQconninfoFree(connOptions); - - /* - * Compute derived options - */ - if (!connectOptions2(conn)) - return conn; - - /* - * Connect to the database - */ - if (!connectDBStart(conn)) - { - /* Just in case we failed to set it in connectDBStart */ - conn->status = CONNECTION_BAD; - } - - return conn; -} - -/* - * PQconnectStart - * - * Begins the establishment of a connection to a postgres backend through the - * postmaster using connection information in a string. - * - * See comment for PQconnectdb for the definition of the string format. - * - * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and - * you should not attempt to proceed with this connection. If the status - * field of the connection returned is CONNECTION_BAD, an error has - * occurred. In this case you should call PQfinish on the result, (perhaps - * inspecting the error message first). Other fields of the structure may not - * be valid if that occurs. If the status field is not CONNECTION_BAD, then - * this stage has succeeded - call PQconnectPoll, using select(2) to see when - * this is necessary. - * - * See PQconnectPoll for more info. - */ -PGconn * -PQconnectStart(const char *conninfo) -{ - PGconn *conn; - - /* - * Allocate memory for the conn structure - */ - conn = makeEmptyPGconn(); - if (conn == NULL) - return NULL; - - /* - * Parse the conninfo string - */ - if (!connectOptions1(conn, conninfo)) - return conn; - - /* - * Compute derived options - */ - if (!connectOptions2(conn)) - return conn; - - /* - * Connect to the database - */ - if (!connectDBStart(conn)) - { - /* Just in case we failed to set it in connectDBStart */ - conn->status = CONNECTION_BAD; - } - - return conn; -} - -/* - * Move option values into conn structure - * - * Don't put anything cute here --- intelligence should be in - * connectOptions2 ... - * - * Returns true on success. On failure, returns false and sets error message. - */ -static bool -fillPGconn(PGconn *conn, PQconninfoOption *connOptions) -{ - const internalPQconninfoOption *option; - - for (option = PQconninfoOptions; option->keyword; option++) - { - if (option->connofs >= 0) - { - const char *tmp = conninfo_getval(connOptions, option->keyword); - - if (tmp) - { - char **connmember = (char **) ((char *) conn + option->connofs); - - if (*connmember) - free(*connmember); - *connmember = strdup(tmp); - if (*connmember == NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - } - } - } - - return true; -} - -/* - * connectOptions1 - * - * Internal subroutine to set up connection parameters given an already- - * created PGconn and a conninfo string. Derived settings should be - * processed by calling connectOptions2 next. (We split them because - * PQsetdbLogin overrides defaults in between.) - * - * Returns true if OK, false if trouble (in which case errorMessage is set - * and so is conn->status). - */ -static bool -connectOptions1(PGconn *conn, const char *conninfo) -{ - PQconninfoOption *connOptions; - - /* - * Parse the conninfo string - */ - connOptions = parse_connection_string(conninfo, &conn->errorMessage, true); - if (connOptions == NULL) - { - conn->status = CONNECTION_BAD; - /* errorMessage is already set */ - return false; - } - - /* - * Move option values into conn structure - */ - if (!fillPGconn(conn, connOptions)) - { - conn->status = CONNECTION_BAD; - PQconninfoFree(connOptions); - return false; - } - - /* - * Free the option info - all is in conn now - */ - PQconninfoFree(connOptions); - - return true; -} - -/* - * connectOptions2 - * - * Compute derived connection options after absorbing all user-supplied info. - * - * Returns true if OK, false if trouble (in which case errorMessage is set - * and so is conn->status). - */ -static bool -connectOptions2(PGconn *conn) -{ - /* - * If user name was not given, fetch it. (Most likely, the fetch will - * fail, since the only way we get here is if pg_fe_getauthname() failed - * during conninfo_add_defaults(). But now we want an error message.) - */ - if (conn->pguser == NULL || conn->pguser[0] == '\0') - { - if (conn->pguser) - free(conn->pguser); - conn->pguser = pg_fe_getauthname(&conn->errorMessage); - if (!conn->pguser) - { - conn->status = CONNECTION_BAD; - return false; - } - } - - /* - * If database name was not given, default it to equal user name - */ - if (conn->dbName == NULL || conn->dbName[0] == '\0') - { - if (conn->dbName) - free(conn->dbName); - conn->dbName = strdup(conn->pguser); - if (!conn->dbName) - goto oom_error; - } - - /* - * Supply default password if none given - */ - if (conn->pgpass == NULL || conn->pgpass[0] == '\0') - { - if (conn->pgpass) - free(conn->pgpass); - conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport, - conn->dbName, conn->pguser); - if (conn->pgpass == NULL) - { - conn->pgpass = strdup(DefaultPassword); - if (!conn->pgpass) - goto oom_error; - } - else - conn->dot_pgpass_used = true; - } - - /* - * Allow unix socket specification in the host name - */ - if (conn->pghost && is_absolute_path(conn->pghost)) - { - if (conn->pgunixsocket) - free(conn->pgunixsocket); - conn->pgunixsocket = conn->pghost; - conn->pghost = NULL; - } - - /* - * validate sslmode option - */ - if (conn->sslmode) - { - if (strcmp(conn->sslmode, "disable") != 0 - && strcmp(conn->sslmode, "allow") != 0 - && strcmp(conn->sslmode, "prefer") != 0 - && strcmp(conn->sslmode, "require") != 0 - && strcmp(conn->sslmode, "verify-ca") != 0 - && strcmp(conn->sslmode, "verify-full") != 0) - { - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid sslmode value: \"%s\"\n"), - conn->sslmode); - return false; - } - -#ifndef USE_SSL - switch (conn->sslmode[0]) - { - case 'a': /* "allow" */ - case 'p': /* "prefer" */ - - /* - * warn user that an SSL connection will never be negotiated - * since SSL was not compiled in? - */ - break; - - case 'r': /* "require" */ - case 'v': /* "verify-ca" or "verify-full" */ - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"), - conn->sslmode); - return false; - } -#endif - } - else - { - conn->sslmode = strdup(DefaultSSLMode); - if (!conn->sslmode) - goto oom_error; - } - - /* - * Resolve special "auto" client_encoding from the locale - */ - if (conn->client_encoding_initial && - strcmp(conn->client_encoding_initial, "auto") == 0) - { - free(conn->client_encoding_initial); - conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true))); - if (!conn->client_encoding_initial) - goto oom_error; - } - - /* - * Only if we get this far is it appropriate to try to connect. (We need a - * state flag, rather than just the boolean result of this function, in - * case someone tries to PQreset() the PGconn.) - */ - conn->options_valid = true; - - return true; - -oom_error: - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return false; -} - -/* - * PQconndefaults - * - * Construct a default connection options array, which identifies all the - * available options and shows any default values that are available from the - * environment etc. On error (eg out of memory), NULL is returned. - * - * Using this function, an application may determine all possible options - * and their current default values. - * - * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated - * and should be freed when no longer needed via PQconninfoFree(). (In prior - * versions, the returned array was static, but that's not thread-safe.) - * Pre-7.0 applications that use this function will see a small memory leak - * until they are updated to call PQconninfoFree. - */ -PQconninfoOption * -PQconndefaults(void) -{ - PQExpBufferData errorBuf; - PQconninfoOption *connOptions; - - /* We don't actually report any errors here, but callees want a buffer */ - initPQExpBuffer(&errorBuf); - if (PQExpBufferDataBroken(errorBuf)) - return NULL; /* out of memory already :-( */ - - connOptions = conninfo_init(&errorBuf); - if (connOptions != NULL) - { - /* pass NULL errorBuf to ignore errors */ - if (!conninfo_add_defaults(connOptions, NULL)) - { - PQconninfoFree(connOptions); - connOptions = NULL; - } - } - - termPQExpBuffer(&errorBuf); - return connOptions; -} - -/* ---------------- - * PQsetdbLogin - * - * establishes a connection to a postgres backend through the postmaster - * at the specified host and port. - * - * returns a PGconn* which is needed for all subsequent libpq calls - * - * if the status field of the connection returned is CONNECTION_BAD, - * then only the errorMessage is likely to be useful. - * ---------------- - */ -PGconn * -PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, - const char *pgtty, const char *dbName, const char *login, - const char *pwd) -{ - PGconn *conn; - - /* - * Allocate memory for the conn structure - */ - conn = makeEmptyPGconn(); - if (conn == NULL) - return NULL; - - /* - * If the dbName parameter contains what looks like a connection string, - * parse it into conn struct using connectOptions1. - */ - if (dbName && recognized_connection_string(dbName)) - { - if (!connectOptions1(conn, dbName)) - return conn; - } - else - { - /* - * Old-style path: first, parse an empty conninfo string in order to - * set up the same defaults that PQconnectdb() would use. - */ - if (!connectOptions1(conn, "")) - return conn; - - /* Insert dbName parameter value into struct */ - if (dbName && dbName[0] != '\0') - { - if (conn->dbName) - free(conn->dbName); - conn->dbName = strdup(dbName); - if (!conn->dbName) - goto oom_error; - } - } - - /* - * Insert remaining parameters into struct, overriding defaults (as well - * as any conflicting data from dbName taken as a conninfo). - */ - if (pghost && pghost[0] != '\0') - { - if (conn->pghost) - free(conn->pghost); - conn->pghost = strdup(pghost); - if (!conn->pghost) - goto oom_error; - } - - if (pgport && pgport[0] != '\0') - { - if (conn->pgport) - free(conn->pgport); - conn->pgport = strdup(pgport); - if (!conn->pgport) - goto oom_error; - } - - if (pgoptions && pgoptions[0] != '\0') - { - if (conn->pgoptions) - free(conn->pgoptions); - conn->pgoptions = strdup(pgoptions); - if (!conn->pgoptions) - goto oom_error; - } - - if (pgtty && pgtty[0] != '\0') - { - if (conn->pgtty) - free(conn->pgtty); - conn->pgtty = strdup(pgtty); - if (!conn->pgtty) - goto oom_error; - } - - if (login && login[0] != '\0') - { - if (conn->pguser) - free(conn->pguser); - conn->pguser = strdup(login); - if (!conn->pguser) - goto oom_error; - } - - if (pwd && pwd[0] != '\0') - { - if (conn->pgpass) - free(conn->pgpass); - conn->pgpass = strdup(pwd); - if (!conn->pgpass) - goto oom_error; - } - - /* - * Compute derived options - */ - if (!connectOptions2(conn)) - return conn; - - /* - * Connect to the database - */ - if (connectDBStart(conn)) - (void) connectDBComplete(conn); - - return conn; - -oom_error: - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return conn; -} - - -/* ---------- - * connectNoDelay - - * Sets the TCP_NODELAY socket option. - * Returns 1 if successful, 0 if not. - * ---------- - */ -static int -connectNoDelay(PGconn *conn) -{ -#ifdef TCP_NODELAY - int on = 1; - - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, - (char *) &on, - sizeof(on)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to TCP no delay mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#endif - - return 1; -} - - -/* ---------- - * connectFailureMessage - - * create a friendly error message on connection failure. - * ---------- - */ -static void -connectFailureMessage(PGconn *conn, int errorno) -{ - char sebuf[256]; - -#ifdef HAVE_UNIX_SOCKETS - if (IS_AF_UNIX(conn->raddr.addr.ss_family)) - { - char service[NI_MAXHOST]; - - pg_getnameinfo_all(&conn->raddr.addr, conn->raddr.salen, - NULL, 0, - service, sizeof(service), - NI_NUMERICSERV); - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running locally and accepting\n" - "\tconnections on Unix domain socket \"%s\"?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), - service); - } - else -#endif /* HAVE_UNIX_SOCKETS */ - { - char host_addr[NI_MAXHOST]; - const char *displayed_host; - struct sockaddr_storage *addr = &conn->raddr.addr; - - /* - * Optionally display the network address with the hostname. This is - * useful to distinguish between IPv4 and IPv6 connections. - */ - if (conn->pghostaddr != NULL) - strlcpy(host_addr, conn->pghostaddr, NI_MAXHOST); - else if (addr->ss_family == AF_INET) - { - if (inet_net_ntop(AF_INET, - &((struct sockaddr_in *) addr)->sin_addr.s_addr, - 32, - host_addr, sizeof(host_addr)) == NULL) - strcpy(host_addr, "???"); - } -#ifdef HAVE_IPV6 - else if (addr->ss_family == AF_INET6) - { - if (inet_net_ntop(AF_INET6, - &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, - 128, - host_addr, sizeof(host_addr)) == NULL) - strcpy(host_addr, "???"); - } -#endif - else - strcpy(host_addr, "???"); - - if (conn->pghostaddr && conn->pghostaddr[0] != '\0') - displayed_host = conn->pghostaddr; - else if (conn->pghost && conn->pghost[0] != '\0') - displayed_host = conn->pghost; - else - displayed_host = DefaultHost; - - /* - * If the user did not supply an IP address using 'hostaddr', and - * 'host' was missing or does not match our lookup, display the - * looked-up IP address. - */ - if ((conn->pghostaddr == NULL) && - (conn->pghost == NULL || strcmp(conn->pghost, host_addr) != 0)) - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running on host \"%s\" (%s) and accepting\n" - "\tTCP/IP connections on port %s?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), - displayed_host, - host_addr, - conn->pgport); - else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not connect to server: %s\n" - "\tIs the server running on host \"%s\" and accepting\n" - "\tTCP/IP connections on port %s?\n"), - SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), - displayed_host, - conn->pgport); - } -} - -/* - * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if - * conn->keepalives is set to a value which is not parseable as an - * integer. - */ -static int -useKeepalives(PGconn *conn) -{ - char *ep; - int val; - - if (conn->keepalives == NULL) - return 1; - val = strtol(conn->keepalives, &ep, 10); - if (*ep) - return -1; - return val != 0 ? 1 : 0; -} - -#ifndef WIN32 -/* - * Set the keepalive idle timer. - */ -static int -setKeepalivesIdle(PGconn *conn) -{ - int idle; - - if (conn->keepalives_idle == NULL) - return 1; - - idle = atoi(conn->keepalives_idle); - if (idle < 0) - idle = 0; - -#ifdef PG_TCP_KEEPALIVE_IDLE - if (setsockopt(conn->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE, - (char *) &idle, sizeof(idle)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(%s) failed: %s\n"), - PG_TCP_KEEPALIVE_IDLE_STR, - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#endif - - return 1; -} - -/* - * Set the keepalive interval. - */ -static int -setKeepalivesInterval(PGconn *conn) -{ - int interval; - - if (conn->keepalives_interval == NULL) - return 1; - - interval = atoi(conn->keepalives_interval); - if (interval < 0) - interval = 0; - -#ifdef TCP_KEEPINTVL - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL, - (char *) &interval, sizeof(interval)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(%s) failed: %s\n"), - "TCP_KEEPINTVL", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#endif - - return 1; -} - -/* - * Set the count of lost keepalive packets that will trigger a connection - * break. - */ -static int -setKeepalivesCount(PGconn *conn) -{ - int count; - - if (conn->keepalives_count == NULL) - return 1; - - count = atoi(conn->keepalives_count); - if (count < 0) - count = 0; - -#ifdef TCP_KEEPCNT - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT, - (char *) &count, sizeof(count)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(%s) failed: %s\n"), - "TCP_KEEPCNT", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#endif - - return 1; -} -#else /* WIN32 */ -#ifdef SIO_KEEPALIVE_VALS -/* - * Enable keepalives and set the keepalive values on Win32, - * where they are always set in one batch. - */ -static int -setKeepalivesWin32(PGconn *conn) -{ - struct tcp_keepalive ka; - DWORD retsize; - int idle = 0; - int interval = 0; - - if (conn->keepalives_idle) - idle = atoi(conn->keepalives_idle); - if (idle <= 0) - idle = 2 * 60 * 60; /* 2 hours = default */ - - if (conn->keepalives_interval) - interval = atoi(conn->keepalives_interval); - if (interval <= 0) - interval = 1; /* 1 second = default */ - - ka.onoff = 1; - ka.keepalivetime = idle * 1000; - ka.keepaliveinterval = interval * 1000; - - if (WSAIoctl(conn->sock, - SIO_KEEPALIVE_VALS, - (LPVOID) &ka, - sizeof(ka), - NULL, - 0, - &retsize, - NULL, - NULL) - != 0) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("WSAIoctl(SIO_KEEPALIVE_VALS) failed: %ui\n"), - WSAGetLastError()); - return 0; - } - return 1; -} -#endif /* SIO_KEEPALIVE_VALS */ -#endif /* WIN32 */ - -/* ---------- - * connectDBStart - - * Begin the process of making a connection to the backend. - * - * Returns 1 if successful, 0 if not. - * ---------- - */ -static int -connectDBStart(PGconn *conn) -{ - int portnum; - char portstr[MAXPGPATH]; - struct addrinfo *addrs = NULL; - struct addrinfo hint; - const char *node; - int ret; - - if (!conn) - return 0; - - if (!conn->options_valid) - goto connect_errReturn; - - /* Ensure our buffers are empty */ - conn->inStart = conn->inCursor = conn->inEnd = 0; - conn->outCount = 0; - - /* - * Determine the parameters to pass to pg_getaddrinfo_all. - */ - - /* Initialize hint structure */ - MemSet(&hint, 0, sizeof(hint)); - hint.ai_socktype = SOCK_STREAM; - hint.ai_family = AF_UNSPEC; - - /* Set up port number as a string */ - if (conn->pgport != NULL && conn->pgport[0] != '\0') - { - portnum = atoi(conn->pgport); - if (portnum < 1 || portnum > 65535) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid port number: \"%s\"\n"), - conn->pgport); - conn->options_valid = false; - goto connect_errReturn; - } - } - else - portnum = DEF_PGPORT; - snprintf(portstr, sizeof(portstr), "%d", portnum); - - if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') - { - /* Using pghostaddr avoids a hostname lookup */ - node = conn->pghostaddr; - hint.ai_family = AF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - } - else if (conn->pghost != NULL && conn->pghost[0] != '\0') - { - /* Using pghost, so we have to look-up the hostname */ - node = conn->pghost; - hint.ai_family = AF_UNSPEC; - } - else - { -#ifdef HAVE_UNIX_SOCKETS - /* pghostaddr and pghost are NULL, so use Unix domain socket */ - node = NULL; - hint.ai_family = AF_UNIX; - UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket); - if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("Unix-domain socket path \"%s\" is too long (maximum %d bytes)\n"), - portstr, - (int) (UNIXSOCK_PATH_BUFLEN - 1)); - conn->options_valid = false; - goto connect_errReturn; - } -#else - /* Without Unix sockets, default to localhost instead */ - node = DefaultHost; - hint.ai_family = AF_UNSPEC; -#endif /* HAVE_UNIX_SOCKETS */ - } - - /* Use pg_getaddrinfo_all() to resolve the address */ - ret = pg_getaddrinfo_all(node, portstr, &hint, &addrs); - if (ret || !addrs) - { - if (node) - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate host name \"%s\" to address: %s\n"), - node, gai_strerror(ret)); - else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"), - portstr, gai_strerror(ret)); - if (addrs) - pg_freeaddrinfo_all(hint.ai_family, addrs); - conn->options_valid = false; - goto connect_errReturn; - } - -#ifdef USE_SSL - /* setup values based on SSL mode */ - if (conn->sslmode[0] == 'd') /* "disable" */ - conn->allow_ssl_try = false; - else if (conn->sslmode[0] == 'a') /* "allow" */ - conn->wait_ssl_try = true; -#endif - - /* - * Set up to try to connect, with protocol 3.0 as the first attempt. - */ - conn->addrlist = addrs; - conn->addr_cur = addrs; - conn->addrlist_family = hint.ai_family; - conn->pversion = PG_PROTOCOL(3, 0); - conn->send_appname = true; - conn->status = CONNECTION_NEEDED; - - /* - * The code for processing CONNECTION_NEEDED state is in PQconnectPoll(), - * so that it can easily be re-executed if needed again during the - * asynchronous startup process. However, we must run it once here, - * because callers expect a success return from this routine to mean that - * we are in PGRES_POLLING_WRITING connection state. - */ - if (PQconnectPoll(conn) == PGRES_POLLING_WRITING) - return 1; - -connect_errReturn: - pqDropConnection(conn, true); - conn->status = CONNECTION_BAD; - return 0; -} - - -/* - * connectDBComplete - * - * Block and complete a connection. - * - * Returns 1 on success, 0 on failure. - */ -static int -connectDBComplete(PGconn *conn) -{ - PostgresPollingStatusType flag = PGRES_POLLING_WRITING; - time_t finish_time = ((time_t) -1); - - if (conn == NULL || conn->status == CONNECTION_BAD) - return 0; - - /* - * Set up a time limit, if connect_timeout isn't zero. - */ - if (conn->connect_timeout != NULL) - { - int timeout = atoi(conn->connect_timeout); - - if (timeout > 0) - { - /* - * Rounding could cause connection to fail; need at least 2 secs - */ - if (timeout < 2) - timeout = 2; - /* calculate the finish time based on start + timeout */ - finish_time = time(NULL) + timeout; - } - } - - for (;;) - { - /* - * Wait, if necessary. Note that the initial state (just after - * PQconnectStart) is to wait for the socket to select for writing. - */ - switch (flag) - { - case PGRES_POLLING_OK: - - /* - * Reset stored error messages since we now have a working - * connection - */ - resetPQExpBuffer(&conn->errorMessage); - return 1; /* success! */ - - case PGRES_POLLING_READING: - if (pqWaitTimed(1, 0, conn, finish_time)) - { - conn->status = CONNECTION_BAD; - return 0; - } - break; - - case PGRES_POLLING_WRITING: - if (pqWaitTimed(0, 1, conn, finish_time)) - { - conn->status = CONNECTION_BAD; - return 0; - } - break; - - default: - /* Just in case we failed to set it in PQconnectPoll */ - conn->status = CONNECTION_BAD; - return 0; - } - - /* - * Now try to advance the state machine. - */ - flag = PQconnectPoll(conn); - } -} - -/* ---------------- - * PQconnectPoll - * - * Poll an asynchronous connection. - * - * Returns a PostgresPollingStatusType. - * Before calling this function, use select(2) to determine when data - * has arrived.. - * - * You must call PQfinish whether or not this fails. - * - * This function and PQconnectStart are intended to allow connections to be - * made without blocking the execution of your program on remote I/O. However, - * there are a number of caveats: - * - * o If you call PQtrace, ensure that the stream object into which you trace - * will not block. - * o If you do not supply an IP address for the remote host (i.e. you - * supply a host name instead) then PQconnectStart will block on - * gethostbyname. You will be fine if using Unix sockets (i.e. by - * supplying neither a host name nor a host address). - * o If your backend wants to use Kerberos authentication then you must - * supply both a host name and a host address, otherwise this function - * may block on gethostname. - * - * ---------------- - */ -PostgresPollingStatusType -PQconnectPoll(PGconn *conn) -{ - PGresult *res; - char sebuf[256]; - int optval; - - if (conn == NULL) - return PGRES_POLLING_FAILED; - - /* Get the new data */ - switch (conn->status) - { - /* - * We really shouldn't have been polled in these two cases, but we - * can handle it. - */ - case CONNECTION_BAD: - return PGRES_POLLING_FAILED; - case CONNECTION_OK: - return PGRES_POLLING_OK; - - /* These are reading states */ - case CONNECTION_AWAITING_RESPONSE: - case CONNECTION_AUTH_OK: - { - /* Load waiting data */ - int n = pqReadData(conn); - - if (n < 0) - goto error_return; - if (n == 0) - return PGRES_POLLING_READING; - - break; - } - - /* These are writing states, so we just proceed. */ - case CONNECTION_STARTED: - case CONNECTION_MADE: - break; - - /* We allow pqSetenvPoll to decide whether to proceed. */ - case CONNECTION_SETENV: - break; - - /* Special cases: proceed without waiting. */ - case CONNECTION_SSL_STARTUP: - case CONNECTION_NEEDED: - break; - - default: - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext( - "invalid connection state, " - "probably indicative of memory corruption\n" - )); - goto error_return; - } - - -keep_going: /* We will come back to here until there is - * nothing left to do. */ - switch (conn->status) - { - case CONNECTION_NEEDED: - { - /* - * Try to initiate a connection to one of the addresses - * returned by pg_getaddrinfo_all(). conn->addr_cur is the - * next one to try. We fail when we run out of addresses. - */ - while (conn->addr_cur != NULL) - { - struct addrinfo *addr_cur = conn->addr_cur; - - /* Remember current address for possible error msg */ - memcpy(&conn->raddr.addr, addr_cur->ai_addr, - addr_cur->ai_addrlen); - conn->raddr.salen = addr_cur->ai_addrlen; - - conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0); - if (conn->sock == PGINVALID_SOCKET) - { - /* - * ignore socket() failure if we have more addresses - * to try - */ - if (addr_cur->ai_next != NULL) - { - conn->addr_cur = addr_cur->ai_next; - continue; - } - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not create socket: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - break; - } - - /* - * Select socket options: no delay of outgoing data for - * TCP sockets, nonblock mode, close-on-exec. Fail if any - * of this fails. - */ - if (!IS_AF_UNIX(addr_cur->ai_family)) - { - if (!connectNoDelay(conn)) - { - pqDropConnection(conn, true); - conn->addr_cur = addr_cur->ai_next; - continue; - } - } - if (!pg_set_noblock(conn->sock)) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to nonblocking mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - pqDropConnection(conn, true); - conn->addr_cur = addr_cur->ai_next; - continue; - } - -#ifdef F_SETFD - if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not set socket to close-on-exec mode: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - pqDropConnection(conn, true); - conn->addr_cur = addr_cur->ai_next; - continue; - } -#endif /* F_SETFD */ - - if (!IS_AF_UNIX(addr_cur->ai_family)) - { -#ifndef WIN32 - int on = 1; -#endif - int usekeepalives = useKeepalives(conn); - int err = 0; - - if (usekeepalives < 0) - { - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("keepalives parameter must be an integer\n")); - err = 1; - } - else if (usekeepalives == 0) - { - /* Do nothing */ - } -#ifndef WIN32 - else if (setsockopt(conn->sock, - SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof(on)) < 0) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(%s) failed: %s\n"), - "SO_KEEPALIVE", - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - err = 1; - } - else if (!setKeepalivesIdle(conn) - || !setKeepalivesInterval(conn) - || !setKeepalivesCount(conn)) - err = 1; -#else /* WIN32 */ -#ifdef SIO_KEEPALIVE_VALS - else if (!setKeepalivesWin32(conn)) - err = 1; -#endif /* SIO_KEEPALIVE_VALS */ -#endif /* WIN32 */ - - if (err) - { - pqDropConnection(conn, true); - conn->addr_cur = addr_cur->ai_next; - continue; - } - } - - /*---------- - * We have three methods of blocking SIGPIPE during - * send() calls to this socket: - * - * - setsockopt(sock, SO_NOSIGPIPE) - * - send(sock, ..., MSG_NOSIGNAL) - * - setting the signal mask to SIG_IGN during send() - * - * The third method requires three syscalls per send, - * so we prefer either of the first two, but they are - * less portable. The state is tracked in the following - * members of PGconn: - * - * conn->sigpipe_so - we have set up SO_NOSIGPIPE - * conn->sigpipe_flag - we're specifying MSG_NOSIGNAL - * - * If we can use SO_NOSIGPIPE, then set sigpipe_so here - * and we're done. Otherwise, set sigpipe_flag so that - * we will try MSG_NOSIGNAL on sends. If we get an error - * with MSG_NOSIGNAL, we'll clear that flag and revert to - * signal masking. - *---------- - */ - conn->sigpipe_so = false; -#ifdef MSG_NOSIGNAL - conn->sigpipe_flag = true; -#else - conn->sigpipe_flag = false; -#endif /* MSG_NOSIGNAL */ - -#ifdef SO_NOSIGPIPE - optval = 1; - if (setsockopt(conn->sock, SOL_SOCKET, SO_NOSIGPIPE, - (char *) &optval, sizeof(optval)) == 0) - { - conn->sigpipe_so = true; - conn->sigpipe_flag = false; - } -#endif /* SO_NOSIGPIPE */ - - /* - * Start/make connection. This should not block, since we - * are in nonblock mode. If it does, well, too bad. - */ - if (connect(conn->sock, addr_cur->ai_addr, - addr_cur->ai_addrlen) < 0) - { - if (SOCK_ERRNO == EINPROGRESS || -#ifdef WIN32 - SOCK_ERRNO == EWOULDBLOCK || -#endif - SOCK_ERRNO == EINTR) - { - /* - * This is fine - we're in non-blocking mode, and - * the connection is in progress. Tell caller to - * wait for write-ready on socket. - */ - conn->status = CONNECTION_STARTED; - return PGRES_POLLING_WRITING; - } - /* otherwise, trouble */ - } - else - { - /* - * Hm, we're connected already --- seems the "nonblock - * connection" wasn't. Advance the state machine and - * go do the next stuff. - */ - conn->status = CONNECTION_STARTED; - goto keep_going; - } - - /* - * This connection failed --- set up error report, then - * close socket (do it this way in case close() affects - * the value of errno...). We will ignore the connect() - * failure and keep going if there are more addresses. - */ - connectFailureMessage(conn, SOCK_ERRNO); - pqDropConnection(conn, true); - - /* - * Try the next address, if any. - */ - conn->addr_cur = addr_cur->ai_next; - } /* loop over addresses */ - - /* - * Ooops, no more addresses. An appropriate error message is - * already set up, so just set the right status. - */ - goto error_return; - } - - case CONNECTION_STARTED: - { - ACCEPT_TYPE_ARG3 optlen = sizeof(optval); - - /* - * Write ready, since we've made it here, so the connection - * has been made ... or has failed. - */ - - /* - * Now check (using getsockopt) that there is not an error - * state waiting for us on the socket. - */ - - if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, - (char *) &optval, &optlen) == -1) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get socket error status: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - goto error_return; - } - else if (optval != 0) - { - /* - * When using a nonblocking connect, we will typically see - * connect failures at this point, so provide a friendly - * error message. - */ - connectFailureMessage(conn, optval); - pqDropConnection(conn, true); - - /* - * If more addresses remain, keep trying, just as in the - * case where connect() returned failure immediately. - */ - if (conn->addr_cur->ai_next != NULL) - { - conn->addr_cur = conn->addr_cur->ai_next; - conn->status = CONNECTION_NEEDED; - goto keep_going; - } - goto error_return; - } - - /* Fill in the client address */ - conn->laddr.salen = sizeof(conn->laddr.addr); - if (getsockname(conn->sock, - (struct sockaddr *) & conn->laddr.addr, - &conn->laddr.salen) < 0) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get client address from socket: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - goto error_return; - } - - /* - * Make sure we can write before advancing to next step. - */ - conn->status = CONNECTION_MADE; - return PGRES_POLLING_WRITING; - } - - case CONNECTION_MADE: - { - char *startpacket; - int packetlen; - -#ifdef HAVE_UNIX_SOCKETS - - /* - * Implement requirepeer check, if requested and it's a - * Unix-domain socket. - */ - if (conn->requirepeer && conn->requirepeer[0] && - IS_AF_UNIX(conn->raddr.addr.ss_family)) - { - char pwdbuf[BUFSIZ]; - struct passwd pass_buf; - struct passwd *pass; - int passerr; - uid_t uid; - gid_t gid; - - errno = 0; - if (getpeereid(conn->sock, &uid, &gid) != 0) - { - /* - * Provide special error message if getpeereid is a - * stub - */ - if (errno == ENOSYS) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("requirepeer parameter is not supported on this platform\n")); - else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not get peer credentials: %s\n"), - pqStrerror(errno, sebuf, sizeof(sebuf))); - goto error_return; - } - - passerr = pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass); - if (pass == NULL) - { - if (passerr != 0) - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not look up local user ID %d: %s\n"), - (int) uid, - pqStrerror(passerr, sebuf, sizeof(sebuf))); - else - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("local user with ID %d does not exist\n"), - (int) uid); - goto error_return; - } - - if (strcmp(pass->pw_name, conn->requirepeer) != 0) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("requirepeer specifies \"%s\", but actual peer user name is \"%s\"\n"), - conn->requirepeer, pass->pw_name); - goto error_return; - } - } -#endif /* HAVE_UNIX_SOCKETS */ - -#ifdef USE_SSL - - /* - * If SSL is enabled and we haven't already got it running, - * request it instead of sending the startup message. - */ - if (IS_AF_UNIX(conn->raddr.addr.ss_family)) - { - /* Don't bother requesting SSL over a Unix socket */ - conn->allow_ssl_try = false; - } - if (conn->allow_ssl_try && !conn->wait_ssl_try && - !conn->ssl_in_use) - { - ProtocolVersion pv; - - /* - * Send the SSL request packet. - * - * Theoretically, this could block, but it really - * shouldn't since we only got here if the socket is - * write-ready. - */ - pv = htonl(NEGOTIATE_SSL_CODE); - if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send SSL negotiation packet: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - goto error_return; - } - /* Ok, wait for response */ - conn->status = CONNECTION_SSL_STARTUP; - return PGRES_POLLING_READING; - } -#endif /* USE_SSL */ - - /* - * Build the startup packet. - */ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - startpacket = pqBuildStartupPacket3(conn, &packetlen, - EnvironmentOptions); - else - startpacket = pqBuildStartupPacket2(conn, &packetlen, - EnvironmentOptions); - if (!startpacket) - { - /* - * will not appendbuffer here, since it's likely to also - * run out of memory - */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - goto error_return; - } - - /* - * Send the startup packet. - * - * Theoretically, this could block, but it really shouldn't - * since we only got here if the socket is write-ready. - */ - if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send startup packet: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - free(startpacket); - goto error_return; - } - - free(startpacket); - - conn->status = CONNECTION_AWAITING_RESPONSE; - return PGRES_POLLING_READING; - } - - /* - * Handle SSL negotiation: wait for postmaster messages and - * respond as necessary. - */ - case CONNECTION_SSL_STARTUP: - { -#ifdef USE_SSL - PostgresPollingStatusType pollres; - - /* - * On first time through, get the postmaster's response to our - * SSL negotiation packet. - */ - if (!conn->ssl_in_use) - { - /* - * We use pqReadData here since it has the logic to - * distinguish no-data-yet from connection closure. Since - * conn->ssl isn't set, a plain recv() will occur. - */ - char SSLok; - int rdresult; - - rdresult = pqReadData(conn); - if (rdresult < 0) - { - /* errorMessage is already filled in */ - goto error_return; - } - if (rdresult == 0) - { - /* caller failed to wait for data */ - return PGRES_POLLING_READING; - } - if (pqGetc(&SSLok, conn) < 0) - { - /* should not happen really */ - return PGRES_POLLING_READING; - } - if (SSLok == 'S') - { - /* mark byte consumed */ - conn->inStart = conn->inCursor; - /* Set up global SSL state if required */ - if (pqsecure_initialize(conn) != 0) - goto error_return; - } - else if (SSLok == 'N') - { - /* mark byte consumed */ - conn->inStart = conn->inCursor; - /* OK to do without SSL? */ - if (conn->sslmode[0] == 'r' || /* "require" */ - conn->sslmode[0] == 'v') /* "verify-ca" or - * "verify-full" */ - { - /* Require SSL, but server does not want it */ - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("server does not support SSL, but SSL was required\n")); - goto error_return; - } - /* Otherwise, proceed with normal startup */ - conn->allow_ssl_try = false; - conn->status = CONNECTION_MADE; - return PGRES_POLLING_WRITING; - } - else if (SSLok == 'E') - { - /* - * Server failure of some sort, such as failure to - * fork a backend process. We need to process and - * report the error message, which might be formatted - * according to either protocol 2 or protocol 3. - * Rather than duplicate the code for that, we flip - * into AWAITING_RESPONSE state and let the code there - * deal with it. Note we have *not* consumed the "E" - * byte here. - */ - conn->status = CONNECTION_AWAITING_RESPONSE; - goto keep_going; - } - else - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("received invalid response to SSL negotiation: %c\n"), - SSLok); - goto error_return; - } - } - - /* - * Begin or continue the SSL negotiation process. - */ - pollres = pqsecure_open_client(conn); - if (pollres == PGRES_POLLING_OK) - { - /* SSL handshake done, ready to send startup packet */ - conn->status = CONNECTION_MADE; - return PGRES_POLLING_WRITING; - } - if (pollres == PGRES_POLLING_FAILED) - { - /* - * Failed ... if sslmode is "prefer" then do a non-SSL - * retry - */ - if (conn->sslmode[0] == 'p' /* "prefer" */ - && conn->allow_ssl_try /* redundant? */ - && !conn->wait_ssl_try) /* redundant? */ - { - /* only retry once */ - conn->allow_ssl_try = false; - /* Must drop the old connection */ - pqDropConnection(conn, true); - conn->status = CONNECTION_NEEDED; - goto keep_going; - } - } - return pollres; -#else /* !USE_SSL */ - /* can't get here */ - goto error_return; -#endif /* USE_SSL */ - } - - /* - * Handle authentication exchange: wait for postmaster messages - * and respond as necessary. - */ - case CONNECTION_AWAITING_RESPONSE: - { - char beresp; - int msgLength; - int avail; - AuthRequest areq; - - /* - * Scan the message from current point (note that if we find - * the message is incomplete, we will return without advancing - * inStart, and resume here next time). - */ - conn->inCursor = conn->inStart; - - /* Read type byte */ - if (pqGetc(&beresp, conn)) - { - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - - /* - * Validate message type: we expect only an authentication - * request or an error here. Anything else probably means - * it's not Postgres on the other end at all. - */ - if (!(beresp == 'R' || beresp == 'E')) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "expected authentication request from " - "server, but received %c\n"), - beresp); - goto error_return; - } - - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - /* Read message length word */ - if (pqGetInt(&msgLength, 4, conn)) - { - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - } - else - { - /* Set phony message length to disable checks below */ - msgLength = 8; - } - - /* - * Try to validate message length before using it. - * Authentication requests can't be very large, although GSS - * auth requests may not be that small. Errors can be a - * little larger, but not huge. If we see a large apparent - * length in an error, it means we're really talking to a - * pre-3.0-protocol server; cope. - */ - if (beresp == 'R' && (msgLength < 8 || msgLength > 2000)) - { - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "expected authentication request from " - "server, but received %c\n"), - beresp); - goto error_return; - } - - if (beresp == 'E' && (msgLength < 8 || msgLength > 30000)) - { - /* Handle error from a pre-3.0 server */ - conn->inCursor = conn->inStart + 1; /* reread data */ - if (pqGets_append(&conn->errorMessage, conn)) - { - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - /* OK, we read the message; mark data consumed */ - conn->inStart = conn->inCursor; - - /* - * The postmaster typically won't end its message with a - * newline, so add one to conform to libpq conventions. - */ - appendPQExpBufferChar(&conn->errorMessage, '\n'); - - /* - * If we tried to open the connection in 3.0 protocol, - * fall back to 2.0 protocol. - */ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - conn->pversion = PG_PROTOCOL(2, 0); - /* Must drop the old connection */ - pqDropConnection(conn, true); - conn->status = CONNECTION_NEEDED; - goto keep_going; - } - - goto error_return; - } - - /* - * Can't process if message body isn't all here yet. - * - * (In protocol 2.0 case, we are assuming messages carry at - * least 4 bytes of data.) - */ - msgLength -= 4; - avail = conn->inEnd - conn->inCursor; - if (avail < msgLength) - { - /* - * Before returning, try to enlarge the input buffer if - * needed to hold the whole message; see notes in - * pqParseInput3. - */ - if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, - conn)) - goto error_return; - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - - /* Handle errors. */ - if (beresp == 'E') - { - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - if (pqGetErrorNotice3(conn, true)) - { - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - } - else - { - if (pqGets_append(&conn->errorMessage, conn)) - { - /* We'll come back when there is more data */ - return PGRES_POLLING_READING; - } - } - /* OK, we read the message; mark data consumed */ - conn->inStart = conn->inCursor; - -#ifdef USE_SSL - - /* - * if sslmode is "allow" and we haven't tried an SSL - * connection already, then retry with an SSL connection - */ - if (conn->sslmode[0] == 'a' /* "allow" */ - && !conn->ssl_in_use - && conn->allow_ssl_try - && conn->wait_ssl_try) - { - /* only retry once */ - conn->wait_ssl_try = false; - /* Must drop the old connection */ - pqDropConnection(conn, true); - conn->status = CONNECTION_NEEDED; - goto keep_going; - } - - /* - * if sslmode is "prefer" and we're in an SSL connection, - * then do a non-SSL retry - */ - if (conn->sslmode[0] == 'p' /* "prefer" */ - && conn->allow_ssl_try - && !conn->wait_ssl_try) /* redundant? */ - { - /* only retry once */ - conn->allow_ssl_try = false; - /* Must drop the old connection */ - pqDropConnection(conn, true); - conn->status = CONNECTION_NEEDED; - goto keep_going; - } -#endif - - goto error_return; - } - - /* It is an authentication request. */ - conn->auth_req_received = true; - - /* Get the type of request. */ - if (pqGetInt((int *) &areq, 4, conn)) - { - /* We'll come back when there are more data */ - return PGRES_POLLING_READING; - } - - /* Get the password salt if there is one. */ - if (areq == AUTH_REQ_MD5) - { - if (pqGetnchar(conn->md5Salt, - sizeof(conn->md5Salt), conn)) - { - /* We'll come back when there are more data */ - return PGRES_POLLING_READING; - } - } -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - - /* - * Continue GSSAPI/SSPI authentication - */ - if (areq == AUTH_REQ_GSS_CONT) - { - int llen = msgLength - 4; - - /* - * We can be called repeatedly for the same buffer. Avoid - * re-allocating the buffer in this case - just re-use the - * old buffer. - */ - if (llen != conn->ginbuf.length) - { - if (conn->ginbuf.value) - free(conn->ginbuf.value); - - conn->ginbuf.length = llen; - conn->ginbuf.value = malloc(llen); - if (!conn->ginbuf.value) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory allocating GSSAPI buffer (%d)"), - llen); - goto error_return; - } - } - - if (pqGetnchar(conn->ginbuf.value, llen, conn)) - { - /* We'll come back when there is more data. */ - return PGRES_POLLING_READING; - } - } -#endif - - /* - * OK, we successfully read the message; mark data consumed - */ - conn->inStart = conn->inCursor; - - /* Respond to the request if necessary. */ - - /* - * Note that conn->pghost must be non-NULL if we are going to - * avoid the Kerberos code doing a hostname look-up. - */ - - if (pg_fe_sendauth(areq, conn) != STATUS_OK) - { - conn->errorMessage.len = strlen(conn->errorMessage.data); - goto error_return; - } - conn->errorMessage.len = strlen(conn->errorMessage.data); - - /* - * Just make sure that any data sent by pg_fe_sendauth is - * flushed out. Although this theoretically could block, it - * really shouldn't since we don't send large auth responses. - */ - if (pqFlush(conn)) - goto error_return; - - if (areq == AUTH_REQ_OK) - { - /* We are done with authentication exchange */ - conn->status = CONNECTION_AUTH_OK; - - /* - * Set asyncStatus so that PQgetResult will think that - * what comes back next is the result of a query. See - * below. - */ - conn->asyncStatus = PGASYNC_BUSY; - } - - /* Look to see if we have more data yet. */ - goto keep_going; - } - - case CONNECTION_AUTH_OK: - { - /* - * Now we expect to hear from the backend. A ReadyForQuery - * message indicates that startup is successful, but we might - * also get an Error message indicating failure. (Notice - * messages indicating nonfatal warnings are also allowed by - * the protocol, as are ParameterStatus and BackendKeyData - * messages.) Easiest way to handle this is to let - * PQgetResult() read the messages. We just have to fake it - * out about the state of the connection, by setting - * asyncStatus = PGASYNC_BUSY (done above). - */ - - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - /* - * NULL return indicating we have gone to IDLE state is - * expected - */ - if (res) - { - if (res->resultStatus != PGRES_FATAL_ERROR) - appendPQExpBufferStr(&conn->errorMessage, - libpq_gettext("unexpected message from server during startup\n")); - else if (conn->send_appname && - (conn->appname || conn->fbappname)) - { - /* - * If we tried to send application_name, check to see - * if the error is about that --- pre-9.0 servers will - * reject it at this stage of the process. If so, - * close the connection and retry without sending - * application_name. We could possibly get a false - * SQLSTATE match here and retry uselessly, but there - * seems no great harm in that; we'll just get the - * same error again if it's unrelated. - */ - const char *sqlstate; - - sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); - if (sqlstate && - strcmp(sqlstate, ERRCODE_APPNAME_UNKNOWN) == 0) - { - PQclear(res); - conn->send_appname = false; - /* Must drop the old connection */ - pqDropConnection(conn, true); - conn->status = CONNECTION_NEEDED; - goto keep_going; - } - } - - /* - * if the resultStatus is FATAL, then conn->errorMessage - * already has a copy of the error; needn't copy it back. - * But add a newline if it's not there already, since - * postmaster error messages may not have one. - */ - if (conn->errorMessage.len <= 0 || - conn->errorMessage.data[conn->errorMessage.len - 1] != '\n') - appendPQExpBufferChar(&conn->errorMessage, '\n'); - PQclear(res); - goto error_return; - } - - /* We can release the address list now. */ - pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); - conn->addrlist = NULL; - conn->addr_cur = NULL; - - /* Fire up post-connection housekeeping if needed */ - if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) - { - conn->status = CONNECTION_SETENV; - conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND; - conn->next_eo = EnvironmentOptions; - return PGRES_POLLING_WRITING; - } - - /* Otherwise, we are open for business! */ - conn->status = CONNECTION_OK; - return PGRES_POLLING_OK; - } - - case CONNECTION_SETENV: - - /* - * Do post-connection housekeeping (only needed in protocol 2.0). - * - * We pretend that the connection is OK for the duration of these - * queries. - */ - conn->status = CONNECTION_OK; - - switch (pqSetenvPoll(conn)) - { - case PGRES_POLLING_OK: /* Success */ - break; - - case PGRES_POLLING_READING: /* Still going */ - conn->status = CONNECTION_SETENV; - return PGRES_POLLING_READING; - - case PGRES_POLLING_WRITING: /* Still going */ - conn->status = CONNECTION_SETENV; - return PGRES_POLLING_WRITING; - - default: - goto error_return; - } - - /* We are open for business! */ - conn->status = CONNECTION_OK; - return PGRES_POLLING_OK; - - default: - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid connection state %d, " - "probably indicative of memory corruption\n"), - conn->status); - goto error_return; - } - - /* Unreachable */ - -error_return: - - dot_pg_pass_warning(conn); - - /* - * We used to close the socket at this point, but that makes it awkward - * for those above us if they wish to remove this socket from their own - * records (an fd_set for example). We'll just have this socket closed - * when PQfinish is called (which is compulsory even after an error, since - * the connection structure must be freed). - */ - conn->status = CONNECTION_BAD; - return PGRES_POLLING_FAILED; -} - - -/* - * internal_ping - * Determine if a server is running and if we can connect to it. - * - * The argument is a connection that's been started, but not completed. - */ -static PGPing -internal_ping(PGconn *conn) -{ - /* Say "no attempt" if we never got to PQconnectPoll */ - if (!conn || !conn->options_valid) - return PQPING_NO_ATTEMPT; - - /* Attempt to complete the connection */ - if (conn->status != CONNECTION_BAD) - (void) connectDBComplete(conn); - - /* Definitely OK if we succeeded */ - if (conn->status != CONNECTION_BAD) - return PQPING_OK; - - /* - * Here begins the interesting part of "ping": determine the cause of the - * failure in sufficient detail to decide what to return. We do not want - * to report that the server is not up just because we didn't have a valid - * password, for example. In fact, any sort of authentication request - * implies the server is up. (We need this check since the libpq side of - * things might have pulled the plug on the connection before getting an - * error as such from the postmaster.) - */ - if (conn->auth_req_received) - return PQPING_OK; - - /* - * If we failed to get any ERROR response from the postmaster, report - * PQPING_NO_RESPONSE. This result could be somewhat misleading for a - * pre-7.4 server, since it won't send back a SQLSTATE, but those are long - * out of support. Another corner case where the server could return a - * failure without a SQLSTATE is fork failure, but NO_RESPONSE isn't - * totally unreasonable for that anyway. We expect that every other - * failure case in a modern server will produce a report with a SQLSTATE. - * - * NOTE: whenever we get around to making libpq generate SQLSTATEs for - * client-side errors, we should either not store those into - * last_sqlstate, or add an extra flag so we can tell client-side errors - * apart from server-side ones. - */ - if (strlen(conn->last_sqlstate) != 5) - return PQPING_NO_RESPONSE; - - /* - * Report PQPING_REJECT if server says it's not accepting connections. (We - * distinguish this case mainly for the convenience of pg_ctl.) - */ - if (strcmp(conn->last_sqlstate, ERRCODE_CANNOT_CONNECT_NOW) == 0) - return PQPING_REJECT; - - /* - * Any other SQLSTATE can be taken to indicate that the server is up. - * Presumably it didn't like our username, password, or database name; or - * perhaps it had some transient failure, but that should not be taken as - * meaning "it's down". - */ - return PQPING_OK; -} - - -/* - * makeEmptyPGconn - * - create a PGconn data structure with (as yet) no interesting data - */ -static PGconn * -makeEmptyPGconn(void) -{ - PGconn *conn; - -#ifdef WIN32 - - /* - * Make sure socket support is up and running. - */ - WSADATA wsaData; - - if (WSAStartup(MAKEWORD(1, 1), &wsaData)) - return NULL; - WSASetLastError(0); -#endif - - conn = (PGconn *) malloc(sizeof(PGconn)); - if (conn == NULL) - { -#ifdef WIN32 - WSACleanup(); -#endif - return conn; - } - - /* Zero all pointers and booleans */ - MemSet(conn, 0, sizeof(PGconn)); - - /* install default notice hooks */ - conn->noticeHooks.noticeRec = defaultNoticeReceiver; - conn->noticeHooks.noticeProc = defaultNoticeProcessor; - - conn->status = CONNECTION_BAD; - conn->asyncStatus = PGASYNC_IDLE; - conn->xactStatus = PQTRANS_IDLE; - conn->options_valid = false; - conn->nonblocking = false; - conn->setenv_state = SETENV_STATE_IDLE; - conn->client_encoding = PG_SQL_ASCII; - conn->std_strings = false; /* unless server says differently */ - conn->verbosity = PQERRORS_DEFAULT; - conn->show_context = PQSHOW_CONTEXT_ERRORS; - conn->sock = PGINVALID_SOCKET; - conn->auth_req_received = false; - conn->password_needed = false; - conn->dot_pgpass_used = false; -#ifdef USE_SSL - conn->allow_ssl_try = true; - conn->wait_ssl_try = false; - conn->ssl_in_use = false; -#endif - - /* - * We try to send at least 8K at a time, which is the usual size of pipe - * buffers on Unix systems. That way, when we are sending a large amount - * of data, we avoid incurring extra kernel context swaps for partial - * bufferloads. The output buffer is initially made 16K in size, and we - * try to dump it after accumulating 8K. - * - * With the same goal of minimizing context swaps, the input buffer will - * be enlarged anytime it has less than 8K free, so we initially allocate - * twice that. - */ - conn->inBufSize = 16 * 1024; - conn->inBuffer = (char *) malloc(conn->inBufSize); - conn->outBufSize = 16 * 1024; - conn->outBuffer = (char *) malloc(conn->outBufSize); - conn->rowBufLen = 32; - conn->rowBuf = (PGdataValue *) malloc(conn->rowBufLen * sizeof(PGdataValue)); - initPQExpBuffer(&conn->errorMessage); - initPQExpBuffer(&conn->workBuffer); - - if (conn->inBuffer == NULL || - conn->outBuffer == NULL || - conn->rowBuf == NULL || - PQExpBufferBroken(&conn->errorMessage) || - PQExpBufferBroken(&conn->workBuffer)) - { - /* out of memory already :-( */ - freePGconn(conn); - conn = NULL; - } - - return conn; -} - -/* - * freePGconn - * - free an idle (closed) PGconn data structure - * - * NOTE: this should not overlap any functionality with closePGconn(). - * Clearing/resetting of transient state belongs there; what we do here is - * release data that is to be held for the life of the PGconn structure. - * If a value ought to be cleared/freed during PQreset(), do it there not here. - */ -static void -freePGconn(PGconn *conn) -{ - int i; - - /* let any event procs clean up their state data */ - for (i = 0; i < conn->nEvents; i++) - { - PGEventConnDestroy evt; - - evt.conn = conn; - (void) conn->events[i].proc(PGEVT_CONNDESTROY, &evt, - conn->events[i].passThrough); - free(conn->events[i].name); - } - - if (conn->client_encoding_initial) - free(conn->client_encoding_initial); - if (conn->events) - free(conn->events); - if (conn->pghost) - free(conn->pghost); - if (conn->pghostaddr) - free(conn->pghostaddr); - if (conn->pgport) - free(conn->pgport); - if (conn->pgunixsocket) - free(conn->pgunixsocket); - if (conn->pgtty) - free(conn->pgtty); - if (conn->connect_timeout) - free(conn->connect_timeout); - if (conn->pgoptions) - free(conn->pgoptions); - if (conn->appname) - free(conn->appname); - if (conn->fbappname) - free(conn->fbappname); - if (conn->dbName) - free(conn->dbName); - if (conn->replication) - free(conn->replication); - if (conn->pguser) - free(conn->pguser); - if (conn->pgpass) - free(conn->pgpass); - if (conn->keepalives) - free(conn->keepalives); - if (conn->keepalives_idle) - free(conn->keepalives_idle); - if (conn->keepalives_interval) - free(conn->keepalives_interval); - if (conn->keepalives_count) - free(conn->keepalives_count); - if (conn->sslmode) - free(conn->sslmode); - if (conn->sslcert) - free(conn->sslcert); - if (conn->sslkey) - free(conn->sslkey); - if (conn->sslrootcert) - free(conn->sslrootcert); - if (conn->sslcrl) - free(conn->sslcrl); - if (conn->sslcompression) - free(conn->sslcompression); - if (conn->requirepeer) - free(conn->requirepeer); -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - if (conn->krbsrvname) - free(conn->krbsrvname); -#endif -#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) - if (conn->gsslib) - free(conn->gsslib); -#endif - /* Note that conn->Pfdebug is not ours to close or free */ - if (conn->last_query) - free(conn->last_query); - if (conn->inBuffer) - free(conn->inBuffer); - if (conn->outBuffer) - free(conn->outBuffer); - if (conn->rowBuf) - free(conn->rowBuf); - termPQExpBuffer(&conn->errorMessage); - termPQExpBuffer(&conn->workBuffer); - - free(conn); - -#ifdef WIN32 - WSACleanup(); -#endif -} - -/* - * closePGconn - * - properly close a connection to the backend - * - * This should reset or release all transient state, but NOT the connection - * parameters. On exit, the PGconn should be in condition to start a fresh - * connection with the same parameters (see PQreset()). - */ -static void -closePGconn(PGconn *conn) -{ - PGnotify *notify; - pgParameterStatus *pstatus; - - /* - * Note that the protocol doesn't allow us to send Terminate messages - * during the startup phase. - */ - if (conn->sock != PGINVALID_SOCKET && conn->status == CONNECTION_OK) - { - /* - * Try to send "close connection" message to backend. Ignore any - * error. - */ - pqPutMsgStart('X', false, conn); - pqPutMsgEnd(conn); - (void) pqFlush(conn); - } - - /* - * Must reset the blocking status so a possible reconnect will work. - * - * Don't call PQsetnonblocking() because it will fail if it's unable to - * flush the connection. - */ - conn->nonblocking = FALSE; - - /* - * Close the connection, reset all transient state, flush I/O buffers. - */ - pqDropConnection(conn, true); - conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just - * absent */ - conn->asyncStatus = PGASYNC_IDLE; - pqClearAsyncResult(conn); /* deallocate result */ - resetPQExpBuffer(&conn->errorMessage); - pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist); - conn->addrlist = NULL; - conn->addr_cur = NULL; - notify = conn->notifyHead; - while (notify != NULL) - { - PGnotify *prev = notify; - - notify = notify->next; - free(prev); - } - conn->notifyHead = conn->notifyTail = NULL; - pstatus = conn->pstatus; - while (pstatus != NULL) - { - pgParameterStatus *prev = pstatus; - - pstatus = pstatus->next; - free(prev); - } - conn->pstatus = NULL; - if (conn->lobjfuncs) - free(conn->lobjfuncs); - conn->lobjfuncs = NULL; -} - -/* - * PQfinish: properly close a connection to the backend. Also frees - * the PGconn data structure so it shouldn't be re-used after this. - */ -void -PQfinish(PGconn *conn) -{ - if (conn) - { - closePGconn(conn); - freePGconn(conn); - } -} - -/* - * PQreset: resets the connection to the backend by closing the - * existing connection and creating a new one. - */ -void -PQreset(PGconn *conn) -{ - if (conn) - { - closePGconn(conn); - - if (connectDBStart(conn) && connectDBComplete(conn)) - { - /* - * Notify event procs of successful reset. We treat an event proc - * failure as disabling the connection ... good idea? - */ - int i; - - for (i = 0; i < conn->nEvents; i++) - { - PGEventConnReset evt; - - evt.conn = conn; - if (!conn->events[i].proc(PGEVT_CONNRESET, &evt, - conn->events[i].passThrough)) - { - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), - conn->events[i].name); - break; - } - } - } - } -} - - -/* - * PQresetStart: - * resets the connection to the backend - * closes the existing connection and makes a new one - * Returns 1 on success, 0 on failure. - */ -int -PQresetStart(PGconn *conn) -{ - if (conn) - { - closePGconn(conn); - - return connectDBStart(conn); - } - - return 0; -} - - -/* - * PQresetPoll: - * resets the connection to the backend - * closes the existing connection and makes a new one - */ -PostgresPollingStatusType -PQresetPoll(PGconn *conn) -{ - if (conn) - { - PostgresPollingStatusType status = PQconnectPoll(conn); - - if (status == PGRES_POLLING_OK) - { - /* - * Notify event procs of successful reset. We treat an event proc - * failure as disabling the connection ... good idea? - */ - int i; - - for (i = 0; i < conn->nEvents; i++) - { - PGEventConnReset evt; - - evt.conn = conn; - if (!conn->events[i].proc(PGEVT_CONNRESET, &evt, - conn->events[i].passThrough)) - { - conn->status = CONNECTION_BAD; - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PGEventProc \"%s\" failed during PGEVT_CONNRESET event\n"), - conn->events[i].name); - return PGRES_POLLING_FAILED; - } - } - } - - return status; - } - - return PGRES_POLLING_FAILED; -} - -/* - * PQgetCancel: get a PGcancel structure corresponding to a connection. - * - * A copy is needed to be able to cancel a running query from a different - * thread. If the same structure is used all structure members would have - * to be individually locked (if the entire structure was locked, it would - * be impossible to cancel a synchronous query because the structure would - * have to stay locked for the duration of the query). - */ -PGcancel * -PQgetCancel(PGconn *conn) -{ - PGcancel *cancel; - - if (!conn) - return NULL; - - if (conn->sock == PGINVALID_SOCKET) - return NULL; - - cancel = malloc(sizeof(PGcancel)); - if (cancel == NULL) - return NULL; - - memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr)); - cancel->be_pid = conn->be_pid; - cancel->be_key = conn->be_key; - - return cancel; -} - -/* PQfreeCancel: free a cancel structure */ -void -PQfreeCancel(PGcancel *cancel) -{ - if (cancel) - free(cancel); -} - - -/* - * PQcancel and PQrequestCancel: attempt to request cancellation of the - * current operation. - * - * The return value is TRUE if the cancel request was successfully - * dispatched, FALSE if not (in which case an error message is available). - * Note: successful dispatch is no guarantee that there will be any effect at - * the backend. The application must read the operation result as usual. - * - * CAUTION: we want this routine to be safely callable from a signal handler - * (for example, an application might want to call it in a SIGINT handler). - * This means we cannot use any C library routine that might be non-reentrant. - * malloc/free are often non-reentrant, and anything that might call them is - * just as dangerous. We avoid sprintf here for that reason. Building up - * error messages with strcpy/strcat is tedious but should be quite safe. - * We also save/restore errno in case the signal handler support doesn't. - * - * internal_cancel() is an internal helper function to make code-sharing - * between the two versions of the cancel function possible. - */ -static int -internal_cancel(SockAddr *raddr, int be_pid, int be_key, - char *errbuf, int errbufsize) -{ - int save_errno = SOCK_ERRNO; - pgsocket tmpsock = PGINVALID_SOCKET; - char sebuf[256]; - int maxlen; - struct - { - uint32 packetlen; - CancelRequestPacket cp; - } crp; - - /* - * We need to open a temporary connection to the postmaster. Do this with - * only kernel calls. - */ - if ((tmpsock = socket(raddr->addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET) - { - strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize); - goto cancel_errReturn; - } -retry3: - if (connect(tmpsock, (struct sockaddr *) & raddr->addr, - raddr->salen) < 0) - { - if (SOCK_ERRNO == EINTR) - /* Interrupted system call - we'll just try again */ - goto retry3; - strlcpy(errbuf, "PQcancel() -- connect() failed: ", errbufsize); - goto cancel_errReturn; - } - - /* - * We needn't set nonblocking I/O or NODELAY options here. - */ - - /* Create and send the cancel request packet. */ - - crp.packetlen = htonl((uint32) sizeof(crp)); - crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE); - crp.cp.backendPID = htonl(be_pid); - crp.cp.cancelAuthCode = htonl(be_key); - -retry4: - if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp)) - { - if (SOCK_ERRNO == EINTR) - /* Interrupted system call - we'll just try again */ - goto retry4; - strlcpy(errbuf, "PQcancel() -- send() failed: ", errbufsize); - goto cancel_errReturn; - } - - /* - * Wait for the postmaster to close the connection, which indicates that - * it's processed the request. Without this delay, we might issue another - * command only to find that our cancel zaps that command instead of the - * one we thought we were canceling. Note we don't actually expect this - * read to obtain any data, we are just waiting for EOF to be signaled. - */ -retry5: - if (recv(tmpsock, (char *) &crp, 1, 0) < 0) - { - if (SOCK_ERRNO == EINTR) - /* Interrupted system call - we'll just try again */ - goto retry5; - /* we ignore other error conditions */ - } - - /* All done */ - closesocket(tmpsock); - SOCK_ERRNO_SET(save_errno); - return TRUE; - -cancel_errReturn: - - /* - * Make sure we don't overflow the error buffer. Leave space for the \n at - * the end, and for the terminating zero. - */ - maxlen = errbufsize - strlen(errbuf) - 2; - if (maxlen >= 0) - { - strncat(errbuf, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)), - maxlen); - strcat(errbuf, "\n"); - } - if (tmpsock != PGINVALID_SOCKET) - closesocket(tmpsock); - SOCK_ERRNO_SET(save_errno); - return FALSE; -} - -/* - * PQcancel: request query cancel - * - * Returns TRUE if able to send the cancel request, FALSE if not. - * - * On failure, an error message is stored in *errbuf, which must be of size - * errbufsize (recommended size is 256 bytes). *errbuf is not changed on - * success return. - */ -int -PQcancel(PGcancel *cancel, char *errbuf, int errbufsize) -{ - if (!cancel) - { - strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize); - return FALSE; - } - - return internal_cancel(&cancel->raddr, cancel->be_pid, cancel->be_key, - errbuf, errbufsize); -} - -/* - * PQrequestCancel: old, not thread-safe function for requesting query cancel - * - * Returns TRUE if able to send the cancel request, FALSE if not. - * - * On failure, the error message is saved in conn->errorMessage; this means - * that this can't be used when there might be other active operations on - * the connection object. - * - * NOTE: error messages will be cut off at the current size of the - * error message buffer, since we dare not try to expand conn->errorMessage! - */ -int -PQrequestCancel(PGconn *conn) -{ - int r; - - /* Check we have an open connection */ - if (!conn) - return FALSE; - - if (conn->sock == PGINVALID_SOCKET) - { - strlcpy(conn->errorMessage.data, - "PQrequestCancel() -- connection is not open\n", - conn->errorMessage.maxlen); - conn->errorMessage.len = strlen(conn->errorMessage.data); - - return FALSE; - } - - r = internal_cancel(&conn->raddr, conn->be_pid, conn->be_key, - conn->errorMessage.data, conn->errorMessage.maxlen); - - if (!r) - conn->errorMessage.len = strlen(conn->errorMessage.data); - - return r; -} - - -/* - * pqPacketSend() -- convenience routine to send a message to server. - * - * pack_type: the single-byte message type code. (Pass zero for startup - * packets, which have no message type code.) - * - * buf, buf_len: contents of message. The given length includes only what - * is in buf; the message type and message length fields are added here. - * - * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise. - * SIDE_EFFECTS: may block. - * - * Note: all messages sent with this routine have a length word, whether - * it's protocol 2.0 or 3.0. - */ -int -pqPacketSend(PGconn *conn, char pack_type, - const void *buf, size_t buf_len) -{ - /* Start the message. */ - if (pqPutMsgStart(pack_type, true, conn)) - return STATUS_ERROR; - - /* Send the message body. */ - if (pqPutnchar(buf, buf_len, conn)) - return STATUS_ERROR; - - /* Finish the message. */ - if (pqPutMsgEnd(conn)) - return STATUS_ERROR; - - /* Flush to ensure backend gets it. */ - if (pqFlush(conn)) - return STATUS_ERROR; - - return STATUS_OK; -} - -#ifdef USE_LDAP - -#define LDAP_URL "ldap://" -#define LDAP_DEF_PORT 389 -#define PGLDAP_TIMEOUT 2 - -#define ld_is_sp_tab(x) ((x) == ' ' || (x) == '\t') -#define ld_is_nl_cr(x) ((x) == '\r' || (x) == '\n') - - -/* - * ldapServiceLookup - * - * Search the LDAP URL passed as first argument, treat the result as a - * string of connection options that are parsed and added to the array of - * options passed as second argument. - * - * LDAP URLs must conform to RFC 1959 without escape sequences. - * ldap://host:port/dn?attributes?scope?filter?extensions - * - * Returns - * 0 if the lookup was successful, - * 1 if the connection to the LDAP server could be established but - * the search was unsuccessful, - * 2 if a connection could not be established, and - * 3 if a fatal error occurred. - * - * An error message is returned in the third argument for return codes 1 and 3. - */ -static int -ldapServiceLookup(const char *purl, PQconninfoOption *options, - PQExpBuffer errorMessage) -{ - int port = LDAP_DEF_PORT, - scope, - rc, - size, - state, - oldstate, - i; -#ifndef WIN32 - int msgid; -#endif - bool found_keyword; - char *url, - *hostname, - *portstr, - *endptr, - *dn, - *scopestr, - *filter, - *result, - *p, - *p1 = NULL, - *optname = NULL, - *optval = NULL; - char *attrs[2] = {NULL, NULL}; - LDAP *ld = NULL; - LDAPMessage *res, - *entry; - struct berval **values; - LDAP_TIMEVAL time = {PGLDAP_TIMEOUT, 0}; - - if ((url = strdup(purl)) == NULL) - { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); - return 3; - } - - /* - * Parse URL components, check for correctness. Basically, url has '\0' - * placed at component boundaries and variables are pointed at each - * component. - */ - - if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid LDAP URL \"%s\": scheme must be ldap://\n"), purl); - free(url); - return 3; - } - - /* hostname */ - hostname = url + strlen(LDAP_URL); - if (*hostname == '/') /* no hostname? */ - hostname = DefaultHost; /* the default */ - - /* dn, "distinguished name" */ - p = strchr(url + strlen(LDAP_URL), '/'); - if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?') - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "invalid LDAP URL \"%s\": missing distinguished name\n"), purl); - free(url); - return 3; - } - *p = '\0'; /* terminate hostname */ - dn = p + 1; - - /* attribute */ - if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); - free(url); - return 3; - } - *p = '\0'; - attrs[0] = p + 1; - - /* scope */ - if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') - { - printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); - free(url); - return 3; - } - *p = '\0'; - scopestr = p + 1; - - /* filter */ - if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') - { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid LDAP URL \"%s\": no filter\n"), purl); - free(url); - return 3; - } - *p = '\0'; - filter = p + 1; - if ((p = strchr(filter, '?')) != NULL) - *p = '\0'; - - /* port number? */ - if ((p1 = strchr(hostname, ':')) != NULL) - { - long lport; - - *p1 = '\0'; - portstr = p1 + 1; - errno = 0; - lport = strtol(portstr, &endptr, 10); - if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535) - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "invalid LDAP URL \"%s\": invalid port number\n"), purl); - free(url); - return 3; - } - port = (int) lport; - } - - /* Allow only one attribute */ - if (strchr(attrs[0], ',') != NULL) - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "invalid LDAP URL \"%s\": must have exactly one attribute\n"), purl); - free(url); - return 3; - } - - /* set scope */ - if (pg_strcasecmp(scopestr, "base") == 0) - scope = LDAP_SCOPE_BASE; - else if (pg_strcasecmp(scopestr, "one") == 0) - scope = LDAP_SCOPE_ONELEVEL; - else if (pg_strcasecmp(scopestr, "sub") == 0) - scope = LDAP_SCOPE_SUBTREE; - else - { - printfPQExpBuffer(errorMessage, libpq_gettext("invalid LDAP URL \"%s\": must have search scope (base/one/sub)\n"), purl); - free(url); - return 3; - } - - /* initialize LDAP structure */ - if ((ld = ldap_init(hostname, port)) == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("could not create LDAP structure\n")); - free(url); - return 3; - } - - /* - * Perform an explicit anonymous bind. - * - * LDAP does not require that an anonymous bind is performed explicitly, - * but we want to distinguish between the case where LDAP bind does not - * succeed within PGLDAP_TIMEOUT seconds (return 2 to continue parsing the - * service control file) and the case where querying the LDAP server fails - * (return 1 to end parsing). - * - * Unfortunately there is no way of setting a timeout that works for both - * Windows and OpenLDAP. - */ -#ifdef WIN32 - /* the nonstandard ldap_connect function performs an anonymous bind */ - if (ldap_connect(ld, &time) != LDAP_SUCCESS) - { - /* error or timeout in ldap_connect */ - free(url); - ldap_unbind(ld); - return 2; - } -#else /* !WIN32 */ - /* in OpenLDAP, use the LDAP_OPT_NETWORK_TIMEOUT option */ - if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS) - { - free(url); - ldap_unbind(ld); - return 3; - } - - /* anonymous bind */ - if ((msgid = ldap_simple_bind(ld, NULL, NULL)) == -1) - { - /* error or network timeout */ - free(url); - ldap_unbind(ld); - return 2; - } - - /* wait some time for the connection to succeed */ - res = NULL; - if ((rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res)) == -1 || - res == NULL) - { - /* error or timeout */ - if (res != NULL) - ldap_msgfree(res); - free(url); - ldap_unbind(ld); - return 2; - } - ldap_msgfree(res); - - /* reset timeout */ - time.tv_sec = -1; - if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS) - { - free(url); - ldap_unbind(ld); - return 3; - } -#endif /* WIN32 */ - - /* search */ - res = NULL; - if ((rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res)) - != LDAP_SUCCESS) - { - if (res != NULL) - ldap_msgfree(res); - printfPQExpBuffer(errorMessage, - libpq_gettext("lookup on LDAP server failed: %s\n"), - ldap_err2string(rc)); - ldap_unbind(ld); - free(url); - return 1; - } - - /* complain if there was not exactly one result */ - if ((rc = ldap_count_entries(ld, res)) != 1) - { - printfPQExpBuffer(errorMessage, - rc ? libpq_gettext("more than one entry found on LDAP lookup\n") - : libpq_gettext("no entry found on LDAP lookup\n")); - ldap_msgfree(res); - ldap_unbind(ld); - free(url); - return 1; - } - - /* get entry */ - if ((entry = ldap_first_entry(ld, res)) == NULL) - { - /* should never happen */ - printfPQExpBuffer(errorMessage, - libpq_gettext("no entry found on LDAP lookup\n")); - ldap_msgfree(res); - ldap_unbind(ld); - free(url); - return 1; - } - - /* get values */ - if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); - ldap_msgfree(res); - ldap_unbind(ld); - free(url); - return 1; - } - - ldap_msgfree(res); - free(url); - - if (values[0] == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("attribute has no values on LDAP lookup\n")); - ldap_value_free_len(values); - ldap_unbind(ld); - return 1; - } - - /* concatenate values into a single string with newline terminators */ - size = 1; /* for the trailing null */ - for (i = 0; values[i] != NULL; i++) - size += values[i]->bv_len + 1; - if ((result = malloc(size)) == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - ldap_value_free_len(values); - ldap_unbind(ld); - return 3; - } - p = result; - for (i = 0; values[i] != NULL; i++) - { - memcpy(p, values[i]->bv_val, values[i]->bv_len); - p += values[i]->bv_len; - *(p++) = '\n'; - } - *p = '\0'; - - ldap_value_free_len(values); - ldap_unbind(ld); - - /* parse result string */ - oldstate = state = 0; - for (p = result; *p != '\0'; ++p) - { - switch (state) - { - case 0: /* between entries */ - if (!ld_is_sp_tab(*p) && !ld_is_nl_cr(*p)) - { - optname = p; - state = 1; - } - break; - case 1: /* in option name */ - if (ld_is_sp_tab(*p)) - { - *p = '\0'; - state = 2; - } - else if (ld_is_nl_cr(*p)) - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "missing \"=\" after \"%s\" in connection info string\n"), - optname); - free(result); - return 3; - } - else if (*p == '=') - { - *p = '\0'; - state = 3; - } - break; - case 2: /* after option name */ - if (*p == '=') - { - state = 3; - } - else if (!ld_is_sp_tab(*p)) - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "missing \"=\" after \"%s\" in connection info string\n"), - optname); - free(result); - return 3; - } - break; - case 3: /* before option value */ - if (*p == '\'') - { - optval = p + 1; - p1 = p + 1; - state = 5; - } - else if (ld_is_nl_cr(*p)) - { - optval = optname + strlen(optname); /* empty */ - state = 0; - } - else if (!ld_is_sp_tab(*p)) - { - optval = p; - state = 4; - } - break; - case 4: /* in unquoted option value */ - if (ld_is_sp_tab(*p) || ld_is_nl_cr(*p)) - { - *p = '\0'; - state = 0; - } - break; - case 5: /* in quoted option value */ - if (*p == '\'') - { - *p1 = '\0'; - state = 0; - } - else if (*p == '\\') - state = 6; - else - *(p1++) = *p; - break; - case 6: /* in quoted option value after escape */ - *(p1++) = *p; - state = 5; - break; - } - - if (state == 0 && oldstate != 0) - { - found_keyword = false; - for (i = 0; options[i].keyword; i++) - { - if (strcmp(options[i].keyword, optname) == 0) - { - if (options[i].val == NULL) - { - options[i].val = strdup(optval); - if (!options[i].val) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - free(result); - return 3; - } - } - found_keyword = true; - break; - } - } - if (!found_keyword) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid connection option \"%s\"\n"), - optname); - free(result); - return 1; - } - optname = NULL; - optval = NULL; - } - oldstate = state; - } - - free(result); - - if (state == 5 || state == 6) - { - printfPQExpBuffer(errorMessage, libpq_gettext( - "unterminated quoted string in connection info string\n")); - return 3; - } - - return 0; -} - -#endif /* USE_LDAP */ - -#define MAXBUFSIZE 256 - -static int -parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) -{ - const char *service = conninfo_getval(options, "service"); - char serviceFile[MAXPGPATH]; - char *env; - bool group_found = false; - int status; - struct stat stat_buf; - - /* - * We have to special-case the environment variable PGSERVICE here, since - * this is and should be called before inserting environment defaults for - * other connection options. - */ - if (service == NULL) - service = getenv("PGSERVICE"); - - if (service == NULL) - return 0; - - if ((env = getenv("PGSERVICEFILE")) != NULL) - strlcpy(serviceFile, env, sizeof(serviceFile)); - else - { - char homedir[MAXPGPATH]; - - if (!pqGetHomeDirectory(homedir, sizeof(homedir))) - { - printfPQExpBuffer(errorMessage, libpq_gettext("could not get home directory to locate service definition file")); - return 1; - } - snprintf(serviceFile, MAXPGPATH, "%s/%s", homedir, ".pg_service.conf"); - errno = 0; - if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT) - goto next_file; - } - - status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); - if (group_found || status != 0) - return status; - -next_file: - - /* - * This could be used by any application so we can't use the binary - * location to find our config files. - */ - snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf", - getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR); - errno = 0; - if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT) - goto last_file; - - status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); - if (status != 0) - return status; - -last_file: - if (!group_found) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("definition of service \"%s\" not found\n"), service); - return 3; - } - - return 0; -} - -static int -parseServiceFile(const char *serviceFile, - const char *service, - PQconninfoOption *options, - PQExpBuffer errorMessage, - bool *group_found) -{ - int linenr = 0, - i; - FILE *f; - char buf[MAXBUFSIZE], - *line; - - f = fopen(serviceFile, "r"); - if (f == NULL) - { - printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"), - serviceFile); - return 1; - } - - while ((line = fgets(buf, sizeof(buf), f)) != NULL) - { - linenr++; - - if (strlen(line) >= sizeof(buf) - 1) - { - fclose(f); - printfPQExpBuffer(errorMessage, - libpq_gettext("line %d too long in service file \"%s\"\n"), - linenr, - serviceFile); - return 2; - } - - /* ignore EOL at end of line */ - if (strlen(line) && line[strlen(line) - 1] == '\n') - line[strlen(line) - 1] = 0; - - /* ignore leading blanks */ - while (*line && isspace((unsigned char) line[0])) - line++; - - /* ignore comments and empty lines */ - if (strlen(line) == 0 || line[0] == '#') - continue; - - /* Check for right groupname */ - if (line[0] == '[') - { - if (*group_found) - { - /* group info already read */ - fclose(f); - return 0; - } - - if (strncmp(line + 1, service, strlen(service)) == 0 && - line[strlen(service) + 1] == ']') - *group_found = true; - else - *group_found = false; - } - else - { - if (*group_found) - { - /* - * Finally, we are in the right group and can parse the line - */ - char *key, - *val; - bool found_keyword; - -#ifdef USE_LDAP - if (strncmp(line, "ldap", 4) == 0) - { - int rc = ldapServiceLookup(line, options, errorMessage); - - /* if rc = 2, go on reading for fallback */ - switch (rc) - { - case 0: - fclose(f); - return 0; - case 1: - case 3: - fclose(f); - return 3; - case 2: - continue; - } - } -#endif - - key = line; - val = strchr(line, '='); - if (val == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("syntax error in service file \"%s\", line %d\n"), - serviceFile, - linenr); - fclose(f); - return 3; - } - *val++ = '\0'; - - if (strcmp(key, "service") == 0) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("nested service specifications not supported in service file \"%s\", line %d\n"), - serviceFile, - linenr); - fclose(f); - return 3; - } - - /* - * Set the parameter --- but don't override any previous - * explicit setting. - */ - found_keyword = false; - for (i = 0; options[i].keyword; i++) - { - if (strcmp(options[i].keyword, key) == 0) - { - if (options[i].val == NULL) - options[i].val = strdup(val); - if (!options[i].val) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - fclose(f); - return 3; - } - found_keyword = true; - break; - } - } - - if (!found_keyword) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("syntax error in service file \"%s\", line %d\n"), - serviceFile, - linenr); - fclose(f); - return 3; - } - } - } - } - - fclose(f); - - return 0; -} - - -/* - * PQconninfoParse - * - * Parse a string like PQconnectdb() would do and return the - * resulting connection options array. NULL is returned on failure. - * The result contains only options specified directly in the string, - * not any possible default values. - * - * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd - * string on failure (use PQfreemem to free it). In out-of-memory conditions - * both *errmsg and the result could be NULL. - * - * NOTE: the returned array is dynamically allocated and should - * be freed when no longer needed via PQconninfoFree(). - */ -PQconninfoOption * -PQconninfoParse(const char *conninfo, char **errmsg) -{ - PQExpBufferData errorBuf; - PQconninfoOption *connOptions; - - if (errmsg) - *errmsg = NULL; /* default */ - initPQExpBuffer(&errorBuf); - if (PQExpBufferDataBroken(errorBuf)) - return NULL; /* out of memory already :-( */ - connOptions = parse_connection_string(conninfo, &errorBuf, false); - if (connOptions == NULL && errmsg) - *errmsg = errorBuf.data; - else - termPQExpBuffer(&errorBuf); - return connOptions; -} - -/* - * Build a working copy of the constant PQconninfoOptions array. - */ -static PQconninfoOption * -conninfo_init(PQExpBuffer errorMessage) -{ - PQconninfoOption *options; - PQconninfoOption *opt_dest; - const internalPQconninfoOption *cur_opt; - - /* - * Get enough memory for all options in PQconninfoOptions, even if some - * end up being filtered out. - */ - options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0])); - if (options == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - return NULL; - } - opt_dest = options; - - for (cur_opt = PQconninfoOptions; cur_opt->keyword; cur_opt++) - { - /* Only copy the public part of the struct, not the full internal */ - memcpy(opt_dest, cur_opt, sizeof(PQconninfoOption)); - opt_dest++; - } - MemSet(opt_dest, 0, sizeof(PQconninfoOption)); - - return options; -} - -/* - * Connection string parser - * - * Returns a malloc'd PQconninfoOption array, if parsing is successful. - * Otherwise, NULL is returned and an error message is left in errorMessage. - * - * If use_defaults is TRUE, default values are filled in (from a service file, - * environment variables, etc). - */ -static PQconninfoOption * -parse_connection_string(const char *connstr, PQExpBuffer errorMessage, - bool use_defaults) -{ - /* Parse as URI if connection string matches URI prefix */ - if (uri_prefix_length(connstr) != 0) - return conninfo_uri_parse(connstr, errorMessage, use_defaults); - - /* Parse as default otherwise */ - return conninfo_parse(connstr, errorMessage, use_defaults); -} - -/* - * Checks if connection string starts with either of the valid URI prefix - * designators. - * - * Returns the URI prefix length, 0 if the string doesn't contain a URI prefix. - * - * XXX this is duplicated in psql/common.c. - */ -static int -uri_prefix_length(const char *connstr) -{ - if (strncmp(connstr, uri_designator, - sizeof(uri_designator) - 1) == 0) - return sizeof(uri_designator) - 1; - - if (strncmp(connstr, short_uri_designator, - sizeof(short_uri_designator) - 1) == 0) - return sizeof(short_uri_designator) - 1; - - return 0; -} - -/* - * Recognized connection string either starts with a valid URI prefix or - * contains a "=" in it. - * - * Must be consistent with parse_connection_string: anything for which this - * returns true should at least look like it's parseable by that routine. - * - * XXX this is duplicated in psql/common.c - */ -static bool -recognized_connection_string(const char *connstr) -{ - return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL; -} - -/* - * Subroutine for parse_connection_string - * - * Deal with a string containing key=value pairs. - */ -static PQconninfoOption * -conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, - bool use_defaults) -{ - char *pname; - char *pval; - char *buf; - char *cp; - char *cp2; - PQconninfoOption *options; - - /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); - if (options == NULL) - return NULL; - - /* Need a modifiable copy of the input string */ - if ((buf = strdup(conninfo)) == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - PQconninfoFree(options); - return NULL; - } - cp = buf; - - while (*cp) - { - /* Skip blanks before the parameter name */ - if (isspace((unsigned char) *cp)) - { - cp++; - continue; - } - - /* Get the parameter name */ - pname = cp; - while (*cp) - { - if (*cp == '=') - break; - if (isspace((unsigned char) *cp)) - { - *cp++ = '\0'; - while (*cp) - { - if (!isspace((unsigned char) *cp)) - break; - cp++; - } - break; - } - cp++; - } - - /* Check that there is a following '=' */ - if (*cp != '=') - { - printfPQExpBuffer(errorMessage, - libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"), - pname); - PQconninfoFree(options); - free(buf); - return NULL; - } - *cp++ = '\0'; - - /* Skip blanks after the '=' */ - while (*cp) - { - if (!isspace((unsigned char) *cp)) - break; - cp++; - } - - /* Get the parameter value */ - pval = cp; - - if (*cp != '\'') - { - cp2 = pval; - while (*cp) - { - if (isspace((unsigned char) *cp)) - { - *cp++ = '\0'; - break; - } - if (*cp == '\\') - { - cp++; - if (*cp != '\0') - *cp2++ = *cp++; - } - else - *cp2++ = *cp++; - } - *cp2 = '\0'; - } - else - { - cp2 = pval; - cp++; - for (;;) - { - if (*cp == '\0') - { - printfPQExpBuffer(errorMessage, - libpq_gettext("unterminated quoted string in connection info string\n")); - PQconninfoFree(options); - free(buf); - return NULL; - } - if (*cp == '\\') - { - cp++; - if (*cp != '\0') - *cp2++ = *cp++; - continue; - } - if (*cp == '\'') - { - *cp2 = '\0'; - cp++; - break; - } - *cp2++ = *cp++; - } - } - - /* - * Now that we have the name and the value, store the record. - */ - if (!conninfo_storeval(options, pname, pval, errorMessage, false, false)) - { - PQconninfoFree(options); - free(buf); - return NULL; - } - } - - /* Done with the modifiable input string */ - free(buf); - - /* - * Add in defaults if the caller wants that. - */ - if (use_defaults) - { - if (!conninfo_add_defaults(options, errorMessage)) - { - PQconninfoFree(options); - return NULL; - } - } - - return options; -} - -/* - * Conninfo array parser routine - * - * If successful, a malloc'd PQconninfoOption array is returned. - * If not successful, NULL is returned and an error message is - * left in errorMessage. - * Defaults are supplied (from a service file, environment variables, etc) - * for unspecified options, but only if use_defaults is TRUE. - * - * If expand_dbname is non-zero, and the value passed for the first occurrence - * of "dbname" keyword is a connection string (as indicated by - * recognized_connection_string) then parse and process it, overriding any - * previously processed conflicting keywords. Subsequent keywords will take - * precedence, however. In-tree programs generally specify expand_dbname=true, - * so command-line arguments naming a database can use a connection string. - * Some code acquires arbitrary database names from known-literal sources like - * PQdb(), PQconninfoParse() and pg_database.datname. When connecting to such - * a database, in-tree code first wraps the name in a connection string. - */ -static PQconninfoOption * -conninfo_array_parse(const char *const * keywords, const char *const * values, - PQExpBuffer errorMessage, bool use_defaults, - int expand_dbname) -{ - PQconninfoOption *options; - PQconninfoOption *dbname_options = NULL; - PQconninfoOption *option; - int i = 0; - - /* - * If expand_dbname is non-zero, check keyword "dbname" to see if val is - * actually a recognized connection string. - */ - while (expand_dbname && keywords[i]) - { - const char *pname = keywords[i]; - const char *pvalue = values[i]; - - /* first find "dbname" if any */ - if (strcmp(pname, "dbname") == 0 && pvalue) - { - /* - * If value is a connection string, parse it, but do not use - * defaults here -- those get picked up later. We only want to - * override for those parameters actually passed. - */ - if (recognized_connection_string(pvalue)) - { - dbname_options = parse_connection_string(pvalue, errorMessage, false); - if (dbname_options == NULL) - return NULL; - } - break; - } - ++i; - } - - /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); - if (options == NULL) - { - PQconninfoFree(dbname_options); - return NULL; - } - - /* Parse the keywords/values arrays */ - i = 0; - while (keywords[i]) - { - const char *pname = keywords[i]; - const char *pvalue = values[i]; - - if (pvalue != NULL && pvalue[0] != '\0') - { - /* Search for the param record */ - for (option = options; option->keyword != NULL; option++) - { - if (strcmp(option->keyword, pname) == 0) - break; - } - - /* Check for invalid connection option */ - if (option->keyword == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid connection option \"%s\"\n"), - pname); - PQconninfoFree(options); - PQconninfoFree(dbname_options); - return NULL; - } - - /* - * If we are on the first dbname parameter, and we have a parsed - * connection string, copy those parameters across, overriding any - * existing previous settings. - */ - if (strcmp(pname, "dbname") == 0 && dbname_options) - { - PQconninfoOption *str_option; - - for (str_option = dbname_options; str_option->keyword != NULL; str_option++) - { - if (str_option->val != NULL) - { - int k; - - for (k = 0; options[k].keyword; k++) - { - if (strcmp(options[k].keyword, str_option->keyword) == 0) - { - if (options[k].val) - free(options[k].val); - options[k].val = strdup(str_option->val); - if (!options[k].val) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - PQconninfoFree(options); - PQconninfoFree(dbname_options); - return NULL; - } - break; - } - } - } - } - - /* - * Forget the parsed connection string, so that any subsequent - * dbname parameters will not be expanded. - */ - PQconninfoFree(dbname_options); - dbname_options = NULL; - } - else - { - /* - * Store the value, overriding previous settings - */ - if (option->val) - free(option->val); - option->val = strdup(pvalue); - if (!option->val) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - PQconninfoFree(options); - PQconninfoFree(dbname_options); - return NULL; - } - } - } - ++i; - } - PQconninfoFree(dbname_options); - - /* - * Add in defaults if the caller wants that. - */ - if (use_defaults) - { - if (!conninfo_add_defaults(options, errorMessage)) - { - PQconninfoFree(options); - return NULL; - } - } - - return options; -} - -/* - * Add the default values for any unspecified options to the connection - * options array. - * - * Defaults are obtained from a service file, environment variables, etc. - * - * Returns TRUE if successful, otherwise FALSE; errorMessage, if supplied, - * is filled in upon failure. Note that failure to locate a default value - * is not an error condition here --- we just leave the option's value as - * NULL. - */ -static bool -conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage) -{ - PQconninfoOption *option; - char *tmp; - - /* - * If there's a service spec, use it to obtain any not-explicitly-given - * parameters. Ignore error if no error message buffer is passed because - * there is no way to pass back the failure message. - */ - if (parseServiceInfo(options, errorMessage) != 0 && errorMessage) - return false; - - /* - * Get the fallback resources for parameters not specified in the conninfo - * string nor the service. - */ - for (option = options; option->keyword != NULL; option++) - { - if (option->val != NULL) - continue; /* Value was in conninfo or service */ - - /* - * Try to get the environment variable fallback - */ - if (option->envvar != NULL) - { - if ((tmp = getenv(option->envvar)) != NULL) - { - option->val = strdup(tmp); - if (!option->val) - { - if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - continue; - } - } - - /* - * Interpret the deprecated PGREQUIRESSL environment variable. Per - * tradition, translate values starting with "1" to sslmode=require, - * and ignore other values. Given both PGREQUIRESSL=1 and PGSSLMODE, - * PGSSLMODE takes precedence; the opposite was true before v9.3. - */ - if (strcmp(option->keyword, "sslmode") == 0) - { - const char *requiresslenv = getenv("PGREQUIRESSL"); - - if (requiresslenv != NULL && requiresslenv[0] == '1') - { - option->val = strdup("require"); - if (!option->val) - { - if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - continue; - } - } - - /* - * No environment variable specified or the variable isn't set - try - * compiled-in default - */ - if (option->compiled != NULL) - { - option->val = strdup(option->compiled); - if (!option->val) - { - if (errorMessage) - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - continue; - } - - /* - * Special handling for "user" option. Note that if pg_fe_getauthname - * fails, we just leave the value as NULL; there's no need for this to - * be an error condition if the caller provides a user name. The only - * reason we do this now at all is so that callers of PQconndefaults - * will see a correct default (barring error, of course). - */ - if (strcmp(option->keyword, "user") == 0) - { - option->val = pg_fe_getauthname(NULL); - continue; - } - } - - return true; -} - -/* - * Subroutine for parse_connection_string - * - * Deal with a URI connection string. - */ -static PQconninfoOption * -conninfo_uri_parse(const char *uri, PQExpBuffer errorMessage, - bool use_defaults) -{ - PQconninfoOption *options; - - /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); - if (options == NULL) - return NULL; - - if (!conninfo_uri_parse_options(options, uri, errorMessage)) - { - PQconninfoFree(options); - return NULL; - } - - /* - * Add in defaults if the caller wants that. - */ - if (use_defaults) - { - if (!conninfo_add_defaults(options, errorMessage)) - { - PQconninfoFree(options); - return NULL; - } - } - - return options; -} - -/* - * conninfo_uri_parse_options - * Actual URI parser. - * - * If successful, returns true while the options array is filled with parsed - * options from the URI. - * If not successful, returns false and fills errorMessage accordingly. - * - * Parses the connection URI string in 'uri' according to the URI syntax (RFC - * 3986): - * - * postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...] - * - * where "netloc" is a hostname, an IPv4 address, or an IPv6 address surrounded - * by literal square brackets. - * - * Any of the URI parts might use percent-encoding (%xy). - */ -static bool -conninfo_uri_parse_options(PQconninfoOption *options, const char *uri, - PQExpBuffer errorMessage) -{ - int prefix_len; - char *p; - char *buf; - char *start; - char prevchar = '\0'; - char *user = NULL; - char *host = NULL; - bool retval = false; - - /* need a modifiable copy of the input URI */ - buf = strdup(uri); - if (buf == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - return false; - } - start = buf; - - /* Skip the URI prefix */ - prefix_len = uri_prefix_length(uri); - if (prefix_len == 0) - { - /* Should never happen */ - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid URI propagated to internal parser routine: \"%s\"\n"), - uri); - goto cleanup; - } - start += prefix_len; - p = start; - - /* Look ahead for possible user credentials designator */ - while (*p && *p != '@' && *p != '/') - ++p; - if (*p == '@') - { - /* - * Found username/password designator, so URI should be of the form - * "scheme://user[:password]@[netloc]". - */ - user = start; - - p = user; - while (*p != ':' && *p != '@') - ++p; - - /* Save last char and cut off at end of user name */ - prevchar = *p; - *p = '\0'; - - if (*user && - !conninfo_storeval(options, "user", user, - errorMessage, false, true)) - goto cleanup; - - if (prevchar == ':') - { - const char *password = p + 1; - - while (*p != '@') - ++p; - *p = '\0'; - - if (*password && - !conninfo_storeval(options, "password", password, - errorMessage, false, true)) - goto cleanup; - } - - /* Advance past end of parsed user name or password token */ - ++p; - } - else - { - /* - * No username/password designator found. Reset to start of URI. - */ - p = start; - } - - /* - * "p" has been incremented past optional URI credential information at - * this point and now points at the "netloc" part of the URI. - * - * Look for IPv6 address. - */ - if (*p == '[') - { - host = ++p; - while (*p && *p != ']') - ++p; - if (!*p) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"\n"), - uri); - goto cleanup; - } - if (p == host) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("IPv6 host address may not be empty in URI: \"%s\"\n"), - uri); - goto cleanup; - } - - /* Cut off the bracket and advance */ - *(p++) = '\0'; - - /* - * The address may be followed by a port specifier or a slash or a - * query. - */ - if (*p && *p != ':' && *p != '/' && *p != '?') - { - printfPQExpBuffer(errorMessage, - libpq_gettext("unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"\n"), - *p, (int) (p - buf + 1), uri); - goto cleanup; - } - } - else - { - /* not an IPv6 address: DNS-named or IPv4 netloc */ - host = p; - - /* - * Look for port specifier (colon) or end of host specifier (slash), - * or query (question mark). - */ - while (*p && *p != ':' && *p != '/' && *p != '?') - ++p; - } - - /* Save the hostname terminator before we null it */ - prevchar = *p; - *p = '\0'; - - if (*host && - !conninfo_storeval(options, "host", host, - errorMessage, false, true)) - goto cleanup; - - - if (prevchar == ':') - { - const char *port = ++p; /* advance past host terminator */ - - while (*p && *p != '/' && *p != '?') - ++p; - - prevchar = *p; - *p = '\0'; - - if (*port && - !conninfo_storeval(options, "port", port, - errorMessage, false, true)) - goto cleanup; - } - - if (prevchar && prevchar != '?') - { - const char *dbname = ++p; /* advance past host terminator */ - - /* Look for query parameters */ - while (*p && *p != '?') - ++p; - - prevchar = *p; - *p = '\0'; - - /* - * Avoid setting dbname to an empty string, as it forces the default - * value (username) and ignores $PGDATABASE, as opposed to not setting - * it at all. - */ - if (*dbname && - !conninfo_storeval(options, "dbname", dbname, - errorMessage, false, true)) - goto cleanup; - } - - if (prevchar) - { - ++p; /* advance past terminator */ - - if (!conninfo_uri_parse_params(p, options, errorMessage)) - goto cleanup; - } - - /* everything parsed okay */ - retval = true; - -cleanup: - free(buf); - return retval; -} - -/* - * Connection URI parameters parser routine - * - * If successful, returns true while connOptions is filled with parsed - * parameters. Otherwise, returns false and fills errorMessage appropriately. - * - * Destructively modifies 'params' buffer. - */ -static bool -conninfo_uri_parse_params(char *params, - PQconninfoOption *connOptions, - PQExpBuffer errorMessage) -{ - while (*params) - { - char *keyword = params; - char *value = NULL; - char *p = params; - bool malloced = false; - - /* - * Scan the params string for '=' and '&', marking the end of keyword - * and value respectively. - */ - for (;;) - { - if (*p == '=') - { - /* Was there '=' already? */ - if (value != NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("extra key/value separator \"=\" in URI query parameter: \"%s\"\n"), - keyword); - return false; - } - /* Cut off keyword, advance to value */ - *p++ = '\0'; - value = p; - } - else if (*p == '&' || *p == '\0') - { - /* - * If not at the end, cut off value and advance; leave p - * pointing to start of the next parameter, if any. - */ - if (*p != '\0') - *p++ = '\0'; - /* Was there '=' at all? */ - if (value == NULL) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("missing key/value separator \"=\" in URI query parameter: \"%s\"\n"), - keyword); - return false; - } - /* Got keyword and value, go process them. */ - break; - } - else - ++p; /* Advance over all other bytes. */ - } - - keyword = conninfo_uri_decode(keyword, errorMessage); - if (keyword == NULL) - { - /* conninfo_uri_decode already set an error message */ - return false; - } - value = conninfo_uri_decode(value, errorMessage); - if (value == NULL) - { - /* conninfo_uri_decode already set an error message */ - free(keyword); - return false; - } - malloced = true; - - /* - * Special keyword handling for improved JDBC compatibility. - */ - if (strcmp(keyword, "ssl") == 0 && - strcmp(value, "true") == 0) - { - free(keyword); - free(value); - malloced = false; - - keyword = "sslmode"; - value = "require"; - } - - /* - * Store the value if the corresponding option exists; ignore - * otherwise. At this point both keyword and value are not - * URI-encoded. - */ - if (!conninfo_storeval(connOptions, keyword, value, - errorMessage, true, false)) - { - /* Insert generic message if conninfo_storeval didn't give one. */ - if (errorMessage->len == 0) - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid URI query parameter: \"%s\"\n"), - keyword); - /* And fail. */ - if (malloced) - { - free(keyword); - free(value); - } - return false; - } - - if (malloced) - { - free(keyword); - free(value); - } - - /* Proceed to next key=value pair, if any */ - params = p; - } - - return true; -} - -/* - * Connection URI decoder routine - * - * If successful, returns the malloc'd decoded string. - * If not successful, returns NULL and fills errorMessage accordingly. - * - * The string is decoded by replacing any percent-encoded tokens with - * corresponding characters, while preserving any non-encoded characters. A - * percent-encoded token is a character triplet: a percent sign, followed by a - * pair of hexadecimal digits (0-9A-F), where lower- and upper-case letters are - * treated identically. - */ -static char * -conninfo_uri_decode(const char *str, PQExpBuffer errorMessage) -{ - char *buf; - char *p; - const char *q = str; - - buf = malloc(strlen(str) + 1); - if (buf == NULL) - { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); - return NULL; - } - p = buf; - - for (;;) - { - if (*q != '%') - { - /* copy and check for NUL terminator */ - if (!(*(p++) = *(q++))) - break; - } - else - { - int hi; - int lo; - int c; - - ++q; /* skip the percent sign itself */ - - /* - * Possible EOL will be caught by the first call to - * get_hexdigit(), so we never dereference an invalid q pointer. - */ - if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo))) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid percent-encoded token: \"%s\"\n"), - str); - free(buf); - return NULL; - } - - c = (hi << 4) | lo; - if (c == 0) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("forbidden value %%00 in percent-encoded value: \"%s\"\n"), - str); - free(buf); - return NULL; - } - *(p++) = c; - } - } - - return buf; -} - -/* - * Convert hexadecimal digit character to its integer value. - * - * If successful, returns true and value is filled with digit's base 16 value. - * If not successful, returns false. - * - * Lower- and upper-case letters in the range A-F are treated identically. - */ -static bool -get_hexdigit(char digit, int *value) -{ - if ('0' <= digit && digit <= '9') - *value = digit - '0'; - else if ('A' <= digit && digit <= 'F') - *value = digit - 'A' + 10; - else if ('a' <= digit && digit <= 'f') - *value = digit - 'a' + 10; - else - return false; - - return true; -} - -/* - * Find an option value corresponding to the keyword in the connOptions array. - * - * If successful, returns a pointer to the corresponding option's value. - * If not successful, returns NULL. - */ -static const char * -conninfo_getval(PQconninfoOption *connOptions, - const char *keyword) -{ - PQconninfoOption *option; - - option = conninfo_find(connOptions, keyword); - - return option ? option->val : NULL; -} - -/* - * Store a (new) value for an option corresponding to the keyword in - * connOptions array. - * - * If uri_decode is true, the value is URI-decoded. The keyword is always - * assumed to be non URI-encoded. - * - * If successful, returns a pointer to the corresponding PQconninfoOption, - * which value is replaced with a strdup'd copy of the passed value string. - * The existing value for the option is free'd before replacing, if any. - * - * If not successful, returns NULL and fills errorMessage accordingly. - * However, if the reason of failure is an invalid keyword being passed and - * ignoreMissing is TRUE, errorMessage will be left untouched. - */ -static PQconninfoOption * -conninfo_storeval(PQconninfoOption *connOptions, - const char *keyword, const char *value, - PQExpBuffer errorMessage, bool ignoreMissing, - bool uri_decode) -{ - PQconninfoOption *option; - char *value_copy; - - /* - * For backwards compatibility, requiressl=1 gets translated to - * sslmode=require, and requiressl=0 gets translated to sslmode=prefer - * (which is the default for sslmode). - */ - if (strcmp(keyword, "requiressl") == 0) - { - keyword = "sslmode"; - if (value[0] == '1') - value = "require"; - else - value = "prefer"; - } - - option = conninfo_find(connOptions, keyword); - if (option == NULL) - { - if (!ignoreMissing) - printfPQExpBuffer(errorMessage, - libpq_gettext("invalid connection option \"%s\"\n"), - keyword); - return NULL; - } - - if (uri_decode) - { - value_copy = conninfo_uri_decode(value, errorMessage); - if (value_copy == NULL) - /* conninfo_uri_decode already set an error message */ - return NULL; - } - else - { - value_copy = strdup(value); - if (value_copy == NULL) - { - printfPQExpBuffer(errorMessage, libpq_gettext("out of memory\n")); - return NULL; - } - } - - if (option->val) - free(option->val); - option->val = value_copy; - - return option; -} - -/* - * Find a PQconninfoOption option corresponding to the keyword in the - * connOptions array. - * - * If successful, returns a pointer to the corresponding PQconninfoOption - * structure. - * If not successful, returns NULL. - */ -static PQconninfoOption * -conninfo_find(PQconninfoOption *connOptions, const char *keyword) -{ - PQconninfoOption *option; - - for (option = connOptions; option->keyword != NULL; option++) - { - if (strcmp(option->keyword, keyword) == 0) - return option; - } - - return NULL; -} - - -/* - * Return the connection options used for the connection - */ -PQconninfoOption * -PQconninfo(PGconn *conn) -{ - PQExpBufferData errorBuf; - PQconninfoOption *connOptions; - - if (conn == NULL) - return NULL; - - /* We don't actually report any errors here, but callees want a buffer */ - initPQExpBuffer(&errorBuf); - if (PQExpBufferDataBroken(errorBuf)) - return NULL; /* out of memory already :-( */ - - connOptions = conninfo_init(&errorBuf); - - if (connOptions != NULL) - { - const internalPQconninfoOption *option; - - for (option = PQconninfoOptions; option->keyword; option++) - { - char **connmember; - - if (option->connofs < 0) - continue; - - connmember = (char **) ((char *) conn + option->connofs); - - if (*connmember) - conninfo_storeval(connOptions, option->keyword, *connmember, - &errorBuf, true, false); - } - } - - termPQExpBuffer(&errorBuf); - - return connOptions; -} - - -void -PQconninfoFree(PQconninfoOption *connOptions) -{ - PQconninfoOption *option; - - if (connOptions == NULL) - return; - - for (option = connOptions; option->keyword != NULL; option++) - { - if (option->val != NULL) - free(option->val); - } - free(connOptions); -} - - -/* =========== accessor functions for PGconn ========= */ -char * -PQdb(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->dbName; -} - -char * -PQuser(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->pguser; -} - -char * -PQpass(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->pgpass; -} - -char * -PQhost(const PGconn *conn) -{ - if (!conn) - return NULL; - if (conn->pghost != NULL && conn->pghost[0] != '\0') - return conn->pghost; - else - { -#ifdef HAVE_UNIX_SOCKETS - if (conn->pgunixsocket != NULL && conn->pgunixsocket[0] != '\0') - return conn->pgunixsocket; - else - return DEFAULT_PGSOCKET_DIR; -#else - return DefaultHost; -#endif - } -} - -char * -PQport(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->pgport; -} - -char * -PQtty(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->pgtty; -} - -char * -PQoptions(const PGconn *conn) -{ - if (!conn) - return NULL; - return conn->pgoptions; -} - -ConnStatusType -PQstatus(const PGconn *conn) -{ - if (!conn) - return CONNECTION_BAD; - return conn->status; -} - -PGTransactionStatusType -PQtransactionStatus(const PGconn *conn) -{ - if (!conn || conn->status != CONNECTION_OK) - return PQTRANS_UNKNOWN; - if (conn->asyncStatus != PGASYNC_IDLE) - return PQTRANS_ACTIVE; - return conn->xactStatus; -} - -const char * -PQparameterStatus(const PGconn *conn, const char *paramName) -{ - const pgParameterStatus *pstatus; - - if (!conn || !paramName) - return NULL; - for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next) - { - if (strcmp(pstatus->name, paramName) == 0) - return pstatus->value; - } - return NULL; -} - -int -PQprotocolVersion(const PGconn *conn) -{ - if (!conn) - return 0; - if (conn->status == CONNECTION_BAD) - return 0; - return PG_PROTOCOL_MAJOR(conn->pversion); -} - -int -PQserverVersion(const PGconn *conn) -{ - if (!conn) - return 0; - if (conn->status == CONNECTION_BAD) - return 0; - return conn->sversion; -} - -char * -PQerrorMessage(const PGconn *conn) -{ - if (!conn) - return libpq_gettext("connection pointer is NULL\n"); - - return conn->errorMessage.data; -} - -/* - * In Windows, socket values are unsigned, and an invalid socket value - * (INVALID_SOCKET) is ~0, which equals -1 in comparisons (with no compiler - * warning). Ideally we would return an unsigned value for PQsocket() on - * Windows, but that would cause the function's return value to differ from - * Unix, so we just return -1 for invalid sockets. - * http://msdn.microsoft.com/en-us/library/windows/desktop/cc507522%28v=vs.85%29.aspx - * http://stackoverflow.com/questions/10817252/why-is-invalid-socket-defined-as-0-in-winsock2-h-c - */ -int -PQsocket(const PGconn *conn) -{ - if (!conn) - return -1; - return (conn->sock != PGINVALID_SOCKET) ? conn->sock : -1; -} - -int -PQbackendPID(const PGconn *conn) -{ - if (!conn || conn->status != CONNECTION_OK) - return 0; - return conn->be_pid; -} - -int -PQconnectionNeedsPassword(const PGconn *conn) -{ - if (!conn) - return false; - if (conn->password_needed && - (conn->pgpass == NULL || conn->pgpass[0] == '\0')) - return true; - else - return false; -} - -int -PQconnectionUsedPassword(const PGconn *conn) -{ - if (!conn) - return false; - if (conn->password_needed) - return true; - else - return false; -} - -int -PQclientEncoding(const PGconn *conn) -{ - if (!conn || conn->status != CONNECTION_OK) - return -1; - return conn->client_encoding; -} - -int -PQsetClientEncoding(PGconn *conn, const char *encoding) -{ - char qbuf[128]; - static const char query[] = "set client_encoding to '%s'"; - PGresult *res; - int status; - - if (!conn || conn->status != CONNECTION_OK) - return -1; - - if (!encoding) - return -1; - - /* Resolve special "auto" value from the locale */ - if (strcmp(encoding, "auto") == 0) - encoding = pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)); - - /* check query buffer overflow */ - if (sizeof(qbuf) < (sizeof(query) + strlen(encoding))) - return -1; - - /* ok, now send a query */ - sprintf(qbuf, query, encoding); - res = PQexec(conn, qbuf); - - if (res == NULL) - return -1; - if (res->resultStatus != PGRES_COMMAND_OK) - status = -1; - else - { - /* - * In protocol 2 we have to assume the setting will stick, and adjust - * our state immediately. In protocol 3 and up we can rely on the - * backend to report the parameter value, and we'll change state at - * that time. - */ - if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) - pqSaveParameterStatus(conn, "client_encoding", encoding); - status = 0; /* everything is ok */ - } - PQclear(res); - return status; -} - -PGVerbosity -PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity) -{ - PGVerbosity old; - - if (!conn) - return PQERRORS_DEFAULT; - old = conn->verbosity; - conn->verbosity = verbosity; - return old; -} - -PGContextVisibility -PQsetErrorContextVisibility(PGconn *conn, PGContextVisibility show_context) -{ - PGContextVisibility old; - - if (!conn) - return PQSHOW_CONTEXT_ERRORS; - old = conn->show_context; - conn->show_context = show_context; - return old; -} - -void -PQtrace(PGconn *conn, FILE *debug_port) -{ - if (conn == NULL) - return; - PQuntrace(conn); - conn->Pfdebug = debug_port; -} - -void -PQuntrace(PGconn *conn) -{ - if (conn == NULL) - return; - if (conn->Pfdebug) - { - fflush(conn->Pfdebug); - conn->Pfdebug = NULL; - } -} - -PQnoticeReceiver -PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg) -{ - PQnoticeReceiver old; - - if (conn == NULL) - return NULL; - - old = conn->noticeHooks.noticeRec; - if (proc) - { - conn->noticeHooks.noticeRec = proc; - conn->noticeHooks.noticeRecArg = arg; - } - return old; -} - -PQnoticeProcessor -PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg) -{ - PQnoticeProcessor old; - - if (conn == NULL) - return NULL; - - old = conn->noticeHooks.noticeProc; - if (proc) - { - conn->noticeHooks.noticeProc = proc; - conn->noticeHooks.noticeProcArg = arg; - } - return old; -} - -/* - * The default notice message receiver just gets the standard notice text - * and sends it to the notice processor. This two-level setup exists - * mostly for backwards compatibility; perhaps we should deprecate use of - * PQsetNoticeProcessor? - */ -static void -defaultNoticeReceiver(void *arg, const PGresult *res) -{ - (void) arg; /* not used */ - if (res->noticeHooks.noticeProc != NULL) - (*res->noticeHooks.noticeProc) (res->noticeHooks.noticeProcArg, - PQresultErrorMessage(res)); -} - -/* - * The default notice message processor just prints the - * message on stderr. Applications can override this if they - * want the messages to go elsewhere (a window, for example). - * Note that simply discarding notices is probably a bad idea. - */ -static void -defaultNoticeProcessor(void *arg, const char *message) -{ - (void) arg; /* not used */ - /* Note: we expect the supplied string to end with a newline already. */ - fprintf(stderr, "%s", message); -} - -/* - * returns a pointer to the next token or NULL if the current - * token doesn't match - */ -static char * -pwdfMatchesString(char *buf, char *token) -{ - char *tbuf, - *ttok; - bool bslash = false; - - if (buf == NULL || token == NULL) - return NULL; - tbuf = buf; - ttok = token; - if (tbuf[0] == '*' && tbuf[1] == ':') - return tbuf + 2; - while (*tbuf != 0) - { - if (*tbuf == '\\' && !bslash) - { - tbuf++; - bslash = true; - } - if (*tbuf == ':' && *ttok == 0 && !bslash) - return tbuf + 1; - bslash = false; - if (*ttok == 0) - return NULL; - if (*tbuf == *ttok) - { - tbuf++; - ttok++; - } - else - return NULL; - } - return NULL; -} - -/* Get a password from the password file. Return value is malloc'd. */ -static char * -PasswordFromFile(char *hostname, char *port, char *dbname, char *username) -{ - FILE *fp; - char pgpassfile[MAXPGPATH]; - struct stat stat_buf; - -#define LINELEN NAMEDATALEN*5 - char buf[LINELEN]; - - if (dbname == NULL || strlen(dbname) == 0) - return NULL; - - if (username == NULL || strlen(username) == 0) - return NULL; - - /* 'localhost' matches pghost of '' or the default socket directory */ - if (hostname == NULL) - hostname = DefaultHost; - else if (is_absolute_path(hostname)) - - /* - * We should probably use canonicalize_path(), but then we have to - * bring path.c into libpq, and it doesn't seem worth it. - */ - if (strcmp(hostname, DEFAULT_PGSOCKET_DIR) == 0) - hostname = DefaultHost; - - if (port == NULL) - port = DEF_PGPORT_STR; - - if (!getPgPassFilename(pgpassfile)) - return NULL; - - /* If password file cannot be opened, ignore it. */ - if (stat(pgpassfile, &stat_buf) != 0) - return NULL; - -#ifndef WIN32 - if (!S_ISREG(stat_buf.st_mode)) - { - fprintf(stderr, - libpq_gettext("WARNING: password file \"%s\" is not a plain file\n"), - pgpassfile); - return NULL; - } - - /* If password file is insecure, alert the user and ignore it. */ - if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) - { - fprintf(stderr, - libpq_gettext("WARNING: password file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), - pgpassfile); - return NULL; - } -#else - - /* - * On Win32, the directory is protected, so we don't have to check the - * file. - */ -#endif - - fp = fopen(pgpassfile, "r"); - if (fp == NULL) - return NULL; - - while (!feof(fp) && !ferror(fp)) - { - char *t = buf, - *ret, - *p1, - *p2; - int len; - - if (fgets(buf, sizeof(buf), fp) == NULL) - break; - - len = strlen(buf); - - /* Remove trailing newline */ - if (len > 0 && buf[len - 1] == '\n') - { - buf[--len] = '\0'; - /* Handle DOS-style line endings, too, even when not on Windows */ - if (len > 0 && buf[len - 1] == '\r') - buf[--len] = '\0'; - } - - if (len == 0) - continue; - - if ((t = pwdfMatchesString(t, hostname)) == NULL || - (t = pwdfMatchesString(t, port)) == NULL || - (t = pwdfMatchesString(t, dbname)) == NULL || - (t = pwdfMatchesString(t, username)) == NULL) - continue; - - /* Found a match. */ - ret = strdup(t); - fclose(fp); - - if (!ret) - { - /* Out of memory. XXX: an error message would be nice. */ - return NULL; - } - - /* De-escape password. */ - for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2) - { - if (*p1 == '\\' && p1[1] != '\0') - ++p1; - *p2 = *p1; - } - *p2 = '\0'; - - return ret; - } - - fclose(fp); - return NULL; - -#undef LINELEN -} - - -static bool -getPgPassFilename(char *pgpassfile) -{ - char *passfile_env; - - if ((passfile_env = getenv("PGPASSFILE")) != NULL) - /* use the literal path from the environment, if set */ - strlcpy(pgpassfile, passfile_env, MAXPGPATH); - else - { - char homedir[MAXPGPATH]; - - if (!pqGetHomeDirectory(homedir, sizeof(homedir))) - return false; - snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE); - } - return true; -} - -/* - * If the connection failed, we should mention if - * we got the password from .pgpass in case that - * password is wrong. - */ -static void -dot_pg_pass_warning(PGconn *conn) -{ - /* If it was 'invalid authorization', add .pgpass mention */ - /* only works with >= 9.0 servers */ - if (conn->dot_pgpass_used && conn->password_needed && conn->result && - strcmp(PQresultErrorField(conn->result, PG_DIAG_SQLSTATE), - ERRCODE_INVALID_PASSWORD) == 0) - { - char pgpassfile[MAXPGPATH]; - - if (!getPgPassFilename(pgpassfile)) - return; - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("password retrieved from file \"%s\"\n"), - pgpassfile); - } -} - - -/* - * Obtain user's home directory, return in given buffer - * - * On Unix, this actually returns the user's home directory. On Windows - * it returns the PostgreSQL-specific application data folder. - * - * This is essentially the same as get_home_path(), but we don't use that - * because we don't want to pull path.c into libpq (it pollutes application - * namespace) - */ -bool -pqGetHomeDirectory(char *buf, int bufsize) -{ -#ifndef WIN32 - char pwdbuf[BUFSIZ]; - struct passwd pwdstr; - struct passwd *pwd = NULL; - - (void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd); - if (pwd == NULL) - return false; - strlcpy(buf, pwd->pw_dir, bufsize); - return true; -#else - char tmppath[MAX_PATH]; - - ZeroMemory(tmppath, sizeof(tmppath)); - if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, tmppath) != S_OK) - return false; - snprintf(buf, bufsize, "%s/postgresql", tmppath); - return true; -#endif -} - -/* - * To keep the API consistent, the locking stubs are always provided, even - * if they are not required. - */ - -static void -default_threadlock(int acquire) -{ -#ifdef ENABLE_THREAD_SAFETY -#ifndef WIN32 - static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER; -#else - static pthread_mutex_t singlethread_lock = NULL; - static long mutex_initlock = 0; - - if (singlethread_lock == NULL) - { - while (InterlockedExchange(&mutex_initlock, 1) == 1) - /* loop, another thread own the lock */ ; - if (singlethread_lock == NULL) - { - if (pthread_mutex_init(&singlethread_lock, NULL)) - PGTHREAD_ERROR("failed to initialize mutex"); - } - InterlockedExchange(&mutex_initlock, 0); - } -#endif - if (acquire) - { - if (pthread_mutex_lock(&singlethread_lock)) - PGTHREAD_ERROR("failed to lock mutex"); - } - else - { - if (pthread_mutex_unlock(&singlethread_lock)) - PGTHREAD_ERROR("failed to unlock mutex"); - } -#endif -} - -pgthreadlock_t -PQregisterThreadLock(pgthreadlock_t newhandler) -{ - pgthreadlock_t prev = pg_g_threadlock; - - if (newhandler) - pg_g_threadlock = newhandler; - else - pg_g_threadlock = default_threadlock; - - return prev; -} diff --git a/libpq/fe-exec.c b/libpq/fe-exec.c deleted file mode 100644 index 87ff565..0000000 --- a/libpq/fe-exec.c +++ /dev/null @@ -1,3764 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-exec.c - * functions related to sending a query down to the backend - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-exec.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include -#include - -#include "libpq-fe.h" -#include "libpq-int.h" - -#include "mb/pg_wchar.h" - -#ifdef WIN32 -#include "win32.h" -#else -#include -#endif - -/* keep this in same order as ExecStatusType in libpq-fe.h */ -char *const pgresStatus[] = { - "PGRES_EMPTY_QUERY", - "PGRES_COMMAND_OK", - "PGRES_TUPLES_OK", - "PGRES_COPY_OUT", - "PGRES_COPY_IN", - "PGRES_BAD_RESPONSE", - "PGRES_NONFATAL_ERROR", - "PGRES_FATAL_ERROR", - "PGRES_COPY_BOTH", - "PGRES_SINGLE_TUPLE" -}; - -/* - * static state needed by PQescapeString and PQescapeBytea; initialize to - * values that result in backward-compatible behavior - */ -static int static_client_encoding = PG_SQL_ASCII; -static bool static_std_strings = false; - - -static PGEvent *dupEvents(PGEvent *events, int count); -static bool pqAddTuple(PGresult *res, PGresAttValue *tup); -static bool PQsendQueryStart(PGconn *conn); -static int PQsendQueryGuts(PGconn *conn, - const char *command, - const char *stmtName, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat); -static void parseInput(PGconn *conn); -static PGresult *getCopyResult(PGconn *conn, ExecStatusType copytype); -static bool PQexecStart(PGconn *conn); -static PGresult *PQexecFinish(PGconn *conn); -static int PQsendDescribe(PGconn *conn, char desc_type, - const char *desc_target); -static int check_field_number(const PGresult *res, int field_num); - - -/* ---------------- - * Space management for PGresult. - * - * Formerly, libpq did a separate malloc() for each field of each tuple - * returned by a query. This was remarkably expensive --- malloc/free - * consumed a sizable part of the application's runtime. And there is - * no real need to keep track of the fields separately, since they will - * all be freed together when the PGresult is released. So now, we grab - * large blocks of storage from malloc and allocate space for query data - * within these blocks, using a trivially simple allocator. This reduces - * the number of malloc/free calls dramatically, and it also avoids - * fragmentation of the malloc storage arena. - * The PGresult structure itself is still malloc'd separately. We could - * combine it with the first allocation block, but that would waste space - * for the common case that no extra storage is actually needed (that is, - * the SQL command did not return tuples). - * - * We also malloc the top-level array of tuple pointers separately, because - * we need to be able to enlarge it via realloc, and our trivial space - * allocator doesn't handle that effectively. (Too bad the FE/BE protocol - * doesn't tell us up front how many tuples will be returned.) - * All other subsidiary storage for a PGresult is kept in PGresult_data blocks - * of size PGRESULT_DATA_BLOCKSIZE. The overhead at the start of each block - * is just a link to the next one, if any. Free-space management info is - * kept in the owning PGresult. - * A query returning a small amount of data will thus require three malloc - * calls: one for the PGresult, one for the tuples pointer array, and one - * PGresult_data block. - * - * Only the most recently allocated PGresult_data block is a candidate to - * have more stuff added to it --- any extra space left over in older blocks - * is wasted. We could be smarter and search the whole chain, but the point - * here is to be simple and fast. Typical applications do not keep a PGresult - * around very long anyway, so some wasted space within one is not a problem. - * - * Tuning constants for the space allocator are: - * PGRESULT_DATA_BLOCKSIZE: size of a standard allocation block, in bytes - * PGRESULT_ALIGN_BOUNDARY: assumed alignment requirement for binary data - * PGRESULT_SEP_ALLOC_THRESHOLD: objects bigger than this are given separate - * blocks, instead of being crammed into a regular allocation block. - * Requirements for correct function are: - * PGRESULT_ALIGN_BOUNDARY must be a multiple of the alignment requirements - * of all machine data types. (Currently this is set from configure - * tests, so it should be OK automatically.) - * PGRESULT_SEP_ALLOC_THRESHOLD + PGRESULT_BLOCK_OVERHEAD <= - * PGRESULT_DATA_BLOCKSIZE - * pqResultAlloc assumes an object smaller than the threshold will fit - * in a new block. - * The amount of space wasted at the end of a block could be as much as - * PGRESULT_SEP_ALLOC_THRESHOLD, so it doesn't pay to make that too large. - * ---------------- - */ - -#define PGRESULT_DATA_BLOCKSIZE 2048 -#define PGRESULT_ALIGN_BOUNDARY MAXIMUM_ALIGNOF /* from configure */ -#define PGRESULT_BLOCK_OVERHEAD Max(sizeof(PGresult_data), PGRESULT_ALIGN_BOUNDARY) -#define PGRESULT_SEP_ALLOC_THRESHOLD (PGRESULT_DATA_BLOCKSIZE / 2) - - -/* - * PQmakeEmptyPGresult - * returns a newly allocated, initialized PGresult with given status. - * If conn is not NULL and status indicates an error, the conn's - * errorMessage is copied. Also, any PGEvents are copied from the conn. - */ -PGresult * -PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) -{ - PGresult *result; - - result = (PGresult *) malloc(sizeof(PGresult)); - if (!result) - return NULL; - - result->ntups = 0; - result->numAttributes = 0; - result->attDescs = NULL; - result->tuples = NULL; - result->tupArrSize = 0; - result->numParameters = 0; - result->paramDescs = NULL; - result->resultStatus = status; - result->cmdStatus[0] = '\0'; - result->binary = 0; - result->events = NULL; - result->nEvents = 0; - result->errMsg = NULL; - result->errFields = NULL; - result->errQuery = NULL; - result->null_field[0] = '\0'; - result->curBlock = NULL; - result->curOffset = 0; - result->spaceLeft = 0; - - if (conn) - { - /* copy connection data we might need for operations on PGresult */ - result->noticeHooks = conn->noticeHooks; - result->client_encoding = conn->client_encoding; - - /* consider copying conn's errorMessage */ - switch (status) - { - case PGRES_EMPTY_QUERY: - case PGRES_COMMAND_OK: - case PGRES_TUPLES_OK: - case PGRES_COPY_OUT: - case PGRES_COPY_IN: - case PGRES_COPY_BOTH: - case PGRES_SINGLE_TUPLE: - /* non-error cases */ - break; - default: - pqSetResultError(result, conn->errorMessage.data); - break; - } - - /* copy events last; result must be valid if we need to PQclear */ - if (conn->nEvents > 0) - { - result->events = dupEvents(conn->events, conn->nEvents); - if (!result->events) - { - PQclear(result); - return NULL; - } - result->nEvents = conn->nEvents; - } - } - else - { - /* defaults... */ - result->noticeHooks.noticeRec = NULL; - result->noticeHooks.noticeRecArg = NULL; - result->noticeHooks.noticeProc = NULL; - result->noticeHooks.noticeProcArg = NULL; - result->client_encoding = PG_SQL_ASCII; - } - - return result; -} - -/* - * PQsetResultAttrs - * - * Set the attributes for a given result. This function fails if there are - * already attributes contained in the provided result. The call is - * ignored if numAttributes is zero or attDescs is NULL. If the - * function fails, it returns zero. If the function succeeds, it - * returns a non-zero value. - */ -int -PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs) -{ - int i; - - /* If attrs already exist, they cannot be overwritten. */ - if (!res || res->numAttributes > 0) - return FALSE; - - /* ignore no-op request */ - if (numAttributes <= 0 || !attDescs) - return TRUE; - - res->attDescs = (PGresAttDesc *) - PQresultAlloc(res, numAttributes * sizeof(PGresAttDesc)); - - if (!res->attDescs) - return FALSE; - - res->numAttributes = numAttributes; - memcpy(res->attDescs, attDescs, numAttributes * sizeof(PGresAttDesc)); - - /* deep-copy the attribute names, and determine format */ - res->binary = 1; - for (i = 0; i < res->numAttributes; i++) - { - if (res->attDescs[i].name) - res->attDescs[i].name = pqResultStrdup(res, res->attDescs[i].name); - else - res->attDescs[i].name = res->null_field; - - if (!res->attDescs[i].name) - return FALSE; - - if (res->attDescs[i].format == 0) - res->binary = 0; - } - - return TRUE; -} - -/* - * PQcopyResult - * - * Returns a deep copy of the provided 'src' PGresult, which cannot be NULL. - * The 'flags' argument controls which portions of the result will or will - * NOT be copied. The created result is always put into the - * PGRES_TUPLES_OK status. The source result error message is not copied, - * although cmdStatus is. - * - * To set custom attributes, use PQsetResultAttrs. That function requires - * that there are no attrs contained in the result, so to use that - * function you cannot use the PG_COPYRES_ATTRS or PG_COPYRES_TUPLES - * options with this function. - * - * Options: - * PG_COPYRES_ATTRS - Copy the source result's attributes - * - * PG_COPYRES_TUPLES - Copy the source result's tuples. This implies - * copying the attrs, seeing how the attrs are needed by the tuples. - * - * PG_COPYRES_EVENTS - Copy the source result's events. - * - * PG_COPYRES_NOTICEHOOKS - Copy the source result's notice hooks. - */ -PGresult * -PQcopyResult(const PGresult *src, int flags) -{ - PGresult *dest; - int i; - - if (!src) - return NULL; - - dest = PQmakeEmptyPGresult(NULL, PGRES_TUPLES_OK); - if (!dest) - return NULL; - - /* Always copy these over. Is cmdStatus really useful here? */ - dest->client_encoding = src->client_encoding; - strcpy(dest->cmdStatus, src->cmdStatus); - - /* Wants attrs? */ - if (flags & (PG_COPYRES_ATTRS | PG_COPYRES_TUPLES)) - { - if (!PQsetResultAttrs(dest, src->numAttributes, src->attDescs)) - { - PQclear(dest); - return NULL; - } - } - - /* Wants to copy tuples? */ - if (flags & PG_COPYRES_TUPLES) - { - int tup, - field; - - for (tup = 0; tup < src->ntups; tup++) - { - for (field = 0; field < src->numAttributes; field++) - { - if (!PQsetvalue(dest, tup, field, - src->tuples[tup][field].value, - src->tuples[tup][field].len)) - { - PQclear(dest); - return NULL; - } - } - } - } - - /* Wants to copy notice hooks? */ - if (flags & PG_COPYRES_NOTICEHOOKS) - dest->noticeHooks = src->noticeHooks; - - /* Wants to copy PGEvents? */ - if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0) - { - dest->events = dupEvents(src->events, src->nEvents); - if (!dest->events) - { - PQclear(dest); - return NULL; - } - dest->nEvents = src->nEvents; - } - - /* Okay, trigger PGEVT_RESULTCOPY event */ - for (i = 0; i < dest->nEvents; i++) - { - if (src->events[i].resultInitialized) - { - PGEventResultCopy evt; - - evt.src = src; - evt.dest = dest; - if (!dest->events[i].proc(PGEVT_RESULTCOPY, &evt, - dest->events[i].passThrough)) - { - PQclear(dest); - return NULL; - } - dest->events[i].resultInitialized = TRUE; - } - } - - return dest; -} - -/* - * Copy an array of PGEvents (with no extra space for more). - * Does not duplicate the event instance data, sets this to NULL. - * Also, the resultInitialized flags are all cleared. - */ -static PGEvent * -dupEvents(PGEvent *events, int count) -{ - PGEvent *newEvents; - int i; - - if (!events || count <= 0) - return NULL; - - newEvents = (PGEvent *) malloc(count * sizeof(PGEvent)); - if (!newEvents) - return NULL; - - for (i = 0; i < count; i++) - { - newEvents[i].proc = events[i].proc; - newEvents[i].passThrough = events[i].passThrough; - newEvents[i].data = NULL; - newEvents[i].resultInitialized = FALSE; - newEvents[i].name = strdup(events[i].name); - if (!newEvents[i].name) - { - while (--i >= 0) - free(newEvents[i].name); - free(newEvents); - return NULL; - } - } - - return newEvents; -} - - -/* - * Sets the value for a tuple field. The tup_num must be less than or - * equal to PQntuples(res). If it is equal, a new tuple is created and - * added to the result. - * Returns a non-zero value for success and zero for failure. - */ -int -PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len) -{ - PGresAttValue *attval; - - if (!check_field_number(res, field_num)) - return FALSE; - - /* Invalid tup_num, must be <= ntups */ - if (tup_num < 0 || tup_num > res->ntups) - return FALSE; - - /* need to allocate a new tuple? */ - if (tup_num == res->ntups) - { - PGresAttValue *tup; - int i; - - tup = (PGresAttValue *) - pqResultAlloc(res, res->numAttributes * sizeof(PGresAttValue), - TRUE); - - if (!tup) - return FALSE; - - /* initialize each column to NULL */ - for (i = 0; i < res->numAttributes; i++) - { - tup[i].len = NULL_LEN; - tup[i].value = res->null_field; - } - - /* add it to the array */ - if (!pqAddTuple(res, tup)) - return FALSE; - } - - attval = &res->tuples[tup_num][field_num]; - - /* treat either NULL_LEN or NULL value pointer as a NULL field */ - if (len == NULL_LEN || value == NULL) - { - attval->len = NULL_LEN; - attval->value = res->null_field; - } - else if (len <= 0) - { - attval->len = 0; - attval->value = res->null_field; - } - else - { - attval->value = (char *) pqResultAlloc(res, len + 1, TRUE); - if (!attval->value) - return FALSE; - attval->len = len; - memcpy(attval->value, value, len); - attval->value[len] = '\0'; - } - - return TRUE; -} - -/* - * pqResultAlloc - exported routine to allocate local storage in a PGresult. - * - * We force all such allocations to be maxaligned, since we don't know - * whether the value might be binary. - */ -void * -PQresultAlloc(PGresult *res, size_t nBytes) -{ - return pqResultAlloc(res, nBytes, TRUE); -} - -/* - * pqResultAlloc - - * Allocate subsidiary storage for a PGresult. - * - * nBytes is the amount of space needed for the object. - * If isBinary is true, we assume that we need to align the object on - * a machine allocation boundary. - * If isBinary is false, we assume the object is a char string and can - * be allocated on any byte boundary. - */ -void * -pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary) -{ - char *space; - PGresult_data *block; - - if (!res) - return NULL; - - if (nBytes <= 0) - return res->null_field; - - /* - * If alignment is needed, round up the current position to an alignment - * boundary. - */ - if (isBinary) - { - int offset = res->curOffset % PGRESULT_ALIGN_BOUNDARY; - - if (offset) - { - res->curOffset += PGRESULT_ALIGN_BOUNDARY - offset; - res->spaceLeft -= PGRESULT_ALIGN_BOUNDARY - offset; - } - } - - /* If there's enough space in the current block, no problem. */ - if (nBytes <= (size_t) res->spaceLeft) - { - space = res->curBlock->space + res->curOffset; - res->curOffset += nBytes; - res->spaceLeft -= nBytes; - return space; - } - - /* - * If the requested object is very large, give it its own block; this - * avoids wasting what might be most of the current block to start a new - * block. (We'd have to special-case requests bigger than the block size - * anyway.) The object is always given binary alignment in this case. - */ - if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD) - { - block = (PGresult_data *) malloc(nBytes + PGRESULT_BLOCK_OVERHEAD); - if (!block) - return NULL; - space = block->space + PGRESULT_BLOCK_OVERHEAD; - if (res->curBlock) - { - /* - * Tuck special block below the active block, so that we don't - * have to waste the free space in the active block. - */ - block->next = res->curBlock->next; - res->curBlock->next = block; - } - else - { - /* Must set up the new block as the first active block. */ - block->next = NULL; - res->curBlock = block; - res->spaceLeft = 0; /* be sure it's marked full */ - } - return space; - } - - /* Otherwise, start a new block. */ - block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE); - if (!block) - return NULL; - block->next = res->curBlock; - res->curBlock = block; - if (isBinary) - { - /* object needs full alignment */ - res->curOffset = PGRESULT_BLOCK_OVERHEAD; - res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - PGRESULT_BLOCK_OVERHEAD; - } - else - { - /* we can cram it right after the overhead pointer */ - res->curOffset = sizeof(PGresult_data); - res->spaceLeft = PGRESULT_DATA_BLOCKSIZE - sizeof(PGresult_data); - } - - space = block->space + res->curOffset; - res->curOffset += nBytes; - res->spaceLeft -= nBytes; - return space; -} - -/* - * pqResultStrdup - - * Like strdup, but the space is subsidiary PGresult space. - */ -char * -pqResultStrdup(PGresult *res, const char *str) -{ - char *space = (char *) pqResultAlloc(res, strlen(str) + 1, FALSE); - - if (space) - strcpy(space, str); - return space; -} - -/* - * pqSetResultError - - * assign a new error message to a PGresult - */ -void -pqSetResultError(PGresult *res, const char *msg) -{ - if (!res) - return; - if (msg && *msg) - res->errMsg = pqResultStrdup(res, msg); - else - res->errMsg = NULL; -} - -/* - * pqCatenateResultError - - * concatenate a new error message to the one already in a PGresult - */ -void -pqCatenateResultError(PGresult *res, const char *msg) -{ - PQExpBufferData errorBuf; - - if (!res || !msg) - return; - initPQExpBuffer(&errorBuf); - if (res->errMsg) - appendPQExpBufferStr(&errorBuf, res->errMsg); - appendPQExpBufferStr(&errorBuf, msg); - pqSetResultError(res, errorBuf.data); - termPQExpBuffer(&errorBuf); -} - -/* - * PQclear - - * free's the memory associated with a PGresult - */ -void -PQclear(PGresult *res) -{ - PGresult_data *block; - int i; - - if (!res) - return; - - for (i = 0; i < res->nEvents; i++) - { - /* only send DESTROY to successfully-initialized event procs */ - if (res->events[i].resultInitialized) - { - PGEventResultDestroy evt; - - evt.result = res; - (void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt, - res->events[i].passThrough); - } - free(res->events[i].name); - } - - if (res->events) - free(res->events); - - /* Free all the subsidiary blocks */ - while ((block = res->curBlock) != NULL) - { - res->curBlock = block->next; - free(block); - } - - /* Free the top-level tuple pointer array */ - if (res->tuples) - free(res->tuples); - - /* zero out the pointer fields to catch programming errors */ - res->attDescs = NULL; - res->tuples = NULL; - res->paramDescs = NULL; - res->errFields = NULL; - res->events = NULL; - res->nEvents = 0; - /* res->curBlock was zeroed out earlier */ - - /* Free the PGresult structure itself */ - free(res); -} - -/* - * Handy subroutine to deallocate any partially constructed async result. - * - * Any "next" result gets cleared too. - */ -void -pqClearAsyncResult(PGconn *conn) -{ - if (conn->result) - PQclear(conn->result); - conn->result = NULL; - if (conn->next_result) - PQclear(conn->next_result); - conn->next_result = NULL; -} - -/* - * This subroutine deletes any existing async result, sets conn->result - * to a PGresult with status PGRES_FATAL_ERROR, and stores the current - * contents of conn->errorMessage into that result. It differs from a - * plain call on PQmakeEmptyPGresult() in that if there is already an - * async result with status PGRES_FATAL_ERROR, the current error message - * is APPENDED to the old error message instead of replacing it. This - * behavior lets us report multiple error conditions properly, if necessary. - * (An example where this is needed is when the backend sends an 'E' message - * and immediately closes the connection --- we want to report both the - * backend error and the connection closure error.) - */ -void -pqSaveErrorResult(PGconn *conn) -{ - /* - * If no old async result, just let PQmakeEmptyPGresult make one. Likewise - * if old result is not an error message. - */ - if (conn->result == NULL || - conn->result->resultStatus != PGRES_FATAL_ERROR || - conn->result->errMsg == NULL) - { - pqClearAsyncResult(conn); - conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - } - else - { - /* Else, concatenate error message to existing async result. */ - pqCatenateResultError(conn->result, conn->errorMessage.data); - } -} - -/* - * This subroutine prepares an async result object for return to the caller. - * If there is not already an async result object, build an error object - * using whatever is in conn->errorMessage. In any case, clear the async - * result storage and make sure PQerrorMessage will agree with the result's - * error string. - */ -PGresult * -pqPrepareAsyncResult(PGconn *conn) -{ - PGresult *res; - - /* - * conn->result is the PGresult to return. If it is NULL (which probably - * shouldn't happen) we assume there is an appropriate error message in - * conn->errorMessage. - */ - res = conn->result; - if (!res) - res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - else - { - /* - * Make sure PQerrorMessage agrees with result; it could be different - * if we have concatenated messages. - */ - resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, - PQresultErrorMessage(res)); - } - - /* - * Replace conn->result with next_result, if any. In the normal case - * there isn't a next result and we're just dropping ownership of the - * current result. In single-row mode this restores the situation to what - * it was before we created the current single-row result. - */ - conn->result = conn->next_result; - conn->next_result = NULL; - - return res; -} - -/* - * pqInternalNotice - produce an internally-generated notice message - * - * A format string and optional arguments can be passed. Note that we do - * libpq_gettext() here, so callers need not. - * - * The supplied text is taken as primary message (ie., it should not include - * a trailing newline, and should not be more than one line). - */ -void -pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) -{ - char msgBuf[1024]; - va_list args; - PGresult *res; - - if (hooks->noticeRec == NULL) - return; /* nobody home to receive notice? */ - - /* Format the message */ - va_start(args, fmt); - vsnprintf(msgBuf, sizeof(msgBuf), libpq_gettext(fmt), args); - va_end(args); - msgBuf[sizeof(msgBuf) - 1] = '\0'; /* make real sure it's terminated */ - - /* Make a PGresult to pass to the notice receiver */ - res = PQmakeEmptyPGresult(NULL, PGRES_NONFATAL_ERROR); - if (!res) - return; - res->noticeHooks = *hooks; - - /* - * Set up fields of notice. - */ - pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, msgBuf); - pqSaveMessageField(res, PG_DIAG_SEVERITY, libpq_gettext("NOTICE")); - pqSaveMessageField(res, PG_DIAG_SEVERITY_NONLOCALIZED, "NOTICE"); - /* XXX should provide a SQLSTATE too? */ - - /* - * Result text is always just the primary message + newline. If we can't - * allocate it, don't bother invoking the receiver. - */ - res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, FALSE); - if (res->errMsg) - { - sprintf(res->errMsg, "%s\n", msgBuf); - - /* - * Pass to receiver, then free it. - */ - (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); - } - PQclear(res); -} - -/* - * pqAddTuple - * add a row pointer to the PGresult structure, growing it if necessary - * Returns TRUE if OK, FALSE if not enough memory to add the row - */ -static bool -pqAddTuple(PGresult *res, PGresAttValue *tup) -{ - if (res->ntups >= res->tupArrSize) - { - /* - * Try to grow the array. - * - * We can use realloc because shallow copying of the structure is - * okay. Note that the first time through, res->tuples is NULL. While - * ANSI says that realloc() should act like malloc() in that case, - * some old C libraries (like SunOS 4.1.x) coredump instead. On - * failure realloc is supposed to return NULL without damaging the - * existing allocation. Note that the positions beyond res->ntups are - * garbage, not necessarily NULL. - */ - int newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128; - PGresAttValue **newTuples; - - if (res->tuples == NULL) - newTuples = (PGresAttValue **) - malloc(newSize * sizeof(PGresAttValue *)); - else - newTuples = (PGresAttValue **) - realloc(res->tuples, newSize * sizeof(PGresAttValue *)); - if (!newTuples) - return FALSE; /* malloc or realloc failed */ - res->tupArrSize = newSize; - res->tuples = newTuples; - } - res->tuples[res->ntups] = tup; - res->ntups++; - return TRUE; -} - -/* - * pqSaveMessageField - save one field of an error or notice message - */ -void -pqSaveMessageField(PGresult *res, char code, const char *value) -{ - PGMessageField *pfield; - - pfield = (PGMessageField *) - pqResultAlloc(res, - offsetof(PGMessageField, contents) + - strlen(value) + 1, - TRUE); - if (!pfield) - return; /* out of memory? */ - pfield->code = code; - strcpy(pfield->contents, value); - pfield->next = res->errFields; - res->errFields = pfield; -} - -/* - * pqSaveParameterStatus - remember parameter status sent by backend - */ -void -pqSaveParameterStatus(PGconn *conn, const char *name, const char *value) -{ - pgParameterStatus *pstatus; - pgParameterStatus *prev; - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n", - name, value); - - /* - * Forget any old information about the parameter - */ - for (pstatus = conn->pstatus, prev = NULL; - pstatus != NULL; - prev = pstatus, pstatus = pstatus->next) - { - if (strcmp(pstatus->name, name) == 0) - { - if (prev) - prev->next = pstatus->next; - else - conn->pstatus = pstatus->next; - free(pstatus); /* frees name and value strings too */ - break; - } - } - - /* - * Store new info as a single malloc block - */ - pstatus = (pgParameterStatus *) malloc(sizeof(pgParameterStatus) + - strlen(name) +strlen(value) + 2); - if (pstatus) - { - char *ptr; - - ptr = ((char *) pstatus) + sizeof(pgParameterStatus); - pstatus->name = ptr; - strcpy(ptr, name); - ptr += strlen(name) + 1; - pstatus->value = ptr; - strcpy(ptr, value); - pstatus->next = conn->pstatus; - conn->pstatus = pstatus; - } - - /* - * Special hacks: remember client_encoding and - * standard_conforming_strings, and convert server version to a numeric - * form. We keep the first two of these in static variables as well, so - * that PQescapeString and PQescapeBytea can behave somewhat sanely (at - * least in single-connection-using programs). - */ - if (strcmp(name, "client_encoding") == 0) - { - conn->client_encoding = pg_char_to_encoding(value); - /* if we don't recognize the encoding name, fall back to SQL_ASCII */ - if (conn->client_encoding < 0) - conn->client_encoding = PG_SQL_ASCII; - static_client_encoding = conn->client_encoding; - } - else if (strcmp(name, "standard_conforming_strings") == 0) - { - conn->std_strings = (strcmp(value, "on") == 0); - static_std_strings = conn->std_strings; - } - else if (strcmp(name, "server_version") == 0) - { - int cnt; - int vmaj, - vmin, - vrev; - - cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev); - - if (cnt == 3) - { - /* old style, e.g. 9.6.1 */ - conn->sversion = (100 * vmaj + vmin) * 100 + vrev; - } - else if (cnt == 2) - { - if (vmaj >= 10) - { - /* new style, e.g. 10.1 */ - conn->sversion = 100 * 100 * vmaj + vmin; - } - else - { - /* old style without minor version, e.g. 9.6devel */ - conn->sversion = (100 * vmaj + vmin) * 100; - } - } - else if (cnt == 1) - { - /* new style without minor version, e.g. 10devel */ - conn->sversion = 100 * 100 * vmaj; - } - else - conn->sversion = 0; /* unknown */ - } -} - - -/* - * pqRowProcessor - * Add the received row to the current async result (conn->result). - * Returns 1 if OK, 0 if error occurred. - * - * On error, *errmsgp can be set to an error string to be returned. - * If it is left NULL, the error is presumed to be "out of memory". - * - * In single-row mode, we create a new result holding just the current row, - * stashing the previous result in conn->next_result so that it becomes - * active again after pqPrepareAsyncResult(). This allows the result metadata - * (column descriptions) to be carried forward to each result row. - */ -int -pqRowProcessor(PGconn *conn, const char **errmsgp) -{ - PGresult *res = conn->result; - int nfields = res->numAttributes; - const PGdataValue *columns = conn->rowBuf; - PGresAttValue *tup; - int i; - - /* - * In single-row mode, make a new PGresult that will hold just this one - * row; the original conn->result is left unchanged so that it can be used - * again as the template for future rows. - */ - if (conn->singleRowMode) - { - /* Copy everything that should be in the result at this point */ - res = PQcopyResult(res, - PG_COPYRES_ATTRS | PG_COPYRES_EVENTS | - PG_COPYRES_NOTICEHOOKS); - if (!res) - return 0; - } - - /* - * Basically we just allocate space in the PGresult for each field and - * copy the data over. - * - * Note: on malloc failure, we return 0 leaving *errmsgp still NULL, which - * caller will take to mean "out of memory". This is preferable to trying - * to set up such a message here, because evidently there's not enough - * memory for gettext() to do anything. - */ - tup = (PGresAttValue *) - pqResultAlloc(res, nfields * sizeof(PGresAttValue), TRUE); - if (tup == NULL) - goto fail; - - for (i = 0; i < nfields; i++) - { - int clen = columns[i].len; - - if (clen < 0) - { - /* null field */ - tup[i].len = NULL_LEN; - tup[i].value = res->null_field; - } - else - { - bool isbinary = (res->attDescs[i].format != 0); - char *val; - - val = (char *) pqResultAlloc(res, clen + 1, isbinary); - if (val == NULL) - goto fail; - - /* copy and zero-terminate the data (even if it's binary) */ - memcpy(val, columns[i].value, clen); - val[clen] = '\0'; - - tup[i].len = clen; - tup[i].value = val; - } - } - - /* And add the tuple to the PGresult's tuple array */ - if (!pqAddTuple(res, tup)) - goto fail; - - /* - * Success. In single-row mode, make the result available to the client - * immediately. - */ - if (conn->singleRowMode) - { - /* Change result status to special single-row value */ - res->resultStatus = PGRES_SINGLE_TUPLE; - /* Stash old result for re-use later */ - conn->next_result = conn->result; - conn->result = res; - /* And mark the result ready to return */ - conn->asyncStatus = PGASYNC_READY; - } - - return 1; - -fail: - /* release locally allocated PGresult, if we made one */ - if (res != conn->result) - PQclear(res); - return 0; -} - - -/* - * PQsendQuery - * Submit a query, but don't wait for it to finish - * - * Returns: 1 if successfully submitted - * 0 if error (conn->errorMessage is set) - */ -int -PQsendQuery(PGconn *conn, const char *query) -{ - if (!PQsendQueryStart(conn)) - return 0; - - /* check the argument */ - if (!query) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); - return 0; - } - - /* construct the outgoing Query message */ - if (pqPutMsgStart('Q', false, conn) < 0 || - pqPuts(query, conn) < 0 || - pqPutMsgEnd(conn) < 0) - { - pqHandleSendFailure(conn); - return 0; - } - - /* remember we are using simple query protocol */ - conn->queryclass = PGQUERY_SIMPLE; - - /* and remember the query text too, if possible */ - /* if insufficient memory, last_query just winds up NULL */ - if (conn->last_query) - free(conn->last_query); - conn->last_query = strdup(query); - - /* - * Give the data a push. In nonblock mode, don't complain if we're unable - * to send it all; PQgetResult() will do any additional flushing needed. - */ - if (pqFlush(conn) < 0) - { - pqHandleSendFailure(conn); - return 0; - } - - /* OK, it's launched! */ - conn->asyncStatus = PGASYNC_BUSY; - return 1; -} - -/* - * PQsendQueryParams - * Like PQsendQuery, but use protocol 3.0 so we can pass parameters - */ -int -PQsendQueryParams(PGconn *conn, - const char *command, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat) -{ - if (!PQsendQueryStart(conn)) - return 0; - - /* check the arguments */ - if (!command) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); - return 0; - } - if (nParams < 0 || nParams > 65535) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); - return 0; - } - - return PQsendQueryGuts(conn, - command, - "", /* use unnamed statement */ - nParams, - paramTypes, - paramValues, - paramLengths, - paramFormats, - resultFormat); -} - -/* - * PQsendPrepare - * Submit a Parse message, but don't wait for it to finish - * - * Returns: 1 if successfully submitted - * 0 if error (conn->errorMessage is set) - */ -int -PQsendPrepare(PGconn *conn, - const char *stmtName, const char *query, - int nParams, const Oid *paramTypes) -{ - if (!PQsendQueryStart(conn)) - return 0; - - /* check the arguments */ - if (!stmtName) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); - return 0; - } - if (!query) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("command string is a null pointer\n")); - return 0; - } - if (nParams < 0 || nParams > 65535) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); - return 0; - } - - /* This isn't gonna work on a 2.0 server */ - if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); - return 0; - } - - /* construct the Parse message */ - if (pqPutMsgStart('P', false, conn) < 0 || - pqPuts(stmtName, conn) < 0 || - pqPuts(query, conn) < 0) - goto sendFailed; - - if (nParams > 0 && paramTypes) - { - int i; - - if (pqPutInt(nParams, 2, conn) < 0) - goto sendFailed; - for (i = 0; i < nParams; i++) - { - if (pqPutInt(paramTypes[i], 4, conn) < 0) - goto sendFailed; - } - } - else - { - if (pqPutInt(0, 2, conn) < 0) - goto sendFailed; - } - if (pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* construct the Sync message */ - if (pqPutMsgStart('S', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* remember we are doing just a Parse */ - conn->queryclass = PGQUERY_PREPARE; - - /* and remember the query text too, if possible */ - /* if insufficient memory, last_query just winds up NULL */ - if (conn->last_query) - free(conn->last_query); - conn->last_query = strdup(query); - - /* - * Give the data a push. In nonblock mode, don't complain if we're unable - * to send it all; PQgetResult() will do any additional flushing needed. - */ - if (pqFlush(conn) < 0) - goto sendFailed; - - /* OK, it's launched! */ - conn->asyncStatus = PGASYNC_BUSY; - return 1; - -sendFailed: - pqHandleSendFailure(conn); - return 0; -} - -/* - * PQsendQueryPrepared - * Like PQsendQuery, but execute a previously prepared statement, - * using protocol 3.0 so we can pass parameters - */ -int -PQsendQueryPrepared(PGconn *conn, - const char *stmtName, - int nParams, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat) -{ - if (!PQsendQueryStart(conn)) - return 0; - - /* check the arguments */ - if (!stmtName) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("statement name is a null pointer\n")); - return 0; - } - if (nParams < 0 || nParams > 65535) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("number of parameters must be between 0 and 65535\n")); - return 0; - } - - return PQsendQueryGuts(conn, - NULL, /* no command to parse */ - stmtName, - nParams, - NULL, /* no param types */ - paramValues, - paramLengths, - paramFormats, - resultFormat); -} - -/* - * Common startup code for PQsendQuery and sibling routines - */ -static bool -PQsendQueryStart(PGconn *conn) -{ - if (!conn) - return false; - - /* clear the error string */ - resetPQExpBuffer(&conn->errorMessage); - - /* Don't try to send if we know there's no live connection. */ - if (conn->status != CONNECTION_OK) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no connection to the server\n")); - return false; - } - /* Can't send while already busy, either. */ - if (conn->asyncStatus != PGASYNC_IDLE) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("another command is already in progress\n")); - return false; - } - - /* initialize async result-accumulation state */ - pqClearAsyncResult(conn); - - /* reset single-row processing mode */ - conn->singleRowMode = false; - - /* ready to send command message */ - return true; -} - -/* - * PQsendQueryGuts - * Common code for protocol-3.0 query sending - * PQsendQueryStart should be done already - * - * command may be NULL to indicate we use an already-prepared statement - */ -static int -PQsendQueryGuts(PGconn *conn, - const char *command, - const char *stmtName, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat) -{ - int i; - - /* This isn't gonna work on a 2.0 server */ - if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); - return 0; - } - - /* - * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync, - * using specified statement name and the unnamed portal. - */ - - if (command) - { - /* construct the Parse message */ - if (pqPutMsgStart('P', false, conn) < 0 || - pqPuts(stmtName, conn) < 0 || - pqPuts(command, conn) < 0) - goto sendFailed; - if (nParams > 0 && paramTypes) - { - if (pqPutInt(nParams, 2, conn) < 0) - goto sendFailed; - for (i = 0; i < nParams; i++) - { - if (pqPutInt(paramTypes[i], 4, conn) < 0) - goto sendFailed; - } - } - else - { - if (pqPutInt(0, 2, conn) < 0) - goto sendFailed; - } - if (pqPutMsgEnd(conn) < 0) - goto sendFailed; - } - - /* Construct the Bind message */ - if (pqPutMsgStart('B', false, conn) < 0 || - pqPuts("", conn) < 0 || - pqPuts(stmtName, conn) < 0) - goto sendFailed; - - /* Send parameter formats */ - if (nParams > 0 && paramFormats) - { - if (pqPutInt(nParams, 2, conn) < 0) - goto sendFailed; - for (i = 0; i < nParams; i++) - { - if (pqPutInt(paramFormats[i], 2, conn) < 0) - goto sendFailed; - } - } - else - { - if (pqPutInt(0, 2, conn) < 0) - goto sendFailed; - } - - if (pqPutInt(nParams, 2, conn) < 0) - goto sendFailed; - - /* Send parameters */ - for (i = 0; i < nParams; i++) - { - if (paramValues && paramValues[i]) - { - int nbytes; - - if (paramFormats && paramFormats[i] != 0) - { - /* binary parameter */ - if (paramLengths) - nbytes = paramLengths[i]; - else - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("length must be given for binary parameter\n")); - goto sendFailed; - } - } - else - { - /* text parameter, do not use paramLengths */ - nbytes = strlen(paramValues[i]); - } - if (pqPutInt(nbytes, 4, conn) < 0 || - pqPutnchar(paramValues[i], nbytes, conn) < 0) - goto sendFailed; - } - else - { - /* take the param as NULL */ - if (pqPutInt(-1, 4, conn) < 0) - goto sendFailed; - } - } - if (pqPutInt(1, 2, conn) < 0 || - pqPutInt(resultFormat, 2, conn)) - goto sendFailed; - if (pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* construct the Describe Portal message */ - if (pqPutMsgStart('D', false, conn) < 0 || - pqPutc('P', conn) < 0 || - pqPuts("", conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* construct the Execute message */ - if (pqPutMsgStart('E', false, conn) < 0 || - pqPuts("", conn) < 0 || - pqPutInt(0, 4, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* construct the Sync message */ - if (pqPutMsgStart('S', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* remember we are using extended query protocol */ - conn->queryclass = PGQUERY_EXTENDED; - - /* and remember the query text too, if possible */ - /* if insufficient memory, last_query just winds up NULL */ - if (conn->last_query) - free(conn->last_query); - if (command) - conn->last_query = strdup(command); - else - conn->last_query = NULL; - - /* - * Give the data a push. In nonblock mode, don't complain if we're unable - * to send it all; PQgetResult() will do any additional flushing needed. - */ - if (pqFlush(conn) < 0) - goto sendFailed; - - /* OK, it's launched! */ - conn->asyncStatus = PGASYNC_BUSY; - return 1; - -sendFailed: - pqHandleSendFailure(conn); - return 0; -} - -/* - * pqHandleSendFailure: try to clean up after failure to send command. - * - * Primarily, what we want to accomplish here is to process any ERROR or - * NOTICE messages that the backend might have sent just before it died. - * Since we're in IDLE state, all such messages will get sent to the notice - * processor. - * - * NOTE: this routine should only be called in PGASYNC_IDLE state. - */ -void -pqHandleSendFailure(PGconn *conn) -{ - /* - * Accept and parse any available input data, ignoring I/O errors. Note - * that if pqReadData decides the backend has closed the channel, it will - * close our side of the socket --- that's just what we want here. - */ - while (pqReadData(conn) > 0) - parseInput(conn); - - /* - * Be sure to parse available input messages even if we read no data. - * (Note: calling parseInput within the above loop isn't really necessary, - * but it prevents buffer bloat if there's a lot of data available.) - */ - parseInput(conn); -} - -/* - * Select row-by-row processing mode - */ -int -PQsetSingleRowMode(PGconn *conn) -{ - /* - * Only allow setting the flag when we have launched a query and not yet - * received any results. - */ - if (!conn) - return 0; - if (conn->asyncStatus != PGASYNC_BUSY) - return 0; - if (conn->queryclass != PGQUERY_SIMPLE && - conn->queryclass != PGQUERY_EXTENDED) - return 0; - if (conn->result) - return 0; - - /* OK, set flag */ - conn->singleRowMode = true; - return 1; -} - -/* - * Consume any available input from the backend - * 0 return: some kind of trouble - * 1 return: no problem - */ -int -PQconsumeInput(PGconn *conn) -{ - if (!conn) - return 0; - - /* - * for non-blocking connections try to flush the send-queue, otherwise we - * may never get a response for something that may not have already been - * sent because it's in our write buffer! - */ - if (pqIsnonblocking(conn)) - { - if (pqFlush(conn) < 0) - return 0; - } - - /* - * Load more data, if available. We do this no matter what state we are - * in, since we are probably getting called because the application wants - * to get rid of a read-select condition. Note that we will NOT block - * waiting for more input. - */ - if (pqReadData(conn) < 0) - return 0; - - /* Parsing of the data waits till later. */ - return 1; -} - - -/* - * parseInput: if appropriate, parse input data from backend - * until input is exhausted or a stopping state is reached. - * Note that this function will NOT attempt to read more data from the backend. - */ -static void -parseInput(PGconn *conn) -{ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - pqParseInput3(conn); - else - pqParseInput2(conn); -} - -/* - * PQisBusy - * Return TRUE if PQgetResult would block waiting for input. - */ - -int -PQisBusy(PGconn *conn) -{ - if (!conn) - return FALSE; - - /* Parse any available data, if our state permits. */ - parseInput(conn); - - /* PQgetResult will return immediately in all states except BUSY. */ - return conn->asyncStatus == PGASYNC_BUSY; -} - - -/* - * PQgetResult - * Get the next PGresult produced by a query. Returns NULL if no - * query work remains or an error has occurred (e.g. out of - * memory). - */ - -PGresult * -PQgetResult(PGconn *conn) -{ - PGresult *res; - - if (!conn) - return NULL; - - /* Parse any available data, if our state permits. */ - parseInput(conn); - - /* If not ready to return something, block until we are. */ - while (conn->asyncStatus == PGASYNC_BUSY) - { - int flushResult; - - /* - * If data remains unsent, send it. Else we might be waiting for the - * result of a command the backend hasn't even got yet. - */ - while ((flushResult = pqFlush(conn)) > 0) - { - if (pqWait(FALSE, TRUE, conn)) - { - flushResult = -1; - break; - } - } - - /* Wait for some more data, and load it. */ - if (flushResult || - pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - { - /* - * conn->errorMessage has been set by pqWait or pqReadData. We - * want to append it to any already-received error message. - */ - pqSaveErrorResult(conn); - conn->asyncStatus = PGASYNC_IDLE; - return pqPrepareAsyncResult(conn); - } - - /* Parse it. */ - parseInput(conn); - } - - /* Return the appropriate thing. */ - switch (conn->asyncStatus) - { - case PGASYNC_IDLE: - res = NULL; /* query is complete */ - break; - case PGASYNC_READY: - res = pqPrepareAsyncResult(conn); - /* Set the state back to BUSY, allowing parsing to proceed. */ - conn->asyncStatus = PGASYNC_BUSY; - break; - case PGASYNC_COPY_IN: - res = getCopyResult(conn, PGRES_COPY_IN); - break; - case PGASYNC_COPY_OUT: - res = getCopyResult(conn, PGRES_COPY_OUT); - break; - case PGASYNC_COPY_BOTH: - res = getCopyResult(conn, PGRES_COPY_BOTH); - break; - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("unexpected asyncStatus: %d\n"), - (int) conn->asyncStatus); - res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - break; - } - - if (res) - { - int i; - - for (i = 0; i < res->nEvents; i++) - { - PGEventResultCreate evt; - - evt.conn = conn; - evt.result = res; - if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, - res->events[i].passThrough)) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PGEventProc \"%s\" failed during PGEVT_RESULTCREATE event\n"), - res->events[i].name); - pqSetResultError(res, conn->errorMessage.data); - res->resultStatus = PGRES_FATAL_ERROR; - break; - } - res->events[i].resultInitialized = TRUE; - } - } - - return res; -} - -/* - * getCopyResult - * Helper for PQgetResult: generate result for COPY-in-progress cases - */ -static PGresult * -getCopyResult(PGconn *conn, ExecStatusType copytype) -{ - /* - * If the server connection has been lost, don't pretend everything is - * hunky-dory; instead return a PGRES_FATAL_ERROR result, and reset the - * asyncStatus to idle (corresponding to what we'd do if we'd detected I/O - * error in the earlier steps in PQgetResult). The text returned in the - * result is whatever is in conn->errorMessage; we hope that was filled - * with something relevant when the lost connection was detected. - */ - if (conn->status != CONNECTION_OK) - { - pqSaveErrorResult(conn); - conn->asyncStatus = PGASYNC_IDLE; - return pqPrepareAsyncResult(conn); - } - - /* If we have an async result for the COPY, return that */ - if (conn->result && conn->result->resultStatus == copytype) - return pqPrepareAsyncResult(conn); - - /* Otherwise, invent a suitable PGresult */ - return PQmakeEmptyPGresult(conn, copytype); -} - - -/* - * PQexec - * send a query to the backend and package up the result in a PGresult - * - * If the query was not even sent, return NULL; conn->errorMessage is set to - * a relevant message. - * If the query was sent, a new PGresult is returned (which could indicate - * either success or failure). - * The user is responsible for freeing the PGresult via PQclear() - * when done with it. - */ -PGresult * -PQexec(PGconn *conn, const char *query) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendQuery(conn, query)) - return NULL; - return PQexecFinish(conn); -} - -/* - * PQexecParams - * Like PQexec, but use protocol 3.0 so we can pass parameters - */ -PGresult * -PQexecParams(PGconn *conn, - const char *command, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendQueryParams(conn, command, - nParams, paramTypes, paramValues, paramLengths, - paramFormats, resultFormat)) - return NULL; - return PQexecFinish(conn); -} - -/* - * PQprepare - * Creates a prepared statement by issuing a v3.0 parse message. - * - * If the query was not even sent, return NULL; conn->errorMessage is set to - * a relevant message. - * If the query was sent, a new PGresult is returned (which could indicate - * either success or failure). - * The user is responsible for freeing the PGresult via PQclear() - * when done with it. - */ -PGresult * -PQprepare(PGconn *conn, - const char *stmtName, const char *query, - int nParams, const Oid *paramTypes) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendPrepare(conn, stmtName, query, nParams, paramTypes)) - return NULL; - return PQexecFinish(conn); -} - -/* - * PQexecPrepared - * Like PQexec, but execute a previously prepared statement, - * using protocol 3.0 so we can pass parameters - */ -PGresult * -PQexecPrepared(PGconn *conn, - const char *stmtName, - int nParams, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendQueryPrepared(conn, stmtName, - nParams, paramValues, paramLengths, - paramFormats, resultFormat)) - return NULL; - return PQexecFinish(conn); -} - -/* - * Common code for PQexec and sibling routines: prepare to send command - */ -static bool -PQexecStart(PGconn *conn) -{ - PGresult *result; - - if (!conn) - return false; - - /* - * Silently discard any prior query result that application didn't eat. - * This is probably poor design, but it's here for backward compatibility. - */ - while ((result = PQgetResult(conn)) != NULL) - { - ExecStatusType resultStatus = result->resultStatus; - - PQclear(result); /* only need its status */ - if (resultStatus == PGRES_COPY_IN) - { - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - /* In protocol 3, we can get out of a COPY IN state */ - if (PQputCopyEnd(conn, - libpq_gettext("COPY terminated by new PQexec")) < 0) - return false; - /* keep waiting to swallow the copy's failure message */ - } - else - { - /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY IN state must be terminated first\n")); - return false; - } - } - else if (resultStatus == PGRES_COPY_OUT) - { - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - /* - * In protocol 3, we can get out of a COPY OUT state: we just - * switch back to BUSY and allow the remaining COPY data to be - * dropped on the floor. - */ - conn->asyncStatus = PGASYNC_BUSY; - /* keep waiting to swallow the copy's completion message */ - } - else - { - /* In older protocols we have to punt */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("COPY OUT state must be terminated first\n")); - return false; - } - } - else if (resultStatus == PGRES_COPY_BOTH) - { - /* We don't allow PQexec during COPY BOTH */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQexec not allowed during COPY BOTH\n")); - return false; - } - /* check for loss of connection, too */ - if (conn->status == CONNECTION_BAD) - return false; - } - - /* OK to send a command */ - return true; -} - -/* - * Common code for PQexec and sibling routines: wait for command result - */ -static PGresult * -PQexecFinish(PGconn *conn) -{ - PGresult *result; - PGresult *lastResult; - - /* - * For backwards compatibility, return the last result if there are more - * than one --- but merge error messages if we get more than one error - * result. - * - * We have to stop if we see copy in/out/both, however. We will resume - * parsing after application performs the data transfer. - * - * Also stop if the connection is lost (else we'll loop infinitely). - */ - lastResult = NULL; - while ((result = PQgetResult(conn)) != NULL) - { - if (lastResult) - { - if (lastResult->resultStatus == PGRES_FATAL_ERROR && - result->resultStatus == PGRES_FATAL_ERROR) - { - pqCatenateResultError(lastResult, result->errMsg); - PQclear(result); - result = lastResult; - - /* - * Make sure PQerrorMessage agrees with concatenated result - */ - resetPQExpBuffer(&conn->errorMessage); - appendPQExpBufferStr(&conn->errorMessage, result->errMsg); - } - else - PQclear(lastResult); - } - lastResult = result; - if (result->resultStatus == PGRES_COPY_IN || - result->resultStatus == PGRES_COPY_OUT || - result->resultStatus == PGRES_COPY_BOTH || - conn->status == CONNECTION_BAD) - break; - } - - return lastResult; -} - -/* - * PQdescribePrepared - * Obtain information about a previously prepared statement - * - * If the query was not even sent, return NULL; conn->errorMessage is set to - * a relevant message. - * If the query was sent, a new PGresult is returned (which could indicate - * either success or failure). On success, the PGresult contains status - * PGRES_COMMAND_OK, and its parameter and column-heading fields describe - * the statement's inputs and outputs respectively. - * The user is responsible for freeing the PGresult via PQclear() - * when done with it. - */ -PGresult * -PQdescribePrepared(PGconn *conn, const char *stmt) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendDescribe(conn, 'S', stmt)) - return NULL; - return PQexecFinish(conn); -} - -/* - * PQdescribePortal - * Obtain information about a previously created portal - * - * This is much like PQdescribePrepared, except that no parameter info is - * returned. Note that at the moment, libpq doesn't really expose portals - * to the client; but this can be used with a portal created by a SQL - * DECLARE CURSOR command. - */ -PGresult * -PQdescribePortal(PGconn *conn, const char *portal) -{ - if (!PQexecStart(conn)) - return NULL; - if (!PQsendDescribe(conn, 'P', portal)) - return NULL; - return PQexecFinish(conn); -} - -/* - * PQsendDescribePrepared - * Submit a Describe Statement command, but don't wait for it to finish - * - * Returns: 1 if successfully submitted - * 0 if error (conn->errorMessage is set) - */ -int -PQsendDescribePrepared(PGconn *conn, const char *stmt) -{ - return PQsendDescribe(conn, 'S', stmt); -} - -/* - * PQsendDescribePortal - * Submit a Describe Portal command, but don't wait for it to finish - * - * Returns: 1 if successfully submitted - * 0 if error (conn->errorMessage is set) - */ -int -PQsendDescribePortal(PGconn *conn, const char *portal) -{ - return PQsendDescribe(conn, 'P', portal); -} - -/* - * PQsendDescribe - * Common code to send a Describe command - * - * Available options for desc_type are - * 'S' to describe a prepared statement; or - * 'P' to describe a portal. - * Returns 1 on success and 0 on failure. - */ -static int -PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target) -{ - /* Treat null desc_target as empty string */ - if (!desc_target) - desc_target = ""; - - if (!PQsendQueryStart(conn)) - return 0; - - /* This isn't gonna work on a 2.0 server */ - if (PG_PROTOCOL_MAJOR(conn->pversion) < 3) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); - return 0; - } - - /* construct the Describe message */ - if (pqPutMsgStart('D', false, conn) < 0 || - pqPutc(desc_type, conn) < 0 || - pqPuts(desc_target, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* construct the Sync message */ - if (pqPutMsgStart('S', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - goto sendFailed; - - /* remember we are doing a Describe */ - conn->queryclass = PGQUERY_DESCRIBE; - - /* reset last-query string (not relevant now) */ - if (conn->last_query) - { - free(conn->last_query); - conn->last_query = NULL; - } - - /* - * Give the data a push. In nonblock mode, don't complain if we're unable - * to send it all; PQgetResult() will do any additional flushing needed. - */ - if (pqFlush(conn) < 0) - goto sendFailed; - - /* OK, it's launched! */ - conn->asyncStatus = PGASYNC_BUSY; - return 1; - -sendFailed: - pqHandleSendFailure(conn); - return 0; -} - -/* - * PQnotifies - * returns a PGnotify* structure of the latest async notification - * that has not yet been handled - * - * returns NULL, if there is currently - * no unhandled async notification from the backend - * - * the CALLER is responsible for FREE'ing the structure returned - */ -PGnotify * -PQnotifies(PGconn *conn) -{ - PGnotify *event; - - if (!conn) - return NULL; - - /* Parse any available data to see if we can extract NOTIFY messages. */ - parseInput(conn); - - event = conn->notifyHead; - if (event) - { - conn->notifyHead = event->next; - if (!conn->notifyHead) - conn->notifyTail = NULL; - event->next = NULL; /* don't let app see the internal state */ - } - return event; -} - -/* - * PQputCopyData - send some data to the backend during COPY IN or COPY BOTH - * - * Returns 1 if successful, 0 if data could not be sent (only possible - * in nonblock mode), or -1 if an error occurs. - */ -int -PQputCopyData(PGconn *conn, const char *buffer, int nbytes) -{ - if (!conn) - return -1; - if (conn->asyncStatus != PGASYNC_COPY_IN && - conn->asyncStatus != PGASYNC_COPY_BOTH) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); - return -1; - } - - /* - * Process any NOTICE or NOTIFY messages that might be pending in the - * input buffer. Since the server might generate many notices during the - * COPY, we want to clean those out reasonably promptly to prevent - * indefinite expansion of the input buffer. (Note: the actual read of - * input data into the input buffer happens down inside pqSendSome, but - * it's not authorized to get rid of the data again.) - */ - parseInput(conn); - - if (nbytes > 0) - { - /* - * Try to flush any previously sent data in preference to growing the - * output buffer. If we can't enlarge the buffer enough to hold the - * data, return 0 in the nonblock case, else hard error. (For - * simplicity, always assume 5 bytes of overhead even in protocol 2.0 - * case.) - */ - if ((conn->outBufSize - conn->outCount - 5) < nbytes) - { - if (pqFlush(conn) < 0) - return -1; - if (pqCheckOutBufferSpace(conn->outCount + 5 + (size_t) nbytes, - conn)) - return pqIsnonblocking(conn) ? 0 : -1; - } - /* Send the data (too simple to delegate to fe-protocol files) */ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - if (pqPutMsgStart('d', false, conn) < 0 || - pqPutnchar(buffer, nbytes, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - else - { - if (pqPutMsgStart(0, false, conn) < 0 || - pqPutnchar(buffer, nbytes, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - } - return 1; -} - -/* - * PQputCopyEnd - send EOF indication to the backend during COPY IN - * - * After calling this, use PQgetResult() to check command completion status. - * - * Returns 1 if successful, 0 if data could not be sent (only possible - * in nonblock mode), or -1 if an error occurs. - */ -int -PQputCopyEnd(PGconn *conn, const char *errormsg) -{ - if (!conn) - return -1; - if (conn->asyncStatus != PGASYNC_COPY_IN && - conn->asyncStatus != PGASYNC_COPY_BOTH) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); - return -1; - } - - /* - * Send the COPY END indicator. This is simple enough that we don't - * bother delegating it to the fe-protocol files. - */ - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - if (errormsg) - { - /* Send COPY FAIL */ - if (pqPutMsgStart('f', false, conn) < 0 || - pqPuts(errormsg, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - else - { - /* Send COPY DONE */ - if (pqPutMsgStart('c', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - - /* - * If we sent the COPY command in extended-query mode, we must issue a - * Sync as well. - */ - if (conn->queryclass != PGQUERY_SIMPLE) - { - if (pqPutMsgStart('S', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - } - else - { - if (errormsg) - { - /* Ooops, no way to do this in 2.0 */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("function requires at least protocol version 3.0\n")); - return -1; - } - else - { - /* Send old-style end-of-data marker */ - if (pqPutMsgStart(0, false, conn) < 0 || - pqPutnchar("\\.\n", 3, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return -1; - } - } - - /* Return to active duty */ - if (conn->asyncStatus == PGASYNC_COPY_BOTH) - conn->asyncStatus = PGASYNC_COPY_OUT; - else - conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); - - /* Try to flush data */ - if (pqFlush(conn) < 0) - return -1; - - return 1; -} - -/* - * PQgetCopyData - read a row of data from the backend during COPY OUT - * or COPY BOTH - * - * If successful, sets *buffer to point to a malloc'd row of data, and - * returns row length (always > 0) as result. - * Returns 0 if no row available yet (only possible if async is true), - * -1 if end of copy (consult PQgetResult), or -2 if error (consult - * PQerrorMessage). - */ -int -PQgetCopyData(PGconn *conn, char **buffer, int async) -{ - *buffer = NULL; /* for all failure cases */ - if (!conn) - return -2; - if (conn->asyncStatus != PGASYNC_COPY_OUT && - conn->asyncStatus != PGASYNC_COPY_BOTH) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); - return -2; - } - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - return pqGetCopyData3(conn, buffer, async); - else - return pqGetCopyData2(conn, buffer, async); -} - -/* - * PQgetline - gets a newline-terminated string from the backend. - * - * Chiefly here so that applications can use "COPY to stdout" - * and read the output string. Returns a null-terminated string in s. - * - * XXX this routine is now deprecated, because it can't handle binary data. - * If called during a COPY BINARY we return EOF. - * - * PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips - * the terminating \n (like gets(3)). - * - * CAUTION: the caller is responsible for detecting the end-of-copy signal - * (a line containing just "\.") when using this routine. - * - * RETURNS: - * EOF if error (eg, invalid arguments are given) - * 0 if EOL is reached (i.e., \n has been read) - * (this is required for backward-compatibility -- this - * routine used to always return EOF or 0, assuming that - * the line ended within maxlen bytes.) - * 1 in other cases (i.e., the buffer was filled before \n is reached) - */ -int -PQgetline(PGconn *conn, char *s, int maxlen) -{ - if (!s || maxlen <= 0) - return EOF; - *s = '\0'; - /* maxlen must be at least 3 to hold the \. terminator! */ - if (maxlen < 3) - return EOF; - - if (!conn) - return EOF; - - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - return pqGetline3(conn, s, maxlen); - else - return pqGetline2(conn, s, maxlen); -} - -/* - * PQgetlineAsync - gets a COPY data row without blocking. - * - * This routine is for applications that want to do "COPY to stdout" - * asynchronously, that is without blocking. Having issued the COPY command - * and gotten a PGRES_COPY_OUT response, the app should call PQconsumeInput - * and this routine until the end-of-data signal is detected. Unlike - * PQgetline, this routine takes responsibility for detecting end-of-data. - * - * On each call, PQgetlineAsync will return data if a complete data row - * is available in libpq's input buffer. Otherwise, no data is returned - * until the rest of the row arrives. - * - * If -1 is returned, the end-of-data signal has been recognized (and removed - * from libpq's input buffer). The caller *must* next call PQendcopy and - * then return to normal processing. - * - * RETURNS: - * -1 if the end-of-copy-data marker has been recognized - * 0 if no data is available - * >0 the number of bytes returned. - * - * The data returned will not extend beyond a data-row boundary. If possible - * a whole row will be returned at one time. But if the buffer offered by - * the caller is too small to hold a row sent by the backend, then a partial - * data row will be returned. In text mode this can be detected by testing - * whether the last returned byte is '\n' or not. - * - * The returned data is *not* null-terminated. - */ - -int -PQgetlineAsync(PGconn *conn, char *buffer, int bufsize) -{ - if (!conn) - return -1; - - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - return pqGetlineAsync3(conn, buffer, bufsize); - else - return pqGetlineAsync2(conn, buffer, bufsize); -} - -/* - * PQputline -- sends a string to the backend during COPY IN. - * Returns 0 if OK, EOF if not. - * - * This is deprecated primarily because the return convention doesn't allow - * caller to tell the difference between a hard error and a nonblock-mode - * send failure. - */ -int -PQputline(PGconn *conn, const char *s) -{ - return PQputnbytes(conn, s, strlen(s)); -} - -/* - * PQputnbytes -- like PQputline, but buffer need not be null-terminated. - * Returns 0 if OK, EOF if not. - */ -int -PQputnbytes(PGconn *conn, const char *buffer, int nbytes) -{ - if (PQputCopyData(conn, buffer, nbytes) > 0) - return 0; - else - return EOF; -} - -/* - * PQendcopy - * After completing the data transfer portion of a copy in/out, - * the application must call this routine to finish the command protocol. - * - * When using protocol 3.0 this is deprecated; it's cleaner to use PQgetResult - * to get the transfer status. Note however that when using 2.0 protocol, - * recovering from a copy failure often requires a PQreset. PQendcopy will - * take care of that, PQgetResult won't. - * - * RETURNS: - * 0 on success - * 1 on failure - */ -int -PQendcopy(PGconn *conn) -{ - if (!conn) - return 0; - - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - return pqEndcopy3(conn); - else - return pqEndcopy2(conn); -} - - -/* ---------------- - * PQfn - Send a function call to the POSTGRES backend. - * - * conn : backend connection - * fnid : OID of function to be called - * result_buf : pointer to result buffer - * result_len : actual length of result is returned here - * result_is_int : If the result is an integer, this must be 1, - * otherwise this should be 0 - * args : pointer to an array of function arguments - * (each has length, if integer, and value/pointer) - * nargs : # of arguments in args array. - * - * RETURNS - * PGresult with status = PGRES_COMMAND_OK if successful. - * *result_len is > 0 if there is a return value, 0 if not. - * PGresult with status = PGRES_FATAL_ERROR if backend returns an error. - * NULL on communications failure. conn->errorMessage will be set. - * ---------------- - */ - -PGresult * -PQfn(PGconn *conn, - int fnid, - int *result_buf, - int *result_len, - int result_is_int, - const PQArgBlock *args, - int nargs) -{ - *result_len = 0; - - if (!conn) - return NULL; - - /* clear the error string */ - resetPQExpBuffer(&conn->errorMessage); - - if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || - conn->result != NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection in wrong state\n")); - return NULL; - } - - if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - return pqFunctionCall3(conn, fnid, - result_buf, result_len, - result_is_int, - args, nargs); - else - return pqFunctionCall2(conn, fnid, - result_buf, result_len, - result_is_int, - args, nargs); -} - - -/* ====== accessor funcs for PGresult ======== */ - -ExecStatusType -PQresultStatus(const PGresult *res) -{ - if (!res) - return PGRES_FATAL_ERROR; - return res->resultStatus; -} - -char * -PQresStatus(ExecStatusType status) -{ - if ((unsigned int) status >= sizeof pgresStatus / sizeof pgresStatus[0]) - return libpq_gettext("invalid ExecStatusType code"); - return pgresStatus[status]; -} - -char * -PQresultErrorMessage(const PGresult *res) -{ - if (!res || !res->errMsg) - return ""; - return res->errMsg; -} - -char * -PQresultVerboseErrorMessage(const PGresult *res, - PGVerbosity verbosity, - PGContextVisibility show_context) -{ - PQExpBufferData workBuf; - - /* - * Because the caller is expected to free the result string, we must - * strdup any constant result. We use plain strdup and document that - * callers should expect NULL if out-of-memory. - */ - if (!res || - (res->resultStatus != PGRES_FATAL_ERROR && - res->resultStatus != PGRES_NONFATAL_ERROR)) - return strdup(libpq_gettext("PGresult is not an error result\n")); - - initPQExpBuffer(&workBuf); - - /* - * Currently, we pass this off to fe-protocol3.c in all cases; it will - * behave reasonably sanely with an error reported by fe-protocol2.c as - * well. If necessary, we could record the protocol version in PGresults - * so as to be able to invoke a version-specific message formatter, but - * for now there's no need. - */ - pqBuildErrorMessage3(&workBuf, res, verbosity, show_context); - - /* If insufficient memory to format the message, fail cleanly */ - if (PQExpBufferDataBroken(workBuf)) - { - termPQExpBuffer(&workBuf); - return strdup(libpq_gettext("out of memory\n")); - } - - return workBuf.data; -} - -char * -PQresultErrorField(const PGresult *res, int fieldcode) -{ - PGMessageField *pfield; - - if (!res) - return NULL; - for (pfield = res->errFields; pfield != NULL; pfield = pfield->next) - { - if (pfield->code == fieldcode) - return pfield->contents; - } - return NULL; -} - -int -PQntuples(const PGresult *res) -{ - if (!res) - return 0; - return res->ntups; -} - -int -PQnfields(const PGresult *res) -{ - if (!res) - return 0; - return res->numAttributes; -} - -int -PQbinaryTuples(const PGresult *res) -{ - if (!res) - return 0; - return res->binary; -} - -/* - * Helper routines to range-check field numbers and tuple numbers. - * Return TRUE if OK, FALSE if not - */ - -static int -check_field_number(const PGresult *res, int field_num) -{ - if (!res) - return FALSE; /* no way to display error message... */ - if (field_num < 0 || field_num >= res->numAttributes) - { - pqInternalNotice(&res->noticeHooks, - "column number %d is out of range 0..%d", - field_num, res->numAttributes - 1); - return FALSE; - } - return TRUE; -} - -static int -check_tuple_field_number(const PGresult *res, - int tup_num, int field_num) -{ - if (!res) - return FALSE; /* no way to display error message... */ - if (tup_num < 0 || tup_num >= res->ntups) - { - pqInternalNotice(&res->noticeHooks, - "row number %d is out of range 0..%d", - tup_num, res->ntups - 1); - return FALSE; - } - if (field_num < 0 || field_num >= res->numAttributes) - { - pqInternalNotice(&res->noticeHooks, - "column number %d is out of range 0..%d", - field_num, res->numAttributes - 1); - return FALSE; - } - return TRUE; -} - -static int -check_param_number(const PGresult *res, int param_num) -{ - if (!res) - return FALSE; /* no way to display error message... */ - if (param_num < 0 || param_num >= res->numParameters) - { - pqInternalNotice(&res->noticeHooks, - "parameter number %d is out of range 0..%d", - param_num, res->numParameters - 1); - return FALSE; - } - - return TRUE; -} - -/* - * returns NULL if the field_num is invalid - */ -char * -PQfname(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return NULL; - if (res->attDescs) - return res->attDescs[field_num].name; - else - return NULL; -} - -/* - * PQfnumber: find column number given column name - * - * The column name is parsed as if it were in a SQL statement, including - * case-folding and double-quote processing. But note a possible gotcha: - * downcasing in the frontend might follow different locale rules than - * downcasing in the backend... - * - * Returns -1 if no match. In the present backend it is also possible - * to have multiple matches, in which case the first one is found. - */ -int -PQfnumber(const PGresult *res, const char *field_name) -{ - char *field_case; - bool in_quotes; - bool all_lower = true; - const char *iptr; - char *optr; - int i; - - if (!res) - return -1; - - /* - * Note: it is correct to reject a zero-length input string; the proper - * input to match a zero-length field name would be "". - */ - if (field_name == NULL || - field_name[0] == '\0' || - res->attDescs == NULL) - return -1; - - /* - * Check if we can avoid the strdup() and related work because the - * passed-in string wouldn't be changed before we do the check anyway. - */ - for (iptr = field_name; *iptr; iptr++) - { - char c = *iptr; - - if (c == '"' || c != pg_tolower((unsigned char) c)) - { - all_lower = false; - break; - } - } - - if (all_lower) - for (i = 0; i < res->numAttributes; i++) - if (strcmp(field_name, res->attDescs[i].name) == 0) - return i; - - /* Fall through to the normal check if that didn't work out. */ - - /* - * Note: this code will not reject partially quoted strings, eg - * foo"BAR"foo will become fooBARfoo when it probably ought to be an error - * condition. - */ - field_case = strdup(field_name); - if (field_case == NULL) - return -1; /* grotty */ - - in_quotes = false; - optr = field_case; - for (iptr = field_case; *iptr; iptr++) - { - char c = *iptr; - - if (in_quotes) - { - if (c == '"') - { - if (iptr[1] == '"') - { - /* doubled quotes become a single quote */ - *optr++ = '"'; - iptr++; - } - else - in_quotes = false; - } - else - *optr++ = c; - } - else if (c == '"') - in_quotes = true; - else - { - c = pg_tolower((unsigned char) c); - *optr++ = c; - } - } - *optr = '\0'; - - for (i = 0; i < res->numAttributes; i++) - { - if (strcmp(field_case, res->attDescs[i].name) == 0) - { - free(field_case); - return i; - } - } - free(field_case); - return -1; -} - -Oid -PQftable(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return InvalidOid; - if (res->attDescs) - return res->attDescs[field_num].tableid; - else - return InvalidOid; -} - -int -PQftablecol(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return 0; - if (res->attDescs) - return res->attDescs[field_num].columnid; - else - return 0; -} - -int -PQfformat(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return 0; - if (res->attDescs) - return res->attDescs[field_num].format; - else - return 0; -} - -Oid -PQftype(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return InvalidOid; - if (res->attDescs) - return res->attDescs[field_num].typid; - else - return InvalidOid; -} - -int -PQfsize(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return 0; - if (res->attDescs) - return res->attDescs[field_num].typlen; - else - return 0; -} - -int -PQfmod(const PGresult *res, int field_num) -{ - if (!check_field_number(res, field_num)) - return 0; - if (res->attDescs) - return res->attDescs[field_num].atttypmod; - else - return 0; -} - -char * -PQcmdStatus(PGresult *res) -{ - if (!res) - return NULL; - return res->cmdStatus; -} - -/* - * PQoidStatus - - * if the last command was an INSERT, return the oid string - * if not, return "" - */ -char * -PQoidStatus(const PGresult *res) -{ - /* - * This must be enough to hold the result. Don't laugh, this is better - * than what this function used to do. - */ - static char buf[24]; - - size_t len; - - if (!res || strncmp(res->cmdStatus, "INSERT ", 7) != 0) - return ""; - - len = strspn(res->cmdStatus + 7, "0123456789"); - if (len > sizeof(buf) - 1) - len = sizeof(buf) - 1; - memcpy(buf, res->cmdStatus + 7, len); - buf[len] = '\0'; - - return buf; -} - -/* - * PQoidValue - - * a perhaps preferable form of the above which just returns - * an Oid type - */ -Oid -PQoidValue(const PGresult *res) -{ - char *endptr = NULL; - unsigned long result; - - if (!res || - strncmp(res->cmdStatus, "INSERT ", 7) != 0 || - res->cmdStatus[7] < '0' || - res->cmdStatus[7] > '9') - return InvalidOid; - - result = strtoul(res->cmdStatus + 7, &endptr, 10); - - if (!endptr || (*endptr != ' ' && *endptr != '\0')) - return InvalidOid; - else - return (Oid) result; -} - - -/* - * PQcmdTuples - - * If the last command was INSERT/UPDATE/DELETE/MOVE/FETCH/COPY, return - * a string containing the number of inserted/affected tuples. If not, - * return "". - * - * XXX: this should probably return an int - */ -char * -PQcmdTuples(PGresult *res) -{ - char *p, - *c; - - if (!res) - return ""; - - if (strncmp(res->cmdStatus, "INSERT ", 7) == 0) - { - p = res->cmdStatus + 7; - /* INSERT: skip oid and space */ - while (*p && *p != ' ') - p++; - if (*p == 0) - goto interpret_error; /* no space? */ - p++; - } - else if (strncmp(res->cmdStatus, "SELECT ", 7) == 0 || - strncmp(res->cmdStatus, "DELETE ", 7) == 0 || - strncmp(res->cmdStatus, "UPDATE ", 7) == 0) - p = res->cmdStatus + 7; - else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0) - p = res->cmdStatus + 6; - else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0 || - strncmp(res->cmdStatus, "COPY ", 5) == 0) - p = res->cmdStatus + 5; - else - return ""; - - /* check that we have an integer (at least one digit, nothing else) */ - for (c = p; *c; c++) - { - if (!isdigit((unsigned char) *c)) - goto interpret_error; - } - if (c == p) - goto interpret_error; - - return p; - -interpret_error: - pqInternalNotice(&res->noticeHooks, - "could not interpret result from server: %s", - res->cmdStatus); - return ""; -} - -/* - * PQgetvalue: - * return the value of field 'field_num' of row 'tup_num' - */ -char * -PQgetvalue(const PGresult *res, int tup_num, int field_num) -{ - if (!check_tuple_field_number(res, tup_num, field_num)) - return NULL; - return res->tuples[tup_num][field_num].value; -} - -/* PQgetlength: - * returns the actual length of a field value in bytes. - */ -int -PQgetlength(const PGresult *res, int tup_num, int field_num) -{ - if (!check_tuple_field_number(res, tup_num, field_num)) - return 0; - if (res->tuples[tup_num][field_num].len != NULL_LEN) - return res->tuples[tup_num][field_num].len; - else - return 0; -} - -/* PQgetisnull: - * returns the null status of a field value. - */ -int -PQgetisnull(const PGresult *res, int tup_num, int field_num) -{ - if (!check_tuple_field_number(res, tup_num, field_num)) - return 1; /* pretend it is null */ - if (res->tuples[tup_num][field_num].len == NULL_LEN) - return 1; - else - return 0; -} - -/* PQnparams: - * returns the number of input parameters of a prepared statement. - */ -int -PQnparams(const PGresult *res) -{ - if (!res) - return 0; - return res->numParameters; -} - -/* PQparamtype: - * returns type Oid of the specified statement parameter. - */ -Oid -PQparamtype(const PGresult *res, int param_num) -{ - if (!check_param_number(res, param_num)) - return InvalidOid; - if (res->paramDescs) - return res->paramDescs[param_num].typid; - else - return InvalidOid; -} - - -/* PQsetnonblocking: - * sets the PGconn's database connection non-blocking if the arg is TRUE - * or makes it blocking if the arg is FALSE, this will not protect - * you from PQexec(), you'll only be safe when using the non-blocking API. - * Needs to be called only on a connected database connection. - */ -int -PQsetnonblocking(PGconn *conn, int arg) -{ - bool barg; - - if (!conn || conn->status == CONNECTION_BAD) - return -1; - - barg = (arg ? TRUE : FALSE); - - /* early out if the socket is already in the state requested */ - if (barg == conn->nonblocking) - return 0; - - /* - * to guarantee constancy for flushing/query/result-polling behavior we - * need to flush the send queue at this point in order to guarantee proper - * behavior. this is ok because either they are making a transition _from_ - * or _to_ blocking mode, either way we can block them. - */ - /* if we are going from blocking to non-blocking flush here */ - if (pqFlush(conn)) - return -1; - - conn->nonblocking = barg; - - return 0; -} - -/* - * return the blocking status of the database connection - * TRUE == nonblocking, FALSE == blocking - */ -int -PQisnonblocking(const PGconn *conn) -{ - return pqIsnonblocking(conn); -} - -/* libpq is thread-safe? */ -int -PQisthreadsafe(void) -{ -#ifdef ENABLE_THREAD_SAFETY - return true; -#else - return false; -#endif -} - - -/* try to force data out, really only useful for non-blocking users */ -int -PQflush(PGconn *conn) -{ - return pqFlush(conn); -} - - -/* - * PQfreemem - safely frees memory allocated - * - * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6) - * Used for freeing memory from PQescapeByte()a/PQunescapeBytea() - */ -void -PQfreemem(void *ptr) -{ - free(ptr); -} - -/* - * PQfreeNotify - free's the memory associated with a PGnotify - * - * This function is here only for binary backward compatibility. - * New code should use PQfreemem(). A macro will automatically map - * calls to PQfreemem. It should be removed in the future. bjm 2003-03-24 - */ - -#undef PQfreeNotify -void PQfreeNotify(PGnotify *notify); - -void -PQfreeNotify(PGnotify *notify) -{ - PQfreemem(notify); -} - - -/* - * Escaping arbitrary strings to get valid SQL literal strings. - * - * Replaces "'" with "''", and if not std_strings, replaces "\" with "\\". - * - * length is the length of the source string. (Note: if a terminating NUL - * is encountered sooner, PQescapeString stops short of "length"; the behavior - * is thus rather like strncpy.) - * - * For safety the buffer at "to" must be at least 2*length + 1 bytes long. - * A terminating NUL character is added to the output string, whether the - * input is NUL-terminated or not. - * - * Returns the actual length of the output (not counting the terminating NUL). - */ -static size_t -PQescapeStringInternal(PGconn *conn, - char *to, const char *from, size_t length, - int *error, - int encoding, bool std_strings) -{ - const char *source = from; - char *target = to; - size_t remaining = length; - - if (error) - *error = 0; - - while (remaining > 0 && *source != '\0') - { - char c = *source; - int len; - int i; - - /* Fast path for plain ASCII */ - if (!IS_HIGHBIT_SET(c)) - { - /* Apply quoting if needed */ - if (SQL_STR_DOUBLE(c, !std_strings)) - *target++ = c; - /* Copy the character */ - *target++ = c; - source++; - remaining--; - continue; - } - - /* Slow path for possible multibyte characters */ - len = pg_encoding_mblen(encoding, source); - - /* Copy the character */ - for (i = 0; i < len; i++) - { - if (remaining == 0 || *source == '\0') - break; - *target++ = *source++; - remaining--; - } - - /* - * If we hit premature end of string (ie, incomplete multibyte - * character), try to pad out to the correct length with spaces. We - * may not be able to pad completely, but we will always be able to - * insert at least one pad space (since we'd not have quoted a - * multibyte character). This should be enough to make a string that - * the server will error out on. - */ - if (i < len) - { - if (error) - *error = 1; - if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); - for (; i < len; i++) - { - if (((size_t) (target - to)) / 2 >= length) - break; - *target++ = ' '; - } - break; - } - } - - /* Write the terminating NUL character. */ - *target = '\0'; - - return target - to; -} - -size_t -PQescapeStringConn(PGconn *conn, - char *to, const char *from, size_t length, - int *error) -{ - if (!conn) - { - /* force empty-string result */ - *to = '\0'; - if (error) - *error = 1; - return 0; - } - return PQescapeStringInternal(conn, to, from, length, error, - conn->client_encoding, - conn->std_strings); -} - -size_t -PQescapeString(char *to, const char *from, size_t length) -{ - return PQescapeStringInternal(NULL, to, from, length, NULL, - static_client_encoding, - static_std_strings); -} - - -/* - * Escape arbitrary strings. If as_ident is true, we escape the result - * as an identifier; if false, as a literal. The result is returned in - * a newly allocated buffer. If we fail due to an encoding violation or out - * of memory condition, we return NULL, storing an error message into conn. - */ -static char * -PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident) -{ - const char *s; - char *result; - char *rp; - int num_quotes = 0; /* single or double, depending on as_ident */ - int num_backslashes = 0; - int input_len; - int result_size; - char quote_char = as_ident ? '"' : '\''; - - /* We must have a connection, else fail immediately. */ - if (!conn) - return NULL; - - /* Scan the string for characters that must be escaped. */ - for (s = str; (s - str) < len && *s != '\0'; ++s) - { - if (*s == quote_char) - ++num_quotes; - else if (*s == '\\') - ++num_backslashes; - else if (IS_HIGHBIT_SET(*s)) - { - int charlen; - - /* Slow path for possible multibyte characters */ - charlen = pg_encoding_mblen(conn->client_encoding, s); - - /* Multibyte character overruns allowable length. */ - if ((s - str) + charlen > len || memchr(s, 0, charlen) != NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("incomplete multibyte character\n")); - return NULL; - } - - /* Adjust s, bearing in mind that for loop will increment it. */ - s += charlen - 1; - } - } - - /* Allocate output buffer. */ - input_len = s - str; - result_size = input_len + num_quotes + 3; /* two quotes, plus a NUL */ - if (!as_ident && num_backslashes > 0) - result_size += num_backslashes + 2; - result = rp = (char *) malloc(result_size); - if (rp == NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return NULL; - } - - /* - * If we are escaping a literal that contains backslashes, we use the - * escape string syntax so that the result is correct under either value - * of standard_conforming_strings. We also emit a leading space in this - * case, to guard against the possibility that the result might be - * interpolated immediately following an identifier. - */ - if (!as_ident && num_backslashes > 0) - { - *rp++ = ' '; - *rp++ = 'E'; - } - - /* Opening quote. */ - *rp++ = quote_char; - - /* - * Use fast path if possible. - * - * We've already verified that the input string is well-formed in the - * current encoding. If it contains no quotes and, in the case of - * literal-escaping, no backslashes, then we can just copy it directly to - * the output buffer, adding the necessary quotes. - * - * If not, we must rescan the input and process each character - * individually. - */ - if (num_quotes == 0 && (num_backslashes == 0 || as_ident)) - { - memcpy(rp, str, input_len); - rp += input_len; - } - else - { - for (s = str; s - str < input_len; ++s) - { - if (*s == quote_char || (!as_ident && *s == '\\')) - { - *rp++ = *s; - *rp++ = *s; - } - else if (!IS_HIGHBIT_SET(*s)) - *rp++ = *s; - else - { - int i = pg_encoding_mblen(conn->client_encoding, s); - - while (1) - { - *rp++ = *s; - if (--i == 0) - break; - ++s; /* for loop will provide the final increment */ - } - } - } - } - - /* Closing quote and terminating NUL. */ - *rp++ = quote_char; - *rp = '\0'; - - return result; -} - -char * -PQescapeLiteral(PGconn *conn, const char *str, size_t len) -{ - return PQescapeInternal(conn, str, len, false); -} - -char * -PQescapeIdentifier(PGconn *conn, const char *str, size_t len) -{ - return PQescapeInternal(conn, str, len, true); -} - -/* HEX encoding support for bytea */ -static const char hextbl[] = "0123456789abcdef"; - -static const int8 hexlookup[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -static inline char -get_hex(char c) -{ - int res = -1; - - if (c > 0 && c < 127) - res = hexlookup[(unsigned char) c]; - - return (char) res; -} - - -/* - * PQescapeBytea - converts from binary string to the - * minimal encoding necessary to include the string in an SQL - * INSERT statement with a bytea type column as the target. - * - * We can use either hex or escape (traditional) encoding. - * In escape mode, the following transformations are applied: - * '\0' == ASCII 0 == \000 - * '\'' == ASCII 39 == '' - * '\\' == ASCII 92 == \\ - * anything < 0x20, or > 0x7e ---> \ooo - * (where ooo is an octal expression) - * - * If not std_strings, all backslashes sent to the output are doubled. - */ -static unsigned char * -PQescapeByteaInternal(PGconn *conn, - const unsigned char *from, size_t from_length, - size_t *to_length, bool std_strings, bool use_hex) -{ - const unsigned char *vp; - unsigned char *rp; - unsigned char *result; - size_t i; - size_t len; - size_t bslash_len = (std_strings ? 1 : 2); - - /* - * empty string has 1 char ('\0') - */ - len = 1; - - if (use_hex) - { - len += bslash_len + 1 + 2 * from_length; - } - else - { - vp = from; - for (i = from_length; i > 0; i--, vp++) - { - if (*vp < 0x20 || *vp > 0x7e) - len += bslash_len + 3; - else if (*vp == '\'') - len += 2; - else if (*vp == '\\') - len += bslash_len + bslash_len; - else - len++; - } - } - - *to_length = len; - rp = result = (unsigned char *) malloc(len); - if (rp == NULL) - { - if (conn) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return NULL; - } - - if (use_hex) - { - if (!std_strings) - *rp++ = '\\'; - *rp++ = '\\'; - *rp++ = 'x'; - } - - vp = from; - for (i = from_length; i > 0; i--, vp++) - { - unsigned char c = *vp; - - if (use_hex) - { - *rp++ = hextbl[(c >> 4) & 0xF]; - *rp++ = hextbl[c & 0xF]; - } - else if (c < 0x20 || c > 0x7e) - { - if (!std_strings) - *rp++ = '\\'; - *rp++ = '\\'; - *rp++ = (c >> 6) + '0'; - *rp++ = ((c >> 3) & 07) + '0'; - *rp++ = (c & 07) + '0'; - } - else if (c == '\'') - { - *rp++ = '\''; - *rp++ = '\''; - } - else if (c == '\\') - { - if (!std_strings) - { - *rp++ = '\\'; - *rp++ = '\\'; - } - *rp++ = '\\'; - *rp++ = '\\'; - } - else - *rp++ = c; - } - *rp = '\0'; - - return result; -} - -unsigned char * -PQescapeByteaConn(PGconn *conn, - const unsigned char *from, size_t from_length, - size_t *to_length) -{ - if (!conn) - return NULL; - return PQescapeByteaInternal(conn, from, from_length, to_length, - conn->std_strings, - (conn->sversion >= 90000)); -} - -unsigned char * -PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length) -{ - return PQescapeByteaInternal(NULL, from, from_length, to_length, - static_std_strings, - false /* can't use hex */ ); -} - - -#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3') -#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7') -#define OCTVAL(CH) ((CH) - '0') - -/* - * PQunescapeBytea - converts the null terminated string representation - * of a bytea, strtext, into binary, filling a buffer. It returns a - * pointer to the buffer (or NULL on error), and the size of the - * buffer in retbuflen. The pointer may subsequently be used as an - * argument to the function PQfreemem. - * - * The following transformations are made: - * \\ == ASCII 92 == \ - * \ooo == a byte whose value = ooo (ooo is an octal number) - * \x == x (x is any character not matched by the above transformations) - */ -unsigned char * -PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) -{ - size_t strtextlen, - buflen; - unsigned char *buffer, - *tmpbuf; - size_t i, - j; - - if (strtext == NULL) - return NULL; - - strtextlen = strlen((const char *) strtext); - - if (strtext[0] == '\\' && strtext[1] == 'x') - { - const unsigned char *s; - unsigned char *p; - - buflen = (strtextlen - 2) / 2; - /* Avoid unportable malloc(0) */ - buffer = (unsigned char *) malloc(buflen > 0 ? buflen : 1); - if (buffer == NULL) - return NULL; - - s = strtext + 2; - p = buffer; - while (*s) - { - char v1, - v2; - - /* - * Bad input is silently ignored. Note that this includes - * whitespace between hex pairs, which is allowed by byteain. - */ - v1 = get_hex(*s++); - if (!*s || v1 == (char) -1) - continue; - v2 = get_hex(*s++); - if (v2 != (char) -1) - *p++ = (v1 << 4) | v2; - } - - buflen = p - buffer; - } - else - { - /* - * Length of input is max length of output, but add one to avoid - * unportable malloc(0) if input is zero-length. - */ - buffer = (unsigned char *) malloc(strtextlen + 1); - if (buffer == NULL) - return NULL; - - for (i = j = 0; i < strtextlen;) - { - switch (strtext[i]) - { - case '\\': - i++; - if (strtext[i] == '\\') - buffer[j++] = strtext[i++]; - else - { - if ((ISFIRSTOCTDIGIT(strtext[i])) && - (ISOCTDIGIT(strtext[i + 1])) && - (ISOCTDIGIT(strtext[i + 2]))) - { - int byte; - - byte = OCTVAL(strtext[i++]); - byte = (byte << 3) + OCTVAL(strtext[i++]); - byte = (byte << 3) + OCTVAL(strtext[i++]); - buffer[j++] = byte; - } - } - - /* - * Note: if we see '\' followed by something that isn't a - * recognized escape sequence, we loop around having done - * nothing except advance i. Therefore the something will - * be emitted as ordinary data on the next cycle. Corner - * case: '\' at end of string will just be discarded. - */ - break; - - default: - buffer[j++] = strtext[i++]; - break; - } - } - buflen = j; /* buflen is the length of the dequoted data */ - } - - /* Shrink the buffer to be no larger than necessary */ - /* +1 avoids unportable behavior when buflen==0 */ - tmpbuf = realloc(buffer, buflen + 1); - - /* It would only be a very brain-dead realloc that could fail, but... */ - if (!tmpbuf) - { - free(buffer); - return NULL; - } - - *retbuflen = buflen; - return tmpbuf; -} diff --git a/libpq/fe-lobj.c b/libpq/fe-lobj.c deleted file mode 100644 index 3b08768..0000000 --- a/libpq/fe-lobj.c +++ /dev/null @@ -1,1103 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-lobj.c - * Front-end large object interface - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-lobj.c - * - *------------------------------------------------------------------------- - */ - -#ifdef WIN32 -/* - * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h - * must be included first on MS C. Might as well do it for all WIN32's - * here. - */ -#include -#endif - -#include "postgres_fe.h" - -#ifdef WIN32 -#include "win32.h" -#else -#include -#endif - -#include -#include -#include -#include /* for ntohl/htonl */ -#include - -#include "libpq-fe.h" -#include "libpq-int.h" -#include "libpq/libpq-fs.h" /* must come after sys/stat.h */ - -#define LO_BUFSIZE 8192 - -static int lo_initialize(PGconn *conn); -static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid); -static pg_int64 lo_hton64(pg_int64 host64); -static pg_int64 lo_ntoh64(pg_int64 net64); - -/* - * lo_open - * opens an existing large object - * - * returns the file descriptor for use in later lo_* calls - * return -1 upon failure. - */ -int -lo_open(PGconn *conn, Oid lobjId, int mode) -{ - int fd; - int result_len; - PQArgBlock argv[2]; - PGresult *res; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = lobjId; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = mode; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return fd; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_close - * closes an existing large object - * - * returns 0 upon success - * returns -1 upon failure. - */ -int -lo_close(PGconn *conn, int fd) -{ - PQArgBlock argv[1]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - res = PQfn(conn, conn->lobjfuncs->fn_lo_close, - &retval, &result_len, 1, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_truncate - * truncates an existing large object to the given size - * - * returns 0 upon success - * returns -1 upon failure - */ -int -lo_truncate(PGconn *conn, int fd, size_t len) -{ - PQArgBlock argv[2]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - /* Must check this on-the-fly because it's not there pre-8.3 */ - if (conn->lobjfuncs->fn_lo_truncate == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate\n")); - return -1; - } - - /* - * Long ago, somebody thought it'd be a good idea to declare this function - * as taking size_t ... but the underlying backend function only accepts a - * signed int32 length. So throw error if the given value overflows - * int32. (A possible alternative is to automatically redirect the call - * to lo_truncate64; but if the caller wanted to rely on that backend - * function being available, he could have called lo_truncate64 for - * himself.) - */ - if (len > (size_t) INT_MAX) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_truncate exceeds integer range\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = (int) len; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate, - &retval, &result_len, 1, argv, 2); - - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_truncate64 - * truncates an existing large object to the given size - * - * returns 0 upon success - * returns -1 upon failure - */ -int -lo_truncate64(PGconn *conn, int fd, pg_int64 len) -{ - PQArgBlock argv[2]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - if (conn->lobjfuncs->fn_lo_truncate64 == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_truncate64\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - len = lo_hton64(len); - argv[1].isint = 0; - argv[1].len = 8; - argv[1].u.ptr = (int *) &len; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64, - &retval, &result_len, 1, argv, 2); - - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_read - * read len bytes of the large object into buf - * - * returns the number of bytes read, or -1 on failure. - * the CALLER must have allocated enough space to hold the result returned - */ - -int -lo_read(PGconn *conn, int fd, char *buf, size_t len) -{ - PQArgBlock argv[2]; - PGresult *res; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - /* - * Long ago, somebody thought it'd be a good idea to declare this function - * as taking size_t ... but the underlying backend function only accepts a - * signed int32 length. So throw error if the given value overflows - * int32. - */ - if (len > (size_t) INT_MAX) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_read exceeds integer range\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = (int) len; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_read, - (void *) buf, &result_len, 0, argv, 2); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return result_len; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_write - * write len bytes of buf into the large object fd - * - * returns the number of bytes written, or -1 on failure. - */ -int -lo_write(PGconn *conn, int fd, const char *buf, size_t len) -{ - PQArgBlock argv[2]; - PGresult *res; - int result_len; - int retval; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - /* - * Long ago, somebody thought it'd be a good idea to declare this function - * as taking size_t ... but the underlying backend function only accepts a - * signed int32 length. So throw error if the given value overflows - * int32. - */ - if (len > (size_t) INT_MAX) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("argument of lo_write exceeds integer range\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - argv[1].isint = 0; - argv[1].len = (int) len; - argv[1].u.ptr = (int *) buf; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_write, - &retval, &result_len, 1, argv, 2); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_lseek - * change the current read or write location on a large object - */ -int -lo_lseek(PGconn *conn, int fd, int offset, int whence) -{ - PQArgBlock argv[3]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = offset; - - argv[2].isint = 1; - argv[2].len = 4; - argv[2].u.integer = whence; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek, - &retval, &result_len, 1, argv, 3); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_lseek64 - * change the current read or write location on a large object - */ -pg_int64 -lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) -{ - PQArgBlock argv[3]; - PGresult *res; - pg_int64 retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - if (conn->lobjfuncs->fn_lo_lseek64 == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek64\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - offset = lo_hton64(offset); - argv[1].isint = 0; - argv[1].len = 8; - argv[1].u.ptr = (int *) &offset; - - argv[2].isint = 1; - argv[2].len = 4; - argv[2].u.integer = whence; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64, - (void *) &retval, &result_len, 0, argv, 3); - if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) - { - PQclear(res); - return lo_ntoh64(retval); - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_creat - * create a new large object - * the mode is ignored (once upon a time it had a use) - * - * returns the oid of the large object created or - * InvalidOid upon failure - */ -Oid -lo_creat(PGconn *conn, int mode) -{ - PQArgBlock argv[1]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = mode; - res = PQfn(conn, conn->lobjfuncs->fn_lo_creat, - &retval, &result_len, 1, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return (Oid) retval; - } - else - { - PQclear(res); - return InvalidOid; - } -} - -/* - * lo_create - * create a new large object - * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create - * - * returns the oid of the large object created or - * InvalidOid upon failure - */ -Oid -lo_create(PGconn *conn, Oid lobjId) -{ - PQArgBlock argv[1]; - PGresult *res; - int retval; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return InvalidOid; - } - - /* Must check this on-the-fly because it's not there pre-8.1 */ - if (conn->lobjfuncs->fn_lo_create == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_create\n")); - return InvalidOid; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = lobjId; - res = PQfn(conn, conn->lobjfuncs->fn_lo_create, - &retval, &result_len, 1, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return (Oid) retval; - } - else - { - PQclear(res); - return InvalidOid; - } -} - - -/* - * lo_tell - * returns the current seek location of the large object - */ -int -lo_tell(PGconn *conn, int fd) -{ - int retval; - PQArgBlock argv[1]; - PGresult *res; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_tell, - &retval, &result_len, 1, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_tell64 - * returns the current seek location of the large object - */ -pg_int64 -lo_tell64(PGconn *conn, int fd) -{ - pg_int64 retval; - PQArgBlock argv[1]; - PGresult *res; - int result_len; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - if (conn->lobjfuncs->fn_lo_tell64 == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell64\n")); - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64, - (void *) &retval, &result_len, 0, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8) - { - PQclear(res); - return lo_ntoh64(retval); - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_unlink - * delete a file - */ - -int -lo_unlink(PGconn *conn, Oid lobjId) -{ - PQArgBlock argv[1]; - PGresult *res; - int result_len; - int retval; - - if (conn == NULL || conn->lobjfuncs == NULL) - { - if (lo_initialize(conn) < 0) - return -1; - } - - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = lobjId; - - res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink, - &retval, &result_len, 1, argv, 1); - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - PQclear(res); - return retval; - } - else - { - PQclear(res); - return -1; - } -} - -/* - * lo_import - - * imports a file as an (inversion) large object. - * - * returns the oid of that object upon success, - * returns InvalidOid upon failure - */ - -Oid -lo_import(PGconn *conn, const char *filename) -{ - return lo_import_internal(conn, filename, InvalidOid); -} - -/* - * lo_import_with_oid - - * imports a file as an (inversion) large object. - * large object id can be specified. - * - * returns the oid of that object upon success, - * returns InvalidOid upon failure - */ - -Oid -lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId) -{ - return lo_import_internal(conn, filename, lobjId); -} - -static Oid -lo_import_internal(PGconn *conn, const char *filename, Oid oid) -{ - int fd; - int nbytes, - tmp; - char buf[LO_BUFSIZE]; - Oid lobjOid; - int lobj; - char sebuf[256]; - - /* - * open the file to be read in - */ - fd = open(filename, O_RDONLY | PG_BINARY, 0666); - if (fd < 0) - { /* error */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not open file \"%s\": %s\n"), - filename, pqStrerror(errno, sebuf, sizeof(sebuf))); - return InvalidOid; - } - - /* - * create an inversion object - */ - if (oid == InvalidOid) - lobjOid = lo_creat(conn, INV_READ | INV_WRITE); - else - lobjOid = lo_create(conn, oid); - - if (lobjOid == InvalidOid) - { - /* we assume lo_create() already set a suitable error message */ - (void) close(fd); - return InvalidOid; - } - - lobj = lo_open(conn, lobjOid, INV_WRITE); - if (lobj == -1) - { - /* we assume lo_open() already set a suitable error message */ - (void) close(fd); - return InvalidOid; - } - - /* - * read in from the file and write to the large object - */ - while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0) - { - tmp = lo_write(conn, lobj, buf, nbytes); - if (tmp != nbytes) - { - /* - * If lo_write() failed, we are now in an aborted transaction so - * there's no need for lo_close(); furthermore, if we tried it - * we'd overwrite the useful error result with a useless one. So - * just nail the doors shut and get out of town. - */ - (void) close(fd); - return InvalidOid; - } - } - - if (nbytes < 0) - { - /* We must do lo_close before setting the errorMessage */ - int save_errno = errno; - - (void) lo_close(conn, lobj); - (void) close(fd); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not read from file \"%s\": %s\n"), - filename, - pqStrerror(save_errno, sebuf, sizeof(sebuf))); - return InvalidOid; - } - - (void) close(fd); - - if (lo_close(conn, lobj) != 0) - { - /* we assume lo_close() already set a suitable error message */ - return InvalidOid; - } - - return lobjOid; -} - -/* - * lo_export - - * exports an (inversion) large object. - * returns -1 upon failure, 1 if OK - */ -int -lo_export(PGconn *conn, Oid lobjId, const char *filename) -{ - int result = 1; - int fd; - int nbytes, - tmp; - char buf[LO_BUFSIZE]; - int lobj; - char sebuf[256]; - - /* - * open the large object. - */ - lobj = lo_open(conn, lobjId, INV_READ); - if (lobj == -1) - { - /* we assume lo_open() already set a suitable error message */ - return -1; - } - - /* - * create the file to be written to - */ - fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); - if (fd < 0) - { - /* We must do lo_close before setting the errorMessage */ - int save_errno = errno; - - (void) lo_close(conn, lobj); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not open file \"%s\": %s\n"), - filename, - pqStrerror(save_errno, sebuf, sizeof(sebuf))); - return -1; - } - - /* - * read in from the large object and write to the file - */ - while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0) - { - tmp = write(fd, buf, nbytes); - if (tmp != nbytes) - { - /* We must do lo_close before setting the errorMessage */ - int save_errno = errno; - - (void) lo_close(conn, lobj); - (void) close(fd); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not write to file \"%s\": %s\n"), - filename, - pqStrerror(save_errno, sebuf, sizeof(sebuf))); - return -1; - } - } - - /* - * If lo_read() failed, we are now in an aborted transaction so there's no - * need for lo_close(); furthermore, if we tried it we'd overwrite the - * useful error result with a useless one. So skip lo_close() if we got a - * failure result. - */ - if (nbytes < 0 || - lo_close(conn, lobj) != 0) - { - /* assume lo_read() or lo_close() left a suitable error message */ - result = -1; - } - - /* if we already failed, don't overwrite that msg with a close error */ - if (close(fd) && result >= 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not write to file \"%s\": %s\n"), - filename, pqStrerror(errno, sebuf, sizeof(sebuf))); - result = -1; - } - - return result; -} - - -/* - * lo_initialize - * - * Initialize the large object interface for an existing connection. - * We ask the backend about the functions OID's in pg_proc for all - * functions that are required for large object operations. - */ -static int -lo_initialize(PGconn *conn) -{ - PGresult *res; - PGlobjfuncs *lobjfuncs; - int n; - const char *query; - const char *fname; - Oid foid; - - if (!conn) - return -1; - - /* - * Allocate the structure to hold the functions OID's - */ - lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); - if (lobjfuncs == NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return -1; - } - MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); - - /* - * Execute the query to get all the functions at once. In 7.3 and later - * we need to be schema-safe. lo_create only exists in 8.1 and up. - * lo_truncate only exists in 8.3 and up. - */ - if (conn->sversion >= 70300) - query = "select proname, oid from pg_catalog.pg_proc " - "where proname in (" - "'lo_open', " - "'lo_close', " - "'lo_creat', " - "'lo_create', " - "'lo_unlink', " - "'lo_lseek', " - "'lo_lseek64', " - "'lo_tell', " - "'lo_tell64', " - "'lo_truncate', " - "'lo_truncate64', " - "'loread', " - "'lowrite') " - "and pronamespace = (select oid from pg_catalog.pg_namespace " - "where nspname = 'pg_catalog')"; - else - query = "select proname, oid from pg_proc " - "where proname = 'lo_open' " - "or proname = 'lo_close' " - "or proname = 'lo_creat' " - "or proname = 'lo_unlink' " - "or proname = 'lo_lseek' " - "or proname = 'lo_tell' " - "or proname = 'loread' " - "or proname = 'lowrite'"; - - res = PQexec(conn, query); - if (res == NULL) - { - free(lobjfuncs); - return -1; - } - - if (res->resultStatus != PGRES_TUPLES_OK) - { - free(lobjfuncs); - PQclear(res); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("query to initialize large object functions did not return data\n")); - return -1; - } - - /* - * Examine the result and put the OID's into the struct - */ - for (n = 0; n < PQntuples(res); n++) - { - fname = PQgetvalue(res, n, 0); - foid = (Oid) atoi(PQgetvalue(res, n, 1)); - if (strcmp(fname, "lo_open") == 0) - lobjfuncs->fn_lo_open = foid; - else if (strcmp(fname, "lo_close") == 0) - lobjfuncs->fn_lo_close = foid; - else if (strcmp(fname, "lo_creat") == 0) - lobjfuncs->fn_lo_creat = foid; - else if (strcmp(fname, "lo_create") == 0) - lobjfuncs->fn_lo_create = foid; - else if (strcmp(fname, "lo_unlink") == 0) - lobjfuncs->fn_lo_unlink = foid; - else if (strcmp(fname, "lo_lseek") == 0) - lobjfuncs->fn_lo_lseek = foid; - else if (strcmp(fname, "lo_lseek64") == 0) - lobjfuncs->fn_lo_lseek64 = foid; - else if (strcmp(fname, "lo_tell") == 0) - lobjfuncs->fn_lo_tell = foid; - else if (strcmp(fname, "lo_tell64") == 0) - lobjfuncs->fn_lo_tell64 = foid; - else if (strcmp(fname, "lo_truncate") == 0) - lobjfuncs->fn_lo_truncate = foid; - else if (strcmp(fname, "lo_truncate64") == 0) - lobjfuncs->fn_lo_truncate64 = foid; - else if (strcmp(fname, "loread") == 0) - lobjfuncs->fn_lo_read = foid; - else if (strcmp(fname, "lowrite") == 0) - lobjfuncs->fn_lo_write = foid; - } - - PQclear(res); - - /* - * Finally check that we got all required large object interface functions - * (ones that have been added later than the stone age are instead checked - * only if used) - */ - if (lobjfuncs->fn_lo_open == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_open\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_close == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_close\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_creat == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_creat\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_unlink == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_unlink\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_lseek == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_lseek\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_tell == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lo_tell\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_read == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function loread\n")); - free(lobjfuncs); - return -1; - } - if (lobjfuncs->fn_lo_write == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("cannot determine OID of function lowrite\n")); - free(lobjfuncs); - return -1; - } - - /* - * Put the structure into the connection control - */ - conn->lobjfuncs = lobjfuncs; - return 0; -} - -/* - * lo_hton64 - * converts a 64-bit integer from host byte order to network byte order - */ -static pg_int64 -lo_hton64(pg_int64 host64) -{ - union - { - pg_int64 i64; - uint32 i32[2]; - } swap; - uint32 t; - - /* High order half first, since we're doing MSB-first */ - t = (uint32) (host64 >> 32); - swap.i32[0] = htonl(t); - - /* Now the low order half */ - t = (uint32) host64; - swap.i32[1] = htonl(t); - - return swap.i64; -} - -/* - * lo_ntoh64 - * converts a 64-bit integer from network byte order to host byte order - */ -static pg_int64 -lo_ntoh64(pg_int64 net64) -{ - union - { - pg_int64 i64; - uint32 i32[2]; - } swap; - pg_int64 result; - - swap.i64 = net64; - - result = (uint32) ntohl(swap.i32[0]); - result <<= 32; - result |= (uint32) ntohl(swap.i32[1]); - - return result; -} diff --git a/libpq/fe-misc.c b/libpq/fe-misc.c deleted file mode 100644 index 32da8ca..0000000 --- a/libpq/fe-misc.c +++ /dev/null @@ -1,1267 +0,0 @@ -/*------------------------------------------------------------------------- - * - * FILE - * fe-misc.c - * - * DESCRIPTION - * miscellaneous useful functions - * - * The communication routines here are analogous to the ones in - * backend/libpq/pqcomm.c and backend/libpq/pqcomprim.c, but operate - * in the considerably different environment of the frontend libpq. - * In particular, we work with a bare nonblock-mode socket, rather than - * a stdio stream, so that we can avoid unwanted blocking of the application. - * - * XXX: MOVE DEBUG PRINTOUT TO HIGHER LEVEL. As is, block and restart - * will cause repeat printouts. - * - * We must speak the same transmitted data representations as the backend - * routines. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * src/interfaces/libpq/fe-misc.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres_fe.h" - -#include -#include - -#include -#include - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#endif - -#ifdef HAVE_POLL_H -#include -#endif -#ifdef HAVE_SYS_POLL_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#include "libpq-fe.h" -#include "libpq-int.h" -#include "mb/pg_wchar.h" -#include "pg_config_paths.h" - - -static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn); -static int pqSendSome(PGconn *conn, int len); -static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, - time_t end_time); -static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time); - -/* - * PQlibVersion: return the libpq version number - */ -int -PQlibVersion(void) -{ - return PG_VERSION_NUM; -} - -/* - * fputnbytes: print exactly N bytes to a file - * - * We avoid using %.*s here because it can misbehave if the data - * is not valid in what libc thinks is the prevailing encoding. - */ -static void -fputnbytes(FILE *f, const char *str, size_t n) -{ - while (n-- > 0) - fputc(*str++, f); -} - - -/* - * pqGetc: get 1 character from the connection - * - * All these routines return 0 on success, EOF on error. - * Note that for the Get routines, EOF only means there is not enough - * data in the buffer, not that there is necessarily a hard error. - */ -int -pqGetc(char *result, PGconn *conn) -{ - if (conn->inCursor >= conn->inEnd) - return EOF; - - *result = conn->inBuffer[conn->inCursor++]; - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend> %c\n", *result); - - return 0; -} - - -/* - * pqPutc: write 1 char to the current message - */ -int -pqPutc(char c, PGconn *conn) -{ - if (pqPutMsgBytes(&c, 1, conn)) - return EOF; - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> %c\n", c); - - return 0; -} - - -/* - * pqGets[_append]: - * get a null-terminated string from the connection, - * and store it in an expansible PQExpBuffer. - * If we run out of memory, all of the string is still read, - * but the excess characters are silently discarded. - */ -static int -pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer) -{ - /* Copy conn data to locals for faster search loop */ - char *inBuffer = conn->inBuffer; - int inCursor = conn->inCursor; - int inEnd = conn->inEnd; - int slen; - - while (inCursor < inEnd && inBuffer[inCursor]) - inCursor++; - - if (inCursor >= inEnd) - return EOF; - - slen = inCursor - conn->inCursor; - - if (resetbuffer) - resetPQExpBuffer(buf); - - appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen); - - conn->inCursor = ++inCursor; - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend> \"%s\"\n", - buf->data); - - return 0; -} - -int -pqGets(PQExpBuffer buf, PGconn *conn) -{ - return pqGets_internal(buf, conn, true); -} - -int -pqGets_append(PQExpBuffer buf, PGconn *conn) -{ - return pqGets_internal(buf, conn, false); -} - - -/* - * pqPuts: write a null-terminated string to the current message - */ -int -pqPuts(const char *s, PGconn *conn) -{ - if (pqPutMsgBytes(s, strlen(s) + 1, conn)) - return EOF; - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s); - - return 0; -} - -/* - * pqGetnchar: - * get a string of exactly len bytes in buffer s, no null termination - */ -int -pqGetnchar(char *s, size_t len, PGconn *conn) -{ - if (len > (size_t) (conn->inEnd - conn->inCursor)) - return EOF; - - memcpy(s, conn->inBuffer + conn->inCursor, len); - /* no terminating null */ - - conn->inCursor += len; - - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); - fputnbytes(conn->Pfdebug, s, len); - fprintf(conn->Pfdebug, "\n"); - } - - return 0; -} - -/* - * pqSkipnchar: - * skip over len bytes in input buffer. - * - * Note: this is primarily useful for its debug output, which should - * be exactly the same as for pqGetnchar. We assume the data in question - * will actually be used, but just isn't getting copied anywhere as yet. - */ -int -pqSkipnchar(size_t len, PGconn *conn) -{ - if (len > (size_t) (conn->inEnd - conn->inCursor)) - return EOF; - - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); - fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len); - fprintf(conn->Pfdebug, "\n"); - } - - conn->inCursor += len; - - return 0; -} - -/* - * pqPutnchar: - * write exactly len bytes to the current message - */ -int -pqPutnchar(const char *s, size_t len, PGconn *conn) -{ - if (pqPutMsgBytes(s, len, conn)) - return EOF; - - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "To backend> "); - fputnbytes(conn->Pfdebug, s, len); - fprintf(conn->Pfdebug, "\n"); - } - - return 0; -} - -/* - * pqGetInt - * read a 2 or 4 byte integer and convert from network byte order - * to local byte order - */ -int -pqGetInt(int *result, size_t bytes, PGconn *conn) -{ - uint16 tmp2; - uint32 tmp4; - - switch (bytes) - { - case 2: - if (conn->inCursor + 2 > conn->inEnd) - return EOF; - memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2); - conn->inCursor += 2; - *result = (int) ntohs(tmp2); - break; - case 4: - if (conn->inCursor + 4 > conn->inEnd) - return EOF; - memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4); - conn->inCursor += 4; - *result = (int) ntohl(tmp4); - break; - default: - pqInternalNotice(&conn->noticeHooks, - "integer of size %lu not supported by pqGetInt", - (unsigned long) bytes); - return EOF; - } - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result); - - return 0; -} - -/* - * pqPutInt - * write an integer of 2 or 4 bytes, converting from host byte order - * to network byte order. - */ -int -pqPutInt(int value, size_t bytes, PGconn *conn) -{ - uint16 tmp2; - uint32 tmp4; - - switch (bytes) - { - case 2: - tmp2 = htons((uint16) value); - if (pqPutMsgBytes((const char *) &tmp2, 2, conn)) - return EOF; - break; - case 4: - tmp4 = htonl((uint32) value); - if (pqPutMsgBytes((const char *) &tmp4, 4, conn)) - return EOF; - break; - default: - pqInternalNotice(&conn->noticeHooks, - "integer of size %lu not supported by pqPutInt", - (unsigned long) bytes); - return EOF; - } - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value); - - return 0; -} - -/* - * Make sure conn's output buffer can hold bytes_needed bytes (caller must - * include already-stored data into the value!) - * - * Returns 0 on success, EOF if failed to enlarge buffer - */ -int -pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn) -{ - int newsize = conn->outBufSize; - char *newbuf; - - /* Quick exit if we have enough space */ - if (bytes_needed <= (size_t) newsize) - return 0; - - /* - * If we need to enlarge the buffer, we first try to double it in size; if - * that doesn't work, enlarge in multiples of 8K. This avoids thrashing - * the malloc pool by repeated small enlargements. - * - * Note: tests for newsize > 0 are to catch integer overflow. - */ - do - { - newsize *= 2; - } while (newsize > 0 && bytes_needed > (size_t) newsize); - - if (newsize > 0 && bytes_needed <= (size_t) newsize) - { - newbuf = realloc(conn->outBuffer, newsize); - if (newbuf) - { - /* realloc succeeded */ - conn->outBuffer = newbuf; - conn->outBufSize = newsize; - return 0; - } - } - - newsize = conn->outBufSize; - do - { - newsize += 8192; - } while (newsize > 0 && bytes_needed > (size_t) newsize); - - if (newsize > 0 && bytes_needed <= (size_t) newsize) - { - newbuf = realloc(conn->outBuffer, newsize); - if (newbuf) - { - /* realloc succeeded */ - conn->outBuffer = newbuf; - conn->outBufSize = newsize; - return 0; - } - } - - /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for output buffer\n"); - return EOF; -} - -/* - * Make sure conn's input buffer can hold bytes_needed bytes (caller must - * include already-stored data into the value!) - * - * Returns 0 on success, EOF if failed to enlarge buffer - */ -int -pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) -{ - int newsize = conn->inBufSize; - char *newbuf; - - /* Quick exit if we have enough space */ - if (bytes_needed <= (size_t) newsize) - return 0; - - /* - * Before concluding that we need to enlarge the buffer, left-justify - * whatever is in it and recheck. The caller's value of bytes_needed - * includes any data to the left of inStart, but we can delete that in - * preference to enlarging the buffer. It's slightly ugly to have this - * function do this, but it's better than making callers worry about it. - */ - bytes_needed -= conn->inStart; - - if (conn->inStart < conn->inEnd) - { - if (conn->inStart > 0) - { - memmove(conn->inBuffer, conn->inBuffer + conn->inStart, - conn->inEnd - conn->inStart); - conn->inEnd -= conn->inStart; - conn->inCursor -= conn->inStart; - conn->inStart = 0; - } - } - else - { - /* buffer is logically empty, reset it */ - conn->inStart = conn->inCursor = conn->inEnd = 0; - } - - /* Recheck whether we have enough space */ - if (bytes_needed <= (size_t) newsize) - return 0; - - /* - * If we need to enlarge the buffer, we first try to double it in size; if - * that doesn't work, enlarge in multiples of 8K. This avoids thrashing - * the malloc pool by repeated small enlargements. - * - * Note: tests for newsize > 0 are to catch integer overflow. - */ - do - { - newsize *= 2; - } while (newsize > 0 && bytes_needed > (size_t) newsize); - - if (newsize > 0 && bytes_needed <= (size_t) newsize) - { - newbuf = realloc(conn->inBuffer, newsize); - if (newbuf) - { - /* realloc succeeded */ - conn->inBuffer = newbuf; - conn->inBufSize = newsize; - return 0; - } - } - - newsize = conn->inBufSize; - do - { - newsize += 8192; - } while (newsize > 0 && bytes_needed > (size_t) newsize); - - if (newsize > 0 && bytes_needed <= (size_t) newsize) - { - newbuf = realloc(conn->inBuffer, newsize); - if (newbuf) - { - /* realloc succeeded */ - conn->inBuffer = newbuf; - conn->inBufSize = newsize; - return 0; - } - } - - /* realloc failed. Probably out of memory */ - printfPQExpBuffer(&conn->errorMessage, - "cannot allocate memory for input buffer\n"); - return EOF; -} - -/* - * pqPutMsgStart: begin construction of a message to the server - * - * msg_type is the message type byte, or 0 for a message without type byte - * (only startup messages have no type byte) - * - * force_len forces the message to have a length word; otherwise, we add - * a length word if protocol 3. - * - * Returns 0 on success, EOF on error - * - * The idea here is that we construct the message in conn->outBuffer, - * beginning just past any data already in outBuffer (ie, at - * outBuffer+outCount). We enlarge the buffer as needed to hold the message. - * When the message is complete, we fill in the length word (if needed) and - * then advance outCount past the message, making it eligible to send. - * - * The state variable conn->outMsgStart points to the incomplete message's - * length word: it is either outCount or outCount+1 depending on whether - * there is a type byte. If we are sending a message without length word - * (pre protocol 3.0 only), then outMsgStart is -1. The state variable - * conn->outMsgEnd is the end of the data collected so far. - */ -int -pqPutMsgStart(char msg_type, bool force_len, PGconn *conn) -{ - int lenPos; - int endPos; - - /* allow room for message type byte */ - if (msg_type) - endPos = conn->outCount + 1; - else - endPos = conn->outCount; - - /* do we want a length word? */ - if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3) - { - lenPos = endPos; - /* allow room for message length */ - endPos += 4; - } - else - lenPos = -1; - - /* make sure there is room for message header */ - if (pqCheckOutBufferSpace(endPos, conn)) - return EOF; - /* okay, save the message type byte if any */ - if (msg_type) - conn->outBuffer[conn->outCount] = msg_type; - /* set up the message pointers */ - conn->outMsgStart = lenPos; - conn->outMsgEnd = endPos; - /* length word, if needed, will be filled in by pqPutMsgEnd */ - - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> Msg %c\n", - msg_type ? msg_type : ' '); - - return 0; -} - -/* - * pqPutMsgBytes: add bytes to a partially-constructed message - * - * Returns 0 on success, EOF on error - */ -static int -pqPutMsgBytes(const void *buf, size_t len, PGconn *conn) -{ - /* make sure there is room for it */ - if (pqCheckOutBufferSpace(conn->outMsgEnd + len, conn)) - return EOF; - /* okay, save the data */ - memcpy(conn->outBuffer + conn->outMsgEnd, buf, len); - conn->outMsgEnd += len; - /* no Pfdebug call here, caller should do it */ - return 0; -} - -/* - * pqPutMsgEnd: finish constructing a message and possibly send it - * - * Returns 0 on success, EOF on error - * - * We don't actually send anything here unless we've accumulated at least - * 8K worth of data (the typical size of a pipe buffer on Unix systems). - * This avoids sending small partial packets. The caller must use pqFlush - * when it's important to flush all the data out to the server. - */ -int -pqPutMsgEnd(PGconn *conn) -{ - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n", - conn->outMsgEnd - conn->outCount); - - /* Fill in length word if needed */ - if (conn->outMsgStart >= 0) - { - uint32 msgLen = conn->outMsgEnd - conn->outMsgStart; - - msgLen = htonl(msgLen); - memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4); - } - - /* Make message eligible to send */ - conn->outCount = conn->outMsgEnd; - - if (conn->outCount >= 8192) - { - int toSend = conn->outCount - (conn->outCount % 8192); - - if (pqSendSome(conn, toSend) < 0) - return EOF; - /* in nonblock mode, don't complain if unable to send it all */ - } - - return 0; -} - -/* ---------- - * pqReadData: read more data, if any is available - * Possible return values: - * 1: successfully loaded at least one more byte - * 0: no data is presently available, but no error detected - * -1: error detected (including EOF = connection closure); - * conn->errorMessage set - * NOTE: callers must not assume that pointers or indexes into conn->inBuffer - * remain valid across this call! - * ---------- - */ -int -pqReadData(PGconn *conn) -{ - int someread = 0; - int nread; - - if (conn->sock == PGINVALID_SOCKET) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); - return -1; - } - - /* Left-justify any data in the buffer to make room */ - if (conn->inStart < conn->inEnd) - { - if (conn->inStart > 0) - { - memmove(conn->inBuffer, conn->inBuffer + conn->inStart, - conn->inEnd - conn->inStart); - conn->inEnd -= conn->inStart; - conn->inCursor -= conn->inStart; - conn->inStart = 0; - } - } - else - { - /* buffer is logically empty, reset it */ - conn->inStart = conn->inCursor = conn->inEnd = 0; - } - - /* - * If the buffer is fairly full, enlarge it. We need to be able to enlarge - * the buffer in case a single message exceeds the initial buffer size. We - * enlarge before filling the buffer entirely so as to avoid asking the - * kernel for a partial packet. The magic constant here should be large - * enough for a TCP packet or Unix pipe bufferload. 8K is the usual pipe - * buffer size, so... - */ - if (conn->inBufSize - conn->inEnd < 8192) - { - if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn)) - { - /* - * We don't insist that the enlarge worked, but we need some room - */ - if (conn->inBufSize - conn->inEnd < 100) - return -1; /* errorMessage already set */ - } - } - - /* OK, try to read some data */ -retry3: - nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, - conn->inBufSize - conn->inEnd); - if (nread < 0) - { - if (SOCK_ERRNO == EINTR) - goto retry3; - /* Some systems return EAGAIN/EWOULDBLOCK for no data */ -#ifdef EAGAIN - if (SOCK_ERRNO == EAGAIN) - return someread; -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - if (SOCK_ERRNO == EWOULDBLOCK) - return someread; -#endif - /* We might get ECONNRESET here if using TCP and backend died */ -#ifdef ECONNRESET - if (SOCK_ERRNO == ECONNRESET) - goto definitelyFailed; -#endif - /* pqsecure_read set the error message for us */ - return -1; - } - if (nread > 0) - { - conn->inEnd += nread; - - /* - * Hack to deal with the fact that some kernels will only give us back - * 1 packet per recv() call, even if we asked for more and there is - * more available. If it looks like we are reading a long message, - * loop back to recv() again immediately, until we run out of data or - * buffer space. Without this, the block-and-restart behavior of - * libpq's higher levels leads to O(N^2) performance on long messages. - * - * Since we left-justified the data above, conn->inEnd gives the - * amount of data already read in the current message. We consider - * the message "long" once we have acquired 32k ... - */ - if (conn->inEnd > 32768 && - (conn->inBufSize - conn->inEnd) >= 8192) - { - someread = 1; - goto retry3; - } - return 1; - } - - if (someread) - return 1; /* got a zero read after successful tries */ - - /* - * A return value of 0 could mean just that no data is now available, or - * it could mean EOF --- that is, the server has closed the connection. - * Since we have the socket in nonblock mode, the only way to tell the - * difference is to see if select() is saying that the file is ready. - * Grumble. Fortunately, we don't expect this path to be taken much, - * since in normal practice we should not be trying to read data unless - * the file selected for reading already. - * - * In SSL mode it's even worse: SSL_read() could say WANT_READ and then - * data could arrive before we make the pqReadReady() test, but the second - * SSL_read() could still say WANT_READ because the data received was not - * a complete SSL record. So we must play dumb and assume there is more - * data, relying on the SSL layer to detect true EOF. - */ - -#ifdef USE_SSL - if (conn->ssl_in_use) - return 0; -#endif - - switch (pqReadReady(conn)) - { - case 0: - /* definitely no data available */ - return 0; - case 1: - /* ready for read */ - break; - default: - /* we override pqReadReady's message with something more useful */ - goto definitelyEOF; - } - - /* - * Still not sure that it's EOF, because some data could have just - * arrived. - */ -retry4: - nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, - conn->inBufSize - conn->inEnd); - if (nread < 0) - { - if (SOCK_ERRNO == EINTR) - goto retry4; - /* Some systems return EAGAIN/EWOULDBLOCK for no data */ -#ifdef EAGAIN - if (SOCK_ERRNO == EAGAIN) - return 0; -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - if (SOCK_ERRNO == EWOULDBLOCK) - return 0; -#endif - /* We might get ECONNRESET here if using TCP and backend died */ -#ifdef ECONNRESET - if (SOCK_ERRNO == ECONNRESET) - goto definitelyFailed; -#endif - /* pqsecure_read set the error message for us */ - return -1; - } - if (nread > 0) - { - conn->inEnd += nread; - return 1; - } - - /* - * OK, we are getting a zero read even though select() says ready. This - * means the connection has been closed. Cope. - */ -definitelyEOF: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); - - /* Come here if lower-level code already set a suitable errorMessage */ -definitelyFailed: - /* Do *not* drop any already-read data; caller still wants it */ - pqDropConnection(conn, false); - conn->status = CONNECTION_BAD; /* No more connection to backend */ - return -1; -} - -/* - * pqSendSome: send data waiting in the output buffer. - * - * len is how much to try to send (typically equal to outCount, but may - * be less). - * - * Return 0 on success, -1 on failure and 1 when not all data could be sent - * because the socket would block and the connection is non-blocking. - */ -static int -pqSendSome(PGconn *conn, int len) -{ - char *ptr = conn->outBuffer; - int remaining = conn->outCount; - int result = 0; - - if (conn->sock == PGINVALID_SOCKET) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("connection not open\n")); - /* Discard queued data; no chance it'll ever be sent */ - conn->outCount = 0; - return -1; - } - - /* while there's still data to send */ - while (len > 0) - { - int sent; - -#ifndef WIN32 - sent = pqsecure_write(conn, ptr, len); -#else - - /* - * Windows can fail on large sends, per KB article Q201213. The - * failure-point appears to be different in different versions of - * Windows, but 64k should always be safe. - */ - sent = pqsecure_write(conn, ptr, Min(len, 65536)); -#endif - - if (sent < 0) - { - /* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */ - switch (SOCK_ERRNO) - { -#ifdef EAGAIN - case EAGAIN: - break; -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - case EWOULDBLOCK: - break; -#endif - case EINTR: - continue; - - default: - /* pqsecure_write set the error message for us */ - - /* - * We used to close the socket here, but that's a bad idea - * since there might be unread data waiting (typically, a - * NOTICE message from the backend telling us it's - * committing hara-kiri...). Leave the socket open until - * pqReadData finds no more data can be read. But abandon - * attempt to send data. - */ - conn->outCount = 0; - return -1; - } - } - else - { - ptr += sent; - len -= sent; - remaining -= sent; - } - - if (len > 0) - { - /* - * We didn't send it all, wait till we can send more. - * - * There are scenarios in which we can't send data because the - * communications channel is full, but we cannot expect the server - * to clear the channel eventually because it's blocked trying to - * send data to us. (This can happen when we are sending a large - * amount of COPY data, and the server has generated lots of - * NOTICE responses.) To avoid a deadlock situation, we must be - * prepared to accept and buffer incoming data before we try - * again. Furthermore, it is possible that such incoming data - * might not arrive until after we've gone to sleep. Therefore, - * we wait for either read ready or write ready. - * - * In non-blocking mode, we don't wait here directly, but return 1 - * to indicate that data is still pending. The caller should wait - * for both read and write ready conditions, and call - * PQconsumeInput() on read ready, but just in case it doesn't, we - * call pqReadData() ourselves before returning. That's not - * enough if the data has not arrived yet, but it's the best we - * can do, and works pretty well in practice. (The documentation - * used to say that you only need to wait for write-ready, so - * there are still plenty of applications like that out there.) - */ - if (pqReadData(conn) < 0) - { - result = -1; /* error message already set up */ - break; - } - - if (pqIsnonblocking(conn)) - { - result = 1; - break; - } - - if (pqWait(TRUE, TRUE, conn)) - { - result = -1; - break; - } - } - } - - /* shift the remaining contents of the buffer */ - if (remaining > 0) - memmove(conn->outBuffer, ptr, remaining); - conn->outCount = remaining; - - return result; -} - - -/* - * pqFlush: send any data waiting in the output buffer - * - * Return 0 on success, -1 on failure and 1 when not all data could be sent - * because the socket would block and the connection is non-blocking. - */ -int -pqFlush(PGconn *conn) -{ - if (conn->Pfdebug) - fflush(conn->Pfdebug); - - if (conn->outCount > 0) - return pqSendSome(conn, conn->outCount); - - return 0; -} - - -/* - * pqWait: wait until we can read or write the connection socket - * - * JAB: If SSL enabled and used and forRead, buffered bytes short-circuit the - * call to select(). - * - * We also stop waiting and return if the kernel flags an exception condition - * on the socket. The actual error condition will be detected and reported - * when the caller tries to read or write the socket. - */ -int -pqWait(int forRead, int forWrite, PGconn *conn) -{ - return pqWaitTimed(forRead, forWrite, conn, (time_t) -1); -} - -/* - * pqWaitTimed: wait, but not past finish_time. - * - * If finish_time is exceeded then we return failure (EOF). This is like - * the response for a kernel exception because we don't want the caller - * to try to read/write in that case. - * - * finish_time = ((time_t) -1) disables the wait limit. - */ -int -pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time) -{ - int result; - - result = pqSocketCheck(conn, forRead, forWrite, finish_time); - - if (result < 0) - return EOF; /* errorMessage is already set */ - - if (result == 0) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("timeout expired\n")); - return EOF; - } - - return 0; -} - -/* - * pqReadReady: is select() saying the file is ready to read? - * Returns -1 on failure, 0 if not ready, 1 if ready. - */ -int -pqReadReady(PGconn *conn) -{ - return pqSocketCheck(conn, 1, 0, (time_t) 0); -} - -/* - * pqWriteReady: is select() saying the file is ready to write? - * Returns -1 on failure, 0 if not ready, 1 if ready. - */ -int -pqWriteReady(PGconn *conn) -{ - return pqSocketCheck(conn, 0, 1, (time_t) 0); -} - -/* - * Checks a socket, using poll or select, for data to be read, written, - * or both. Returns >0 if one or more conditions are met, 0 if it timed - * out, -1 if an error occurred. - * - * If SSL is in use, the SSL buffer is checked prior to checking the socket - * for read data directly. - */ -static int -pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) -{ - int result; - - if (!conn) - return -1; - if (conn->sock == PGINVALID_SOCKET) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid socket\n")); - return -1; - } - -#ifdef USE_SSL - /* Check for SSL library buffering read bytes */ - if (forRead && conn->ssl_in_use && pgtls_read_pending(conn) > 0) - { - /* short-circuit the select */ - return 1; - } -#endif - - /* We will retry as long as we get EINTR */ - do - result = pqSocketPoll(conn->sock, forRead, forWrite, end_time); - while (result < 0 && SOCK_ERRNO == EINTR); - - if (result < 0) - { - char sebuf[256]; - - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("select() failed: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - } - - return result; -} - - -/* - * Check a file descriptor for read and/or write data, possibly waiting. - * If neither forRead nor forWrite are set, immediately return a timeout - * condition (without waiting). Return >0 if condition is met, 0 - * if a timeout occurred, -1 if an error or interrupt occurred. - * - * Timeout is infinite if end_time is -1. Timeout is immediate (no blocking) - * if end_time is 0 (or indeed, any time before now). - */ -static int -pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time) -{ - /* We use poll(2) if available, otherwise select(2) */ -#ifdef HAVE_POLL - struct pollfd input_fd; - int timeout_ms; - - if (!forRead && !forWrite) - return 0; - - input_fd.fd = sock; - input_fd.events = POLLERR; - input_fd.revents = 0; - - if (forRead) - input_fd.events |= POLLIN; - if (forWrite) - input_fd.events |= POLLOUT; - - /* Compute appropriate timeout interval */ - if (end_time == ((time_t) -1)) - timeout_ms = -1; - else - { - time_t now = time(NULL); - - if (end_time > now) - timeout_ms = (end_time - now) * 1000; - else - timeout_ms = 0; - } - - return poll(&input_fd, 1, timeout_ms); -#else /* !HAVE_POLL */ - - fd_set input_mask; - fd_set output_mask; - fd_set except_mask; - struct timeval timeout; - struct timeval *ptr_timeout; - - if (!forRead && !forWrite) - return 0; - - FD_ZERO(&input_mask); - FD_ZERO(&output_mask); - FD_ZERO(&except_mask); - if (forRead) - FD_SET(sock, &input_mask); - - if (forWrite) - FD_SET(sock, &output_mask); - FD_SET(sock, &except_mask); - - /* Compute appropriate timeout interval */ - if (end_time == ((time_t) -1)) - ptr_timeout = NULL; - else - { - time_t now = time(NULL); - - if (end_time > now) - timeout.tv_sec = end_time - now; - else - timeout.tv_sec = 0; - timeout.tv_usec = 0; - ptr_timeout = &timeout; - } - - return select(sock + 1, &input_mask, &output_mask, - &except_mask, ptr_timeout); -#endif /* HAVE_POLL */ -} - - -/* - * A couple of "miscellaneous" multibyte related functions. They used - * to be in fe-print.c but that file is doomed. - */ - -/* - * returns the byte length of the character beginning at s, using the - * specified encoding. - */ -int -PQmblen(const char *s, int encoding) -{ - return pg_encoding_mblen(encoding, s); -} - -/* - * returns the display length of the character beginning at s, using the - * specified encoding. - */ -int -PQdsplen(const char *s, int encoding) -{ - return pg_encoding_dsplen(encoding, s); -} - -/* - * Get encoding id from environment variable PGCLIENTENCODING. - */ -int -PQenv2encoding(void) -{ - char *str; - int encoding = PG_SQL_ASCII; - - str = getenv("PGCLIENTENCODING"); - if (str && *str != '\0') - { - encoding = pg_char_to_encoding(str); - if (encoding < 0) - encoding = PG_SQL_ASCII; - } - return encoding; -} - - -#ifdef ENABLE_NLS - -static void -libpq_binddomain() -{ - static bool already_bound = false; - - if (!already_bound) - { - /* bindtextdomain() does not preserve errno */ -#ifdef WIN32 - int save_errno = GetLastError(); -#else - int save_errno = errno; -#endif - const char *ldir; - - already_bound = true; - /* No relocatable lookup here because the binary could be anywhere */ - ldir = getenv("PGLOCALEDIR"); - if (!ldir) - ldir = LOCALEDIR; - bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir); -#ifdef WIN32 - SetLastError(save_errno); -#else - errno = save_errno; -#endif - } -} - -char * -libpq_gettext(const char *msgid) -{ - libpq_binddomain(); - return dgettext(PG_TEXTDOMAIN("libpq"), msgid); -} - -char * -libpq_ngettext(const char *msgid, const char *msgid_plural, unsigned long n) -{ - libpq_binddomain(); - return dngettext(PG_TEXTDOMAIN("libpq"), msgid, msgid_plural, n); -} - -#endif /* ENABLE_NLS */ diff --git a/libpq/fe-print.c b/libpq/fe-print.c deleted file mode 100644 index e596a51..0000000 --- a/libpq/fe-print.c +++ /dev/null @@ -1,761 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-print.c - * functions for pretty-printing query results - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * These functions were formerly part of fe-exec.c, but they - * didn't really belong there. - * - * IDENTIFICATION - * src/interfaces/libpq/fe-print.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#endif - -#ifdef HAVE_TERMIOS_H -#include -#else -#ifndef WIN32 -#include -#endif -#endif - -#include "libpq-fe.h" -#include "libpq-int.h" - - -static void do_field(const PQprintOpt *po, const PGresult *res, - const int i, const int j, const int fs_len, - char **fields, - const int nFields, const char **fieldNames, - unsigned char *fieldNotNum, int *fieldMax, - const int fieldMaxLen, FILE *fout); -static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields, - int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum, - const int fs_len, const PGresult *res); -static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields, - unsigned char *fieldNotNum, int *fieldMax, char *border, - const int row_index); -static void fill(int length, int max, char filler, FILE *fp); - -/* - * PQprint() - * - * Format results of a query for printing. - * - * PQprintOpt is a typedef (structure) that contains - * various flags and options. consult libpq-fe.h for - * details - * - * This function should probably be removed sometime since psql - * doesn't use it anymore. It is unclear to what extent this is used - * by external clients, however. - */ -void -PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po) -{ - int nFields; - - nFields = PQnfields(res); - - if (nFields > 0) - { /* only print rows with at least 1 field. */ - int i, - j; - int nTups; - int *fieldMax = NULL; /* in case we don't use them */ - unsigned char *fieldNotNum = NULL; - char *border = NULL; - char **fields = NULL; - const char **fieldNames; - int fieldMaxLen = 0; - int numFieldName; - int fs_len = strlen(po->fieldSep); - int total_line_length = 0; - int usePipe = 0; - char *pagerenv; - -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) - sigset_t osigset; - bool sigpipe_masked = false; - bool sigpipe_pending; -#endif -#if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) - pqsigfunc oldsigpipehandler = NULL; -#endif - -#ifdef TIOCGWINSZ - struct winsize screen_size; -#else - struct winsize - { - int ws_row; - int ws_col; - } screen_size; -#endif - - nTups = PQntuples(res); - if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *)))) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1))) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - if (!(fieldMax = (int *) calloc(nFields, sizeof(int)))) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - for (numFieldName = 0; - po->fieldName && po->fieldName[numFieldName]; - numFieldName++) - ; - for (j = 0; j < nFields; j++) - { - int len; - const char *s = (j < numFieldName && po->fieldName[j][0]) ? - po->fieldName[j] : PQfname(res, j); - - fieldNames[j] = s; - len = s ? strlen(s) : 0; - fieldMax[j] = len; - len += fs_len; - if (len > fieldMaxLen) - fieldMaxLen = len; - total_line_length += len; - } - - total_line_length += nFields * strlen(po->fieldSep) + 1; - - if (fout == NULL) - fout = stdout; - if (po->pager && fout == stdout && isatty(fileno(stdin)) && - isatty(fileno(stdout))) - { - /* - * If we think there'll be more than one screen of output, try to - * pipe to the pager program. - */ -#ifdef TIOCGWINSZ - if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0) - { - screen_size.ws_row = 24; - screen_size.ws_col = 80; - } -#else - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#endif - pagerenv = getenv("PAGER"); - /* if PAGER is unset, empty or all-white-space, don't use pager */ - if (pagerenv != NULL && - strspn(pagerenv, " \t\r\n") != strlen(pagerenv) && - !po->html3 && - ((po->expanded && - nTups * (nFields + 1) >= screen_size.ws_row) || - (!po->expanded && - nTups * (total_line_length / screen_size.ws_col + 1) * - (1 + (po->standard != 0)) >= screen_size.ws_row - - (po->header != 0) * - (total_line_length / screen_size.ws_col + 1) * 2 - - (po->header != 0) * 2 /* row count and newline */ - ))) - { - fout = popen(pagerenv, "w"); - if (fout) - { - usePipe = 1; -#ifndef WIN32 -#ifdef ENABLE_THREAD_SAFETY - if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0) - sigpipe_masked = true; -#else - oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN); -#endif /* ENABLE_THREAD_SAFETY */ -#endif /* WIN32 */ - } - else - fout = stdout; - } - } - - if (!po->expanded && (po->align || po->html3)) - { - if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *)))) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - } - else if (po->header && !po->html3) - { - if (po->expanded) - { - if (po->align) - fprintf(fout, libpq_gettext("%-*s%s Value\n"), - fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep); - else - fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep); - } - else - { - int len = 0; - - for (j = 0; j < nFields; j++) - { - const char *s = fieldNames[j]; - - fputs(s, fout); - len += strlen(s) + fs_len; - if ((j + 1) < nFields) - fputs(po->fieldSep, fout); - } - fputc('\n', fout); - for (len -= fs_len; len--; fputc('-', fout)); - fputc('\n', fout); - } - } - if (po->expanded && po->html3) - { - if (po->caption) - fprintf(fout, "

%s

\n", po->caption); - else - fprintf(fout, - "

" - "Query retrieved %d rows * %d fields" - "

\n", - nTups, nFields); - } - for (i = 0; i < nTups; i++) - { - if (po->expanded) - { - if (po->html3) - fprintf(fout, - "\n", - po->tableOpt ? po->tableOpt : "", i); - else - fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i); - } - for (j = 0; j < nFields; j++) - do_field(po, res, i, j, fs_len, fields, nFields, - fieldNames, fieldNotNum, - fieldMax, fieldMaxLen, fout); - if (po->html3 && po->expanded) - fputs("
%d
\n", fout); - } - if (!po->expanded && (po->align || po->html3)) - { - if (po->html3) - { - if (po->header) - { - if (po->caption) - fprintf(fout, - "\n", - po->tableOpt ? po->tableOpt : "", - po->caption); - else - fprintf(fout, - "
%s
\n", - po->tableOpt ? po->tableOpt : "", nTups, nFields); - } - else - fprintf(fout, "
" - "Retrieved %d rows * %d fields" - "
", po->tableOpt ? po->tableOpt : ""); - } - if (po->header) - border = do_header(fout, po, nFields, fieldMax, fieldNames, - fieldNotNum, fs_len, res); - for (i = 0; i < nTups; i++) - output_row(fout, po, nFields, fields, - fieldNotNum, fieldMax, border, i); - free(fields); - if (border) - free(border); - } - if (po->header && !po->html3) - fprintf(fout, "(%d row%s)\n\n", PQntuples(res), - (PQntuples(res) == 1) ? "" : "s"); - free(fieldMax); - free(fieldNotNum); - free((void *) fieldNames); - if (usePipe) - { -#ifdef WIN32 - _pclose(fout); -#else - pclose(fout); - -#ifdef ENABLE_THREAD_SAFETY - /* we can't easily verify if EPIPE occurred, so say it did */ - if (sigpipe_masked) - pq_reset_sigpipe(&osigset, sigpipe_pending, true); -#else - pqsignal(SIGPIPE, oldsigpipehandler); -#endif /* ENABLE_THREAD_SAFETY */ -#endif /* WIN32 */ - } - if (po->html3 && !po->expanded) - fputs("
\n", fout); - } -} - - -static void -do_field(const PQprintOpt *po, const PGresult *res, - const int i, const int j, const int fs_len, - char **fields, - const int nFields, char const ** fieldNames, - unsigned char *fieldNotNum, int *fieldMax, - const int fieldMaxLen, FILE *fout) -{ - const char *pval, - *p; - int plen; - bool skipit; - - plen = PQgetlength(res, i, j); - pval = PQgetvalue(res, i, j); - - if (plen < 1 || !pval || !*pval) - { - if (po->align || po->expanded) - skipit = true; - else - { - skipit = false; - goto efield; - } - } - else - skipit = false; - - if (!skipit) - { - if (po->align && !fieldNotNum[j]) - { - /* Detect whether field contains non-numeric data */ - char ch = '0'; - - for (p = pval; *p; p += PQmblen(p, res->client_encoding)) - { - ch = *p; - if (!((ch >= '0' && ch <= '9') || - ch == '.' || - ch == 'E' || - ch == 'e' || - ch == ' ' || - ch == '-')) - { - fieldNotNum[j] = 1; - break; - } - } - - /* - * Above loop will believe E in first column is numeric; also, we - * insist on a digit in the last column for a numeric. This test - * is still not bulletproof but it handles most cases. - */ - if (*pval == 'E' || *pval == 'e' || - !(ch >= '0' && ch <= '9')) - fieldNotNum[j] = 1; - } - - if (!po->expanded && (po->align || po->html3)) - { - if (plen > fieldMax[j]) - fieldMax[j] = plen; - if (!(fields[i * nFields + j] = (char *) malloc(plen + 1))) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - strcpy(fields[i * nFields + j], pval); - } - else - { - if (po->expanded) - { - if (po->html3) - fprintf(fout, - "%s" - "%s\n", - fieldNames[j], - fieldNotNum[j] ? "left" : "right", - pval); - else - { - if (po->align) - fprintf(fout, - "%-*s%s %s\n", - fieldMaxLen - fs_len, fieldNames[j], - po->fieldSep, - pval); - else - fprintf(fout, - "%s%s%s\n", - fieldNames[j], po->fieldSep, pval); - } - } - else - { - if (!po->html3) - { - fputs(pval, fout); - efield: - if ((j + 1) < nFields) - fputs(po->fieldSep, fout); - else - fputc('\n', fout); - } - } - } - } -} - - -static char * -do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax, - const char **fieldNames, unsigned char *fieldNotNum, - const int fs_len, const PGresult *res) -{ - int j; /* for loop index */ - char *border = NULL; - - if (po->html3) - fputs("", fout); - else - { - int tot = 0; - int n = 0; - char *p = NULL; - - for (; n < nFields; n++) - tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0); - if (po->standard) - tot += fs_len * 2 + 2; - border = malloc(tot + 1); - if (!border) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - p = border; - if (po->standard) - { - char *fs = po->fieldSep; - - while (*fs++) - *p++ = '+'; - } - for (j = 0; j < nFields; j++) - { - int len; - - for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-'); - if (po->standard || (j + 1) < nFields) - { - char *fs = po->fieldSep; - - while (*fs++) - *p++ = '+'; - } - } - *p = '\0'; - if (po->standard) - fprintf(fout, "%s\n", border); - } - if (po->standard) - fputs(po->fieldSep, fout); - for (j = 0; j < nFields; j++) - { - const char *s = PQfname(res, j); - - if (po->html3) - { - fprintf(fout, "%s", - fieldNotNum[j] ? "left" : "right", fieldNames[j]); - } - else - { - int n = strlen(s); - - if (n > fieldMax[j]) - fieldMax[j] = n; - if (po->standard) - fprintf(fout, - fieldNotNum[j] ? " %-*s " : " %*s ", - fieldMax[j], s); - else - fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s); - if (po->standard || (j + 1) < nFields) - fputs(po->fieldSep, fout); - } - } - if (po->html3) - fputs("\n", fout); - else - fprintf(fout, "\n%s\n", border); - return border; -} - - -static void -output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields, - unsigned char *fieldNotNum, int *fieldMax, char *border, - const int row_index) -{ - int field_index; /* for loop index */ - - if (po->html3) - fputs("", fout); - else if (po->standard) - fputs(po->fieldSep, fout); - for (field_index = 0; field_index < nFields; field_index++) - { - char *p = fields[row_index * nFields + field_index]; - - if (po->html3) - fprintf(fout, "%s", - fieldNotNum[field_index] ? "left" : "right", p ? p : ""); - else - { - fprintf(fout, - fieldNotNum[field_index] ? - (po->standard ? " %-*s " : "%-*s") : - (po->standard ? " %*s " : "%*s"), - fieldMax[field_index], - p ? p : ""); - if (po->standard || field_index + 1 < nFields) - fputs(po->fieldSep, fout); - } - if (p) - free(p); - } - if (po->html3) - fputs("", fout); - else if (po->standard) - fprintf(fout, "\n%s", border); - fputc('\n', fout); -} - - - -/* - * really old printing routines - */ - -void -PQdisplayTuples(const PGresult *res, - FILE *fp, /* where to send the output */ - int fillAlign, /* pad the fields with spaces */ - const char *fieldSep, /* field separator */ - int printHeader, /* display headers? */ - int quiet -) -{ -#define DEFAULT_FIELD_SEP " " - - int i, - j; - int nFields; - int nTuples; - int *fLength = NULL; - - if (fieldSep == NULL) - fieldSep = DEFAULT_FIELD_SEP; - - /* Get some useful info about the results */ - nFields = PQnfields(res); - nTuples = PQntuples(res); - - if (fp == NULL) - fp = stdout; - - /* Figure the field lengths to align to */ - /* will be somewhat time consuming for very large results */ - if (fillAlign) - { - fLength = (int *) malloc(nFields * sizeof(int)); - if (!fLength) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - - for (j = 0; j < nFields; j++) - { - fLength[j] = strlen(PQfname(res, j)); - for (i = 0; i < nTuples; i++) - { - int flen = PQgetlength(res, i, j); - - if (flen > fLength[j]) - fLength[j] = flen; - } - } - } - - if (printHeader) - { - /* first, print out the attribute names */ - for (i = 0; i < nFields; i++) - { - fputs(PQfname(res, i), fp); - if (fillAlign) - fill(strlen(PQfname(res, i)), fLength[i], ' ', fp); - fputs(fieldSep, fp); - } - fprintf(fp, "\n"); - - /* Underline the attribute names */ - for (i = 0; i < nFields; i++) - { - if (fillAlign) - fill(0, fLength[i], '-', fp); - fputs(fieldSep, fp); - } - fprintf(fp, "\n"); - } - - /* next, print out the instances */ - for (i = 0; i < nTuples; i++) - { - for (j = 0; j < nFields; j++) - { - fprintf(fp, "%s", PQgetvalue(res, i, j)); - if (fillAlign) - fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp); - fputs(fieldSep, fp); - } - fprintf(fp, "\n"); - } - - if (!quiet) - fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res), - (PQntuples(res) == 1) ? "" : "s"); - - fflush(fp); - - if (fLength) - free(fLength); -} - - - -void -PQprintTuples(const PGresult *res, - FILE *fout, /* output stream */ - int PrintAttNames, /* print attribute names or not */ - int TerseOutput, /* delimiter bars or not? */ - int colWidth /* width of column, if 0, use variable width */ -) -{ - int nFields; - int nTups; - int i, - j; - char formatString[80]; - char *tborder = NULL; - - nFields = PQnfields(res); - nTups = PQntuples(res); - - if (colWidth > 0) - sprintf(formatString, "%%s %%-%ds", colWidth); - else - sprintf(formatString, "%%s %%s"); - - if (nFields > 0) - { /* only print rows with at least 1 field. */ - - if (!TerseOutput) - { - int width; - - width = nFields * 14; - tborder = (char *) malloc(width + 1); - if (!tborder) - { - fprintf(stderr, libpq_gettext("out of memory\n")); - abort(); - } - for (i = 0; i < width; i++) - tborder[i] = '-'; - tborder[width] = '\0'; - fprintf(fout, "%s\n", tborder); - } - - for (i = 0; i < nFields; i++) - { - if (PrintAttNames) - { - fprintf(fout, formatString, - TerseOutput ? "" : "|", - PQfname(res, i)); - } - } - - if (PrintAttNames) - { - if (TerseOutput) - fprintf(fout, "\n"); - else - fprintf(fout, "|\n%s\n", tborder); - } - - for (i = 0; i < nTups; i++) - { - for (j = 0; j < nFields; j++) - { - const char *pval = PQgetvalue(res, i, j); - - fprintf(fout, formatString, - TerseOutput ? "" : "|", - pval ? pval : ""); - } - if (TerseOutput) - fprintf(fout, "\n"); - else - fprintf(fout, "|\n%s\n", tborder); - } - } - - if (tborder) - free(tborder); -} - - -/* simply send out max-length number of filler characters to fp */ - -static void -fill(int length, int max, char filler, FILE *fp) -{ - int count; - - count = max - length; - while (count-- >= 0) - putc(filler, fp); -} diff --git a/libpq/fe-protocol2.c b/libpq/fe-protocol2.c deleted file mode 100644 index f1b90f3..0000000 --- a/libpq/fe-protocol2.c +++ /dev/null @@ -1,1623 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-protocol2.c - * functions that are specific to frontend/backend protocol version 2 - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-protocol2.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include -#include - -#include "libpq-fe.h" -#include "libpq-int.h" - - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#include -#endif - - -static int getRowDescriptions(PGconn *conn); -static int getAnotherTuple(PGconn *conn, bool binary); -static int pqGetErrorNotice2(PGconn *conn, bool isError); -static void checkXactStatus(PGconn *conn, const char *cmdTag); -static int getNotify(PGconn *conn); - - -/* - * pqSetenvPoll - * - * Polls the process of passing the values of a standard set of environment - * variables to the backend. - */ -PostgresPollingStatusType -pqSetenvPoll(PGconn *conn) -{ - PGresult *res; - - if (conn == NULL || conn->status == CONNECTION_BAD) - return PGRES_POLLING_FAILED; - - /* Check whether there are any data for us */ - switch (conn->setenv_state) - { - /* These are reading states */ - case SETENV_STATE_CLIENT_ENCODING_WAIT: - case SETENV_STATE_OPTION_WAIT: - case SETENV_STATE_QUERY1_WAIT: - case SETENV_STATE_QUERY2_WAIT: - { - /* Load waiting data */ - int n = pqReadData(conn); - - if (n < 0) - goto error_return; - if (n == 0) - return PGRES_POLLING_READING; - - break; - } - - /* These are writing states, so we just proceed. */ - case SETENV_STATE_CLIENT_ENCODING_SEND: - case SETENV_STATE_OPTION_SEND: - case SETENV_STATE_QUERY1_SEND: - case SETENV_STATE_QUERY2_SEND: - break; - - /* Should we raise an error if called when not active? */ - case SETENV_STATE_IDLE: - return PGRES_POLLING_OK; - - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "invalid setenv state %c, " - "probably indicative of memory corruption\n" - ), - conn->setenv_state); - goto error_return; - } - - /* We will loop here until there is nothing left to do in this call. */ - for (;;) - { - switch (conn->setenv_state) - { - /* - * The _CLIENT_ENCODING_SEND code is slightly different from - * _OPTION_SEND below (e.g., no getenv() call), which is why a - * different state is used. - */ - case SETENV_STATE_CLIENT_ENCODING_SEND: - { - char setQuery[100]; /* note length limit in - * sprintf below */ - const char *val = conn->client_encoding_initial; - - if (val) - { - if (pg_strcasecmp(val, "default") == 0) - sprintf(setQuery, "SET client_encoding = DEFAULT"); - else - sprintf(setQuery, "SET client_encoding = '%.60s'", - val); -#ifdef CONNECTDEBUG - fprintf(stderr, - "Sending client_encoding with %s\n", - setQuery); -#endif - if (!PQsendQuery(conn, setQuery)) - goto error_return; - - conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT; - } - else - conn->setenv_state = SETENV_STATE_OPTION_SEND; - break; - } - - case SETENV_STATE_OPTION_SEND: - { - /* - * Send SET commands for stuff directed by Environment - * Options. Note: we assume that SET commands won't start - * transaction blocks, even in a 7.3 server with - * autocommit off. - */ - char setQuery[100]; /* note length limit in - * sprintf below */ - - if (conn->next_eo->envName) - { - const char *val; - - if ((val = getenv(conn->next_eo->envName))) - { - if (pg_strcasecmp(val, "default") == 0) - sprintf(setQuery, "SET %s = DEFAULT", - conn->next_eo->pgName); - else - sprintf(setQuery, "SET %s = '%.60s'", - conn->next_eo->pgName, val); -#ifdef CONNECTDEBUG - fprintf(stderr, - "Use environment variable %s to send %s\n", - conn->next_eo->envName, setQuery); -#endif - if (!PQsendQuery(conn, setQuery)) - goto error_return; - - conn->setenv_state = SETENV_STATE_OPTION_WAIT; - } - else - conn->next_eo++; - } - else - { - /* No more options to send, so move on to querying */ - conn->setenv_state = SETENV_STATE_QUERY1_SEND; - } - break; - } - - case SETENV_STATE_CLIENT_ENCODING_WAIT: - { - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - if (res) - { - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - PQclear(res); - goto error_return; - } - PQclear(res); - /* Keep reading until PQgetResult returns NULL */ - } - else - { - /* Query finished, so send the next option */ - conn->setenv_state = SETENV_STATE_OPTION_SEND; - } - break; - } - - case SETENV_STATE_OPTION_WAIT: - { - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - if (res) - { - if (PQresultStatus(res) != PGRES_COMMAND_OK) - { - PQclear(res); - goto error_return; - } - PQclear(res); - /* Keep reading until PQgetResult returns NULL */ - } - else - { - /* Query finished, so send the next option */ - conn->next_eo++; - conn->setenv_state = SETENV_STATE_OPTION_SEND; - } - break; - } - - case SETENV_STATE_QUERY1_SEND: - { - /* - * Issue query to get information we need. Here we must - * use begin/commit in case autocommit is off by default - * in a 7.3 server. - * - * Note: version() exists in all protocol-2.0-supporting - * backends. In 7.3 it would be safer to write - * pg_catalog.version(), but we can't do that without - * causing problems on older versions. - */ - if (!PQsendQuery(conn, "begin; select version(); end")) - goto error_return; - - conn->setenv_state = SETENV_STATE_QUERY1_WAIT; - return PGRES_POLLING_READING; - } - - case SETENV_STATE_QUERY1_WAIT: - { - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - if (res) - { - char *val; - - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - /* ignore begin/commit command results */ - PQclear(res); - continue; - } - - if (PQresultStatus(res) != PGRES_TUPLES_OK || - PQntuples(res) != 1) - { - PQclear(res); - goto error_return; - } - - /* - * Extract server version and save as if - * ParameterStatus - */ - val = PQgetvalue(res, 0, 0); - if (val && strncmp(val, "PostgreSQL ", 11) == 0) - { - char *ptr; - - /* strip off PostgreSQL part */ - val += 11; - - /* - * strip off platform part (scribbles on result, - * naughty naughty) - */ - ptr = strchr(val, ' '); - if (ptr) - *ptr = '\0'; - - pqSaveParameterStatus(conn, "server_version", - val); - } - - PQclear(res); - /* Keep reading until PQgetResult returns NULL */ - } - else - { - /* Query finished, move to next */ - conn->setenv_state = SETENV_STATE_QUERY2_SEND; - } - break; - } - - case SETENV_STATE_QUERY2_SEND: - { - const char *query; - - /* - * pg_client_encoding does not exist in pre-7.2 servers. - * So we need to be prepared for an error here. Do *not* - * start a transaction block, except in 7.3 servers where - * we need to prevent autocommit-off from starting a - * transaction anyway. - */ - if (conn->sversion >= 70300 && - conn->sversion < 70400) - query = "begin; select pg_catalog.pg_client_encoding(); end"; - else - query = "select pg_client_encoding()"; - if (!PQsendQuery(conn, query)) - goto error_return; - - conn->setenv_state = SETENV_STATE_QUERY2_WAIT; - return PGRES_POLLING_READING; - } - - case SETENV_STATE_QUERY2_WAIT: - { - if (PQisBusy(conn)) - return PGRES_POLLING_READING; - - res = PQgetResult(conn); - - if (res) - { - const char *val; - - if (PQresultStatus(res) == PGRES_COMMAND_OK) - { - /* ignore begin/commit command results */ - PQclear(res); - continue; - } - - if (PQresultStatus(res) == PGRES_TUPLES_OK && - PQntuples(res) == 1) - { - /* Extract client encoding and save it */ - val = PQgetvalue(res, 0, 0); - if (val && *val) /* null should not happen, but */ - pqSaveParameterStatus(conn, "client_encoding", - val); - } - else - { - /* - * Error: presumably function not available, so - * use PGCLIENTENCODING or SQL_ASCII as the - * fallback. - */ - val = getenv("PGCLIENTENCODING"); - if (val && *val) - pqSaveParameterStatus(conn, "client_encoding", - val); - else - pqSaveParameterStatus(conn, "client_encoding", - "SQL_ASCII"); - } - - PQclear(res); - /* Keep reading until PQgetResult returns NULL */ - } - else - { - /* Query finished, so we're done */ - conn->setenv_state = SETENV_STATE_IDLE; - return PGRES_POLLING_OK; - } - break; - } - - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid state %c, " - "probably indicative of memory corruption\n"), - conn->setenv_state); - goto error_return; - } - } - - /* Unreachable */ - -error_return: - conn->setenv_state = SETENV_STATE_IDLE; - return PGRES_POLLING_FAILED; -} - - -/* - * parseInput: if appropriate, parse input data from backend - * until input is exhausted or a stopping state is reached. - * Note that this function will NOT attempt to read more data from the backend. - */ -void -pqParseInput2(PGconn *conn) -{ - char id; - - /* - * Loop to parse successive complete messages available in the buffer. - */ - for (;;) - { - /* - * Quit if in COPY_OUT state: we expect raw data from the server until - * PQendcopy is called. Don't try to parse it according to the normal - * protocol. (This is bogus. The data lines ought to be part of the - * protocol and have identifying leading characters.) - */ - if (conn->asyncStatus == PGASYNC_COPY_OUT) - return; - - /* - * OK to try to read a message type code. - */ - conn->inCursor = conn->inStart; - if (pqGetc(&id, conn)) - return; - - /* - * NOTIFY and NOTICE messages can happen in any state besides COPY - * OUT; always process them right away. - * - * Most other messages should only be processed while in BUSY state. - * (In particular, in READY state we hold off further parsing until - * the application collects the current PGresult.) - * - * However, if the state is IDLE then we got trouble; we need to deal - * with the unexpected message somehow. - */ - if (id == 'A') - { - if (getNotify(conn)) - return; - } - else if (id == 'N') - { - if (pqGetErrorNotice2(conn, false)) - return; - } - else if (conn->asyncStatus != PGASYNC_BUSY) - { - /* If not IDLE state, just wait ... */ - if (conn->asyncStatus != PGASYNC_IDLE) - return; - - /* - * Unexpected message in IDLE state; need to recover somehow. - * ERROR messages are displayed using the notice processor; - * anything else is just dropped on the floor after displaying a - * suitable warning notice. (An ERROR is very possibly the - * backend telling us why it is about to close the connection, so - * we don't want to just discard it...) - */ - if (id == 'E') - { - if (pqGetErrorNotice2(conn, false /* treat as notice */ )) - return; - } - else - { - pqInternalNotice(&conn->noticeHooks, - "message type 0x%02x arrived from server while idle", - id); - /* Discard the unexpected message; good idea?? */ - conn->inStart = conn->inEnd; - break; - } - } - else - { - /* - * In BUSY state, we can process everything. - */ - switch (id) - { - case 'C': /* command complete */ - if (pqGets(&conn->workBuffer, conn)) - return; - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_COMMAND_OK); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - if (conn->result) - { - strlcpy(conn->result->cmdStatus, conn->workBuffer.data, - CMDSTATUS_LEN); - } - checkXactStatus(conn, conn->workBuffer.data); - conn->asyncStatus = PGASYNC_READY; - break; - case 'E': /* error return */ - if (pqGetErrorNotice2(conn, true)) - return; - conn->asyncStatus = PGASYNC_READY; - break; - case 'Z': /* backend is ready for new query */ - conn->asyncStatus = PGASYNC_IDLE; - break; - case 'I': /* empty query */ - /* read and throw away the closing '\0' */ - if (pqGetc(&id, conn)) - return; - if (id != '\0') - pqInternalNotice(&conn->noticeHooks, - "unexpected character %c following empty query response (\"I\" message)", - id); - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_EMPTY_QUERY); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - conn->asyncStatus = PGASYNC_READY; - break; - case 'K': /* secret key data from the backend */ - - /* - * This is expected only during backend startup, but it's - * just as easy to handle it as part of the main loop. - * Save the data and continue processing. - */ - if (pqGetInt(&(conn->be_pid), 4, conn)) - return; - if (pqGetInt(&(conn->be_key), 4, conn)) - return; - break; - case 'P': /* synchronous (normal) portal */ - if (pqGets(&conn->workBuffer, conn)) - return; - /* We pretty much ignore this message type... */ - break; - case 'T': /* row descriptions (start of query results) */ - if (conn->result == NULL) - { - /* First 'T' in a query sequence */ - if (getRowDescriptions(conn)) - return; - /* getRowDescriptions() moves inStart itself */ - continue; - } - else - { - /* - * A new 'T' message is treated as the start of - * another PGresult. (It is not clear that this is - * really possible with the current backend.) We stop - * parsing until the application accepts the current - * result. - */ - conn->asyncStatus = PGASYNC_READY; - return; - } - break; - case 'D': /* ASCII data tuple */ - if (conn->result != NULL) - { - /* Read another tuple of a normal query response */ - if (getAnotherTuple(conn, FALSE)) - return; - /* getAnotherTuple() moves inStart itself */ - continue; - } - else - { - pqInternalNotice(&conn->noticeHooks, - "server sent data (\"D\" message) without prior row description (\"T\" message)"); - /* Discard the unexpected message; good idea?? */ - conn->inStart = conn->inEnd; - return; - } - break; - case 'B': /* Binary data tuple */ - if (conn->result != NULL) - { - /* Read another tuple of a normal query response */ - if (getAnotherTuple(conn, TRUE)) - return; - /* getAnotherTuple() moves inStart itself */ - continue; - } - else - { - pqInternalNotice(&conn->noticeHooks, - "server sent binary data (\"B\" message) without prior row description (\"T\" message)"); - /* Discard the unexpected message; good idea?? */ - conn->inStart = conn->inEnd; - return; - } - break; - case 'G': /* Start Copy In */ - conn->asyncStatus = PGASYNC_COPY_IN; - break; - case 'H': /* Start Copy Out */ - conn->asyncStatus = PGASYNC_COPY_OUT; - break; - - /* - * Don't need to process CopyBothResponse here because it - * never arrives from the server during protocol 2.0. - */ - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "unexpected response from server; first received character was \"%c\"\n"), - id); - /* build an error result holding the error message */ - pqSaveErrorResult(conn); - /* Discard the unexpected message; good idea?? */ - conn->inStart = conn->inEnd; - conn->asyncStatus = PGASYNC_READY; - return; - } /* switch on protocol character */ - } - /* Successfully consumed this message */ - conn->inStart = conn->inCursor; - } -} - -/* - * parseInput subroutine to read a 'T' (row descriptions) message. - * We build a PGresult structure containing the attribute data. - * Returns: 0 if completed message, EOF if error or not enough data - * received yet. - * - * Note that if we run out of data, we have to suspend and reprocess - * the message after more data is received. Otherwise, conn->inStart - * must get advanced past the processed data. - */ -static int -getRowDescriptions(PGconn *conn) -{ - PGresult *result; - int nfields; - const char *errmsg; - int i; - - result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); - if (!result) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - - /* parseInput already read the 'T' label. */ - /* the next two bytes are the number of fields */ - if (pqGetInt(&(result->numAttributes), 2, conn)) - goto EOFexit; - nfields = result->numAttributes; - - /* allocate space for the attribute descriptors */ - if (nfields > 0) - { - result->attDescs = (PGresAttDesc *) - pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); - if (!result->attDescs) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); - } - - /* get type info */ - for (i = 0; i < nfields; i++) - { - int typid; - int typlen; - int atttypmod; - - if (pqGets(&conn->workBuffer, conn) || - pqGetInt(&typid, 4, conn) || - pqGetInt(&typlen, 2, conn) || - pqGetInt(&atttypmod, 4, conn)) - goto EOFexit; - - /* - * Since pqGetInt treats 2-byte integers as unsigned, we need to - * coerce the result to signed form. - */ - typlen = (int) ((int16) typlen); - - result->attDescs[i].name = pqResultStrdup(result, - conn->workBuffer.data); - if (!result->attDescs[i].name) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - result->attDescs[i].tableid = 0; - result->attDescs[i].columnid = 0; - result->attDescs[i].format = 0; - result->attDescs[i].typid = typid; - result->attDescs[i].typlen = typlen; - result->attDescs[i].atttypmod = atttypmod; - } - - /* Success! */ - conn->result = result; - - /* Advance inStart to show that the "T" message has been processed. */ - conn->inStart = conn->inCursor; - - /* - * We could perform additional setup for the new result set here, but for - * now there's nothing else to do. - */ - - /* And we're done. */ - return 0; - -advance_and_error: - - /* - * Discard the failed message. Unfortunately we don't know for sure where - * the end is, so just throw away everything in the input buffer. This is - * not very desirable but it's the best we can do in protocol v2. - */ - conn->inStart = conn->inEnd; - - /* - * Replace partially constructed result with an error result. First - * discard the old result to try to win back some memory. - */ - pqClearAsyncResult(conn); - - /* - * If preceding code didn't provide an error message, assume "out of - * memory" was meant. The advantage of having this special case is that - * freeing the old result first greatly improves the odds that gettext() - * will succeed in providing a translation. - */ - if (!errmsg) - errmsg = libpq_gettext("out of memory for query result"); - - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); - - /* - * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can - * do to recover... - */ - conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - conn->asyncStatus = PGASYNC_READY; - -EOFexit: - if (result && result != conn->result) - PQclear(result); - return EOF; -} - -/* - * parseInput subroutine to read a 'B' or 'D' (row data) message. - * We fill rowbuf with column pointers and then call the row processor. - * Returns: 0 if completed message, EOF if error or not enough data - * received yet. - * - * Note that if we run out of data, we have to suspend and reprocess - * the message after more data is received. Otherwise, conn->inStart - * must get advanced past the processed data. - */ -static int -getAnotherTuple(PGconn *conn, bool binary) -{ - PGresult *result = conn->result; - int nfields = result->numAttributes; - const char *errmsg; - PGdataValue *rowbuf; - - /* the backend sends us a bitmap of which attributes are null */ - char std_bitmap[64]; /* used unless it doesn't fit */ - char *bitmap = std_bitmap; - int i; - size_t nbytes; /* the number of bytes in bitmap */ - char bmap; /* One byte of the bitmap */ - int bitmap_index; /* Its index */ - int bitcnt; /* number of bits examined in current byte */ - int vlen; /* length of the current field value */ - - /* Resize row buffer if needed */ - rowbuf = conn->rowBuf; - if (nfields > conn->rowBufLen) - { - rowbuf = (PGdataValue *) realloc(rowbuf, - nfields * sizeof(PGdataValue)); - if (!rowbuf) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - conn->rowBuf = rowbuf; - conn->rowBufLen = nfields; - } - - /* Save format specifier */ - result->binary = binary; - - /* - * If it's binary, fix the column format indicators. We assume the - * backend will consistently send either B or D, not a mix. - */ - if (binary) - { - for (i = 0; i < nfields; i++) - result->attDescs[i].format = 1; - } - - /* Get the null-value bitmap */ - nbytes = (nfields + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - /* malloc() only for unusually large field counts... */ - if (nbytes > sizeof(std_bitmap)) - { - bitmap = (char *) malloc(nbytes); - if (!bitmap) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - } - - if (pqGetnchar(bitmap, nbytes, conn)) - goto EOFexit; - - /* Scan the fields */ - bitmap_index = 0; - bmap = bitmap[bitmap_index]; - bitcnt = 0; - - for (i = 0; i < nfields; i++) - { - /* get the value length */ - if (!(bmap & 0200)) - vlen = NULL_LEN; - else if (pqGetInt(&vlen, 4, conn)) - goto EOFexit; - else - { - if (!binary) - vlen = vlen - 4; - if (vlen < 0) - vlen = 0; - } - rowbuf[i].len = vlen; - - /* - * rowbuf[i].value always points to the next address in the data - * buffer even if the value is NULL. This allows row processors to - * estimate data sizes more easily. - */ - rowbuf[i].value = conn->inBuffer + conn->inCursor; - - /* Skip over the data value */ - if (vlen > 0) - { - if (pqSkipnchar(vlen, conn)) - goto EOFexit; - } - - /* advance the bitmap stuff */ - bitcnt++; - if (bitcnt == BITS_PER_BYTE) - { - bitmap_index++; - bmap = bitmap[bitmap_index]; - bitcnt = 0; - } - else - bmap <<= 1; - } - - /* Release bitmap now if we allocated it */ - if (bitmap != std_bitmap) - free(bitmap); - bitmap = NULL; - - /* Advance inStart to show that the "D" message has been processed. */ - conn->inStart = conn->inCursor; - - /* Process the collected row */ - errmsg = NULL; - if (pqRowProcessor(conn, &errmsg)) - return 0; /* normal, successful exit */ - - goto set_error_result; /* pqRowProcessor failed, report it */ - -advance_and_error: - - /* - * Discard the failed message. Unfortunately we don't know for sure where - * the end is, so just throw away everything in the input buffer. This is - * not very desirable but it's the best we can do in protocol v2. - */ - conn->inStart = conn->inEnd; - -set_error_result: - - /* - * Replace partially constructed result with an error result. First - * discard the old result to try to win back some memory. - */ - pqClearAsyncResult(conn); - - /* - * If preceding code didn't provide an error message, assume "out of - * memory" was meant. The advantage of having this special case is that - * freeing the old result first greatly improves the odds that gettext() - * will succeed in providing a translation. - */ - if (!errmsg) - errmsg = libpq_gettext("out of memory for query result"); - - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); - - /* - * XXX: if PQmakeEmptyPGresult() fails, there's probably not much we can - * do to recover... - */ - conn->result = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR); - conn->asyncStatus = PGASYNC_READY; - -EOFexit: - if (bitmap != NULL && bitmap != std_bitmap) - free(bitmap); - return EOF; -} - - -/* - * Attempt to read an Error or Notice response message. - * This is possible in several places, so we break it out as a subroutine. - * Entry: 'E' or 'N' message type has already been consumed. - * Exit: returns 0 if successfully consumed message. - * returns EOF if not enough data. - */ -static int -pqGetErrorNotice2(PGconn *conn, bool isError) -{ - PGresult *res = NULL; - PQExpBufferData workBuf; - char *startp; - char *splitp; - - /* - * Since the message might be pretty long, we create a temporary - * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended - * for stuff that is expected to be short. - */ - initPQExpBuffer(&workBuf); - if (pqGets(&workBuf, conn)) - goto failure; - - /* - * Make a PGresult to hold the message. We temporarily lie about the - * result status, so that PQmakeEmptyPGresult doesn't uselessly copy - * conn->errorMessage. - * - * NB: This allocation can fail, if you run out of memory. The rest of the - * function handles that gracefully, and we still try to set the error - * message as the connection's error message. - */ - res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); - if (res) - { - res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; - res->errMsg = pqResultStrdup(res, workBuf.data); - } - - /* - * Break the message into fields. We can't do very much here, but we can - * split the severity code off, and remove trailing newlines. Also, we use - * the heuristic that the primary message extends only to the first - * newline --- anything after that is detail message. (In some cases it'd - * be better classed as hint, but we can hardly be expected to guess that - * here.) - */ - while (workBuf.len > 0 && workBuf.data[workBuf.len - 1] == '\n') - workBuf.data[--workBuf.len] = '\0'; - splitp = strstr(workBuf.data, ": "); - if (splitp) - { - /* what comes before the colon is severity */ - *splitp = '\0'; - pqSaveMessageField(res, PG_DIAG_SEVERITY, workBuf.data); - startp = splitp + 3; - } - else - { - /* can't find a colon? oh well... */ - startp = workBuf.data; - } - splitp = strchr(startp, '\n'); - if (splitp) - { - /* what comes before the newline is primary message */ - *splitp++ = '\0'; - pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp); - /* the rest is detail; strip any leading whitespace */ - while (*splitp && isspace((unsigned char) *splitp)) - splitp++; - pqSaveMessageField(res, PG_DIAG_MESSAGE_DETAIL, splitp); - } - else - { - /* single-line message, so all primary */ - pqSaveMessageField(res, PG_DIAG_MESSAGE_PRIMARY, startp); - } - - /* - * Either save error as current async result, or just emit the notice. - * Also, if it's an error and we were in a transaction block, assume the - * server has now gone to error-in-transaction state. - */ - if (isError) - { - pqClearAsyncResult(conn); - conn->result = res; - resetPQExpBuffer(&conn->errorMessage); - if (res && !PQExpBufferDataBroken(workBuf) && res->errMsg) - appendPQExpBufferStr(&conn->errorMessage, res->errMsg); - else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - if (conn->xactStatus == PQTRANS_INTRANS) - conn->xactStatus = PQTRANS_INERROR; - } - else - { - if (res) - { - if (res->noticeHooks.noticeRec != NULL) - (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); - PQclear(res); - } - } - - termPQExpBuffer(&workBuf); - return 0; - -failure: - if (res) - PQclear(res); - termPQExpBuffer(&workBuf); - return EOF; -} - -/* - * checkXactStatus - attempt to track transaction-block status of server - * - * This is called each time we receive a command-complete message. By - * watching for messages from BEGIN/COMMIT/ROLLBACK commands, we can do - * a passable job of tracking the server's xact status. BUT: this does - * not work at all on 7.3 servers with AUTOCOMMIT OFF. (Man, was that - * feature ever a mistake.) Caveat user. - * - * The tags known here are all those used as far back as 7.0; is it worth - * adding those from even-older servers? - */ -static void -checkXactStatus(PGconn *conn, const char *cmdTag) -{ - if (strcmp(cmdTag, "BEGIN") == 0) - conn->xactStatus = PQTRANS_INTRANS; - else if (strcmp(cmdTag, "COMMIT") == 0) - conn->xactStatus = PQTRANS_IDLE; - else if (strcmp(cmdTag, "ROLLBACK") == 0) - conn->xactStatus = PQTRANS_IDLE; - else if (strcmp(cmdTag, "START TRANSACTION") == 0) /* 7.3 only */ - conn->xactStatus = PQTRANS_INTRANS; - - /* - * Normally we get into INERROR state by detecting an Error message. - * However, if we see one of these tags then we know for sure the server - * is in abort state ... - */ - else if (strcmp(cmdTag, "*ABORT STATE*") == 0) /* pre-7.3 only */ - conn->xactStatus = PQTRANS_INERROR; -} - -/* - * Attempt to read a Notify response message. - * This is possible in several places, so we break it out as a subroutine. - * Entry: 'A' message type and length have already been consumed. - * Exit: returns 0 if successfully consumed Notify message. - * returns EOF if not enough data. - */ -static int -getNotify(PGconn *conn) -{ - int be_pid; - int nmlen; - PGnotify *newNotify; - - if (pqGetInt(&be_pid, 4, conn)) - return EOF; - if (pqGets(&conn->workBuffer, conn)) - return EOF; - - /* - * Store the relation name right after the PQnotify structure so it can - * all be freed at once. We don't use NAMEDATALEN because we don't want - * to tie this interface to a specific server name length. - */ - nmlen = strlen(conn->workBuffer.data); - newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + 1); - if (newNotify) - { - newNotify->relname = (char *) newNotify + sizeof(PGnotify); - strcpy(newNotify->relname, conn->workBuffer.data); - /* fake up an empty-string extra field */ - newNotify->extra = newNotify->relname + nmlen; - newNotify->be_pid = be_pid; - newNotify->next = NULL; - if (conn->notifyTail) - conn->notifyTail->next = newNotify; - else - conn->notifyHead = newNotify; - conn->notifyTail = newNotify; - } - - return 0; -} - - -/* - * PQgetCopyData - read a row of data from the backend during COPY OUT - * - * If successful, sets *buffer to point to a malloc'd row of data, and - * returns row length (always > 0) as result. - * Returns 0 if no row available yet (only possible if async is true), - * -1 if end of copy (consult PQgetResult), or -2 if error (consult - * PQerrorMessage). - */ -int -pqGetCopyData2(PGconn *conn, char **buffer, int async) -{ - bool found; - int msgLength; - - for (;;) - { - /* - * Do we have a complete line of data? - */ - conn->inCursor = conn->inStart; - found = false; - while (conn->inCursor < conn->inEnd) - { - char c = conn->inBuffer[conn->inCursor++]; - - if (c == '\n') - { - found = true; - break; - } - } - if (!found) - goto nodata; - msgLength = conn->inCursor - conn->inStart; - - /* - * If it's the end-of-data marker, consume it, exit COPY_OUT mode, and - * let caller read status with PQgetResult(). - */ - if (msgLength == 3 && - strncmp(&conn->inBuffer[conn->inStart], "\\.\n", 3) == 0) - { - conn->inStart = conn->inCursor; - conn->asyncStatus = PGASYNC_BUSY; - return -1; - } - - /* - * Pass the line back to the caller. - */ - *buffer = (char *) malloc(msgLength + 1); - if (*buffer == NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return -2; - } - memcpy(*buffer, &conn->inBuffer[conn->inStart], msgLength); - (*buffer)[msgLength] = '\0'; /* Add terminating null */ - - /* Mark message consumed */ - conn->inStart = conn->inCursor; - - return msgLength; - -nodata: - /* Don't block if async read requested */ - if (async) - return 0; - /* Need to load more data */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - return -2; - } -} - - -/* - * PQgetline - gets a newline-terminated string from the backend. - * - * See fe-exec.c for documentation. - */ -int -pqGetline2(PGconn *conn, char *s, int maxlen) -{ - int result = 1; /* return value if buffer overflows */ - - if (conn->sock == PGINVALID_SOCKET || - conn->asyncStatus != PGASYNC_COPY_OUT) - { - *s = '\0'; - return EOF; - } - - /* - * Since this is a purely synchronous routine, we don't bother to maintain - * conn->inCursor; there is no need to back up. - */ - while (maxlen > 1) - { - if (conn->inStart < conn->inEnd) - { - char c = conn->inBuffer[conn->inStart++]; - - if (c == '\n') - { - result = 0; /* success exit */ - break; - } - *s++ = c; - maxlen--; - } - else - { - /* need to load more data */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - { - result = EOF; - break; - } - } - } - *s = '\0'; - - return result; -} - -/* - * PQgetlineAsync - gets a COPY data row without blocking. - * - * See fe-exec.c for documentation. - */ -int -pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize) -{ - int avail; - - if (conn->asyncStatus != PGASYNC_COPY_OUT) - return -1; /* we are not doing a copy... */ - - /* - * Move data from libpq's buffer to the caller's. We want to accept data - * only in units of whole lines, not partial lines. This ensures that we - * can recognize the terminator line "\\.\n". (Otherwise, if it happened - * to cross a packet/buffer boundary, we might hand the first one or two - * characters off to the caller, which we shouldn't.) - */ - - conn->inCursor = conn->inStart; - - avail = bufsize; - while (avail > 0 && conn->inCursor < conn->inEnd) - { - char c = conn->inBuffer[conn->inCursor++]; - - *buffer++ = c; - --avail; - if (c == '\n') - { - /* Got a complete line; mark the data removed from libpq */ - conn->inStart = conn->inCursor; - /* Is it the endmarker line? */ - if (bufsize - avail == 3 && buffer[-3] == '\\' && buffer[-2] == '.') - return -1; - /* No, return the data line to the caller */ - return bufsize - avail; - } - } - - /* - * We don't have a complete line. We'd prefer to leave it in libpq's - * buffer until the rest arrives, but there is a special case: what if the - * line is longer than the buffer the caller is offering us? In that case - * we'd better hand over a partial line, else we'd get into an infinite - * loop. Do this in a way that ensures we can't misrecognize a terminator - * line later: leave last 3 characters in libpq buffer. - */ - if (avail == 0 && bufsize > 3) - { - conn->inStart = conn->inCursor - 3; - return bufsize - 3; - } - return 0; -} - -/* - * PQendcopy - * - * See fe-exec.c for documentation. - */ -int -pqEndcopy2(PGconn *conn) -{ - PGresult *result; - - if (conn->asyncStatus != PGASYNC_COPY_IN && - conn->asyncStatus != PGASYNC_COPY_OUT) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); - return 1; - } - - /* - * make sure no data is waiting to be sent, abort if we are non-blocking - * and the flush fails - */ - if (pqFlush(conn) && pqIsnonblocking(conn)) - return 1; - - /* non blocking connections may have to abort at this point. */ - if (pqIsnonblocking(conn) && PQisBusy(conn)) - return 1; - - /* Return to active duty */ - conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); - - /* Wait for the completion response */ - result = PQgetResult(conn); - - /* Expecting a successful result */ - if (result && result->resultStatus == PGRES_COMMAND_OK) - { - PQclear(result); - return 0; - } - - /* - * Trouble. For backwards-compatibility reasons, we issue the error - * message as if it were a notice (would be nice to get rid of this - * silliness, but too many apps probably don't handle errors from - * PQendcopy reasonably). Note that the app can still obtain the error - * status from the PGconn object. - */ - if (conn->errorMessage.len > 0) - { - /* We have to strip the trailing newline ... pain in neck... */ - char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; - - if (svLast == '\n') - conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; - pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); - conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; - } - - PQclear(result); - - /* - * The worst case is that we've lost sync with the backend entirely due to - * application screwup of the copy in/out protocol. To recover, reset the - * connection (talk about using a sledgehammer...) - */ - pqInternalNotice(&conn->noticeHooks, - "lost synchronization with server, resetting connection"); - - /* - * Users doing non-blocking connections need to handle the reset - * themselves, they'll need to check the connection status if we return an - * error. - */ - if (pqIsnonblocking(conn)) - PQresetStart(conn); - else - PQreset(conn); - - return 1; -} - - -/* - * PQfn - Send a function call to the POSTGRES backend. - * - * See fe-exec.c for documentation. - */ -PGresult * -pqFunctionCall2(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, - int result_is_int, - const PQArgBlock *args, int nargs) -{ - bool needInput = false; - ExecStatusType status = PGRES_FATAL_ERROR; - char id; - int i; - - /* PQfn already validated connection state */ - - if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ - pqPuts(" ", conn) < 0 || /* dummy string */ - pqPutInt(fnid, 4, conn) != 0 || /* function id */ - pqPutInt(nargs, 4, conn) != 0) /* # of args */ - { - pqHandleSendFailure(conn); - return NULL; - } - - for (i = 0; i < nargs; ++i) - { /* len.int4 + contents */ - if (pqPutInt(args[i].len, 4, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - - if (args[i].isint) - { - if (pqPutInt(args[i].u.integer, 4, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - } - else - { - if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - } - } - - if (pqPutMsgEnd(conn) < 0 || - pqFlush(conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - - for (;;) - { - if (needInput) - { - /* Wait for some data to arrive (or for the channel to close) */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - break; - } - - /* - * Scan the message. If we run out of data, loop around to try again. - */ - conn->inCursor = conn->inStart; - needInput = true; - - if (pqGetc(&id, conn)) - continue; - - /* - * We should see V or E response to the command, but might get N - * and/or A notices first. We also need to swallow the final Z before - * returning. - */ - switch (id) - { - case 'V': /* function result */ - if (pqGetc(&id, conn)) - continue; - if (id == 'G') - { - /* function returned nonempty value */ - if (pqGetInt(actual_result_len, 4, conn)) - continue; - if (result_is_int) - { - if (pqGetInt(result_buf, 4, conn)) - continue; - } - else - { - if (pqGetnchar((char *) result_buf, - *actual_result_len, - conn)) - continue; - } - if (pqGetc(&id, conn)) /* get the last '0' */ - continue; - } - if (id == '0') - { - /* correctly finished function result message */ - status = PGRES_COMMAND_OK; - } - else - { - /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("protocol error: id=0x%x\n"), - id); - pqSaveErrorResult(conn); - conn->inStart = conn->inCursor; - return pqPrepareAsyncResult(conn); - } - break; - case 'E': /* error return */ - if (pqGetErrorNotice2(conn, true)) - continue; - status = PGRES_FATAL_ERROR; - break; - case 'A': /* notify message */ - /* handle notify and go back to processing return values */ - if (getNotify(conn)) - continue; - break; - case 'N': /* notice */ - /* handle notice and go back to processing return values */ - if (pqGetErrorNotice2(conn, false)) - continue; - break; - case 'Z': /* backend is ready for new query */ - /* consume the message and exit */ - conn->inStart = conn->inCursor; - /* if we saved a result object (probably an error), use it */ - if (conn->result) - return pqPrepareAsyncResult(conn); - return PQmakeEmptyPGresult(conn, status); - default: - /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("protocol error: id=0x%x\n"), - id); - pqSaveErrorResult(conn); - conn->inStart = conn->inCursor; - return pqPrepareAsyncResult(conn); - } - /* Completed this message, keep going */ - conn->inStart = conn->inCursor; - needInput = false; - } - - /* - * We fall out of the loop only upon failing to read data. - * conn->errorMessage has been set by pqWait or pqReadData. We want to - * append it to any already-received error message. - */ - pqSaveErrorResult(conn); - return pqPrepareAsyncResult(conn); -} - - -/* - * Construct startup packet - * - * Returns a malloc'd packet buffer, or NULL if out of memory - */ -char * -pqBuildStartupPacket2(PGconn *conn, int *packetlen, - const PQEnvironmentOption *options) -{ - StartupPacket *startpacket; - - *packetlen = sizeof(StartupPacket); - startpacket = (StartupPacket *) malloc(sizeof(StartupPacket)); - if (!startpacket) - return NULL; - - MemSet(startpacket, 0, sizeof(StartupPacket)); - - startpacket->protoVersion = htonl(conn->pversion); - - /* strncpy is safe here: postmaster will handle full fields correctly */ - strncpy(startpacket->user, conn->pguser, SM_USER); - strncpy(startpacket->database, conn->dbName, SM_DATABASE); - strncpy(startpacket->tty, conn->pgtty, SM_TTY); - - if (conn->pgoptions) - strncpy(startpacket->options, conn->pgoptions, SM_OPTIONS); - - return (char *) startpacket; -} diff --git a/libpq/fe-protocol3.c b/libpq/fe-protocol3.c deleted file mode 100644 index a8a987a..0000000 --- a/libpq/fe-protocol3.c +++ /dev/null @@ -1,2204 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-protocol3.c - * functions that are specific to frontend/backend protocol version 3 - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-protocol3.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include -#include - -#include "libpq-fe.h" -#include "libpq-int.h" - -#include "mb/pg_wchar.h" - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#include -#endif - - -/* - * This macro lists the backend message types that could be "long" (more - * than a couple of kilobytes). - */ -#define VALID_LONG_MESSAGE_TYPE(id) \ - ((id) == 'T' || (id) == 'D' || (id) == 'd' || (id) == 'V' || \ - (id) == 'E' || (id) == 'N' || (id) == 'A') - - -static void handleSyncLoss(PGconn *conn, char id, int msgLength); -static int getRowDescriptions(PGconn *conn, int msgLength); -static int getParamDescriptions(PGconn *conn, int msgLength); -static int getAnotherTuple(PGconn *conn, int msgLength); -static int getParameterStatus(PGconn *conn); -static int getNotify(PGconn *conn); -static int getCopyStart(PGconn *conn, ExecStatusType copytype); -static int getReadyForQuery(PGconn *conn); -static void reportErrorPosition(PQExpBuffer msg, const char *query, - int loc, int encoding); -static int build_startup_packet(const PGconn *conn, char *packet, - const PQEnvironmentOption *options); - - -/* - * parseInput: if appropriate, parse input data from backend - * until input is exhausted or a stopping state is reached. - * Note that this function will NOT attempt to read more data from the backend. - */ -void -pqParseInput3(PGconn *conn) -{ - char id; - int msgLength; - int avail; - - /* - * Loop to parse successive complete messages available in the buffer. - */ - for (;;) - { - /* - * Try to read a message. First get the type code and length. Return - * if not enough data. - */ - conn->inCursor = conn->inStart; - if (pqGetc(&id, conn)) - return; - if (pqGetInt(&msgLength, 4, conn)) - return; - - /* - * Try to validate message type/length here. A length less than 4 is - * definitely broken. Large lengths should only be believed for a few - * message types. - */ - if (msgLength < 4) - { - handleSyncLoss(conn, id, msgLength); - return; - } - if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) - { - handleSyncLoss(conn, id, msgLength); - return; - } - - /* - * Can't process if message body isn't all here yet. - */ - msgLength -= 4; - avail = conn->inEnd - conn->inCursor; - if (avail < msgLength) - { - /* - * Before returning, enlarge the input buffer if needed to hold - * the whole message. This is better than leaving it to - * pqReadData because we can avoid multiple cycles of realloc() - * when the message is large; also, we can implement a reasonable - * recovery strategy if we are unable to make the buffer big - * enough. - */ - if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, - conn)) - { - /* - * XXX add some better recovery code... plan is to skip over - * the message using its length, then report an error. For the - * moment, just treat this like loss of sync (which indeed it - * might be!) - */ - handleSyncLoss(conn, id, msgLength); - } - return; - } - - /* - * NOTIFY and NOTICE messages can happen in any state; always process - * them right away. - * - * Most other messages should only be processed while in BUSY state. - * (In particular, in READY state we hold off further parsing until - * the application collects the current PGresult.) - * - * However, if the state is IDLE then we got trouble; we need to deal - * with the unexpected message somehow. - * - * ParameterStatus ('S') messages are a special case: in IDLE state we - * must process 'em (this case could happen if a new value was adopted - * from config file due to SIGHUP), but otherwise we hold off until - * BUSY state. - */ - if (id == 'A') - { - if (getNotify(conn)) - return; - } - else if (id == 'N') - { - if (pqGetErrorNotice3(conn, false)) - return; - } - else if (conn->asyncStatus != PGASYNC_BUSY) - { - /* If not IDLE state, just wait ... */ - if (conn->asyncStatus != PGASYNC_IDLE) - return; - - /* - * Unexpected message in IDLE state; need to recover somehow. - * ERROR messages are handled using the notice processor; - * ParameterStatus is handled normally; anything else is just - * dropped on the floor after displaying a suitable warning - * notice. (An ERROR is very possibly the backend telling us why - * it is about to close the connection, so we don't want to just - * discard it...) - */ - if (id == 'E') - { - if (pqGetErrorNotice3(conn, false /* treat as notice */ )) - return; - } - else if (id == 'S') - { - if (getParameterStatus(conn)) - return; - } - else - { - pqInternalNotice(&conn->noticeHooks, - "message type 0x%02x arrived from server while idle", - id); - /* Discard the unexpected message */ - conn->inCursor += msgLength; - } - } - else - { - /* - * In BUSY state, we can process everything. - */ - switch (id) - { - case 'C': /* command complete */ - if (pqGets(&conn->workBuffer, conn)) - return; - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_COMMAND_OK); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - if (conn->result) - strlcpy(conn->result->cmdStatus, conn->workBuffer.data, - CMDSTATUS_LEN); - conn->asyncStatus = PGASYNC_READY; - break; - case 'E': /* error return */ - if (pqGetErrorNotice3(conn, true)) - return; - conn->asyncStatus = PGASYNC_READY; - break; - case 'Z': /* backend is ready for new query */ - if (getReadyForQuery(conn)) - return; - conn->asyncStatus = PGASYNC_IDLE; - break; - case 'I': /* empty query */ - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_EMPTY_QUERY); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - conn->asyncStatus = PGASYNC_READY; - break; - case '1': /* Parse Complete */ - /* If we're doing PQprepare, we're done; else ignore */ - if (conn->queryclass == PGQUERY_PREPARE) - { - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_COMMAND_OK); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - conn->asyncStatus = PGASYNC_READY; - } - break; - case '2': /* Bind Complete */ - case '3': /* Close Complete */ - /* Nothing to do for these message types */ - break; - case 'S': /* parameter status */ - if (getParameterStatus(conn)) - return; - break; - case 'K': /* secret key data from the backend */ - - /* - * This is expected only during backend startup, but it's - * just as easy to handle it as part of the main loop. - * Save the data and continue processing. - */ - if (pqGetInt(&(conn->be_pid), 4, conn)) - return; - if (pqGetInt(&(conn->be_key), 4, conn)) - return; - break; - case 'T': /* Row Description */ - if (conn->result != NULL && - conn->result->resultStatus == PGRES_FATAL_ERROR) - { - /* - * We've already choked for some reason. Just discard - * the data till we get to the end of the query. - */ - conn->inCursor += msgLength; - } - else if (conn->result == NULL || - conn->queryclass == PGQUERY_DESCRIBE) - { - /* First 'T' in a query sequence */ - if (getRowDescriptions(conn, msgLength)) - return; - /* getRowDescriptions() moves inStart itself */ - continue; - } - else - { - /* - * A new 'T' message is treated as the start of - * another PGresult. (It is not clear that this is - * really possible with the current backend.) We stop - * parsing until the application accepts the current - * result. - */ - conn->asyncStatus = PGASYNC_READY; - return; - } - break; - case 'n': /* No Data */ - - /* - * NoData indicates that we will not be seeing a - * RowDescription message because the statement or portal - * inquired about doesn't return rows. - * - * If we're doing a Describe, we have to pass something - * back to the client, so set up a COMMAND_OK result, - * instead of TUPLES_OK. Otherwise we can just ignore - * this message. - */ - if (conn->queryclass == PGQUERY_DESCRIBE) - { - if (conn->result == NULL) - { - conn->result = PQmakeEmptyPGresult(conn, - PGRES_COMMAND_OK); - if (!conn->result) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - pqSaveErrorResult(conn); - } - } - conn->asyncStatus = PGASYNC_READY; - } - break; - case 't': /* Parameter Description */ - if (getParamDescriptions(conn, msgLength)) - return; - /* getParamDescriptions() moves inStart itself */ - continue; - case 'D': /* Data Row */ - if (conn->result != NULL && - conn->result->resultStatus == PGRES_TUPLES_OK) - { - /* Read another tuple of a normal query response */ - if (getAnotherTuple(conn, msgLength)) - return; - /* getAnotherTuple() moves inStart itself */ - continue; - } - else if (conn->result != NULL && - conn->result->resultStatus == PGRES_FATAL_ERROR) - { - /* - * We've already choked for some reason. Just discard - * tuples till we get to the end of the query. - */ - conn->inCursor += msgLength; - } - else - { - /* Set up to report error at end of query */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("server sent data (\"D\" message) without prior row description (\"T\" message)\n")); - pqSaveErrorResult(conn); - /* Discard the unexpected message */ - conn->inCursor += msgLength; - } - break; - case 'G': /* Start Copy In */ - if (getCopyStart(conn, PGRES_COPY_IN)) - return; - conn->asyncStatus = PGASYNC_COPY_IN; - break; - case 'H': /* Start Copy Out */ - if (getCopyStart(conn, PGRES_COPY_OUT)) - return; - conn->asyncStatus = PGASYNC_COPY_OUT; - conn->copy_already_done = 0; - break; - case 'W': /* Start Copy Both */ - if (getCopyStart(conn, PGRES_COPY_BOTH)) - return; - conn->asyncStatus = PGASYNC_COPY_BOTH; - conn->copy_already_done = 0; - break; - case 'd': /* Copy Data */ - - /* - * If we see Copy Data, just silently drop it. This would - * only occur if application exits COPY OUT mode too - * early. - */ - conn->inCursor += msgLength; - break; - case 'c': /* Copy Done */ - - /* - * If we see Copy Done, just silently drop it. This is - * the normal case during PQendcopy. We will keep - * swallowing data, expecting to see command-complete for - * the COPY command. - */ - break; - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "unexpected response from server; first received character was \"%c\"\n"), - id); - /* build an error result holding the error message */ - pqSaveErrorResult(conn); - /* not sure if we will see more, so go to ready state */ - conn->asyncStatus = PGASYNC_READY; - /* Discard the unexpected message */ - conn->inCursor += msgLength; - break; - } /* switch on protocol character */ - } - /* Successfully consumed this message */ - if (conn->inCursor == conn->inStart + 5 + msgLength) - { - /* Normal case: parsing agrees with specified length */ - conn->inStart = conn->inCursor; - } - else - { - /* Trouble --- report it */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("message contents do not agree with length in message type \"%c\"\n"), - id); - /* build an error result holding the error message */ - pqSaveErrorResult(conn); - conn->asyncStatus = PGASYNC_READY; - /* trust the specified message length as what to skip */ - conn->inStart += 5 + msgLength; - } - } -} - -/* - * handleSyncLoss: clean up after loss of message-boundary sync - * - * There isn't really a lot we can do here except abandon the connection. - */ -static void -handleSyncLoss(PGconn *conn, char id, int msgLength) -{ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "lost synchronization with server: got message type \"%c\", length %d\n"), - id, msgLength); - /* build an error result holding the error message */ - pqSaveErrorResult(conn); - conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */ - /* flush input data since we're giving up on processing it */ - pqDropConnection(conn, true); - conn->status = CONNECTION_BAD; /* No more connection to backend */ -} - -/* - * parseInput subroutine to read a 'T' (row descriptions) message. - * We'll build a new PGresult structure (unless called for a Describe - * command for a prepared statement) containing the attribute data. - * Returns: 0 if processed message successfully, EOF to suspend parsing - * (the latter case is not actually used currently). - * In the former case, conn->inStart has been advanced past the message. - */ -static int -getRowDescriptions(PGconn *conn, int msgLength) -{ - PGresult *result; - int nfields; - const char *errmsg; - int i; - - /* - * When doing Describe for a prepared statement, there'll already be a - * PGresult created by getParamDescriptions, and we should fill data into - * that. Otherwise, create a new, empty PGresult. - */ - if (conn->queryclass == PGQUERY_DESCRIBE) - { - if (conn->result) - result = conn->result; - else - result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); - } - else - result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK); - if (!result) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - - /* parseInput already read the 'T' label and message length. */ - /* the next two bytes are the number of fields */ - if (pqGetInt(&(result->numAttributes), 2, conn)) - { - /* We should not run out of data here, so complain */ - errmsg = libpq_gettext("insufficient data in \"T\" message"); - goto advance_and_error; - } - nfields = result->numAttributes; - - /* allocate space for the attribute descriptors */ - if (nfields > 0) - { - result->attDescs = (PGresAttDesc *) - pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); - if (!result->attDescs) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); - } - - /* result->binary is true only if ALL columns are binary */ - result->binary = (nfields > 0) ? 1 : 0; - - /* get type info */ - for (i = 0; i < nfields; i++) - { - int tableid; - int columnid; - int typid; - int typlen; - int atttypmod; - int format; - - if (pqGets(&conn->workBuffer, conn) || - pqGetInt(&tableid, 4, conn) || - pqGetInt(&columnid, 2, conn) || - pqGetInt(&typid, 4, conn) || - pqGetInt(&typlen, 2, conn) || - pqGetInt(&atttypmod, 4, conn) || - pqGetInt(&format, 2, conn)) - { - /* We should not run out of data here, so complain */ - errmsg = libpq_gettext("insufficient data in \"T\" message"); - goto advance_and_error; - } - - /* - * Since pqGetInt treats 2-byte integers as unsigned, we need to - * coerce these results to signed form. - */ - columnid = (int) ((int16) columnid); - typlen = (int) ((int16) typlen); - format = (int) ((int16) format); - - result->attDescs[i].name = pqResultStrdup(result, - conn->workBuffer.data); - if (!result->attDescs[i].name) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - result->attDescs[i].tableid = tableid; - result->attDescs[i].columnid = columnid; - result->attDescs[i].format = format; - result->attDescs[i].typid = typid; - result->attDescs[i].typlen = typlen; - result->attDescs[i].atttypmod = atttypmod; - - if (format != 1) - result->binary = 0; - } - - /* Sanity check that we absorbed all the data */ - if (conn->inCursor != conn->inStart + 5 + msgLength) - { - errmsg = libpq_gettext("extraneous data in \"T\" message"); - goto advance_and_error; - } - - /* Success! */ - conn->result = result; - - /* Advance inStart to show that the "T" message has been processed. */ - conn->inStart = conn->inCursor; - - /* - * If we're doing a Describe, we're done, and ready to pass the result - * back to the client. - */ - if (conn->queryclass == PGQUERY_DESCRIBE) - { - conn->asyncStatus = PGASYNC_READY; - return 0; - } - - /* - * We could perform additional setup for the new result set here, but for - * now there's nothing else to do. - */ - - /* And we're done. */ - return 0; - -advance_and_error: - /* Discard unsaved result, if any */ - if (result && result != conn->result) - PQclear(result); - - /* Discard the failed message by pretending we read it */ - conn->inStart += 5 + msgLength; - - /* - * Replace partially constructed result with an error result. First - * discard the old result to try to win back some memory. - */ - pqClearAsyncResult(conn); - - /* - * If preceding code didn't provide an error message, assume "out of - * memory" was meant. The advantage of having this special case is that - * freeing the old result first greatly improves the odds that gettext() - * will succeed in providing a translation. - */ - if (!errmsg) - errmsg = libpq_gettext("out of memory for query result"); - - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); - pqSaveErrorResult(conn); - - /* - * Return zero to allow input parsing to continue. Subsequent "D" - * messages will be ignored until we get to end of data, since an error - * result is already set up. - */ - return 0; -} - -/* - * parseInput subroutine to read a 't' (ParameterDescription) message. - * We'll build a new PGresult structure containing the parameter data. - * Returns: 0 if completed message, EOF if not enough data yet. - * In the former case, conn->inStart has been advanced past the message. - * - * Note that if we run out of data, we have to release the partially - * constructed PGresult, and rebuild it again next time. Fortunately, - * that shouldn't happen often, since 't' messages usually fit in a packet. - */ -static int -getParamDescriptions(PGconn *conn, int msgLength) -{ - PGresult *result; - const char *errmsg = NULL; /* means "out of memory", see below */ - int nparams; - int i; - - result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK); - if (!result) - goto advance_and_error; - - /* parseInput already read the 't' label and message length. */ - /* the next two bytes are the number of parameters */ - if (pqGetInt(&(result->numParameters), 2, conn)) - goto not_enough_data; - nparams = result->numParameters; - - /* allocate space for the parameter descriptors */ - if (nparams > 0) - { - result->paramDescs = (PGresParamDesc *) - pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE); - if (!result->paramDescs) - goto advance_and_error; - MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc)); - } - - /* get parameter info */ - for (i = 0; i < nparams; i++) - { - int typid; - - if (pqGetInt(&typid, 4, conn)) - goto not_enough_data; - result->paramDescs[i].typid = typid; - } - - /* Sanity check that we absorbed all the data */ - if (conn->inCursor != conn->inStart + 5 + msgLength) - { - errmsg = libpq_gettext("extraneous data in \"t\" message"); - goto advance_and_error; - } - - /* Success! */ - conn->result = result; - - /* Advance inStart to show that the "t" message has been processed. */ - conn->inStart = conn->inCursor; - - return 0; - -not_enough_data: - PQclear(result); - return EOF; - -advance_and_error: - /* Discard unsaved result, if any */ - if (result && result != conn->result) - PQclear(result); - - /* Discard the failed message by pretending we read it */ - conn->inStart += 5 + msgLength; - - /* - * Replace partially constructed result with an error result. First - * discard the old result to try to win back some memory. - */ - pqClearAsyncResult(conn); - - /* - * If preceding code didn't provide an error message, assume "out of - * memory" was meant. The advantage of having this special case is that - * freeing the old result first greatly improves the odds that gettext() - * will succeed in providing a translation. - */ - if (!errmsg) - errmsg = libpq_gettext("out of memory"); - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); - pqSaveErrorResult(conn); - - /* - * Return zero to allow input parsing to continue. Essentially, we've - * replaced the COMMAND_OK result with an error result, but since this - * doesn't affect the protocol state, it's fine. - */ - return 0; -} - -/* - * parseInput subroutine to read a 'D' (row data) message. - * We fill rowbuf with column pointers and then call the row processor. - * Returns: 0 if processed message successfully, EOF to suspend parsing - * (the latter case is not actually used currently). - * In the former case, conn->inStart has been advanced past the message. - */ -static int -getAnotherTuple(PGconn *conn, int msgLength) -{ - PGresult *result = conn->result; - int nfields = result->numAttributes; - const char *errmsg; - PGdataValue *rowbuf; - int tupnfields; /* # fields from tuple */ - int vlen; /* length of the current field value */ - int i; - - /* Get the field count and make sure it's what we expect */ - if (pqGetInt(&tupnfields, 2, conn)) - { - /* We should not run out of data here, so complain */ - errmsg = libpq_gettext("insufficient data in \"D\" message"); - goto advance_and_error; - } - - if (tupnfields != nfields) - { - errmsg = libpq_gettext("unexpected field count in \"D\" message"); - goto advance_and_error; - } - - /* Resize row buffer if needed */ - rowbuf = conn->rowBuf; - if (nfields > conn->rowBufLen) - { - rowbuf = (PGdataValue *) realloc(rowbuf, - nfields * sizeof(PGdataValue)); - if (!rowbuf) - { - errmsg = NULL; /* means "out of memory", see below */ - goto advance_and_error; - } - conn->rowBuf = rowbuf; - conn->rowBufLen = nfields; - } - - /* Scan the fields */ - for (i = 0; i < nfields; i++) - { - /* get the value length */ - if (pqGetInt(&vlen, 4, conn)) - { - /* We should not run out of data here, so complain */ - errmsg = libpq_gettext("insufficient data in \"D\" message"); - goto advance_and_error; - } - rowbuf[i].len = vlen; - - /* - * rowbuf[i].value always points to the next address in the data - * buffer even if the value is NULL. This allows row processors to - * estimate data sizes more easily. - */ - rowbuf[i].value = conn->inBuffer + conn->inCursor; - - /* Skip over the data value */ - if (vlen > 0) - { - if (pqSkipnchar(vlen, conn)) - { - /* We should not run out of data here, so complain */ - errmsg = libpq_gettext("insufficient data in \"D\" message"); - goto advance_and_error; - } - } - } - - /* Sanity check that we absorbed all the data */ - if (conn->inCursor != conn->inStart + 5 + msgLength) - { - errmsg = libpq_gettext("extraneous data in \"D\" message"); - goto advance_and_error; - } - - /* Advance inStart to show that the "D" message has been processed. */ - conn->inStart = conn->inCursor; - - /* Process the collected row */ - errmsg = NULL; - if (pqRowProcessor(conn, &errmsg)) - return 0; /* normal, successful exit */ - - goto set_error_result; /* pqRowProcessor failed, report it */ - -advance_and_error: - /* Discard the failed message by pretending we read it */ - conn->inStart += 5 + msgLength; - -set_error_result: - - /* - * Replace partially constructed result with an error result. First - * discard the old result to try to win back some memory. - */ - pqClearAsyncResult(conn); - - /* - * If preceding code didn't provide an error message, assume "out of - * memory" was meant. The advantage of having this special case is that - * freeing the old result first greatly improves the odds that gettext() - * will succeed in providing a translation. - */ - if (!errmsg) - errmsg = libpq_gettext("out of memory for query result"); - - printfPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); - pqSaveErrorResult(conn); - - /* - * Return zero to allow input parsing to continue. Subsequent "D" - * messages will be ignored until we get to end of data, since an error - * result is already set up. - */ - return 0; -} - - -/* - * Attempt to read an Error or Notice response message. - * This is possible in several places, so we break it out as a subroutine. - * Entry: 'E' or 'N' message type and length have already been consumed. - * Exit: returns 0 if successfully consumed message. - * returns EOF if not enough data. - */ -int -pqGetErrorNotice3(PGconn *conn, bool isError) -{ - PGresult *res = NULL; - bool have_position = false; - PQExpBufferData workBuf; - char id; - - /* - * Since the fields might be pretty long, we create a temporary - * PQExpBuffer rather than using conn->workBuffer. workBuffer is intended - * for stuff that is expected to be short. We shouldn't use - * conn->errorMessage either, since this might be only a notice. - */ - initPQExpBuffer(&workBuf); - - /* - * Make a PGresult to hold the accumulated fields. We temporarily lie - * about the result status, so that PQmakeEmptyPGresult doesn't uselessly - * copy conn->errorMessage. - * - * NB: This allocation can fail, if you run out of memory. The rest of the - * function handles that gracefully, and we still try to set the error - * message as the connection's error message. - */ - res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); - if (res) - res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR; - - /* - * Read the fields and save into res. - * - * While at it, save the SQLSTATE in conn->last_sqlstate, and note whether - * we saw a PG_DIAG_STATEMENT_POSITION field. - */ - for (;;) - { - if (pqGetc(&id, conn)) - goto fail; - if (id == '\0') - break; /* terminator found */ - if (pqGets(&workBuf, conn)) - goto fail; - pqSaveMessageField(res, id, workBuf.data); - if (id == PG_DIAG_SQLSTATE) - strlcpy(conn->last_sqlstate, workBuf.data, - sizeof(conn->last_sqlstate)); - else if (id == PG_DIAG_STATEMENT_POSITION) - have_position = true; - } - - /* - * Save the active query text, if any, into res as well; but only if we - * might need it for an error cursor display, which is only true if there - * is a PG_DIAG_STATEMENT_POSITION field. - */ - if (have_position && conn->last_query && res) - res->errQuery = pqResultStrdup(res, conn->last_query); - - /* - * Now build the "overall" error message for PQresultErrorMessage. - */ - resetPQExpBuffer(&workBuf); - pqBuildErrorMessage3(&workBuf, res, conn->verbosity, conn->show_context); - - /* - * Either save error as current async result, or just emit the notice. - */ - if (isError) - { - if (res) - res->errMsg = pqResultStrdup(res, workBuf.data); - pqClearAsyncResult(conn); - conn->result = res; - if (PQExpBufferDataBroken(workBuf)) - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory")); - else - appendPQExpBufferStr(&conn->errorMessage, workBuf.data); - } - else - { - /* if we couldn't allocate the result set, just discard the NOTICE */ - if (res) - { - /* We can cheat a little here and not copy the message. */ - res->errMsg = workBuf.data; - if (res->noticeHooks.noticeRec != NULL) - (*res->noticeHooks.noticeRec) (res->noticeHooks.noticeRecArg, res); - PQclear(res); - } - } - - termPQExpBuffer(&workBuf); - return 0; - -fail: - PQclear(res); - termPQExpBuffer(&workBuf); - return EOF; -} - -/* - * Construct an error message from the fields in the given PGresult, - * appending it to the contents of "msg". - */ -void -pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res, - PGVerbosity verbosity, PGContextVisibility show_context) -{ - const char *val; - const char *querytext = NULL; - int querypos = 0; - - /* If we couldn't allocate a PGresult, just say "out of memory" */ - if (res == NULL) - { - appendPQExpBuffer(msg, libpq_gettext("out of memory\n")); - return; - } - - /* - * If we don't have any broken-down fields, just return the base message. - * This mainly applies if we're given a libpq-generated error result. - */ - if (res->errFields == NULL) - { - if (res->errMsg && res->errMsg[0]) - appendPQExpBufferStr(msg, res->errMsg); - else - appendPQExpBuffer(msg, libpq_gettext("no error message available\n")); - return; - } - - /* Else build error message from relevant fields */ - val = PQresultErrorField(res, PG_DIAG_SEVERITY); - if (val) - appendPQExpBuffer(msg, "%s: ", val); - if (verbosity == PQERRORS_VERBOSE) - { - val = PQresultErrorField(res, PG_DIAG_SQLSTATE); - if (val) - appendPQExpBuffer(msg, "%s: ", val); - } - val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); - if (val) - appendPQExpBufferStr(msg, val); - val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); - if (val) - { - if (verbosity != PQERRORS_TERSE && res->errQuery != NULL) - { - /* emit position as a syntax cursor display */ - querytext = res->errQuery; - querypos = atoi(val); - } - else - { - /* emit position as text addition to primary message */ - /* translator: %s represents a digit string */ - appendPQExpBuffer(msg, libpq_gettext(" at character %s"), - val); - } - } - else - { - val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); - if (val) - { - querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); - if (verbosity != PQERRORS_TERSE && querytext != NULL) - { - /* emit position as a syntax cursor display */ - querypos = atoi(val); - } - else - { - /* emit position as text addition to primary message */ - /* translator: %s represents a digit string */ - appendPQExpBuffer(msg, libpq_gettext(" at character %s"), - val); - } - } - } - appendPQExpBufferChar(msg, '\n'); - if (verbosity != PQERRORS_TERSE) - { - if (querytext && querypos > 0) - reportErrorPosition(msg, querytext, querypos, - res->client_encoding); - val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL); - if (val) - appendPQExpBuffer(msg, libpq_gettext("DETAIL: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT); - if (val) - appendPQExpBuffer(msg, libpq_gettext("HINT: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); - if (val) - appendPQExpBuffer(msg, libpq_gettext("QUERY: %s\n"), val); - if (show_context == PQSHOW_CONTEXT_ALWAYS || - (show_context == PQSHOW_CONTEXT_ERRORS && - res->resultStatus == PGRES_FATAL_ERROR)) - { - val = PQresultErrorField(res, PG_DIAG_CONTEXT); - if (val) - appendPQExpBuffer(msg, libpq_gettext("CONTEXT: %s\n"), - val); - } - } - if (verbosity == PQERRORS_VERBOSE) - { - val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME); - if (val) - appendPQExpBuffer(msg, - libpq_gettext("SCHEMA NAME: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_TABLE_NAME); - if (val) - appendPQExpBuffer(msg, - libpq_gettext("TABLE NAME: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME); - if (val) - appendPQExpBuffer(msg, - libpq_gettext("COLUMN NAME: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME); - if (val) - appendPQExpBuffer(msg, - libpq_gettext("DATATYPE NAME: %s\n"), val); - val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME); - if (val) - appendPQExpBuffer(msg, - libpq_gettext("CONSTRAINT NAME: %s\n"), val); - } - if (verbosity == PQERRORS_VERBOSE) - { - const char *valf; - const char *vall; - - valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE); - vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE); - val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION); - if (val || valf || vall) - { - appendPQExpBufferStr(msg, libpq_gettext("LOCATION: ")); - if (val) - appendPQExpBuffer(msg, libpq_gettext("%s, "), val); - if (valf && vall) /* unlikely we'd have just one */ - appendPQExpBuffer(msg, libpq_gettext("%s:%s"), - valf, vall); - appendPQExpBufferChar(msg, '\n'); - } - } -} - -/* - * Add an error-location display to the error message under construction. - * - * The cursor location is measured in logical characters; the query string - * is presumed to be in the specified encoding. - */ -static void -reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding) -{ -#define DISPLAY_SIZE 60 /* screen width limit, in screen cols */ -#define MIN_RIGHT_CUT 10 /* try to keep this far away from EOL */ - - char *wquery; - int slen, - cno, - i, - *qidx, - *scridx, - qoffset, - scroffset, - ibeg, - iend, - loc_line; - bool mb_encoding, - beg_trunc, - end_trunc; - - /* Convert loc from 1-based to 0-based; no-op if out of range */ - loc--; - if (loc < 0) - return; - - /* Need a writable copy of the query */ - wquery = strdup(query); - if (wquery == NULL) - return; /* fail silently if out of memory */ - - /* - * Each character might occupy multiple physical bytes in the string, and - * in some Far Eastern character sets it might take more than one screen - * column as well. We compute the starting byte offset and starting - * screen column of each logical character, and store these in qidx[] and - * scridx[] respectively. - */ - - /* we need a safe allocation size... */ - slen = strlen(wquery) + 1; - - qidx = (int *) malloc(slen * sizeof(int)); - if (qidx == NULL) - { - free(wquery); - return; - } - scridx = (int *) malloc(slen * sizeof(int)); - if (scridx == NULL) - { - free(qidx); - free(wquery); - return; - } - - /* We can optimize a bit if it's a single-byte encoding */ - mb_encoding = (pg_encoding_max_length(encoding) != 1); - - /* - * Within the scanning loop, cno is the current character's logical - * number, qoffset is its offset in wquery, and scroffset is its starting - * logical screen column (all indexed from 0). "loc" is the logical - * character number of the error location. We scan to determine loc_line - * (the 1-based line number containing loc) and ibeg/iend (first character - * number and last+1 character number of the line containing loc). Note - * that qidx[] and scridx[] are filled only as far as iend. - */ - qoffset = 0; - scroffset = 0; - loc_line = 1; - ibeg = 0; - iend = -1; /* -1 means not set yet */ - - for (cno = 0; wquery[qoffset] != '\0'; cno++) - { - char ch = wquery[qoffset]; - - qidx[cno] = qoffset; - scridx[cno] = scroffset; - - /* - * Replace tabs with spaces in the writable copy. (Later we might - * want to think about coping with their variable screen width, but - * not today.) - */ - if (ch == '\t') - wquery[qoffset] = ' '; - - /* - * If end-of-line, count lines and mark positions. Each \r or \n - * counts as a line except when \r \n appear together. - */ - else if (ch == '\r' || ch == '\n') - { - if (cno < loc) - { - if (ch == '\r' || - cno == 0 || - wquery[qidx[cno - 1]] != '\r') - loc_line++; - /* extract beginning = last line start before loc. */ - ibeg = cno + 1; - } - else - { - /* set extract end. */ - iend = cno; - /* done scanning. */ - break; - } - } - - /* Advance */ - if (mb_encoding) - { - int w; - - w = pg_encoding_dsplen(encoding, &wquery[qoffset]); - /* treat any non-tab control chars as width 1 */ - if (w <= 0) - w = 1; - scroffset += w; - qoffset += pg_encoding_mblen(encoding, &wquery[qoffset]); - } - else - { - /* We assume wide chars only exist in multibyte encodings */ - scroffset++; - qoffset++; - } - } - /* Fix up if we didn't find an end-of-line after loc */ - if (iend < 0) - { - iend = cno; /* query length in chars, +1 */ - qidx[iend] = qoffset; - scridx[iend] = scroffset; - } - - /* Print only if loc is within computed query length */ - if (loc <= cno) - { - /* If the line extracted is too long, we truncate it. */ - beg_trunc = false; - end_trunc = false; - if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) - { - /* - * We first truncate right if it is enough. This code might be - * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide - * character right there, but that should be okay. - */ - if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT) - { - while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) - iend--; - end_trunc = true; - } - else - { - /* Truncate right if not too close to loc. */ - while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend]) - { - iend--; - end_trunc = true; - } - - /* Truncate left if still too long. */ - while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE) - { - ibeg++; - beg_trunc = true; - } - } - } - - /* truncate working copy at desired endpoint */ - wquery[qidx[iend]] = '\0'; - - /* Begin building the finished message. */ - i = msg->len; - appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line); - if (beg_trunc) - appendPQExpBufferStr(msg, "..."); - - /* - * While we have the prefix in the msg buffer, compute its screen - * width. - */ - scroffset = 0; - for (; i < msg->len; i += pg_encoding_mblen(encoding, &msg->data[i])) - { - int w = pg_encoding_dsplen(encoding, &msg->data[i]); - - if (w <= 0) - w = 1; - scroffset += w; - } - - /* Finish up the LINE message line. */ - appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]); - if (end_trunc) - appendPQExpBufferStr(msg, "..."); - appendPQExpBufferChar(msg, '\n'); - - /* Now emit the cursor marker line. */ - scroffset += scridx[loc] - scridx[ibeg]; - for (i = 0; i < scroffset; i++) - appendPQExpBufferChar(msg, ' '); - appendPQExpBufferChar(msg, '^'); - appendPQExpBufferChar(msg, '\n'); - } - - /* Clean up. */ - free(scridx); - free(qidx); - free(wquery); -} - - -/* - * Attempt to read a ParameterStatus message. - * This is possible in several places, so we break it out as a subroutine. - * Entry: 'S' message type and length have already been consumed. - * Exit: returns 0 if successfully consumed message. - * returns EOF if not enough data. - */ -static int -getParameterStatus(PGconn *conn) -{ - PQExpBufferData valueBuf; - - /* Get the parameter name */ - if (pqGets(&conn->workBuffer, conn)) - return EOF; - /* Get the parameter value (could be large) */ - initPQExpBuffer(&valueBuf); - if (pqGets(&valueBuf, conn)) - { - termPQExpBuffer(&valueBuf); - return EOF; - } - /* And save it */ - pqSaveParameterStatus(conn, conn->workBuffer.data, valueBuf.data); - termPQExpBuffer(&valueBuf); - return 0; -} - - -/* - * Attempt to read a Notify response message. - * This is possible in several places, so we break it out as a subroutine. - * Entry: 'A' message type and length have already been consumed. - * Exit: returns 0 if successfully consumed Notify message. - * returns EOF if not enough data. - */ -static int -getNotify(PGconn *conn) -{ - int be_pid; - char *svname; - int nmlen; - int extralen; - PGnotify *newNotify; - - if (pqGetInt(&be_pid, 4, conn)) - return EOF; - if (pqGets(&conn->workBuffer, conn)) - return EOF; - /* must save name while getting extra string */ - svname = strdup(conn->workBuffer.data); - if (!svname) - return EOF; - if (pqGets(&conn->workBuffer, conn)) - { - free(svname); - return EOF; - } - - /* - * Store the strings right after the PQnotify structure so it can all be - * freed at once. We don't use NAMEDATALEN because we don't want to tie - * this interface to a specific server name length. - */ - nmlen = strlen(svname); - extralen = strlen(conn->workBuffer.data); - newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2); - if (newNotify) - { - newNotify->relname = (char *) newNotify + sizeof(PGnotify); - strcpy(newNotify->relname, svname); - newNotify->extra = newNotify->relname + nmlen + 1; - strcpy(newNotify->extra, conn->workBuffer.data); - newNotify->be_pid = be_pid; - newNotify->next = NULL; - if (conn->notifyTail) - conn->notifyTail->next = newNotify; - else - conn->notifyHead = newNotify; - conn->notifyTail = newNotify; - } - - free(svname); - return 0; -} - -/* - * getCopyStart - process CopyInResponse, CopyOutResponse or - * CopyBothResponse message - * - * parseInput already read the message type and length. - */ -static int -getCopyStart(PGconn *conn, ExecStatusType copytype) -{ - PGresult *result; - int nfields; - int i; - - result = PQmakeEmptyPGresult(conn, copytype); - if (!result) - goto failure; - - if (pqGetc(&conn->copy_is_binary, conn)) - goto failure; - result->binary = conn->copy_is_binary; - /* the next two bytes are the number of fields */ - if (pqGetInt(&(result->numAttributes), 2, conn)) - goto failure; - nfields = result->numAttributes; - - /* allocate space for the attribute descriptors */ - if (nfields > 0) - { - result->attDescs = (PGresAttDesc *) - pqResultAlloc(result, nfields * sizeof(PGresAttDesc), TRUE); - if (!result->attDescs) - goto failure; - MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc)); - } - - for (i = 0; i < nfields; i++) - { - int format; - - if (pqGetInt(&format, 2, conn)) - goto failure; - - /* - * Since pqGetInt treats 2-byte integers as unsigned, we need to - * coerce these results to signed form. - */ - format = (int) ((int16) format); - result->attDescs[i].format = format; - } - - /* Success! */ - conn->result = result; - return 0; - -failure: - PQclear(result); - return EOF; -} - -/* - * getReadyForQuery - process ReadyForQuery message - */ -static int -getReadyForQuery(PGconn *conn) -{ - char xact_status; - - if (pqGetc(&xact_status, conn)) - return EOF; - switch (xact_status) - { - case 'I': - conn->xactStatus = PQTRANS_IDLE; - break; - case 'T': - conn->xactStatus = PQTRANS_INTRANS; - break; - case 'E': - conn->xactStatus = PQTRANS_INERROR; - break; - default: - conn->xactStatus = PQTRANS_UNKNOWN; - break; - } - - return 0; -} - -/* - * getCopyDataMessage - fetch next CopyData message, process async messages - * - * Returns length word of CopyData message (> 0), or 0 if no complete - * message available, -1 if end of copy, -2 if error. - */ -static int -getCopyDataMessage(PGconn *conn) -{ - char id; - int msgLength; - int avail; - - for (;;) - { - /* - * Do we have the next input message? To make life simpler for async - * callers, we keep returning 0 until the next message is fully - * available, even if it is not Copy Data. - */ - conn->inCursor = conn->inStart; - if (pqGetc(&id, conn)) - return 0; - if (pqGetInt(&msgLength, 4, conn)) - return 0; - if (msgLength < 4) - { - handleSyncLoss(conn, id, msgLength); - return -2; - } - avail = conn->inEnd - conn->inCursor; - if (avail < msgLength - 4) - { - /* - * Before returning, enlarge the input buffer if needed to hold - * the whole message. See notes in parseInput. - */ - if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4, - conn)) - { - /* - * XXX add some better recovery code... plan is to skip over - * the message using its length, then report an error. For the - * moment, just treat this like loss of sync (which indeed it - * might be!) - */ - handleSyncLoss(conn, id, msgLength); - return -2; - } - return 0; - } - - /* - * If it's a legitimate async message type, process it. (NOTIFY - * messages are not currently possible here, but we handle them for - * completeness.) Otherwise, if it's anything except Copy Data, - * report end-of-copy. - */ - switch (id) - { - case 'A': /* NOTIFY */ - if (getNotify(conn)) - return 0; - break; - case 'N': /* NOTICE */ - if (pqGetErrorNotice3(conn, false)) - return 0; - break; - case 'S': /* ParameterStatus */ - if (getParameterStatus(conn)) - return 0; - break; - case 'd': /* Copy Data, pass it back to caller */ - return msgLength; - case 'c': - - /* - * If this is a CopyDone message, exit COPY_OUT mode and let - * caller read status with PQgetResult(). If we're in - * COPY_BOTH mode, return to COPY_IN mode. - */ - if (conn->asyncStatus == PGASYNC_COPY_BOTH) - conn->asyncStatus = PGASYNC_COPY_IN; - else - conn->asyncStatus = PGASYNC_BUSY; - return -1; - default: /* treat as end of copy */ - - /* - * Any other message terminates either COPY_IN or COPY_BOTH - * mode. - */ - conn->asyncStatus = PGASYNC_BUSY; - return -1; - } - - /* Drop the processed message and loop around for another */ - conn->inStart = conn->inCursor; - } -} - -/* - * PQgetCopyData - read a row of data from the backend during COPY OUT - * or COPY BOTH - * - * If successful, sets *buffer to point to a malloc'd row of data, and - * returns row length (always > 0) as result. - * Returns 0 if no row available yet (only possible if async is true), - * -1 if end of copy (consult PQgetResult), or -2 if error (consult - * PQerrorMessage). - */ -int -pqGetCopyData3(PGconn *conn, char **buffer, int async) -{ - int msgLength; - - for (;;) - { - /* - * Collect the next input message. To make life simpler for async - * callers, we keep returning 0 until the next message is fully - * available, even if it is not Copy Data. - */ - msgLength = getCopyDataMessage(conn); - if (msgLength < 0) - return msgLength; /* end-of-copy or error */ - if (msgLength == 0) - { - /* Don't block if async read requested */ - if (async) - return 0; - /* Need to load more data */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - return -2; - continue; - } - - /* - * Drop zero-length messages (shouldn't happen anyway). Otherwise - * pass the data back to the caller. - */ - msgLength -= 4; - if (msgLength > 0) - { - *buffer = (char *) malloc(msgLength + 1); - if (*buffer == NULL) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("out of memory\n")); - return -2; - } - memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength); - (*buffer)[msgLength] = '\0'; /* Add terminating null */ - - /* Mark message consumed */ - conn->inStart = conn->inCursor + msgLength; - - return msgLength; - } - - /* Empty, so drop it and loop around for another */ - conn->inStart = conn->inCursor; - } -} - -/* - * PQgetline - gets a newline-terminated string from the backend. - * - * See fe-exec.c for documentation. - */ -int -pqGetline3(PGconn *conn, char *s, int maxlen) -{ - int status; - - if (conn->sock == PGINVALID_SOCKET || - (conn->asyncStatus != PGASYNC_COPY_OUT && - conn->asyncStatus != PGASYNC_COPY_BOTH) || - conn->copy_is_binary) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("PQgetline: not doing text COPY OUT\n")); - *s = '\0'; - return EOF; - } - - while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0) - { - /* need to load more data */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - { - *s = '\0'; - return EOF; - } - } - - if (status < 0) - { - /* End of copy detected; gin up old-style terminator */ - strcpy(s, "\\."); - return 0; - } - - /* Add null terminator, and strip trailing \n if present */ - if (s[status - 1] == '\n') - { - s[status - 1] = '\0'; - return 0; - } - else - { - s[status] = '\0'; - return 1; - } -} - -/* - * PQgetlineAsync - gets a COPY data row without blocking. - * - * See fe-exec.c for documentation. - */ -int -pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize) -{ - int msgLength; - int avail; - - if (conn->asyncStatus != PGASYNC_COPY_OUT - && conn->asyncStatus != PGASYNC_COPY_BOTH) - return -1; /* we are not doing a copy... */ - - /* - * Recognize the next input message. To make life simpler for async - * callers, we keep returning 0 until the next message is fully available - * even if it is not Copy Data. This should keep PQendcopy from blocking. - * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.) - */ - msgLength = getCopyDataMessage(conn); - if (msgLength < 0) - return -1; /* end-of-copy or error */ - if (msgLength == 0) - return 0; /* no data yet */ - - /* - * Move data from libpq's buffer to the caller's. In the case where a - * prior call found the caller's buffer too small, we use - * conn->copy_already_done to remember how much of the row was already - * returned to the caller. - */ - conn->inCursor += conn->copy_already_done; - avail = msgLength - 4 - conn->copy_already_done; - if (avail <= bufsize) - { - /* Able to consume the whole message */ - memcpy(buffer, &conn->inBuffer[conn->inCursor], avail); - /* Mark message consumed */ - conn->inStart = conn->inCursor + avail; - /* Reset state for next time */ - conn->copy_already_done = 0; - return avail; - } - else - { - /* We must return a partial message */ - memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize); - /* The message is NOT consumed from libpq's buffer */ - conn->copy_already_done += bufsize; - return bufsize; - } -} - -/* - * PQendcopy - * - * See fe-exec.c for documentation. - */ -int -pqEndcopy3(PGconn *conn) -{ - PGresult *result; - - if (conn->asyncStatus != PGASYNC_COPY_IN && - conn->asyncStatus != PGASYNC_COPY_OUT && - conn->asyncStatus != PGASYNC_COPY_BOTH) - { - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("no COPY in progress\n")); - return 1; - } - - /* Send the CopyDone message if needed */ - if (conn->asyncStatus == PGASYNC_COPY_IN || - conn->asyncStatus == PGASYNC_COPY_BOTH) - { - if (pqPutMsgStart('c', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return 1; - - /* - * If we sent the COPY command in extended-query mode, we must issue a - * Sync as well. - */ - if (conn->queryclass != PGQUERY_SIMPLE) - { - if (pqPutMsgStart('S', false, conn) < 0 || - pqPutMsgEnd(conn) < 0) - return 1; - } - } - - /* - * make sure no data is waiting to be sent, abort if we are non-blocking - * and the flush fails - */ - if (pqFlush(conn) && pqIsnonblocking(conn)) - return 1; - - /* Return to active duty */ - conn->asyncStatus = PGASYNC_BUSY; - resetPQExpBuffer(&conn->errorMessage); - - /* - * Non blocking connections may have to abort at this point. If everyone - * played the game there should be no problem, but in error scenarios the - * expected messages may not have arrived yet. (We are assuming that the - * backend's packetizing will ensure that CommandComplete arrives along - * with the CopyDone; are there corner cases where that doesn't happen?) - */ - if (pqIsnonblocking(conn) && PQisBusy(conn)) - return 1; - - /* Wait for the completion response */ - result = PQgetResult(conn); - - /* Expecting a successful result */ - if (result && result->resultStatus == PGRES_COMMAND_OK) - { - PQclear(result); - return 0; - } - - /* - * Trouble. For backwards-compatibility reasons, we issue the error - * message as if it were a notice (would be nice to get rid of this - * silliness, but too many apps probably don't handle errors from - * PQendcopy reasonably). Note that the app can still obtain the error - * status from the PGconn object. - */ - if (conn->errorMessage.len > 0) - { - /* We have to strip the trailing newline ... pain in neck... */ - char svLast = conn->errorMessage.data[conn->errorMessage.len - 1]; - - if (svLast == '\n') - conn->errorMessage.data[conn->errorMessage.len - 1] = '\0'; - pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data); - conn->errorMessage.data[conn->errorMessage.len - 1] = svLast; - } - - PQclear(result); - - return 1; -} - - -/* - * PQfn - Send a function call to the POSTGRES backend. - * - * See fe-exec.c for documentation. - */ -PGresult * -pqFunctionCall3(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, - int result_is_int, - const PQArgBlock *args, int nargs) -{ - bool needInput = false; - ExecStatusType status = PGRES_FATAL_ERROR; - char id; - int msgLength; - int avail; - int i; - - /* PQfn already validated connection state */ - - if (pqPutMsgStart('F', false, conn) < 0 || /* function call msg */ - pqPutInt(fnid, 4, conn) < 0 || /* function id */ - pqPutInt(1, 2, conn) < 0 || /* # of format codes */ - pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */ - pqPutInt(nargs, 2, conn) < 0) /* # of args */ - { - pqHandleSendFailure(conn); - return NULL; - } - - for (i = 0; i < nargs; ++i) - { /* len.int4 + contents */ - if (pqPutInt(args[i].len, 4, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - if (args[i].len == -1) - continue; /* it's NULL */ - - if (args[i].isint) - { - if (pqPutInt(args[i].u.integer, args[i].len, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - } - else - { - if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - } - } - - if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */ - { - pqHandleSendFailure(conn); - return NULL; - } - - if (pqPutMsgEnd(conn) < 0 || - pqFlush(conn)) - { - pqHandleSendFailure(conn); - return NULL; - } - - for (;;) - { - if (needInput) - { - /* Wait for some data to arrive (or for the channel to close) */ - if (pqWait(TRUE, FALSE, conn) || - pqReadData(conn) < 0) - break; - } - - /* - * Scan the message. If we run out of data, loop around to try again. - */ - needInput = true; - - conn->inCursor = conn->inStart; - if (pqGetc(&id, conn)) - continue; - if (pqGetInt(&msgLength, 4, conn)) - continue; - - /* - * Try to validate message type/length here. A length less than 4 is - * definitely broken. Large lengths should only be believed for a few - * message types. - */ - if (msgLength < 4) - { - handleSyncLoss(conn, id, msgLength); - break; - } - if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id)) - { - handleSyncLoss(conn, id, msgLength); - break; - } - - /* - * Can't process if message body isn't all here yet. - */ - msgLength -= 4; - avail = conn->inEnd - conn->inCursor; - if (avail < msgLength) - { - /* - * Before looping, enlarge the input buffer if needed to hold the - * whole message. See notes in parseInput. - */ - if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength, - conn)) - { - /* - * XXX add some better recovery code... plan is to skip over - * the message using its length, then report an error. For the - * moment, just treat this like loss of sync (which indeed it - * might be!) - */ - handleSyncLoss(conn, id, msgLength); - break; - } - continue; - } - - /* - * We should see V or E response to the command, but might get N - * and/or A notices first. We also need to swallow the final Z before - * returning. - */ - switch (id) - { - case 'V': /* function result */ - if (pqGetInt(actual_result_len, 4, conn)) - continue; - if (*actual_result_len != -1) - { - if (result_is_int) - { - if (pqGetInt(result_buf, *actual_result_len, conn)) - continue; - } - else - { - if (pqGetnchar((char *) result_buf, - *actual_result_len, - conn)) - continue; - } - } - /* correctly finished function result message */ - status = PGRES_COMMAND_OK; - break; - case 'E': /* error return */ - if (pqGetErrorNotice3(conn, true)) - continue; - status = PGRES_FATAL_ERROR; - break; - case 'A': /* notify message */ - /* handle notify and go back to processing return values */ - if (getNotify(conn)) - continue; - break; - case 'N': /* notice */ - /* handle notice and go back to processing return values */ - if (pqGetErrorNotice3(conn, false)) - continue; - break; - case 'Z': /* backend is ready for new query */ - if (getReadyForQuery(conn)) - continue; - /* consume the message and exit */ - conn->inStart += 5 + msgLength; - /* if we saved a result object (probably an error), use it */ - if (conn->result) - return pqPrepareAsyncResult(conn); - return PQmakeEmptyPGresult(conn, status); - case 'S': /* parameter status */ - if (getParameterStatus(conn)) - continue; - break; - default: - /* The backend violates the protocol. */ - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("protocol error: id=0x%x\n"), - id); - pqSaveErrorResult(conn); - /* trust the specified message length as what to skip */ - conn->inStart += 5 + msgLength; - return pqPrepareAsyncResult(conn); - } - /* Completed this message, keep going */ - /* trust the specified message length as what to skip */ - conn->inStart += 5 + msgLength; - needInput = false; - } - - /* - * We fall out of the loop only upon failing to read data. - * conn->errorMessage has been set by pqWait or pqReadData. We want to - * append it to any already-received error message. - */ - pqSaveErrorResult(conn); - return pqPrepareAsyncResult(conn); -} - - -/* - * Construct startup packet - * - * Returns a malloc'd packet buffer, or NULL if out of memory - */ -char * -pqBuildStartupPacket3(PGconn *conn, int *packetlen, - const PQEnvironmentOption *options) -{ - char *startpacket; - - *packetlen = build_startup_packet(conn, NULL, options); - startpacket = (char *) malloc(*packetlen); - if (!startpacket) - return NULL; - *packetlen = build_startup_packet(conn, startpacket, options); - return startpacket; -} - -/* - * Build a startup packet given a filled-in PGconn structure. - * - * We need to figure out how much space is needed, then fill it in. - * To avoid duplicate logic, this routine is called twice: the first time - * (with packet == NULL) just counts the space needed, the second time - * (with packet == allocated space) fills it in. Return value is the number - * of bytes used. - */ -static int -build_startup_packet(const PGconn *conn, char *packet, - const PQEnvironmentOption *options) -{ - int packet_len = 0; - const PQEnvironmentOption *next_eo; - const char *val; - - /* Protocol version comes first. */ - if (packet) - { - ProtocolVersion pv = htonl(conn->pversion); - - memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion)); - } - packet_len += sizeof(ProtocolVersion); - - /* Add user name, database name, options */ - -#define ADD_STARTUP_OPTION(optname, optval) \ - do { \ - if (packet) \ - strcpy(packet + packet_len, optname); \ - packet_len += strlen(optname) + 1; \ - if (packet) \ - strcpy(packet + packet_len, optval); \ - packet_len += strlen(optval) + 1; \ - } while(0) - - if (conn->pguser && conn->pguser[0]) - ADD_STARTUP_OPTION("user", conn->pguser); - if (conn->dbName && conn->dbName[0]) - ADD_STARTUP_OPTION("database", conn->dbName); - if (conn->replication && conn->replication[0]) - ADD_STARTUP_OPTION("replication", conn->replication); - if (conn->pgoptions && conn->pgoptions[0]) - ADD_STARTUP_OPTION("options", conn->pgoptions); - if (conn->send_appname) - { - /* Use appname if present, otherwise use fallback */ - val = conn->appname ? conn->appname : conn->fbappname; - if (val && val[0]) - ADD_STARTUP_OPTION("application_name", val); - } - - if (conn->client_encoding_initial && conn->client_encoding_initial[0]) - ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial); - - /* Add any environment-driven GUC settings needed */ - for (next_eo = options; next_eo->envName; next_eo++) - { - if ((val = getenv(next_eo->envName)) != NULL) - { - if (pg_strcasecmp(val, "default") != 0) - ADD_STARTUP_OPTION(next_eo->pgName, val); - } - } - - /* Add trailing terminator */ - if (packet) - packet[packet_len] = '\0'; - packet_len++; - - return packet_len; -} diff --git a/libpq/fe-secure.c b/libpq/fe-secure.c deleted file mode 100644 index 94e47a5..0000000 --- a/libpq/fe-secure.c +++ /dev/null @@ -1,505 +0,0 @@ -/*------------------------------------------------------------------------- - * - * fe-secure.c - * functions related to setting up a secure connection to the backend. - * Secure connections are expected to provide confidentiality, - * message integrity and endpoint authentication. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/fe-secure.c - * - * NOTES - * - * We don't provide informational callbacks here (like - * info_cb() in be-secure.c), since there's no good mechanism to - * display such information to the user. - * - *------------------------------------------------------------------------- - */ - -#include "postgres_fe.h" - -#include -#include -#include - -#include "libpq-fe.h" -#include "fe-auth.h" -#include "libpq-int.h" - -#ifdef WIN32 -#include "win32.h" -#else -#include -#include -#include -#include -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#include -#endif - -#include - -#ifdef ENABLE_THREAD_SAFETY -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include -#endif -#endif - -/* - * Macros to handle disabling and then restoring the state of SIGPIPE handling. - * On Windows, these are all no-ops since there's no SIGPIPEs. - */ - -#ifndef WIN32 - -#define SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag) - -#ifdef ENABLE_THREAD_SAFETY - -struct sigpipe_info -{ - sigset_t oldsigmask; - bool sigpipe_pending; - bool got_epipe; -}; - -#define DECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo - -#define DISABLE_SIGPIPE(conn, spinfo, failaction) \ - do { \ - (spinfo).got_epipe = false; \ - if (!SIGPIPE_MASKED(conn)) \ - { \ - if (pq_block_sigpipe(&(spinfo).oldsigmask, \ - &(spinfo).sigpipe_pending) < 0) \ - failaction; \ - } \ - } while (0) - -#define REMEMBER_EPIPE(spinfo, cond) \ - do { \ - if (cond) \ - (spinfo).got_epipe = true; \ - } while (0) - -#define RESTORE_SIGPIPE(conn, spinfo) \ - do { \ - if (!SIGPIPE_MASKED(conn)) \ - pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \ - (spinfo).got_epipe); \ - } while (0) -#else /* !ENABLE_THREAD_SAFETY */ - -#define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL - -#define DISABLE_SIGPIPE(conn, spinfo, failaction) \ - do { \ - if (!SIGPIPE_MASKED(conn)) \ - spinfo = pqsignal(SIGPIPE, SIG_IGN); \ - } while (0) - -#define REMEMBER_EPIPE(spinfo, cond) - -#define RESTORE_SIGPIPE(conn, spinfo) \ - do { \ - if (!SIGPIPE_MASKED(conn)) \ - pqsignal(SIGPIPE, spinfo); \ - } while (0) -#endif /* ENABLE_THREAD_SAFETY */ -#else /* WIN32 */ - -#define DECLARE_SIGPIPE_INFO(spinfo) -#define DISABLE_SIGPIPE(conn, spinfo, failaction) -#define REMEMBER_EPIPE(spinfo, cond) -#define RESTORE_SIGPIPE(conn, spinfo) -#endif /* WIN32 */ - -/* ------------------------------------------------------------ */ -/* Procedures common to all secure sessions */ -/* ------------------------------------------------------------ */ - - -/* - * Exported function to allow application to tell us it's already - * initialized OpenSSL. - */ -void -PQinitSSL(int do_init) -{ -#ifdef USE_SSL - pgtls_init_library(do_init, do_init); -#endif -} - -/* - * Exported function to allow application to tell us it's already - * initialized OpenSSL and/or libcrypto. - */ -void -PQinitOpenSSL(int do_ssl, int do_crypto) -{ -#ifdef USE_SSL - pgtls_init_library(do_ssl, do_crypto); -#endif -} - -/* - * Initialize global SSL context - */ -int -pqsecure_initialize(PGconn *conn) -{ - int r = 0; - -#ifdef USE_SSL - r = pgtls_init(conn); -#endif - - return r; -} - -/* - * Begin or continue negotiating a secure session. - */ -PostgresPollingStatusType -pqsecure_open_client(PGconn *conn) -{ -#ifdef USE_SSL - return pgtls_open_client(conn); -#else - /* shouldn't get here */ - return PGRES_POLLING_FAILED; -#endif -} - -/* - * Close secure session. - */ -void -pqsecure_close(PGconn *conn) -{ -#ifdef USE_SSL - if (conn->ssl_in_use) - pgtls_close(conn); -#endif -} - -/* - * Read data from a secure connection. - * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only - * to determine whether to continue/retry after error. - */ -ssize_t -pqsecure_read(PGconn *conn, void *ptr, size_t len) -{ - ssize_t n; - -#ifdef USE_SSL - if (conn->ssl_in_use) - { - n = pgtls_read(conn, ptr, len); - } - else -#endif - { - n = pqsecure_raw_read(conn, ptr, len); - } - - return n; -} - -ssize_t -pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) -{ - ssize_t n; - int result_errno = 0; - char sebuf[256]; - - n = recv(conn->sock, ptr, len, 0); - - if (n < 0) - { - result_errno = SOCK_ERRNO; - - /* Set error message if appropriate */ - switch (result_errno) - { -#ifdef EAGAIN - case EAGAIN: -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - case EWOULDBLOCK: -#endif - case EINTR: - /* no error message, caller is expected to retry */ - break; - -#ifdef ECONNRESET - case ECONNRESET: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); - break; -#endif - - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not receive data from server: %s\n"), - SOCK_STRERROR(result_errno, - sebuf, sizeof(sebuf))); - break; - } - } - - /* ensure we return the intended errno to caller */ - SOCK_ERRNO_SET(result_errno); - - return n; -} - -/* - * Write data to a secure connection. - * - * On failure, this function is responsible for putting a suitable message - * into conn->errorMessage. The caller must still inspect errno, but only - * to determine whether to continue/retry after error. - */ -ssize_t -pqsecure_write(PGconn *conn, const void *ptr, size_t len) -{ - ssize_t n; - -#ifdef USE_SSL - if (conn->ssl_in_use) - { - n = pgtls_write(conn, ptr, len); - } - else -#endif - { - n = pqsecure_raw_write(conn, ptr, len); - } - - return n; -} - -ssize_t -pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len) -{ - ssize_t n; - int flags = 0; - int result_errno = 0; - char sebuf[256]; - - DECLARE_SIGPIPE_INFO(spinfo); - -#ifdef MSG_NOSIGNAL - if (conn->sigpipe_flag) - flags |= MSG_NOSIGNAL; - -retry_masked: -#endif /* MSG_NOSIGNAL */ - - DISABLE_SIGPIPE(conn, spinfo, return -1); - - n = send(conn->sock, ptr, len, flags); - - if (n < 0) - { - result_errno = SOCK_ERRNO; - - /* - * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't available - * on this machine. So, clear sigpipe_flag so we don't try the flag - * again, and retry the send(). - */ -#ifdef MSG_NOSIGNAL - if (flags != 0 && result_errno == EINVAL) - { - conn->sigpipe_flag = false; - flags = 0; - goto retry_masked; - } -#endif /* MSG_NOSIGNAL */ - - /* Set error message if appropriate */ - switch (result_errno) - { -#ifdef EAGAIN - case EAGAIN: -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) - case EWOULDBLOCK: -#endif - case EINTR: - /* no error message, caller is expected to retry */ - break; - - case EPIPE: - /* Set flag for EPIPE */ - REMEMBER_EPIPE(spinfo, true); - /* FALL THRU */ - -#ifdef ECONNRESET - case ECONNRESET: -#endif - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext( - "server closed the connection unexpectedly\n" - "\tThis probably means the server terminated abnormally\n" - "\tbefore or while processing the request.\n")); - break; - - default: - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not send data to server: %s\n"), - SOCK_STRERROR(result_errno, - sebuf, sizeof(sebuf))); - break; - } - } - - RESTORE_SIGPIPE(conn, spinfo); - - /* ensure we return the intended errno to caller */ - SOCK_ERRNO_SET(result_errno); - - return n; -} - -/* Dummy versions of SSL info functions, when built without SSL support */ -#ifndef USE_SSL - -int -PQsslInUse(PGconn *conn) -{ - return 0; -} - -void * -PQgetssl(PGconn *conn) -{ - return NULL; -} - -void * -PQsslStruct(PGconn *conn, const char *struct_name) -{ - return NULL; -} - -const char * -PQsslAttribute(PGconn *conn, const char *attribute_name) -{ - return NULL; -} - -const char *const * -PQsslAttributeNames(PGconn *conn) -{ - static const char *const result[] = {NULL}; - - return result; -} -#endif /* USE_SSL */ - - -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) - -/* - * Block SIGPIPE for this thread. This prevents send()/write() from exiting - * the application. - */ -int -pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) -{ - sigset_t sigpipe_sigset; - sigset_t sigset; - - sigemptyset(&sigpipe_sigset); - sigaddset(&sigpipe_sigset, SIGPIPE); - - /* Block SIGPIPE and save previous mask for later reset */ - SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset)); - if (SOCK_ERRNO) - return -1; - - /* We can have a pending SIGPIPE only if it was blocked before */ - if (sigismember(osigset, SIGPIPE)) - { - /* Is there a pending SIGPIPE? */ - if (sigpending(&sigset) != 0) - return -1; - - if (sigismember(&sigset, SIGPIPE)) - *sigpipe_pending = true; - else - *sigpipe_pending = false; - } - else - *sigpipe_pending = false; - - return 0; -} - -/* - * Discard any pending SIGPIPE and reset the signal mask. - * - * Note: we are effectively assuming here that the C library doesn't queue - * up multiple SIGPIPE events. If it did, then we'd accidentally leave - * ours in the queue when an event was already pending and we got another. - * As long as it doesn't queue multiple events, we're OK because the caller - * can't tell the difference. - * - * The caller should say got_epipe = FALSE if it is certain that it - * didn't get an EPIPE error; in that case we'll skip the clear operation - * and things are definitely OK, queuing or no. If it got one or might have - * gotten one, pass got_epipe = TRUE. - * - * We do not want this to change errno, since if it did that could lose - * the error code from a preceding send(). We essentially assume that if - * we were able to do pq_block_sigpipe(), this can't fail. - */ -void -pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe) -{ - int save_errno = SOCK_ERRNO; - int signo; - sigset_t sigset; - - /* Clear SIGPIPE only if none was pending */ - if (got_epipe && !sigpipe_pending) - { - if (sigpending(&sigset) == 0 && - sigismember(&sigset, SIGPIPE)) - { - sigset_t sigpipe_sigset; - - sigemptyset(&sigpipe_sigset); - sigaddset(&sigpipe_sigset, SIGPIPE); - - sigwait(&sigpipe_sigset, &signo); - } - } - - /* Restore saved block mask */ - pthread_sigmask(SIG_SETMASK, osigset, NULL); - - SOCK_ERRNO_SET(save_errno); -} - -#endif /* ENABLE_THREAD_SAFETY && !WIN32 */ diff --git a/libpq/getpeereid.c b/libpq/getpeereid.c deleted file mode 100644 index 5f8c0be..0000000 --- a/libpq/getpeereid.c +++ /dev/null @@ -1,80 +0,0 @@ -/*------------------------------------------------------------------------- - * - * getpeereid.c - * get peer userid for UNIX-domain socket connection - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * - * IDENTIFICATION - * src/port/getpeereid.c - * - *------------------------------------------------------------------------- - */ - -#include "c.h" - -#include -#include -#include -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_UCRED_H -#include -#endif -#ifdef HAVE_SYS_UCRED_H -#include -#endif - - -/* - * BSD-style getpeereid() for platforms that lack it. - */ -int -getpeereid(int sock, uid_t *uid, gid_t *gid) -{ -#if defined(SO_PEERCRED) - /* Linux: use getsockopt(SO_PEERCRED) */ - struct ucred peercred; - ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); - - if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 || - so_len != sizeof(peercred)) - return -1; - *uid = peercred.uid; - *gid = peercred.gid; - return 0; -#elif defined(LOCAL_PEERCRED) - /* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */ - struct xucred peercred; - ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); - - if (getsockopt(sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 || - so_len != sizeof(peercred) || - peercred.cr_version != XUCRED_VERSION) - return -1; - *uid = peercred.cr_uid; - *gid = peercred.cr_gid; - return 0; -#elif defined(HAVE_GETPEERUCRED) - /* Solaris: use getpeerucred() */ - ucred_t *ucred; - - ucred = NULL; /* must be initialized to NULL */ - if (getpeerucred(sock, &ucred) == -1) - return -1; - - *uid = ucred_geteuid(ucred); - *gid = ucred_getegid(ucred); - ucred_free(ucred); - - if (*uid == (uid_t) (-1) || *gid == (gid_t) (-1)) - return -1; - return 0; -#else - /* No implementation available on this platform */ - errno = ENOSYS; - return -1; -#endif -} diff --git a/libpq/inet_net_ntop.c b/libpq/inet_net_ntop.c deleted file mode 100644 index 047895e..0000000 --- a/libpq/inet_net_ntop.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1996,1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * src/backend/utils/adt/inet_net_ntop.c - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $"; -#endif - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#include -#include -#include -#include - -#ifndef FRONTEND -#include "utils/inet.h" -#else -/* - * In a frontend build, we can't include inet.h, but we still need to have - * sensible definitions of these two constants. Note that inet_net_ntop() - * assumes that PGSQL_AF_INET is equal to AF_INET. - */ -#define PGSQL_AF_INET (AF_INET + 0) -#define PGSQL_AF_INET6 (AF_INET + 1) -#endif - - -#define NS_IN6ADDRSZ 16 -#define NS_INT16SZ 2 - -#ifdef SPRINTF_CHAR -#define SPRINTF(x) strlen(sprintf/**/x) -#else -#define SPRINTF(x) ((size_t)sprintf x) -#endif - -static char *inet_net_ntop_ipv4(const u_char *src, int bits, - char *dst, size_t size); -static char *inet_net_ntop_ipv6(const u_char *src, int bits, - char *dst, size_t size); - - -/* - * char * - * inet_net_ntop(af, src, bits, dst, size) - * convert host/network address from network to presentation format. - * "src"'s size is determined from its "af". - * return: - * pointer to dst, or NULL if an error occurred (check errno). - * note: - * 192.5.5.1/28 has a nonzero host part, which means it isn't a network - * as called for by inet_net_pton() but it can be a host address with - * an included netmask. - * author: - * Paul Vixie (ISC), October 1998 - */ -char * -inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) -{ - /* - * We need to cover both the address family constants used by the PG inet - * type (PGSQL_AF_INET and PGSQL_AF_INET6) and those used by the system - * libraries (AF_INET and AF_INET6). We can safely assume PGSQL_AF_INET - * == AF_INET, but the INET6 constants are very likely to be different. If - * AF_INET6 isn't defined, silently ignore it. - */ - switch (af) - { - case PGSQL_AF_INET: - return (inet_net_ntop_ipv4(src, bits, dst, size)); - case PGSQL_AF_INET6: -#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6 - case AF_INET6: -#endif - return (inet_net_ntop_ipv6(src, bits, dst, size)); - default: - errno = EAFNOSUPPORT; - return (NULL); - } -} - -/* - * static char * - * inet_net_ntop_ipv4(src, bits, dst, size) - * convert IPv4 network address from network to presentation format. - * "src"'s size is determined from its "af". - * return: - * pointer to dst, or NULL if an error occurred (check errno). - * note: - * network byte order assumed. this means 192.5.5.240/28 has - * 0b11110000 in its fourth octet. - * author: - * Paul Vixie (ISC), October 1998 - */ -static char * -inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) -{ - char *odst = dst; - char *t; - int len = 4; - int b; - - if (bits < 0 || bits > 32) - { - errno = EINVAL; - return (NULL); - } - - /* Always format all four octets, regardless of mask length. */ - for (b = len; b > 0; b--) - { - if (size <= sizeof ".255") - goto emsgsize; - t = dst; - if (dst != odst) - *dst++ = '.'; - dst += SPRINTF((dst, "%u", *src++)); - size -= (size_t) (dst - t); - } - - /* don't print masklen if 32 bits */ - if (bits != 32) - { - if (size <= sizeof "/32") - goto emsgsize; - dst += SPRINTF((dst, "/%u", bits)); - } - - return (odst); - -emsgsize: - errno = EMSGSIZE; - return (NULL); -} - -static int -decoct(const u_char *src, int bytes, char *dst, size_t size) -{ - char *odst = dst; - char *t; - int b; - - for (b = 1; b <= bytes; b++) - { - if (size <= sizeof "255.") - return (0); - t = dst; - dst += SPRINTF((dst, "%u", *src++)); - if (b != bytes) - { - *dst++ = '.'; - *dst = '\0'; - } - size -= (size_t) (dst - t); - } - return (dst - odst); -} - -static char * -inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) -{ - /* - * Note that int32_t and int16_t need only be "at least" large enough to - * contain a value of the specified size. On some systems, like Crays, - * there is no such thing as an integer variable with 16 bits. Keep this - * in mind if you think this function should have been coded to use - * pointer overlays. All the world's not a VAX. - */ - char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; - char *tp; - struct - { - int base, - len; - } best, cur; - u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; - - if ((bits < -1) || (bits > 128)) - { - errno = EINVAL; - return (NULL); - } - - /* - * Preprocess: Copy the input (bytewise) array into a wordwise array. Find - * the longest run of 0x00's in src[] for :: shorthanding. - */ - memset(words, '\0', sizeof words); - for (i = 0; i < NS_IN6ADDRSZ; i++) - words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); - best.base = -1; - cur.base = -1; - best.len = 0; - cur.len = 0; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - if (words[i] == 0) - { - if (cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } - else - { - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - } - if (cur.base != -1) - { - if (best.base == -1 || cur.len > best.len) - best = cur; - } - if (best.base != -1 && best.len < 2) - best.base = -1; - - /* - * Format the result. - */ - tp = tmp; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) - { - /* Are we inside the best run of 0x00's? */ - if (best.base != -1 && i >= best.base && - i < (best.base + best.len)) - { - if (i == best.base) - *tp++ = ':'; - continue; - } - /* Are we following an initial run of 0x00s or any real hex? */ - if (i != 0) - *tp++ = ':'; - /* Is this address an encapsulated IPv4? */ - if (i == 6 && best.base == 0 && (best.len == 6 || - (best.len == 7 && words[7] != 0x0001) || - (best.len == 5 && words[5] == 0xffff))) - { - int n; - - n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp)); - if (n == 0) - { - errno = EMSGSIZE; - return (NULL); - } - tp += strlen(tp); - break; - } - tp += SPRINTF((tp, "%x", words[i])); - } - - /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == - (NS_IN6ADDRSZ / NS_INT16SZ)) - *tp++ = ':'; - *tp = '\0'; - - if (bits != -1 && bits != 128) - tp += SPRINTF((tp, "/%u", bits)); - - /* - * Check for overflow, copy, and we're done. - */ - if ((size_t) (tp - tmp) > size) - { - errno = EMSGSIZE; - return (NULL); - } - strcpy(dst, tmp); - return (dst); -} diff --git a/libpq/ip.c b/libpq/ip.c deleted file mode 100644 index 9591ed2..0000000 --- a/libpq/ip.c +++ /dev/null @@ -1,819 +0,0 @@ -/*------------------------------------------------------------------------- - * - * ip.c - * IPv6-aware network access. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/backend/libpq/ip.c - * - * This file and the IPV6 implementation were initially provided by - * Nigel Kukard , Linux Based Systems Design - * http://www.lbsd.net. - * - *------------------------------------------------------------------------- - */ - -/* This is intended to be used in both frontend and backend, so use c.h */ -#include "c.h" - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#include -#include - -#include "libpq/ip.h" - - -static int range_sockaddr_AF_INET(const struct sockaddr_in * addr, - const struct sockaddr_in * netaddr, - const struct sockaddr_in * netmask); - -#ifdef HAVE_IPV6 -static int range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr, - const struct sockaddr_in6 * netaddr, - const struct sockaddr_in6 * netmask); -#endif - -#ifdef HAVE_UNIX_SOCKETS -static int getaddrinfo_unix(const char *path, - const struct addrinfo * hintsp, - struct addrinfo ** result); - -static int getnameinfo_unix(const struct sockaddr_un * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags); -#endif - - -/* - * pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets - */ -int -pg_getaddrinfo_all(const char *hostname, const char *servname, - const struct addrinfo * hintp, struct addrinfo ** result) -{ - int rc; - - /* not all versions of getaddrinfo() zero *result on failure */ - *result = NULL; - -#ifdef HAVE_UNIX_SOCKETS - if (hintp->ai_family == AF_UNIX) - return getaddrinfo_unix(servname, hintp, result); -#endif - - /* NULL has special meaning to getaddrinfo(). */ - rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname, - servname, hintp, result); - - return rc; -} - - -/* - * pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix - * - * Note: the ai_family field of the original hint structure must be passed - * so that we can tell whether the addrinfo struct was built by the system's - * getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions - * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's - * not safe to look at ai_family in the addrinfo itself. - */ -void -pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai) -{ -#ifdef HAVE_UNIX_SOCKETS - if (hint_ai_family == AF_UNIX) - { - /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */ - while (ai != NULL) - { - struct addrinfo *p = ai; - - ai = ai->ai_next; - free(p->ai_addr); - free(p); - } - } - else -#endif /* HAVE_UNIX_SOCKETS */ - { - /* struct was built by getaddrinfo() */ - if (ai != NULL) - freeaddrinfo(ai); - } -} - - -/* - * pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets - * - * The API of this routine differs from the standard getnameinfo() definition - * in two ways: first, the addr parameter is declared as sockaddr_storage - * rather than struct sockaddr, and second, the node and service fields are - * guaranteed to be filled with something even on failure return. - */ -int -pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags) -{ - int rc; - -#ifdef HAVE_UNIX_SOCKETS - if (addr && addr->ss_family == AF_UNIX) - rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen, - node, nodelen, - service, servicelen, - flags); - else -#endif - rc = getnameinfo((const struct sockaddr *) addr, salen, - node, nodelen, - service, servicelen, - flags); - - if (rc != 0) - { - if (node) - strlcpy(node, "???", nodelen); - if (service) - strlcpy(service, "???", servicelen); - } - - return rc; -} - - -#if defined(HAVE_UNIX_SOCKETS) - -/* ------- - * getaddrinfo_unix - get unix socket info using IPv6-compatible API - * - * Bugs: only one addrinfo is set even though hintsp is NULL or - * ai_socktype is 0 - * AI_CANONNAME is not supported. - * ------- - */ -static int -getaddrinfo_unix(const char *path, const struct addrinfo * hintsp, - struct addrinfo ** result) -{ - struct addrinfo hints; - struct addrinfo *aip; - struct sockaddr_un *unp; - - *result = NULL; - - MemSet(&hints, 0, sizeof(hints)); - - if (strlen(path) >= sizeof(unp->sun_path)) - return EAI_FAIL; - - if (hintsp == NULL) - { - hints.ai_family = AF_UNIX; - hints.ai_socktype = SOCK_STREAM; - } - else - memcpy(&hints, hintsp, sizeof(hints)); - - if (hints.ai_socktype == 0) - hints.ai_socktype = SOCK_STREAM; - - if (hints.ai_family != AF_UNIX) - { - /* shouldn't have been called */ - return EAI_FAIL; - } - - aip = calloc(1, sizeof(struct addrinfo)); - if (aip == NULL) - return EAI_MEMORY; - - unp = calloc(1, sizeof(struct sockaddr_un)); - if (unp == NULL) - { - free(aip); - return EAI_MEMORY; - } - - aip->ai_family = AF_UNIX; - aip->ai_socktype = hints.ai_socktype; - aip->ai_protocol = hints.ai_protocol; - aip->ai_next = NULL; - aip->ai_canonname = NULL; - *result = aip; - - unp->sun_family = AF_UNIX; - aip->ai_addr = (struct sockaddr *) unp; - aip->ai_addrlen = sizeof(struct sockaddr_un); - - strcpy(unp->sun_path, path); - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN - unp->sun_len = sizeof(struct sockaddr_un); -#endif - - return 0; -} - -/* - * Convert an address to a hostname. - */ -static int -getnameinfo_unix(const struct sockaddr_un * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags) -{ - int ret = -1; - - /* Invalid arguments. */ - if (sa == NULL || sa->sun_family != AF_UNIX || - (node == NULL && service == NULL)) - return EAI_FAIL; - - if (node) - { - ret = snprintf(node, nodelen, "%s", "[local]"); - if (ret == -1 || ret > nodelen) - return EAI_MEMORY; - } - - if (service) - { - ret = snprintf(service, servicelen, "%s", sa->sun_path); - if (ret == -1 || ret > servicelen) - return EAI_MEMORY; - } - - return 0; -} -#endif /* HAVE_UNIX_SOCKETS */ - - -/* - * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ? - * - * Note: caller must already have verified that all three addresses are - * in the same address family; and AF_UNIX addresses are not supported. - */ -int -pg_range_sockaddr(const struct sockaddr_storage * addr, - const struct sockaddr_storage * netaddr, - const struct sockaddr_storage * netmask) -{ - if (addr->ss_family == AF_INET) - return range_sockaddr_AF_INET((const struct sockaddr_in *) addr, - (const struct sockaddr_in *) netaddr, - (const struct sockaddr_in *) netmask); -#ifdef HAVE_IPV6 - else if (addr->ss_family == AF_INET6) - return range_sockaddr_AF_INET6((const struct sockaddr_in6 *) addr, - (const struct sockaddr_in6 *) netaddr, - (const struct sockaddr_in6 *) netmask); -#endif - else - return 0; -} - -static int -range_sockaddr_AF_INET(const struct sockaddr_in * addr, - const struct sockaddr_in * netaddr, - const struct sockaddr_in * netmask) -{ - if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & - netmask->sin_addr.s_addr) == 0) - return 1; - else - return 0; -} - - -#ifdef HAVE_IPV6 - -static int -range_sockaddr_AF_INET6(const struct sockaddr_in6 * addr, - const struct sockaddr_in6 * netaddr, - const struct sockaddr_in6 * netmask) -{ - int i; - - for (i = 0; i < 16; i++) - { - if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & - netmask->sin6_addr.s6_addr[i]) != 0) - return 0; - } - - return 1; -} -#endif /* HAVE_IPV6 */ - -/* - * pg_sockaddr_cidr_mask - make a network mask of the appropriate family - * and required number of significant bits - * - * numbits can be null, in which case the mask is fully set. - * - * The resulting mask is placed in *mask, which had better be big enough. - * - * Return value is 0 if okay, -1 if not. - */ -int -pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family) -{ - long bits; - char *endptr; - - if (numbits == NULL) - { - bits = (family == AF_INET) ? 32 : 128; - } - else - { - bits = strtol(numbits, &endptr, 10); - if (*numbits == '\0' || *endptr != '\0') - return -1; - } - - switch (family) - { - case AF_INET: - { - struct sockaddr_in mask4; - long maskl; - - if (bits < 0 || bits > 32) - return -1; - memset(&mask4, 0, sizeof(mask4)); - /* avoid "x << 32", which is not portable */ - if (bits > 0) - maskl = (0xffffffffUL << (32 - (int) bits)) - & 0xffffffffUL; - else - maskl = 0; - mask4.sin_addr.s_addr = htonl(maskl); - memcpy(mask, &mask4, sizeof(mask4)); - break; - } - -#ifdef HAVE_IPV6 - case AF_INET6: - { - struct sockaddr_in6 mask6; - int i; - - if (bits < 0 || bits > 128) - return -1; - memset(&mask6, 0, sizeof(mask6)); - for (i = 0; i < 16; i++) - { - if (bits <= 0) - mask6.sin6_addr.s6_addr[i] = 0; - else if (bits >= 8) - mask6.sin6_addr.s6_addr[i] = 0xff; - else - { - mask6.sin6_addr.s6_addr[i] = - (0xff << (8 - (int) bits)) & 0xff; - } - bits -= 8; - } - memcpy(mask, &mask6, sizeof(mask6)); - break; - } -#endif - default: - return -1; - } - - mask->ss_family = family; - return 0; -} - - -/* - * Run the callback function for the addr/mask, after making sure the - * mask is sane for the addr. - */ -static void -run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data, - struct sockaddr * addr, struct sockaddr * mask) -{ - struct sockaddr_storage fullmask; - - if (!addr) - return; - - /* Check that the mask is valid */ - if (mask) - { - if (mask->sa_family != addr->sa_family) - { - mask = NULL; - } - else if (mask->sa_family == AF_INET) - { - if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY) - mask = NULL; - } -#ifdef HAVE_IPV6 - else if (mask->sa_family == AF_INET6) - { - if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr)) - mask = NULL; - } -#endif - } - - /* If mask is invalid, generate our own fully-set mask */ - if (!mask) - { - pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family); - mask = (struct sockaddr *) & fullmask; - } - - (*callback) (addr, mask, cb_data); -} - -#ifdef WIN32 - -#include -#include - -/* - * Enumerate the system's network interface addresses and call the callback - * for each one. Returns 0 if successful, -1 if trouble. - * - * This version is for Win32. Uses the Winsock 2 functions (ie: ws2_32.dll) - */ -int -pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) -{ - INTERFACE_INFO *ptr, - *ii = NULL; - unsigned long length, - i; - unsigned long n_ii = 0; - SOCKET sock; - int error; - - sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); - if (sock == INVALID_SOCKET) - return -1; - - while (n_ii < 1024) - { - n_ii += 64; - ptr = realloc(ii, sizeof(INTERFACE_INFO) * n_ii); - if (!ptr) - { - free(ii); - closesocket(sock); - errno = ENOMEM; - return -1; - } - - ii = ptr; - if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, - ii, n_ii * sizeof(INTERFACE_INFO), - &length, 0, 0) == SOCKET_ERROR) - { - error = WSAGetLastError(); - if (error == WSAEFAULT || error == WSAENOBUFS) - continue; /* need to make the buffer bigger */ - closesocket(sock); - free(ii); - return -1; - } - - break; - } - - for (i = 0; i < length / sizeof(INTERFACE_INFO); ++i) - run_ifaddr_callback(callback, cb_data, - (struct sockaddr *) & ii[i].iiAddress, - (struct sockaddr *) & ii[i].iiNetmask); - - closesocket(sock); - free(ii); - return 0; -} -#elif HAVE_GETIFADDRS /* && !WIN32 */ - -#ifdef HAVE_IFADDRS_H -#include -#endif - -/* - * Enumerate the system's network interface addresses and call the callback - * for each one. Returns 0 if successful, -1 if trouble. - * - * This version uses the getifaddrs() interface, which is available on - * BSDs, AIX, and modern Linux. - */ -int -pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) -{ - struct ifaddrs *ifa, - *l; - - if (getifaddrs(&ifa) < 0) - return -1; - - for (l = ifa; l; l = l->ifa_next) - run_ifaddr_callback(callback, cb_data, - l->ifa_addr, l->ifa_netmask); - - freeifaddrs(ifa); - return 0; -} -#else /* !HAVE_GETIFADDRS && !WIN32 */ - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#ifdef HAVE_NET_IF_H -#include -#endif - -#ifdef HAVE_SYS_SOCKIO_H -#include -#endif - -/* - * SIOCGIFCONF does not return IPv6 addresses on Solaris - * and HP/UX. So we prefer SIOCGLIFCONF if it's available. - * - * On HP/UX, however, it *only* returns IPv6 addresses, - * and the structs are named slightly differently too. - * We'd have to do another call with SIOCGIFCONF to get the - * IPv4 addresses as well. We don't currently bother, just - * fall back to SIOCGIFCONF on HP/UX. - */ - -#if defined(SIOCGLIFCONF) && !defined(__hpux) - -/* - * Enumerate the system's network interface addresses and call the callback - * for each one. Returns 0 if successful, -1 if trouble. - * - * This version uses ioctl(SIOCGLIFCONF). - */ -int -pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) -{ - struct lifconf lifc; - struct lifreq *lifr, - lmask; - struct sockaddr *addr, - *mask; - char *ptr, - *buffer = NULL; - size_t n_buffer = 1024; - pgsocket sock, - fd; - -#ifdef HAVE_IPV6 - pgsocket sock6; -#endif - int i, - total; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock == PGINVALID_SOCKET) - return -1; - - while (n_buffer < 1024 * 100) - { - n_buffer += 1024; - ptr = realloc(buffer, n_buffer); - if (!ptr) - { - free(buffer); - close(sock); - errno = ENOMEM; - return -1; - } - - memset(&lifc, 0, sizeof(lifc)); - lifc.lifc_family = AF_UNSPEC; - lifc.lifc_buf = buffer = ptr; - lifc.lifc_len = n_buffer; - - if (ioctl(sock, SIOCGLIFCONF, &lifc) < 0) - { - if (errno == EINVAL) - continue; - free(buffer); - close(sock); - return -1; - } - - /* - * Some Unixes try to return as much data as possible, with no - * indication of whether enough space allocated. Don't believe we have - * it all unless there's lots of slop. - */ - if (lifc.lifc_len < n_buffer - 1024) - break; - } - -#ifdef HAVE_IPV6 - /* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */ - sock6 = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock6 == PGINVALID_SOCKET) - { - free(buffer); - close(sock); - return -1; - } -#endif - - total = lifc.lifc_len / sizeof(struct lifreq); - lifr = lifc.lifc_req; - for (i = 0; i < total; ++i) - { - addr = (struct sockaddr *) & lifr[i].lifr_addr; - memcpy(&lmask, &lifr[i], sizeof(struct lifreq)); -#ifdef HAVE_IPV6 - fd = (addr->sa_family == AF_INET6) ? sock6 : sock; -#else - fd = sock; -#endif - if (ioctl(fd, SIOCGLIFNETMASK, &lmask) < 0) - mask = NULL; - else - mask = (struct sockaddr *) & lmask.lifr_addr; - run_ifaddr_callback(callback, cb_data, addr, mask); - } - - free(buffer); - close(sock); -#ifdef HAVE_IPV6 - close(sock6); -#endif - return 0; -} -#elif defined(SIOCGIFCONF) - -/* - * Remaining Unixes use SIOCGIFCONF. Some only return IPv4 information - * here, so this is the least preferred method. Note that there is no - * standard way to iterate the struct ifreq returned in the array. - * On some OSs the structures are padded large enough for any address, - * on others you have to calculate the size of the struct ifreq. - */ - -/* Some OSs have _SIZEOF_ADDR_IFREQ, so just use that */ -#ifndef _SIZEOF_ADDR_IFREQ - -/* Calculate based on sockaddr.sa_len */ -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN -#define _SIZEOF_ADDR_IFREQ(ifr) \ - ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \ - (sizeof(struct ifreq) - sizeof(struct sockaddr) + \ - (ifr).ifr_addr.sa_len) : sizeof(struct ifreq)) - -/* Padded ifreq structure, simple */ -#else -#define _SIZEOF_ADDR_IFREQ(ifr) \ - sizeof (struct ifreq) -#endif -#endif /* !_SIZEOF_ADDR_IFREQ */ - -/* - * Enumerate the system's network interface addresses and call the callback - * for each one. Returns 0 if successful, -1 if trouble. - * - * This version uses ioctl(SIOCGIFCONF). - */ -int -pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) -{ - struct ifconf ifc; - struct ifreq *ifr, - *end, - addr, - mask; - char *ptr, - *buffer = NULL; - size_t n_buffer = 1024; - pgsocket sock; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock == PGINVALID_SOCKET) - return -1; - - while (n_buffer < 1024 * 100) - { - n_buffer += 1024; - ptr = realloc(buffer, n_buffer); - if (!ptr) - { - free(buffer); - close(sock); - errno = ENOMEM; - return -1; - } - - memset(&ifc, 0, sizeof(ifc)); - ifc.ifc_buf = buffer = ptr; - ifc.ifc_len = n_buffer; - - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - { - if (errno == EINVAL) - continue; - free(buffer); - close(sock); - return -1; - } - - /* - * Some Unixes try to return as much data as possible, with no - * indication of whether enough space allocated. Don't believe we have - * it all unless there's lots of slop. - */ - if (ifc.ifc_len < n_buffer - 1024) - break; - } - - end = (struct ifreq *) (buffer + ifc.ifc_len); - for (ifr = ifc.ifc_req; ifr < end;) - { - memcpy(&addr, ifr, sizeof(addr)); - memcpy(&mask, ifr, sizeof(mask)); - if (ioctl(sock, SIOCGIFADDR, &addr, sizeof(addr)) == 0 && - ioctl(sock, SIOCGIFNETMASK, &mask, sizeof(mask)) == 0) - run_ifaddr_callback(callback, cb_data, - &addr.ifr_addr, &mask.ifr_addr); - ifr = (struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)); - } - - free(buffer); - close(sock); - return 0; -} -#else /* !defined(SIOCGIFCONF) */ - -/* - * Enumerate the system's network interface addresses and call the callback - * for each one. Returns 0 if successful, -1 if trouble. - * - * This version is our fallback if there's no known way to get the - * interface addresses. Just return the standard loopback addresses. - */ -int -pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) -{ - struct sockaddr_in addr; - struct sockaddr_storage mask; - -#ifdef HAVE_IPV6 - struct sockaddr_in6 addr6; -#endif - - /* addr 127.0.0.1/8 */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ntohl(0x7f000001); - memset(&mask, 0, sizeof(mask)); - pg_sockaddr_cidr_mask(&mask, "8", AF_INET); - run_ifaddr_callback(callback, cb_data, - (struct sockaddr *) & addr, - (struct sockaddr *) & mask); - -#ifdef HAVE_IPV6 - /* addr ::1/128 */ - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_addr.s6_addr[15] = 1; - memset(&mask, 0, sizeof(mask)); - pg_sockaddr_cidr_mask(&mask, "128", AF_INET6); - run_ifaddr_callback(callback, cb_data, - (struct sockaddr *) & addr6, - (struct sockaddr *) & mask); -#endif - - return 0; -} -#endif /* !defined(SIOCGIFCONF) */ - -#endif /* !HAVE_GETIFADDRS */ diff --git a/libpq/libpq-events.c b/libpq/libpq-events.c deleted file mode 100644 index 6db3e94..0000000 --- a/libpq/libpq-events.c +++ /dev/null @@ -1,209 +0,0 @@ -/*------------------------------------------------------------------------- - * - * libpq-events.c - * functions for supporting the libpq "events" API - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/interfaces/libpq/libpq-events.c - * - *------------------------------------------------------------------------- - */ -#include "postgres_fe.h" - -#include "libpq-fe.h" -#include "libpq-int.h" - - -/* - * Registers an event proc with the given PGconn. - * - * The same proc can't be registered more than once in a PGconn. This - * restriction is required because we use the proc address to identify - * the event for purposes such as PQinstanceData(). - * - * The name argument is used within error messages to aid in debugging. - * A name must be supplied, but it needn't be unique. The string is - * copied, so the passed value needn't be long-lived. - * - * The passThrough argument is an application specific pointer and can be set - * to NULL if not required. It is passed through to the event proc whenever - * the event proc is called, and is not otherwise touched by libpq. - * - * The function returns a non-zero if successful. If the function fails, - * zero is returned. - */ -int -PQregisterEventProc(PGconn *conn, PGEventProc proc, - const char *name, void *passThrough) -{ - int i; - PGEventRegister regevt; - - if (!proc || !conn || !name || !*name) - return FALSE; /* bad arguments */ - - for (i = 0; i < conn->nEvents; i++) - { - if (conn->events[i].proc == proc) - return FALSE; /* already registered */ - } - - if (conn->nEvents >= conn->eventArraySize) - { - PGEvent *e; - int newSize; - - newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8; - if (conn->events) - e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent)); - else - e = (PGEvent *) malloc(newSize * sizeof(PGEvent)); - - if (!e) - return FALSE; - - conn->eventArraySize = newSize; - conn->events = e; - } - - conn->events[conn->nEvents].proc = proc; - conn->events[conn->nEvents].name = strdup(name); - if (!conn->events[conn->nEvents].name) - return FALSE; - conn->events[conn->nEvents].passThrough = passThrough; - conn->events[conn->nEvents].data = NULL; - conn->events[conn->nEvents].resultInitialized = FALSE; - conn->nEvents++; - - regevt.conn = conn; - if (!proc(PGEVT_REGISTER, ®evt, passThrough)) - { - conn->nEvents--; - free(conn->events[conn->nEvents].name); - return FALSE; - } - - return TRUE; -} - -/* - * Set some "instance data" for an event within a PGconn. - * Returns nonzero on success, zero on failure. - */ -int -PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data) -{ - int i; - - if (!conn || !proc) - return FALSE; - - for (i = 0; i < conn->nEvents; i++) - { - if (conn->events[i].proc == proc) - { - conn->events[i].data = data; - return TRUE; - } - } - - return FALSE; -} - -/* - * Obtain the "instance data", if any, for the event. - */ -void * -PQinstanceData(const PGconn *conn, PGEventProc proc) -{ - int i; - - if (!conn || !proc) - return NULL; - - for (i = 0; i < conn->nEvents; i++) - { - if (conn->events[i].proc == proc) - return conn->events[i].data; - } - - return NULL; -} - -/* - * Set some "instance data" for an event within a PGresult. - * Returns nonzero on success, zero on failure. - */ -int -PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data) -{ - int i; - - if (!result || !proc) - return FALSE; - - for (i = 0; i < result->nEvents; i++) - { - if (result->events[i].proc == proc) - { - result->events[i].data = data; - return TRUE; - } - } - - return FALSE; -} - -/* - * Obtain the "instance data", if any, for the event. - */ -void * -PQresultInstanceData(const PGresult *result, PGEventProc proc) -{ - int i; - - if (!result || !proc) - return NULL; - - for (i = 0; i < result->nEvents; i++) - if (result->events[i].proc == proc) - return result->events[i].data; - - return NULL; -} - -/* - * Fire RESULTCREATE events for an application-created PGresult. - * - * The conn argument can be NULL if event procedures won't use it. - */ -int -PQfireResultCreateEvents(PGconn *conn, PGresult *res) -{ - int i; - - if (!res) - return FALSE; - - for (i = 0; i < res->nEvents; i++) - { - if (!res->events[i].resultInitialized) - { - PGEventResultCreate evt; - - evt.conn = conn; - evt.result = res; - if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt, - res->events[i].passThrough)) - return FALSE; - - res->events[i].resultInitialized = TRUE; - } - } - - return TRUE; -} diff --git a/libpq/libpq-events.h b/libpq/libpq-events.h deleted file mode 100644 index e2bdb28..0000000 --- a/libpq/libpq-events.h +++ /dev/null @@ -1,94 +0,0 @@ -/*------------------------------------------------------------------------- - * - * libpq-events.h - * This file contains definitions that are useful to applications - * that invoke the libpq "events" API, but are not interesting to - * ordinary users of libpq. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/libpq-events.h - * - *------------------------------------------------------------------------- - */ - -#ifndef LIBPQ_EVENTS_H -#define LIBPQ_EVENTS_H - -#include "libpq-fe.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Callback Event Ids */ -typedef enum -{ - PGEVT_REGISTER, - PGEVT_CONNRESET, - PGEVT_CONNDESTROY, - PGEVT_RESULTCREATE, - PGEVT_RESULTCOPY, - PGEVT_RESULTDESTROY -} PGEventId; - -typedef struct -{ - PGconn *conn; -} PGEventRegister; - -typedef struct -{ - PGconn *conn; -} PGEventConnReset; - -typedef struct -{ - PGconn *conn; -} PGEventConnDestroy; - -typedef struct -{ - PGconn *conn; - PGresult *result; -} PGEventResultCreate; - -typedef struct -{ - const PGresult *src; - PGresult *dest; -} PGEventResultCopy; - -typedef struct -{ - PGresult *result; -} PGEventResultDestroy; - -typedef int (*PGEventProc) (PGEventId evtId, void *evtInfo, void *passThrough); - -/* Registers an event proc with the given PGconn. */ -extern int PQregisterEventProc(PGconn *conn, PGEventProc proc, - const char *name, void *passThrough); - -/* Sets the PGconn instance data for the provided proc to data. */ -extern int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data); - -/* Gets the PGconn instance data for the provided proc. */ -extern void *PQinstanceData(const PGconn *conn, PGEventProc proc); - -/* Sets the PGresult instance data for the provided proc to data. */ -extern int PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data); - -/* Gets the PGresult instance data for the provided proc. */ -extern void *PQresultInstanceData(const PGresult *result, PGEventProc proc); - -/* Fires RESULTCREATE events for an application-created PGresult. */ -extern int PQfireResultCreateEvents(PGconn *conn, PGresult *res); - -#ifdef __cplusplus -} -#endif - -#endif /* LIBPQ_EVENTS_H */ diff --git a/libpq/libpq-fe.h b/libpq/libpq-fe.h deleted file mode 100644 index 9ca0756..0000000 --- a/libpq/libpq-fe.h +++ /dev/null @@ -1,607 +0,0 @@ -/*------------------------------------------------------------------------- - * - * libpq-fe.h - * This file contains definitions for structures and - * externs for functions used by frontend postgres applications. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/libpq-fe.h - * - *------------------------------------------------------------------------- - */ - -#ifndef LIBPQ_FE_H -#define LIBPQ_FE_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -/* - * postgres_ext.h defines the backend's externally visible types, - * such as Oid. - */ -#include "postgres_ext.h" - -/* - * Option flags for PQcopyResult - */ -#define PG_COPYRES_ATTRS 0x01 -#define PG_COPYRES_TUPLES 0x02 /* Implies PG_COPYRES_ATTRS */ -#define PG_COPYRES_EVENTS 0x04 -#define PG_COPYRES_NOTICEHOOKS 0x08 - -/* Application-visible enum types */ - -/* - * Although it is okay to add to these lists, values which become unused - * should never be removed, nor should constants be redefined - that would - * break compatibility with existing code. - */ - -typedef enum -{ - CONNECTION_OK, - CONNECTION_BAD, - /* Non-blocking mode only below here */ - - /* - * The existence of these should never be relied upon - they should only - * be used for user feedback or similar purposes. - */ - CONNECTION_STARTED, /* Waiting for connection to be made. */ - CONNECTION_MADE, /* Connection OK; waiting to send. */ - CONNECTION_AWAITING_RESPONSE, /* Waiting for a response from the - * postmaster. */ - CONNECTION_AUTH_OK, /* Received authentication; waiting for - * backend startup. */ - CONNECTION_SETENV, /* Negotiating environment. */ - CONNECTION_SSL_STARTUP, /* Negotiating SSL. */ - CONNECTION_NEEDED /* Internal state: connect() needed */ -} ConnStatusType; - -typedef enum -{ - PGRES_POLLING_FAILED = 0, - PGRES_POLLING_READING, /* These two indicate that one may */ - PGRES_POLLING_WRITING, /* use select before polling again. */ - PGRES_POLLING_OK, - PGRES_POLLING_ACTIVE /* unused; keep for awhile for backwards - * compatibility */ -} PostgresPollingStatusType; - -typedef enum -{ - PGRES_EMPTY_QUERY = 0, /* empty query string was executed */ - PGRES_COMMAND_OK, /* a query command that doesn't return - * anything was executed properly by the - * backend */ - PGRES_TUPLES_OK, /* a query command that returns tuples was - * executed properly by the backend, PGresult - * contains the result tuples */ - PGRES_COPY_OUT, /* Copy Out data transfer in progress */ - PGRES_COPY_IN, /* Copy In data transfer in progress */ - PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the - * backend */ - PGRES_NONFATAL_ERROR, /* notice or warning message */ - PGRES_FATAL_ERROR, /* query failed */ - PGRES_COPY_BOTH, /* Copy In/Out data transfer in progress */ - PGRES_SINGLE_TUPLE /* single tuple from larger resultset */ -} ExecStatusType; - -typedef enum -{ - PQTRANS_IDLE, /* connection idle */ - PQTRANS_ACTIVE, /* command in progress */ - PQTRANS_INTRANS, /* idle, within transaction block */ - PQTRANS_INERROR, /* idle, within failed transaction */ - PQTRANS_UNKNOWN /* cannot determine status */ -} PGTransactionStatusType; - -typedef enum -{ - PQERRORS_TERSE, /* single-line error messages */ - PQERRORS_DEFAULT, /* recommended style */ - PQERRORS_VERBOSE /* all the facts, ma'am */ -} PGVerbosity; - -typedef enum -{ - PQSHOW_CONTEXT_NEVER, /* never show CONTEXT field */ - PQSHOW_CONTEXT_ERRORS, /* show CONTEXT for errors only (default) */ - PQSHOW_CONTEXT_ALWAYS /* always show CONTEXT field */ -} PGContextVisibility; - -/* - * PGPing - The ordering of this enum should not be altered because the - * values are exposed externally via pg_isready. - */ - -typedef enum -{ - PQPING_OK, /* server is accepting connections */ - PQPING_REJECT, /* server is alive but rejecting connections */ - PQPING_NO_RESPONSE, /* could not establish connection */ - PQPING_NO_ATTEMPT /* connection not attempted (bad params) */ -} PGPing; - -/* PGconn encapsulates a connection to the backend. - * The contents of this struct are not supposed to be known to applications. - */ -typedef struct pg_conn PGconn; - -/* PGresult encapsulates the result of a query (or more precisely, of a single - * SQL command --- a query string given to PQsendQuery can contain multiple - * commands and thus return multiple PGresult objects). - * The contents of this struct are not supposed to be known to applications. - */ -typedef struct pg_result PGresult; - -/* PGcancel encapsulates the information needed to cancel a running - * query on an existing connection. - * The contents of this struct are not supposed to be known to applications. - */ -typedef struct pg_cancel PGcancel; - -/* PGnotify represents the occurrence of a NOTIFY message. - * Ideally this would be an opaque typedef, but it's so simple that it's - * unlikely to change. - * NOTE: in Postgres 6.4 and later, the be_pid is the notifying backend's, - * whereas in earlier versions it was always your own backend's PID. - */ -typedef struct pgNotify -{ - char *relname; /* notification condition name */ - int be_pid; /* process ID of notifying server process */ - char *extra; /* notification parameter */ - /* Fields below here are private to libpq; apps should not use 'em */ - struct pgNotify *next; /* list link */ -} PGnotify; - -/* Function types for notice-handling callbacks */ -typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res); -typedef void (*PQnoticeProcessor) (void *arg, const char *message); - -/* Print options for PQprint() */ -typedef char pqbool; - -typedef struct _PQprintOpt -{ - pqbool header; /* print output field headings and row count */ - pqbool align; /* fill align the fields */ - pqbool standard; /* old brain dead format */ - pqbool html3; /* output html tables */ - pqbool expanded; /* expand tables */ - pqbool pager; /* use pager for output if needed */ - char *fieldSep; /* field separator */ - char *tableOpt; /* insert to HTML */ - char *caption; /* HTML
*/ - char **fieldName; /* null terminated array of replacement field - * names */ -} PQprintOpt; - -/* ---------------- - * Structure for the conninfo parameter definitions returned by PQconndefaults - * or PQconninfoParse. - * - * All fields except "val" point at static strings which must not be altered. - * "val" is either NULL or a malloc'd current-value string. PQconninfoFree() - * will release both the val strings and the PQconninfoOption array itself. - * ---------------- - */ -typedef struct _PQconninfoOption -{ - char *keyword; /* The keyword of the option */ - char *envvar; /* Fallback environment variable name */ - char *compiled; /* Fallback compiled in default value */ - char *val; /* Option's current value, or NULL */ - char *label; /* Label for field in connect dialog */ - char *dispchar; /* Indicates how to display this field in a - * connect dialog. Values are: "" Display - * entered value as is "*" Password field - - * hide value "D" Debug option - don't show - * by default */ - int dispsize; /* Field size in characters for dialog */ -} PQconninfoOption; - -/* ---------------- - * PQArgBlock -- structure for PQfn() arguments - * ---------------- - */ -typedef struct -{ - int len; - int isint; - union - { - int *ptr; /* can't use void (dec compiler barfs) */ - int integer; - } u; -} PQArgBlock; - -/* ---------------- - * PGresAttDesc -- Data about a single attribute (column) of a query result - * ---------------- - */ -typedef struct pgresAttDesc -{ - char *name; /* column name */ - Oid tableid; /* source table, if known */ - int columnid; /* source column, if known */ - int format; /* format code for value (text/binary) */ - Oid typid; /* type id */ - int typlen; /* type size */ - int atttypmod; /* type-specific modifier info */ -} PGresAttDesc; - -/* ---------------- - * Exported functions of libpq - * ---------------- - */ - -/* === in fe-connect.c === */ - -/* make a new client connection to the backend */ -/* Asynchronous (non-blocking) */ -extern PGconn *PQconnectStart(const char *conninfo); -extern PGconn *PQconnectStartParams(const char *const * keywords, - const char *const * values, int expand_dbname); -extern PostgresPollingStatusType PQconnectPoll(PGconn *conn); - -/* Synchronous (blocking) */ -extern PGconn *PQconnectdb(const char *conninfo); -extern PGconn *PQconnectdbParams(const char *const * keywords, - const char *const * values, int expand_dbname); -extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport, - const char *pgoptions, const char *pgtty, - const char *dbName, - const char *login, const char *pwd); - -#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) \ - PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL) - -/* close the current connection and free the PGconn data structure */ -extern void PQfinish(PGconn *conn); - -/* get info about connection options known to PQconnectdb */ -extern PQconninfoOption *PQconndefaults(void); - -/* parse connection options in same way as PQconnectdb */ -extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); - -/* return the connection options used by a live connection */ -extern PQconninfoOption *PQconninfo(PGconn *conn); - -/* free the data structure returned by PQconndefaults() or PQconninfoParse() */ -extern void PQconninfoFree(PQconninfoOption *connOptions); - -/* - * close the current connection and restablish a new one with the same - * parameters - */ -/* Asynchronous (non-blocking) */ -extern int PQresetStart(PGconn *conn); -extern PostgresPollingStatusType PQresetPoll(PGconn *conn); - -/* Synchronous (blocking) */ -extern void PQreset(PGconn *conn); - -/* request a cancel structure */ -extern PGcancel *PQgetCancel(PGconn *conn); - -/* free a cancel structure */ -extern void PQfreeCancel(PGcancel *cancel); - -/* issue a cancel request */ -extern int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize); - -/* backwards compatible version of PQcancel; not thread-safe */ -extern int PQrequestCancel(PGconn *conn); - -/* Accessor functions for PGconn objects */ -extern char *PQdb(const PGconn *conn); -extern char *PQuser(const PGconn *conn); -extern char *PQpass(const PGconn *conn); -extern char *PQhost(const PGconn *conn); -extern char *PQport(const PGconn *conn); -extern char *PQtty(const PGconn *conn); -extern char *PQoptions(const PGconn *conn); -extern ConnStatusType PQstatus(const PGconn *conn); -extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn); -extern const char *PQparameterStatus(const PGconn *conn, - const char *paramName); -extern int PQprotocolVersion(const PGconn *conn); -extern int PQserverVersion(const PGconn *conn); -extern char *PQerrorMessage(const PGconn *conn); -extern int PQsocket(const PGconn *conn); -extern int PQbackendPID(const PGconn *conn); -extern int PQconnectionNeedsPassword(const PGconn *conn); -extern int PQconnectionUsedPassword(const PGconn *conn); -extern int PQclientEncoding(const PGconn *conn); -extern int PQsetClientEncoding(PGconn *conn, const char *encoding); - -/* SSL information functions */ -extern int PQsslInUse(PGconn *conn); -extern void *PQsslStruct(PGconn *conn, const char *struct_name); -extern const char *PQsslAttribute(PGconn *conn, const char *attribute_name); -extern const char *const * PQsslAttributeNames(PGconn *conn); - -/* Get the OpenSSL structure associated with a connection. Returns NULL for - * unencrypted connections or if any other TLS library is in use. */ -extern void *PQgetssl(PGconn *conn); - -/* Tell libpq whether it needs to initialize OpenSSL */ -extern void PQinitSSL(int do_init); - -/* More detailed way to tell libpq whether it needs to initialize OpenSSL */ -extern void PQinitOpenSSL(int do_ssl, int do_crypto); - -/* Set verbosity for PQerrorMessage and PQresultErrorMessage */ -extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity); - -/* Set CONTEXT visibility for PQerrorMessage and PQresultErrorMessage */ -extern PGContextVisibility PQsetErrorContextVisibility(PGconn *conn, - PGContextVisibility show_context); - -/* Enable/disable tracing */ -extern void PQtrace(PGconn *conn, FILE *debug_port); -extern void PQuntrace(PGconn *conn); - -/* Override default notice handling routines */ -extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, - PQnoticeReceiver proc, - void *arg); -extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, - PQnoticeProcessor proc, - void *arg); - -/* - * Used to set callback that prevents concurrent access to - * non-thread safe functions that libpq needs. - * The default implementation uses a libpq internal mutex. - * Only required for multithreaded apps that use kerberos - * both within their app and for postgresql connections. - */ -typedef void (*pgthreadlock_t) (int acquire); - -extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler); - -/* === in fe-exec.c === */ - -/* Simple synchronous query */ -extern PGresult *PQexec(PGconn *conn, const char *query); -extern PGresult *PQexecParams(PGconn *conn, - const char *command, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat); -extern PGresult *PQprepare(PGconn *conn, const char *stmtName, - const char *query, int nParams, - const Oid *paramTypes); -extern PGresult *PQexecPrepared(PGconn *conn, - const char *stmtName, - int nParams, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat); - -/* Interface for multiple-result or asynchronous queries */ -extern int PQsendQuery(PGconn *conn, const char *query); -extern int PQsendQueryParams(PGconn *conn, - const char *command, - int nParams, - const Oid *paramTypes, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat); -extern int PQsendPrepare(PGconn *conn, const char *stmtName, - const char *query, int nParams, - const Oid *paramTypes); -extern int PQsendQueryPrepared(PGconn *conn, - const char *stmtName, - int nParams, - const char *const * paramValues, - const int *paramLengths, - const int *paramFormats, - int resultFormat); -extern int PQsetSingleRowMode(PGconn *conn); -extern PGresult *PQgetResult(PGconn *conn); - -/* Routines for managing an asynchronous query */ -extern int PQisBusy(PGconn *conn); -extern int PQconsumeInput(PGconn *conn); - -/* LISTEN/NOTIFY support */ -extern PGnotify *PQnotifies(PGconn *conn); - -/* Routines for copy in/out */ -extern int PQputCopyData(PGconn *conn, const char *buffer, int nbytes); -extern int PQputCopyEnd(PGconn *conn, const char *errormsg); -extern int PQgetCopyData(PGconn *conn, char **buffer, int async); - -/* Deprecated routines for copy in/out */ -extern int PQgetline(PGconn *conn, char *string, int length); -extern int PQputline(PGconn *conn, const char *string); -extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize); -extern int PQputnbytes(PGconn *conn, const char *buffer, int nbytes); -extern int PQendcopy(PGconn *conn); - -/* Set blocking/nonblocking connection to the backend */ -extern int PQsetnonblocking(PGconn *conn, int arg); -extern int PQisnonblocking(const PGconn *conn); -extern int PQisthreadsafe(void); -extern PGPing PQping(const char *conninfo); -extern PGPing PQpingParams(const char *const * keywords, - const char *const * values, int expand_dbname); - -/* Force the write buffer to be written (or at least try) */ -extern int PQflush(PGconn *conn); - -/* - * "Fast path" interface --- not really recommended for application - * use - */ -extern PGresult *PQfn(PGconn *conn, - int fnid, - int *result_buf, - int *result_len, - int result_is_int, - const PQArgBlock *args, - int nargs); - -/* Accessor functions for PGresult objects */ -extern ExecStatusType PQresultStatus(const PGresult *res); -extern char *PQresStatus(ExecStatusType status); -extern char *PQresultErrorMessage(const PGresult *res); -extern char *PQresultVerboseErrorMessage(const PGresult *res, - PGVerbosity verbosity, - PGContextVisibility show_context); -extern char *PQresultErrorField(const PGresult *res, int fieldcode); -extern int PQntuples(const PGresult *res); -extern int PQnfields(const PGresult *res); -extern int PQbinaryTuples(const PGresult *res); -extern char *PQfname(const PGresult *res, int field_num); -extern int PQfnumber(const PGresult *res, const char *field_name); -extern Oid PQftable(const PGresult *res, int field_num); -extern int PQftablecol(const PGresult *res, int field_num); -extern int PQfformat(const PGresult *res, int field_num); -extern Oid PQftype(const PGresult *res, int field_num); -extern int PQfsize(const PGresult *res, int field_num); -extern int PQfmod(const PGresult *res, int field_num); -extern char *PQcmdStatus(PGresult *res); -extern char *PQoidStatus(const PGresult *res); /* old and ugly */ -extern Oid PQoidValue(const PGresult *res); /* new and improved */ -extern char *PQcmdTuples(PGresult *res); -extern char *PQgetvalue(const PGresult *res, int tup_num, int field_num); -extern int PQgetlength(const PGresult *res, int tup_num, int field_num); -extern int PQgetisnull(const PGresult *res, int tup_num, int field_num); -extern int PQnparams(const PGresult *res); -extern Oid PQparamtype(const PGresult *res, int param_num); - -/* Describe prepared statements and portals */ -extern PGresult *PQdescribePrepared(PGconn *conn, const char *stmt); -extern PGresult *PQdescribePortal(PGconn *conn, const char *portal); -extern int PQsendDescribePrepared(PGconn *conn, const char *stmt); -extern int PQsendDescribePortal(PGconn *conn, const char *portal); - -/* Delete a PGresult */ -extern void PQclear(PGresult *res); - -/* For freeing other alloc'd results, such as PGnotify structs */ -extern void PQfreemem(void *ptr); - -/* Exists for backward compatibility. bjm 2003-03-24 */ -#define PQfreeNotify(ptr) PQfreemem(ptr) - -/* Error when no password was given. */ -/* Note: depending on this is deprecated; use PQconnectionNeedsPassword(). */ -#define PQnoPasswordSupplied "fe_sendauth: no password supplied\n" - -/* Create and manipulate PGresults */ -extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status); -extern PGresult *PQcopyResult(const PGresult *src, int flags); -extern int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs); -extern void *PQresultAlloc(PGresult *res, size_t nBytes); -extern int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len); - -/* Quoting strings before inclusion in queries. */ -extern size_t PQescapeStringConn(PGconn *conn, - char *to, const char *from, size_t length, - int *error); -extern char *PQescapeLiteral(PGconn *conn, const char *str, size_t len); -extern char *PQescapeIdentifier(PGconn *conn, const char *str, size_t len); -extern unsigned char *PQescapeByteaConn(PGconn *conn, - const unsigned char *from, size_t from_length, - size_t *to_length); -extern unsigned char *PQunescapeBytea(const unsigned char *strtext, - size_t *retbuflen); - -/* These forms are deprecated! */ -extern size_t PQescapeString(char *to, const char *from, size_t length); -extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length, - size_t *to_length); - - - -/* === in fe-print.c === */ - -extern void PQprint(FILE *fout, /* output stream */ - const PGresult *res, - const PQprintOpt *ps); /* option structure */ - -/* - * really old printing routines - */ -extern void PQdisplayTuples(const PGresult *res, - FILE *fp, /* where to send the output */ - int fillAlign, /* pad the fields with spaces */ - const char *fieldSep, /* field separator */ - int printHeader, /* display headers? */ - int quiet); - -extern void PQprintTuples(const PGresult *res, - FILE *fout, /* output stream */ - int printAttName, /* print attribute names */ - int terseOutput, /* delimiter bars */ - int width); /* width of column, if 0, use variable width */ - - -/* === in fe-lobj.c === */ - -/* Large-object access routines */ -extern int lo_open(PGconn *conn, Oid lobjId, int mode); -extern int lo_close(PGconn *conn, int fd); -extern int lo_read(PGconn *conn, int fd, char *buf, size_t len); -extern int lo_write(PGconn *conn, int fd, const char *buf, size_t len); -extern int lo_lseek(PGconn *conn, int fd, int offset, int whence); -extern pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence); -extern Oid lo_creat(PGconn *conn, int mode); -extern Oid lo_create(PGconn *conn, Oid lobjId); -extern int lo_tell(PGconn *conn, int fd); -extern pg_int64 lo_tell64(PGconn *conn, int fd); -extern int lo_truncate(PGconn *conn, int fd, size_t len); -extern int lo_truncate64(PGconn *conn, int fd, pg_int64 len); -extern int lo_unlink(PGconn *conn, Oid lobjId); -extern Oid lo_import(PGconn *conn, const char *filename); -extern Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId); -extern int lo_export(PGconn *conn, Oid lobjId, const char *filename); - -/* === in fe-misc.c === */ - -/* Get the version of the libpq library in use */ -extern int PQlibVersion(void); - -/* Determine length of multibyte encoded char at *s */ -extern int PQmblen(const char *s, int encoding); - -/* Determine display length of multibyte encoded char at *s */ -extern int PQdsplen(const char *s, int encoding); - -/* Get encoding id from environment variable PGCLIENTENCODING */ -extern int PQenv2encoding(void); - -/* === in fe-auth.c === */ - -extern char *PQencryptPassword(const char *passwd, const char *user); - -/* === in encnames.c === */ - -extern int pg_char_to_encoding(const char *name); -extern const char *pg_encoding_to_char(int encoding); -extern int pg_valid_server_encoding_id(int encoding); - -#ifdef __cplusplus -} -#endif - -#endif /* LIBPQ_FE_H */ diff --git a/libpq/libpq-int.h b/libpq/libpq-int.h deleted file mode 100644 index 9e4e625..0000000 --- a/libpq/libpq-int.h +++ /dev/null @@ -1,675 +0,0 @@ -/*------------------------------------------------------------------------- - * - * libpq-int.h - * This file contains internal definitions meant to be used only by - * the frontend libpq library, not by applications that call it. - * - * An application can include this file if it wants to bypass the - * official API defined by libpq-fe.h, but code that does so is much - * more likely to break across PostgreSQL releases than code that uses - * only the official API. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/libpq-int.h - * - *------------------------------------------------------------------------- - */ - -#ifndef LIBPQ_INT_H -#define LIBPQ_INT_H - -/* We assume libpq-fe.h has already been included. */ -#include "postgres_fe.h" -#include "libpq-events.h" - -#include -#include -#ifndef WIN32 -#include -#endif - -#ifdef ENABLE_THREAD_SAFETY -#ifdef WIN32 -#include "pthread-win32.h" -#else -#include -#endif -#include -#endif - -/* include stuff common to fe and be */ -#include "getaddrinfo.h" -#include "libpq/pqcomm.h" -/* include stuff found in fe only */ -#include "pqexpbuffer.h" - -#ifdef ENABLE_GSS -#if defined(HAVE_GSSAPI_H) -#include -#else -#include -#endif -#endif - -#ifdef ENABLE_SSPI -#define SECURITY_WIN32 -#if defined(WIN32) && !defined(WIN32_ONLY_COMPILER) -#include -#endif -#include -#undef SECURITY_WIN32 - -#ifndef ENABLE_GSS -/* - * Define a fake structure compatible with GSSAPI on Unix. - */ -typedef struct -{ - void *value; - int length; -} gss_buffer_desc; -#endif -#endif /* ENABLE_SSPI */ - -#ifdef USE_OPENSSL -#include -#include - -#if (OPENSSL_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) -#define USE_SSL_ENGINE -#endif -#endif /* USE_OPENSSL */ - -/* - * POSTGRES backend dependent Constants. - */ -#define CMDSTATUS_LEN 64 /* should match COMPLETION_TAG_BUFSIZE */ - -/* - * PGresult and the subsidiary types PGresAttDesc, PGresAttValue - * represent the result of a query (or more precisely, of a single SQL - * command --- a query string given to PQexec can contain multiple commands). - * Note we assume that a single command can return at most one tuple group, - * hence there is no need for multiple descriptor sets. - */ - -/* Subsidiary-storage management structure for PGresult. - * See space management routines in fe-exec.c for details. - * Note that space[k] refers to the k'th byte starting from the physical - * head of the block --- it's a union, not a struct! - */ -typedef union pgresult_data PGresult_data; - -union pgresult_data -{ - PGresult_data *next; /* link to next block, or NULL */ - char space[1]; /* dummy for accessing block as bytes */ -}; - -/* Data about a single parameter of a prepared statement */ -typedef struct pgresParamDesc -{ - Oid typid; /* type id */ -} PGresParamDesc; - -/* - * Data for a single attribute of a single tuple - * - * We use char* for Attribute values. - * - * The value pointer always points to a null-terminated area; we add a - * null (zero) byte after whatever the backend sends us. This is only - * particularly useful for text values ... with a binary value, the - * value might have embedded nulls, so the application can't use C string - * operators on it. But we add a null anyway for consistency. - * Note that the value itself does not contain a length word. - * - * A NULL attribute is a special case in two ways: its len field is NULL_LEN - * and its value field points to null_field in the owning PGresult. All the - * NULL attributes in a query result point to the same place (there's no need - * to store a null string separately for each one). - */ - -#define NULL_LEN (-1) /* pg_result len for NULL value */ - -typedef struct pgresAttValue -{ - int len; /* length in bytes of the value */ - char *value; /* actual value, plus terminating zero byte */ -} PGresAttValue; - -/* Typedef for message-field list entries */ -typedef struct pgMessageField -{ - struct pgMessageField *next; /* list link */ - char code; /* field code */ - char contents[FLEXIBLE_ARRAY_MEMBER]; /* value, nul-terminated */ -} PGMessageField; - -/* Fields needed for notice handling */ -typedef struct -{ - PQnoticeReceiver noticeRec; /* notice message receiver */ - void *noticeRecArg; - PQnoticeProcessor noticeProc; /* notice message processor */ - void *noticeProcArg; -} PGNoticeHooks; - -typedef struct PGEvent -{ - PGEventProc proc; /* the function to call on events */ - char *name; /* used only for error messages */ - void *passThrough; /* pointer supplied at registration time */ - void *data; /* optional state (instance) data */ - bool resultInitialized; /* T if RESULTCREATE/COPY succeeded */ -} PGEvent; - -struct pg_result -{ - int ntups; - int numAttributes; - PGresAttDesc *attDescs; - PGresAttValue **tuples; /* each PGresTuple is an array of - * PGresAttValue's */ - int tupArrSize; /* allocated size of tuples array */ - int numParameters; - PGresParamDesc *paramDescs; - ExecStatusType resultStatus; - char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the query */ - int binary; /* binary tuple values if binary == 1, - * otherwise text */ - - /* - * These fields are copied from the originating PGconn, so that operations - * on the PGresult don't have to reference the PGconn. - */ - PGNoticeHooks noticeHooks; - PGEvent *events; - int nEvents; - int client_encoding; /* encoding id */ - - /* - * Error information (all NULL if not an error result). errMsg is the - * "overall" error message returned by PQresultErrorMessage. If we have - * per-field info then it is stored in a linked list. - */ - char *errMsg; /* error message, or NULL if no error */ - PGMessageField *errFields; /* message broken into fields */ - char *errQuery; /* text of triggering query, if available */ - - /* All NULL attributes in the query result point to this null string */ - char null_field[1]; - - /* - * Space management information. Note that attDescs and error stuff, if - * not null, point into allocated blocks. But tuples points to a - * separately malloc'd block, so that we can realloc it. - */ - PGresult_data *curBlock; /* most recently allocated block */ - int curOffset; /* start offset of free space in block */ - int spaceLeft; /* number of free bytes remaining in block */ -}; - -/* PGAsyncStatusType defines the state of the query-execution state machine */ -typedef enum -{ - PGASYNC_IDLE, /* nothing's happening, dude */ - PGASYNC_BUSY, /* query in progress */ - PGASYNC_READY, /* result ready for PQgetResult */ - PGASYNC_COPY_IN, /* Copy In data transfer in progress */ - PGASYNC_COPY_OUT, /* Copy Out data transfer in progress */ - PGASYNC_COPY_BOTH /* Copy In/Out data transfer in progress */ -} PGAsyncStatusType; - -/* PGQueryClass tracks which query protocol we are now executing */ -typedef enum -{ - PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */ - PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */ - PGQUERY_PREPARE, /* Parse only (PQprepare) */ - PGQUERY_DESCRIBE /* Describe Statement or Portal */ -} PGQueryClass; - -/* PGSetenvStatusType defines the state of the PQSetenv state machine */ -/* (this is used only for 2.0-protocol connections) */ -typedef enum -{ - SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */ - SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */ - SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */ - SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */ - SETENV_STATE_QUERY1_SEND, /* About to send a status query */ - SETENV_STATE_QUERY1_WAIT, /* Waiting for query to complete */ - SETENV_STATE_QUERY2_SEND, /* About to send a status query */ - SETENV_STATE_QUERY2_WAIT, /* Waiting for query to complete */ - SETENV_STATE_IDLE -} PGSetenvStatusType; - -/* Typedef for the EnvironmentOptions[] array */ -typedef struct PQEnvironmentOption -{ - const char *envName, /* name of an environment variable */ - *pgName; /* name of corresponding SET variable */ -} PQEnvironmentOption; - -/* Typedef for parameter-status list entries */ -typedef struct pgParameterStatus -{ - struct pgParameterStatus *next; /* list link */ - char *name; /* parameter name */ - char *value; /* parameter value */ - /* Note: name and value are stored in same malloc block as struct is */ -} pgParameterStatus; - -/* large-object-access data ... allocated only if large-object code is used. */ -typedef struct pgLobjfuncs -{ - Oid fn_lo_open; /* OID of backend function lo_open */ - Oid fn_lo_close; /* OID of backend function lo_close */ - Oid fn_lo_creat; /* OID of backend function lo_creat */ - Oid fn_lo_create; /* OID of backend function lo_create */ - Oid fn_lo_unlink; /* OID of backend function lo_unlink */ - Oid fn_lo_lseek; /* OID of backend function lo_lseek */ - Oid fn_lo_lseek64; /* OID of backend function lo_lseek64 */ - Oid fn_lo_tell; /* OID of backend function lo_tell */ - Oid fn_lo_tell64; /* OID of backend function lo_tell64 */ - Oid fn_lo_truncate; /* OID of backend function lo_truncate */ - Oid fn_lo_truncate64; /* OID of function lo_truncate64 */ - Oid fn_lo_read; /* OID of backend function LOread */ - Oid fn_lo_write; /* OID of backend function LOwrite */ -} PGlobjfuncs; - -/* PGdataValue represents a data field value being passed to a row processor. - * It could be either text or binary data; text data is not zero-terminated. - * A SQL NULL is represented by len < 0; then value is still valid but there - * are no data bytes there. - */ -typedef struct pgDataValue -{ - int len; /* data length in bytes, or <0 if NULL */ - const char *value; /* data value, without zero-termination */ -} PGdataValue; - -/* - * PGconn stores all the state data associated with a single connection - * to a backend. - */ -struct pg_conn -{ - /* Saved values of connection options */ - char *pghost; /* the machine on which the server is running */ - char *pghostaddr; /* the numeric IP address of the machine on - * which the server is running. Takes - * precedence over above. */ - char *pgport; /* the server's communication port number */ - char *pgunixsocket; /* the directory of the server's Unix-domain - * socket; if NULL, use DEFAULT_PGSOCKET_DIR */ - char *pgtty; /* tty on which the backend messages is - * displayed (OBSOLETE, NOT USED) */ - char *connect_timeout; /* connection timeout (numeric string) */ - char *client_encoding_initial; /* encoding to use */ - char *pgoptions; /* options to start the backend with */ - char *appname; /* application name */ - char *fbappname; /* fallback application name */ - char *dbName; /* database name */ - char *replication; /* connect as the replication standby? */ - char *pguser; /* Postgres username and password, if any */ - char *pgpass; - char *keepalives; /* use TCP keepalives? */ - char *keepalives_idle; /* time between TCP keepalives */ - char *keepalives_interval; /* time between TCP keepalive - * retransmits */ - char *keepalives_count; /* maximum number of TCP keepalive - * retransmits */ - char *sslmode; /* SSL mode (require,prefer,allow,disable) */ - char *sslcompression; /* SSL compression (0 or 1) */ - char *sslkey; /* client key filename */ - char *sslcert; /* client certificate filename */ - char *sslrootcert; /* root certificate filename */ - char *sslcrl; /* certificate revocation list filename */ - char *requirepeer; /* required peer credentials for local sockets */ - -#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) - char *krbsrvname; /* Kerberos service name */ -#endif - - /* Optional file to write trace info to */ - FILE *Pfdebug; - - /* Callback procedures for notice message processing */ - PGNoticeHooks noticeHooks; - - /* Event procs registered via PQregisterEventProc */ - PGEvent *events; /* expandable array of event data */ - int nEvents; /* number of active events */ - int eventArraySize; /* allocated array size */ - - /* Status indicators */ - ConnStatusType status; - PGAsyncStatusType asyncStatus; - PGTransactionStatusType xactStatus; /* never changes to ACTIVE */ - PGQueryClass queryclass; - char *last_query; /* last SQL command, or NULL if unknown */ - char last_sqlstate[6]; /* last reported SQLSTATE */ - bool options_valid; /* true if OK to attempt connection */ - bool nonblocking; /* whether this connection is using nonblock - * sending semantics */ - bool singleRowMode; /* return current query result row-by-row? */ - char copy_is_binary; /* 1 = copy binary, 0 = copy text */ - int copy_already_done; /* # bytes already returned in COPY - * OUT */ - PGnotify *notifyHead; /* oldest unreported Notify msg */ - PGnotify *notifyTail; /* newest unreported Notify msg */ - - /* Connection data */ - /* See PQconnectPoll() for how we use 'int' and not 'pgsocket'. */ - pgsocket sock; /* FD for socket, PGINVALID_SOCKET if - * unconnected */ - SockAddr laddr; /* Local address */ - SockAddr raddr; /* Remote address */ - ProtocolVersion pversion; /* FE/BE protocol version in use */ - int sversion; /* server version, e.g. 70401 for 7.4.1 */ - bool auth_req_received; /* true if any type of auth req - * received */ - bool password_needed; /* true if server demanded a password */ - bool dot_pgpass_used; /* true if used .pgpass */ - bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */ - bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */ - - /* Transient state needed while establishing connection */ - struct addrinfo *addrlist; /* list of possible backend addresses */ - struct addrinfo *addr_cur; /* the one currently being tried */ - int addrlist_family; /* needed to know how to free addrlist */ - PGSetenvStatusType setenv_state; /* for 2.0 protocol only */ - const PQEnvironmentOption *next_eo; - bool send_appname; /* okay to send application_name? */ - - /* Miscellaneous stuff */ - int be_pid; /* PID of backend --- needed for cancels */ - int be_key; /* key of backend --- needed for cancels */ - char md5Salt[4]; /* password salt received from backend */ - pgParameterStatus *pstatus; /* ParameterStatus data */ - int client_encoding; /* encoding id */ - bool std_strings; /* standard_conforming_strings */ - PGVerbosity verbosity; /* error/notice message verbosity */ - PGContextVisibility show_context; /* whether to show CONTEXT field */ - PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */ - - /* Buffer for data received from backend and not yet processed */ - char *inBuffer; /* currently allocated buffer */ - int inBufSize; /* allocated size of buffer */ - int inStart; /* offset to first unconsumed data in buffer */ - int inCursor; /* next byte to tentatively consume */ - int inEnd; /* offset to first position after avail data */ - - /* Buffer for data not yet sent to backend */ - char *outBuffer; /* currently allocated buffer */ - int outBufSize; /* allocated size of buffer */ - int outCount; /* number of chars waiting in buffer */ - - /* State for constructing messages in outBuffer */ - int outMsgStart; /* offset to msg start (length word); if -1, - * msg has no length word */ - int outMsgEnd; /* offset to msg end (so far) */ - - /* Row processor interface workspace */ - PGdataValue *rowBuf; /* array for passing values to rowProcessor */ - int rowBufLen; /* number of entries allocated in rowBuf */ - - /* Status for asynchronous result construction */ - PGresult *result; /* result being constructed */ - PGresult *next_result; /* next result (used in single-row mode) */ - - /* Assorted state for SSL, GSS, etc */ - -#ifdef USE_SSL - bool allow_ssl_try; /* Allowed to try SSL negotiation */ - bool wait_ssl_try; /* Delay SSL negotiation until after - * attempting normal connection */ - bool ssl_in_use; -#ifdef USE_OPENSSL - SSL *ssl; /* SSL status, if have SSL connection */ - X509 *peer; /* X509 cert of server */ -#ifdef USE_SSL_ENGINE - ENGINE *engine; /* SSL engine, if any */ -#else - void *engine; /* dummy field to keep struct the same if - * OpenSSL version changes */ -#endif -#endif /* USE_OPENSSL */ -#endif /* USE_SSL */ - -#ifdef ENABLE_GSS - gss_ctx_id_t gctx; /* GSS context */ - gss_name_t gtarg_nam; /* GSS target name */ - gss_buffer_desc ginbuf; /* GSS input token */ - gss_buffer_desc goutbuf; /* GSS output token */ -#endif - -#ifdef ENABLE_SSPI -#ifndef ENABLE_GSS - gss_buffer_desc ginbuf; /* GSS input token */ -#else - char *gsslib; /* What GSS librart to use ("gssapi" or - * "sspi") */ -#endif - CredHandle *sspicred; /* SSPI credentials handle */ - CtxtHandle *sspictx; /* SSPI context */ - char *sspitarget; /* SSPI target name */ - int usesspi; /* Indicate if SSPI is in use on the - * connection */ -#endif - - /* Buffer for current error message */ - PQExpBufferData errorMessage; /* expansible string */ - - /* Buffer for receiving various parts of messages */ - PQExpBufferData workBuffer; /* expansible string */ -}; - -/* PGcancel stores all data necessary to cancel a connection. A copy of this - * data is required to safely cancel a connection running on a different - * thread. - */ -struct pg_cancel -{ - SockAddr raddr; /* Remote address */ - int be_pid; /* PID of backend --- needed for cancels */ - int be_key; /* key of backend --- needed for cancels */ -}; - - -/* String descriptions of the ExecStatusTypes. - * direct use of this array is deprecated; call PQresStatus() instead. - */ -extern char *const pgresStatus[]; - - -#ifdef USE_SSL - -#ifndef WIN32 -#define USER_CERT_FILE ".postgresql/postgresql.crt" -#define USER_KEY_FILE ".postgresql/postgresql.key" -#define ROOT_CERT_FILE ".postgresql/root.crt" -#define ROOT_CRL_FILE ".postgresql/root.crl" -#else -/* On Windows, the "home" directory is already PostgreSQL-specific */ -#define USER_CERT_FILE "postgresql.crt" -#define USER_KEY_FILE "postgresql.key" -#define ROOT_CERT_FILE "root.crt" -#define ROOT_CRL_FILE "root.crl" -#endif - -#endif /* USE_SSL */ - -/* ---------------- - * Internal functions of libpq - * Functions declared here need to be visible across files of libpq, - * but are not intended to be called by applications. We use the - * convention "pqXXX" for internal functions, vs. the "PQxxx" names - * used for application-visible routines. - * ---------------- - */ - -/* === in fe-connect.c === */ - -extern void pqDropConnection(PGconn *conn, bool flushInput); -extern int pqPacketSend(PGconn *conn, char pack_type, - const void *buf, size_t buf_len); -extern bool pqGetHomeDirectory(char *buf, int bufsize); - -#ifdef ENABLE_THREAD_SAFETY -extern pgthreadlock_t pg_g_threadlock; - -#define PGTHREAD_ERROR(msg) \ - do { \ - fprintf(stderr, "%s\n", msg); \ - abort(); \ - } while (0) - - -#define pglock_thread() pg_g_threadlock(true) -#define pgunlock_thread() pg_g_threadlock(false) -#else -#define pglock_thread() ((void) 0) -#define pgunlock_thread() ((void) 0) -#endif - -/* === in fe-exec.c === */ - -extern void pqSetResultError(PGresult *res, const char *msg); -extern void pqCatenateResultError(PGresult *res, const char *msg); -extern void *pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary); -extern char *pqResultStrdup(PGresult *res, const char *str); -extern void pqClearAsyncResult(PGconn *conn); -extern void pqSaveErrorResult(PGconn *conn); -extern PGresult *pqPrepareAsyncResult(PGconn *conn); -extern void pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...) pg_attribute_printf(2, 3); -extern void pqSaveMessageField(PGresult *res, char code, - const char *value); -extern void pqSaveParameterStatus(PGconn *conn, const char *name, - const char *value); -extern int pqRowProcessor(PGconn *conn, const char **errmsgp); -extern void pqHandleSendFailure(PGconn *conn); - -/* === in fe-protocol2.c === */ - -extern PostgresPollingStatusType pqSetenvPoll(PGconn *conn); - -extern char *pqBuildStartupPacket2(PGconn *conn, int *packetlen, - const PQEnvironmentOption *options); -extern void pqParseInput2(PGconn *conn); -extern int pqGetCopyData2(PGconn *conn, char **buffer, int async); -extern int pqGetline2(PGconn *conn, char *s, int maxlen); -extern int pqGetlineAsync2(PGconn *conn, char *buffer, int bufsize); -extern int pqEndcopy2(PGconn *conn); -extern PGresult *pqFunctionCall2(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, - int result_is_int, - const PQArgBlock *args, int nargs); - -/* === in fe-protocol3.c === */ - -extern char *pqBuildStartupPacket3(PGconn *conn, int *packetlen, - const PQEnvironmentOption *options); -extern void pqParseInput3(PGconn *conn); -extern int pqGetErrorNotice3(PGconn *conn, bool isError); -extern void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res, - PGVerbosity verbosity, PGContextVisibility show_context); -extern int pqGetCopyData3(PGconn *conn, char **buffer, int async); -extern int pqGetline3(PGconn *conn, char *s, int maxlen); -extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize); -extern int pqEndcopy3(PGconn *conn); -extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, - int *result_buf, int *actual_result_len, - int result_is_int, - const PQArgBlock *args, int nargs); - -/* === in fe-misc.c === */ - - /* - * "Get" and "Put" routines return 0 if successful, EOF if not. Note that for - * Get, EOF merely means the buffer is exhausted, not that there is - * necessarily any error. - */ -extern int pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn); -extern int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn); -extern int pqGetc(char *result, PGconn *conn); -extern int pqPutc(char c, PGconn *conn); -extern int pqGets(PQExpBuffer buf, PGconn *conn); -extern int pqGets_append(PQExpBuffer buf, PGconn *conn); -extern int pqPuts(const char *s, PGconn *conn); -extern int pqGetnchar(char *s, size_t len, PGconn *conn); -extern int pqSkipnchar(size_t len, PGconn *conn); -extern int pqPutnchar(const char *s, size_t len, PGconn *conn); -extern int pqGetInt(int *result, size_t bytes, PGconn *conn); -extern int pqPutInt(int value, size_t bytes, PGconn *conn); -extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn); -extern int pqPutMsgEnd(PGconn *conn); -extern int pqReadData(PGconn *conn); -extern int pqFlush(PGconn *conn); -extern int pqWait(int forRead, int forWrite, PGconn *conn); -extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn, - time_t finish_time); -extern int pqReadReady(PGconn *conn); -extern int pqWriteReady(PGconn *conn); - -/* === in fe-secure.c === */ - -extern int pqsecure_initialize(PGconn *); -extern void pqsecure_destroy(void); -extern PostgresPollingStatusType pqsecure_open_client(PGconn *); -extern void pqsecure_close(PGconn *); -extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len); -extern ssize_t pqsecure_write(PGconn *, const void *ptr, size_t len); -extern ssize_t pqsecure_raw_read(PGconn *, void *ptr, size_t len); -extern ssize_t pqsecure_raw_write(PGconn *, const void *ptr, size_t len); - -#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) -extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending); -extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, - bool got_epipe); -#endif - -/* - * The SSL implementation provides these functions (fe-secure-openssl.c) - */ -extern void pgtls_init_library(bool do_ssl, int do_crypto); -extern int pgtls_init(PGconn *conn); -extern PostgresPollingStatusType pgtls_open_client(PGconn *conn); -extern void pgtls_close(PGconn *conn); -extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len); -extern bool pgtls_read_pending(PGconn *conn); -extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); - -/* - * this is so that we can check if a connection is non-blocking internally - * without the overhead of a function call - */ -#define pqIsnonblocking(conn) ((conn)->nonblocking) - -#ifdef ENABLE_NLS -extern char *libpq_gettext(const char *msgid) pg_attribute_format_arg(1); -extern char *libpq_ngettext(const char *msgid, const char *msgid_plural, unsigned long n) pg_attribute_format_arg(1) pg_attribute_format_arg(2); -#else -#define libpq_gettext(x) (x) -#define libpq_ngettext(s, p, n) ((n) == 1 ? (s) : (p)) -#endif - -/* - * These macros are needed to let error-handling code be portable between - * Unix and Windows. (ugh) - */ -#ifdef WIN32 -#define SOCK_ERRNO (WSAGetLastError()) -#define SOCK_STRERROR winsock_strerror -#define SOCK_ERRNO_SET(e) WSASetLastError(e) -#else -#define SOCK_ERRNO errno -#define SOCK_STRERROR pqStrerror -#define SOCK_ERRNO_SET(e) (errno = (e)) -#endif - -#endif /* LIBPQ_INT_H */ diff --git a/libpq/libpq/.gitignore b/libpq/libpq/.gitignore new file mode 100644 index 0000000..620b4c8 --- /dev/null +++ b/libpq/libpq/.gitignore @@ -0,0 +1,3 @@ +# Generated version.h. +# +version.h diff --git a/libpq/libpq/buildfile b/libpq/libpq/buildfile new file mode 100644 index 0000000..d77ccf7 --- /dev/null +++ b/libpq/libpq/buildfile @@ -0,0 +1,233 @@ +# file : libpq/buildfile +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL Licenes; see accompanying COPYRIGHT file + +import imp_libs = libssl%lib{ssl} +import imp_libs += libcrypto%lib{crypto} + +# Exclude source code of unused features (authentication methods, etc). +# +# @@ When it becomes possible (probably with ad hoc rules), generate +# libpqdll.map and libpqdll.def on the fly from pq/exports.txt applying +# regex replace to its lines and adding prologue/epilogue. +# +lib{pq}: {h }{* -version} \ + {h }{ version} \ + pq/{h c}{* -fe-gssapi-common -fe-secure-gssapi -*win32*} \ + mb/{ c}{* } \ + port/{h c}{* -strlcpy -getaddrinfo -inet_aton -*win32*} \ + common/{ c}{* } \ + include/{h }{** } \ + {def }{libpqdll } \ + {file}{libpqdll.map } \ + pq/{file}{pg_service.conf.sample } \ + $imp_libs + +tclass = $c.target.class +tsys = $c.target.system + +bsd = ($tclass == 'bsd') +macos = ($tclass == 'macos') +windows = ($tclass == 'windows') + +lib{pq}: port/c{strlcpy}: include = (!$bsd && !$macos) + +lib{pq}: pq/{h c}{*win32* } \ + port/{h c}{*win32* +getaddrinfo +inet_aton}: include = $windows + +# The version file is an internal one (it is only included from pg_config.h) +# so we don't distribute nor install it (see below). +# +h{version}: in{version} $src_root/manifest + +# Build options. +# +# Note that the upstream package also defines a bunch of the VAL_* macros +# (VAL_CONFIGURE, VAL_CC, etc) that are used in get_configdata(), if defined. +# We will omit them for the sake of simplicity. +# +c.poptions += -DFRONTEND -DUNSAFE_STAT_OK -DSO_MAJOR_VERSION=$abi_major + +if! $windows + # Note that the upstream package uses -pthread compiler/linker option. It is + # currently unsupported by build2, so we use -D_REENTRANT and -lpthread + # preprocessor/linker options instead. We also omit -D_THREAD_SAFE (synonym + # for -D_REENTRANT) and Solaris-specific -D_POSIX_PTHREAD_SEMANTICS. + # + c.poptions += -D_REENTRANT +else + # Note that the upstream package defines the WIN32 macro for VC only, + # relying on the fact that MinGW GCC defines it by default. However, the + # macro disappears from the default ones if to compile with -std=c9x (as we + # do). So we define it for both VC and MinGW GCC. + # + # It's tempting to move this definition to libpq/pg_config.h. However this + # header is not included into all files that use the macro, for example, + # libpq/port/open.c. + # + c.poptions += -DWIN32 + +# Note that we need to add "-I$src_root" for the headers auto-generating +# machinery to work properly. +# +c.poptions =+ "-I$out_root" "-I$src_root" "-I$src_base" "-I$src_base/port" \ + "-I$src_base/pq" "-I$src_base/include" + +switch $tclass, $tsys +{ + case 'linux' + c.poptions += -D_GNU_SOURCE + + case 'windows', 'mingw32' + { + c.poptions += -DBUILDING_DLL -DEXEC_BACKEND + c.poptions =+ "-I$src_base/include/port/win32" + } + case 'windows' + { + # Probably some of the *WIN* macro definitions are not really required, + # but let's keep all of them for good measure. + # + c.poptions += -DEXEC_BACKEND -D_WINDLL -D__WINDOWS__ -D__WIN32__ -D_MBCS \ + -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE + + c.poptions =+ "-I$src_base/include/port/win32_msvc" \ + "-I$src_base/include/port/win32" + } +} + +# Define SYSCONFDIR macro. This path is used as a last resort for the +# pg_service.conf file search (see pq/fe-connect.c for details). +# +# The whole idea feels utterly broken (hello cross-compilation) so we will +# just do bare minimum and wait and see. +# +# @@ We should probably allow to configure this macros via configuration +# variable config.libpq.sysconfdir. +# +# For the upstream package if the resulted sysconfdir path doesn't contain the +# 'postgres' or 'pgsql' substring then the '/postgresql' suffix is +# automatically appended (see the upstream INSTALL file for details). Note +# that the same rule is applied for the datadir and docdir paths. Also if the +# root directory is /usr, then the resulting sysconfdir path is +# /etc/postgresql (rather than /usr/etc/postgresql). +# +# Let's do the same for the sysconfdir to increase the chance that libpq will +# find the configuration file. Note that we don't install anything at this +# path and don't amend the install.data and install.doc path variables. We +# also use the same default path as the upstream package. Also note that on +# Windows the default path doesn't make any sense so let's make it empty +# instead. +# +if ($install.root != [null]) +{ + root = $install.resolve($install.root) + sysconfdir = ($windows || $root != /usr ? $root/etc : /etc) + + if! $regex.match("$sysconfdir", '.*(pgsql|postgresql).*') + sysconfdir = $sysconfdir/postgresql +} +else + sysconfdir = ($windows ? '' : /usr/local/pgsql/etc) + +# Escape backslashes and quotes in the directory path prior to representing it +# as C string literals. +# +sd = $regex.replace($sysconfdir, '(\\|")', '\\\1') + +# If we ever enable National Language Support then we will need to define the +# LOCALEDIR macro as well. It refers to the locale data directory and should +# be $install.data/locale by default. We will also need to install this +# directory (see configure script --enable-nls options and the libpq/po +# directory in the upstream package for details). +# +pq/obj{fe-connect}: c.poptions += -DSYSCONFDIR="\"$sd\"" + +switch $c.class +{ + case 'gcc' + { + # Omit -fexcess-precision=standard since -std=9x implies it. + # + c.coptions += -fno-strict-aliasing -fwrapv + + # Disable warnings that pop up with -Wall -Wextra. Upstream doesn't seem + # to care about these and it is not easy to disable specific warnings in a + # way that works across compilers/version (some -Wno-* options are only + # recognized in newer versions). + # + c.coptions += -Wno-all -Wno-extra + } + case 'msvc' + { + c.coptions += /GF + + # Disable warnings that pop up with /W3. + # + c.coptions += /wd4018 /wd4244 /wd4267 + } +} + +# On Windows the upstream package also adds the resource file to the library. +# The file contains only the version information. First, libpq.rc is produced +# from libpq.rc.in with the following command: +# +# sed -e 's/\(VERSION.*\),0 *$/\1,'`date '+%y%j' | \ +# sed 's/^0*//'`'/' libpq.rc.in >libpq.rc +# +# Then libpq.rc is compiled with: +# +# windres -i libpq.rc -o libpqrc.o +# +# Afterwards libpqrc.o is linked to the library. +# +# @@ Currently we don't have support for the first two steps. +# +switch $tclass, $tsys +{ + case 'windows', 'mingw32' + c.libs += -lsecur32 -lws2_32 + + case 'windows' + c.libs += secur32.lib ws2_32.lib advapi32.lib + + case 'linux' | 'bsd' + { + # Make sure all symbols are resolvable. + # + c.loptions += -Wl,--no-undefined + + c.loptions += "-Wl,--version-script=$src_base/libpqdll.map" + + c.libs += -lpthread + } + + default + c.libs += -lpthread +} + +# Export options. +# +lib{pq}: cc.export.poptions = "-I$src_base" "-I$src_base/pq" \ + "-I$src_base/include" + +# See bootstrap.build for details. +# +if $version.pre_release + lib{pq}: bin.lib.version = @"-$version.project_id" +else + lib{pq}: bin.lib.version = @"-$abi_major" linux@"$abi_major.$abi_minor" + +# Install the bare minimum of headers not recreating subdirectories. +# +# Note that upstream also installs several 'unofficial API' headers, that we +# won't install. +# +h{*}: install = false + +for h: pq/{libpq-fe libpq-events} include/postgres_ext pg_config_ext + h{$h}@./$path.directory($h): install = include/ + +# Install the config file example as the upstream does. +# +pq/file{pg_service.conf.sample}@pq/: install = data/ diff --git a/libpq/libpq/common/base64.c b/libpq/libpq/common/base64.c new file mode 120000 index 0000000..6883927 --- /dev/null +++ b/libpq/libpq/common/base64.c @@ -0,0 +1 @@ +../../../upstream/src/common/base64.c \ No newline at end of file diff --git a/libpq/libpq/common/ip.c b/libpq/libpq/common/ip.c new file mode 120000 index 0000000..48e8123 --- /dev/null +++ b/libpq/libpq/common/ip.c @@ -0,0 +1 @@ +../../../upstream/src/common/ip.c \ No newline at end of file diff --git a/libpq/libpq/common/link-canary.c b/libpq/libpq/common/link-canary.c new file mode 120000 index 0000000..cf578d8 --- /dev/null +++ b/libpq/libpq/common/link-canary.c @@ -0,0 +1 @@ +../../../upstream/src/common/link-canary.c \ No newline at end of file diff --git a/libpq/libpq/common/md5.c b/libpq/libpq/common/md5.c new file mode 120000 index 0000000..a2eae90 --- /dev/null +++ b/libpq/libpq/common/md5.c @@ -0,0 +1 @@ +../../../upstream/src/common/md5.c \ No newline at end of file diff --git a/libpq/libpq/common/saslprep.c b/libpq/libpq/common/saslprep.c new file mode 120000 index 0000000..5f5215d --- /dev/null +++ b/libpq/libpq/common/saslprep.c @@ -0,0 +1 @@ +../../../upstream/src/common/saslprep.c \ No newline at end of file diff --git a/libpq/libpq/common/scram-common.c b/libpq/libpq/common/scram-common.c new file mode 120000 index 0000000..11927e2 --- /dev/null +++ b/libpq/libpq/common/scram-common.c @@ -0,0 +1 @@ +../../../upstream/src/common/scram-common.c \ No newline at end of file diff --git a/libpq/libpq/common/sha2_openssl.c b/libpq/libpq/common/sha2_openssl.c new file mode 120000 index 0000000..4d52df2 --- /dev/null +++ b/libpq/libpq/common/sha2_openssl.c @@ -0,0 +1 @@ +../../../upstream/src/common/sha2_openssl.c \ No newline at end of file diff --git a/libpq/libpq/common/unicode_norm.c b/libpq/libpq/common/unicode_norm.c new file mode 120000 index 0000000..fdb3f72 --- /dev/null +++ b/libpq/libpq/common/unicode_norm.c @@ -0,0 +1 @@ +../../../upstream/src/common/unicode_norm.c \ No newline at end of file diff --git a/libpq/libpq/include/c.h b/libpq/libpq/include/c.h new file mode 120000 index 0000000..6f95f77 --- /dev/null +++ b/libpq/libpq/include/c.h @@ -0,0 +1 @@ +../../../upstream/src/include/c.h \ No newline at end of file diff --git a/libpq/libpq/include/common b/libpq/libpq/include/common new file mode 120000 index 0000000..4379965 --- /dev/null +++ b/libpq/libpq/include/common @@ -0,0 +1 @@ +../../../upstream/src/include/common \ No newline at end of file diff --git a/libpq/libpq/include/getaddrinfo.h b/libpq/libpq/include/getaddrinfo.h new file mode 120000 index 0000000..7ab1ba8 --- /dev/null +++ b/libpq/libpq/include/getaddrinfo.h @@ -0,0 +1 @@ +../../../upstream/src/include/getaddrinfo.h \ No newline at end of file diff --git a/libpq/libpq/include/libpq/libpq-fs.h b/libpq/libpq/include/libpq/libpq-fs.h new file mode 120000 index 0000000..9030b6b --- /dev/null +++ b/libpq/libpq/include/libpq/libpq-fs.h @@ -0,0 +1 @@ +../../../../upstream/src/include/libpq/libpq-fs.h \ No newline at end of file diff --git a/libpq/libpq/include/libpq/pqcomm.h b/libpq/libpq/include/libpq/pqcomm.h new file mode 120000 index 0000000..69de3bc --- /dev/null +++ b/libpq/libpq/include/libpq/pqcomm.h @@ -0,0 +1 @@ +../../../../upstream/src/include/libpq/pqcomm.h \ No newline at end of file diff --git a/libpq/libpq/include/mb/pg_wchar.h b/libpq/libpq/include/mb/pg_wchar.h new file mode 120000 index 0000000..ed65657 --- /dev/null +++ b/libpq/libpq/include/mb/pg_wchar.h @@ -0,0 +1 @@ +../../../../upstream/src/include/mb/pg_wchar.h \ No newline at end of file diff --git a/libpq/libpq/include/pg_config_manual.h b/libpq/libpq/include/pg_config_manual.h new file mode 120000 index 0000000..485eb76 --- /dev/null +++ b/libpq/libpq/include/pg_config_manual.h @@ -0,0 +1 @@ +../../../upstream/src/include/pg_config_manual.h \ No newline at end of file diff --git a/libpq/libpq/include/port.h b/libpq/libpq/include/port.h new file mode 120000 index 0000000..82aed06 --- /dev/null +++ b/libpq/libpq/include/port.h @@ -0,0 +1 @@ +../../../upstream/src/include/port.h \ No newline at end of file diff --git a/libpq/libpq/include/port/darwin.h b/libpq/libpq/include/port/darwin.h new file mode 120000 index 0000000..7844da8 --- /dev/null +++ b/libpq/libpq/include/port/darwin.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/darwin.h \ No newline at end of file diff --git a/libpq/libpq/include/port/freebsd.h b/libpq/libpq/include/port/freebsd.h new file mode 120000 index 0000000..7685fa5 --- /dev/null +++ b/libpq/libpq/include/port/freebsd.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/freebsd.h \ No newline at end of file diff --git a/libpq/libpq/include/port/linux.h b/libpq/libpq/include/port/linux.h new file mode 120000 index 0000000..3e054ce --- /dev/null +++ b/libpq/libpq/include/port/linux.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/linux.h \ No newline at end of file diff --git a/libpq/libpq/include/port/pg_bswap.h b/libpq/libpq/include/port/pg_bswap.h new file mode 120000 index 0000000..876bcb7 --- /dev/null +++ b/libpq/libpq/include/port/pg_bswap.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/pg_bswap.h \ No newline at end of file diff --git a/libpq/libpq/include/port/win32 b/libpq/libpq/include/port/win32 new file mode 120000 index 0000000..306f506 --- /dev/null +++ b/libpq/libpq/include/port/win32 @@ -0,0 +1 @@ +../../../../upstream/src/include/port/win32 \ No newline at end of file diff --git a/libpq/libpq/include/port/win32.h b/libpq/libpq/include/port/win32.h new file mode 120000 index 0000000..f48b8ef --- /dev/null +++ b/libpq/libpq/include/port/win32.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/win32.h \ No newline at end of file diff --git a/libpq/libpq/include/port/win32_msvc b/libpq/libpq/include/port/win32_msvc new file mode 120000 index 0000000..bf2a9ef --- /dev/null +++ b/libpq/libpq/include/port/win32_msvc @@ -0,0 +1 @@ +../../../../upstream/src/include/port/win32_msvc \ No newline at end of file diff --git a/libpq/libpq/include/port/win32_port.h b/libpq/libpq/include/port/win32_port.h new file mode 120000 index 0000000..c91e3e1 --- /dev/null +++ b/libpq/libpq/include/port/win32_port.h @@ -0,0 +1 @@ +../../../../upstream/src/include/port/win32_port.h \ No newline at end of file diff --git a/libpq/libpq/include/postgres_ext.h b/libpq/libpq/include/postgres_ext.h new file mode 120000 index 0000000..d0a22aa --- /dev/null +++ b/libpq/libpq/include/postgres_ext.h @@ -0,0 +1 @@ +../../../upstream/src/include/postgres_ext.h \ No newline at end of file diff --git a/libpq/libpq/include/postgres_fe.h b/libpq/libpq/include/postgres_fe.h new file mode 120000 index 0000000..5277360 --- /dev/null +++ b/libpq/libpq/include/postgres_fe.h @@ -0,0 +1 @@ +../../../upstream/src/include/postgres_fe.h \ No newline at end of file diff --git a/libpq/libpq/libpqdll.def b/libpq/libpq/libpqdll.def new file mode 100644 index 0000000..d74056c --- /dev/null +++ b/libpq/libpq/libpqdll.def @@ -0,0 +1,178 @@ +;LIBRARY LIBPQ +EXPORTS + PQconnectdb @ 1 + PQsetdbLogin @ 2 + PQconndefaults @ 3 + PQfinish @ 4 + PQreset @ 5 + PQrequestCancel @ 6 + PQdb @ 7 + PQuser @ 8 + PQpass @ 9 + PQhost @ 10 + PQport @ 11 + PQtty @ 12 + PQoptions @ 13 + PQstatus @ 14 + PQerrorMessage @ 15 + PQsocket @ 16 + PQbackendPID @ 17 + PQtrace @ 18 + PQuntrace @ 19 + PQsetNoticeProcessor @ 20 + PQexec @ 21 + PQnotifies @ 22 + PQsendQuery @ 23 + PQgetResult @ 24 + PQisBusy @ 25 + PQconsumeInput @ 26 + PQgetline @ 27 + PQputline @ 28 + PQgetlineAsync @ 29 + PQputnbytes @ 30 + PQendcopy @ 31 + PQfn @ 32 + PQresultStatus @ 33 + PQntuples @ 34 + PQnfields @ 35 + PQbinaryTuples @ 36 + PQfname @ 37 + PQfnumber @ 38 + PQftype @ 39 + PQfsize @ 40 + PQfmod @ 41 + PQcmdStatus @ 42 + PQoidStatus @ 43 + PQcmdTuples @ 44 + PQgetvalue @ 45 + PQgetlength @ 46 + PQgetisnull @ 47 + PQclear @ 48 + PQmakeEmptyPGresult @ 49 + PQprint @ 50 + PQdisplayTuples @ 51 + PQprintTuples @ 52 + lo_open @ 53 + lo_close @ 54 + lo_read @ 55 + lo_write @ 56 + lo_lseek @ 57 + lo_creat @ 58 + lo_tell @ 59 + lo_unlink @ 60 + lo_import @ 61 + lo_export @ 62 + pgresStatus @ 63 + PQmblen @ 64 + PQresultErrorMessage @ 65 + PQresStatus @ 66 + termPQExpBuffer @ 67 + appendPQExpBufferChar @ 68 + initPQExpBuffer @ 69 + resetPQExpBuffer @ 70 + PQoidValue @ 71 + PQclientEncoding @ 72 + PQenv2encoding @ 73 + appendBinaryPQExpBuffer @ 74 + appendPQExpBufferStr @ 75 + destroyPQExpBuffer @ 76 + createPQExpBuffer @ 77 + PQconninfoFree @ 78 + PQconnectPoll @ 79 + PQconnectStart @ 80 + PQflush @ 81 + PQisnonblocking @ 82 + PQresetPoll @ 83 + PQresetStart @ 84 + PQsetClientEncoding @ 85 + PQsetnonblocking @ 86 + PQfreeNotify @ 87 + PQescapeString @ 88 + PQescapeBytea @ 89 + printfPQExpBuffer @ 90 + appendPQExpBuffer @ 91 + pg_encoding_to_char @ 92 + pg_utf_mblen @ 93 + PQunescapeBytea @ 94 + PQfreemem @ 95 + PQtransactionStatus @ 96 + PQparameterStatus @ 97 + PQprotocolVersion @ 98 + PQsetErrorVerbosity @ 99 + PQsetNoticeReceiver @ 100 + PQexecParams @ 101 + PQsendQueryParams @ 102 + PQputCopyData @ 103 + PQputCopyEnd @ 104 + PQgetCopyData @ 105 + PQresultErrorField @ 106 + PQftable @ 107 + PQftablecol @ 108 + PQfformat @ 109 + PQexecPrepared @ 110 + PQsendQueryPrepared @ 111 + PQdsplen @ 112 + PQserverVersion @ 113 + PQgetssl @ 114 + pg_char_to_encoding @ 115 + pg_valid_server_encoding @ 116 + pqsignal @ 117 + PQprepare @ 118 + PQsendPrepare @ 119 + PQgetCancel @ 120 + PQfreeCancel @ 121 + PQcancel @ 122 + lo_create @ 123 + PQinitSSL @ 124 + PQregisterThreadLock @ 125 + PQescapeStringConn @ 126 + PQescapeByteaConn @ 127 + PQencryptPassword @ 128 + PQisthreadsafe @ 129 + enlargePQExpBuffer @ 130 + PQnparams @ 131 + PQparamtype @ 132 + PQdescribePrepared @ 133 + PQdescribePortal @ 134 + PQsendDescribePrepared @ 135 + PQsendDescribePortal @ 136 + lo_truncate @ 137 + PQconnectionUsedPassword @ 138 + pg_valid_server_encoding_id @ 139 + PQconnectionNeedsPassword @ 140 + lo_import_with_oid @ 141 + PQcopyResult @ 142 + PQsetResultAttrs @ 143 + PQsetvalue @ 144 + PQresultAlloc @ 145 + PQregisterEventProc @ 146 + PQinstanceData @ 147 + PQsetInstanceData @ 148 + PQresultInstanceData @ 149 + PQresultSetInstanceData @ 150 + PQfireResultCreateEvents @ 151 + PQconninfoParse @ 152 + PQinitOpenSSL @ 153 + PQescapeLiteral @ 154 + PQescapeIdentifier @ 155 + PQconnectdbParams @ 156 + PQconnectStartParams @ 157 + PQping @ 158 + PQpingParams @ 159 + PQlibVersion @ 160 + PQsetSingleRowMode @ 161 + lo_lseek64 @ 162 + lo_tell64 @ 163 + lo_truncate64 @ 164 + PQconninfo @ 165 + PQsslInUse @ 166 + PQsslStruct @ 167 + PQsslAttributeNames @ 168 + PQsslAttribute @ 169 + PQsetErrorContextVisibility @ 170 + PQresultVerboseErrorMessage @ 171 + PQencryptPasswordConn @ 172 + PQresultMemorySize @ 173 + PQhostaddr @ 174 + PQgssEncInUse @ 175 + PQgetgssctx @ 176 diff --git a/libpq/libpq/libpqdll.map b/libpq/libpq/libpqdll.map new file mode 100644 index 0000000..893dc86 --- /dev/null +++ b/libpq/libpq/libpqdll.map @@ -0,0 +1,178 @@ +{ global: +PQconnectdb; +PQsetdbLogin; +PQconndefaults; +PQfinish; +PQreset; +PQrequestCancel; +PQdb; +PQuser; +PQpass; +PQhost; +PQport; +PQtty; +PQoptions; +PQstatus; +PQerrorMessage; +PQsocket; +PQbackendPID; +PQtrace; +PQuntrace; +PQsetNoticeProcessor; +PQexec; +PQnotifies; +PQsendQuery; +PQgetResult; +PQisBusy; +PQconsumeInput; +PQgetline; +PQputline; +PQgetlineAsync; +PQputnbytes; +PQendcopy; +PQfn; +PQresultStatus; +PQntuples; +PQnfields; +PQbinaryTuples; +PQfname; +PQfnumber; +PQftype; +PQfsize; +PQfmod; +PQcmdStatus; +PQoidStatus; +PQcmdTuples; +PQgetvalue; +PQgetlength; +PQgetisnull; +PQclear; +PQmakeEmptyPGresult; +PQprint; +PQdisplayTuples; +PQprintTuples; +lo_open; +lo_close; +lo_read; +lo_write; +lo_lseek; +lo_creat; +lo_tell; +lo_unlink; +lo_import; +lo_export; +pgresStatus; +PQmblen; +PQresultErrorMessage; +PQresStatus; +termPQExpBuffer; +appendPQExpBufferChar; +initPQExpBuffer; +resetPQExpBuffer; +PQoidValue; +PQclientEncoding; +PQenv2encoding; +appendBinaryPQExpBuffer; +appendPQExpBufferStr; +destroyPQExpBuffer; +createPQExpBuffer; +PQconninfoFree; +PQconnectPoll; +PQconnectStart; +PQflush; +PQisnonblocking; +PQresetPoll; +PQresetStart; +PQsetClientEncoding; +PQsetnonblocking; +PQfreeNotify; +PQescapeString; +PQescapeBytea; +printfPQExpBuffer; +appendPQExpBuffer; +pg_encoding_to_char; +pg_utf_mblen; +PQunescapeBytea; +PQfreemem; +PQtransactionStatus; +PQparameterStatus; +PQprotocolVersion; +PQsetErrorVerbosity; +PQsetNoticeReceiver; +PQexecParams; +PQsendQueryParams; +PQputCopyData; +PQputCopyEnd; +PQgetCopyData; +PQresultErrorField; +PQftable; +PQftablecol; +PQfformat; +PQexecPrepared; +PQsendQueryPrepared; +PQdsplen; +PQserverVersion; +PQgetssl; +pg_char_to_encoding; +pg_valid_server_encoding; +pqsignal; +PQprepare; +PQsendPrepare; +PQgetCancel; +PQfreeCancel; +PQcancel; +lo_create; +PQinitSSL; +PQregisterThreadLock; +PQescapeStringConn; +PQescapeByteaConn; +PQencryptPassword; +PQisthreadsafe; +enlargePQExpBuffer; +PQnparams; +PQparamtype; +PQdescribePrepared; +PQdescribePortal; +PQsendDescribePrepared; +PQsendDescribePortal; +lo_truncate; +PQconnectionUsedPassword; +pg_valid_server_encoding_id; +PQconnectionNeedsPassword; +lo_import_with_oid; +PQcopyResult; +PQsetResultAttrs; +PQsetvalue; +PQresultAlloc; +PQregisterEventProc; +PQinstanceData; +PQsetInstanceData; +PQresultInstanceData; +PQresultSetInstanceData; +PQfireResultCreateEvents; +PQconninfoParse; +PQinitOpenSSL; +PQescapeLiteral; +PQescapeIdentifier; +PQconnectdbParams; +PQconnectStartParams; +PQping; +PQpingParams; +PQlibVersion; +PQsetSingleRowMode; +lo_lseek64; +lo_tell64; +lo_truncate64; +PQconninfo; +PQsslInUse; +PQsslStruct; +PQsslAttributeNames; +PQsslAttribute; +PQsetErrorContextVisibility; +PQresultVerboseErrorMessage; +PQencryptPasswordConn; +PQresultMemorySize; +PQhostaddr; +PQgssEncInUse; +PQgetgssctx; + local: *; }; diff --git a/libpq/libpq/mb/encnames.c b/libpq/libpq/mb/encnames.c new file mode 120000 index 0000000..c4e83b6 --- /dev/null +++ b/libpq/libpq/mb/encnames.c @@ -0,0 +1 @@ +../../../upstream/src/backend/utils/mb/encnames.c \ No newline at end of file diff --git a/libpq/libpq/mb/wchar.c b/libpq/libpq/mb/wchar.c new file mode 120000 index 0000000..fdacab3 --- /dev/null +++ b/libpq/libpq/mb/wchar.c @@ -0,0 +1 @@ +../../../upstream/src/backend/utils/mb/wchar.c \ No newline at end of file diff --git a/libpq/libpq/pg_config.h b/libpq/libpq/pg_config.h new file mode 100644 index 0000000..12d418e --- /dev/null +++ b/libpq/libpq/pg_config.h @@ -0,0 +1,369 @@ +/* file : libpq/pg_config.h -*- C -*- + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * For the semantics of the following macros refer to pg_config.h.in.orig, + * pg_config.h.win32.orig, and the upstream's configure.in. + * + * Note that we will explicitly undefine macros that are present in the libpq + * source code but should not be defined. While this is not technically + * required, it simplifies the change tracking (see README-DEV). As a bonus we + * also make sure that they are not get eventually defined by some system + * headers. + */ + +#include /* offsetof() */ + +#include /* OPENSSL_VERSION_NUMBER */ + +/* + * Version. + */ +#undef PG_VERSION +#undef PG_VERSION_NUM +#undef PG_MAJORVERSION +#include + +/* + * Endianess. + */ +#ifdef __FreeBSD__ +# include /* BYTE_ORDER */ +#else +# if defined(_WIN32) +# ifndef BYTE_ORDER +# define BIG_ENDIAN 4321 +# define LITTLE_ENDIAN 1234 +# define BYTE_ORDER LITTLE_ENDIAN +# endif +# else +# include /* BYTE_ORDER/__BYTE_ORDER */ +# ifndef BYTE_ORDER +# ifdef __BYTE_ORDER +# define BYTE_ORDER __BYTE_ORDER +# define BIG_ENDIAN __BIG_ENDIAN +# define LITTLE_ENDIAN __LITTLE_ENDIAN +# else +# error no BYTE_ORDER/__BYTE_ORDER define +# endif +# endif +# endif +#endif + +#if BYTE_ORDER == BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +#endif + +/* + * Types, type sizes and alignments. + */ +#define ALIGNOF_(type) offsetof (struct {char c; type m;}, m) +#define ALIGNOF_DOUBLE ALIGNOF_ (double) +#define ALIGNOF_INT ALIGNOF_ (int) +#define ALIGNOF_LONG ALIGNOF_ (long) +#define ALIGNOF_SHORT ALIGNOF_ (short) + +/* + * GCC and Clang provide __SIZEOF_*__ and __*_TYPE__ predefined macros that we + * use to define the required libpq macros. Note that on Windows long and + * long long types are always of 32 and 64 bits width respectively. + */ +#ifndef _WIN32 +# if __SIZEOF_LONG__ == 8 +# define HAVE_LONG_INT_64 1 +# endif +# ifdef __SIZEOF_LONG_LONG__ +# define HAVE_LONG_LONG_INT 1 +# endif +# if __SIZEOF_LONG_LONG__ == 8 +# define HAVE_LONG_LONG_INT_64 1 +# endif +# if __SIZEOF_LONG_LONG__ > __SIZEOF_DOUBLE__ +# define MAXIMUM_ALIGNOF __SIZEOF_LONG_LONG__ +# else +# define MAXIMUM_ALIGNOF __SIZEOF_DOUBLE__ +# endif +# ifdef __SIZEOF_INT128__ +# define PG_INT128_TYPE __int128 +# define ALIGNOF_PG_INT128_TYPE 16 +# endif +# define PG_INT64_TYPE __INT64_TYPE__ +# define ACCEPT_TYPE_ARG3 socklen_t +# define SIZEOF_SIZE_T __SIZEOF_SIZE_T__ +#else +# define HAVE_LONG_LONG_INT 1 +# define HAVE_LONG_LONG_INT_64 1 +# define MAXIMUM_ALIGNOF 8 +# define PG_INT64_TYPE long long int +# define ACCEPT_TYPE_ARG3 int +# ifdef _WIN64 +# define SIZEOF_SIZE_T 8 +# else +# define SIZEOF_SIZE_T 4 +# endif +#endif + +#define INT64_MODIFIER "ll" +#define SIZEOF_BOOL 1 + +/* + * Specific for FreeBSD. + */ +#ifdef __FreeBSD__ +# define HAVE_STRUCT_CMSGCRED 1 +#endif + +/* + * Specific for Mac OS. + */ +#ifdef __APPLE__ +# define HAVE_DECL_F_FULLFSYNC 1 +#else +# define HAVE_DECL_F_FULLFSYNC 0 +#endif + +/* + * Specific for FreeBSD and Linux. + */ +#if defined(__FreeBSD__) || defined(__linux__) +# define HAVE_STRCHRNUL 1 +#endif + +/* + * Specific for FreeBSD and Mac OS. + */ +#if defined(__FreeBSD__) || defined(__APPLE__) +# define HAVE_DECL_STRLCAT 1 +# define HAVE_DECL_STRLCPY 1 +# define STRERROR_R_INT 1 +# define HAVE_FLS 1 +# define HAVE_GETPEEREID 1 +# define HAVE_STRTOQ 1 +# define HAVE_STRTOUQ 1 +# define HAVE_STRUCT_SOCKADDR_SA_LEN 1 +# define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 +# define HAVE_SYS_SOCKIO_H 1 +# define HAVE_SYS_UCRED_H 1 +# define HAVE_UNION_SEMUN 1 +#else +# define HAVE_DECL_STRLCAT 0 +# define HAVE_DECL_STRLCPY 0 +#endif + +/* + * Specific for POSIX. + */ +#ifndef _WIN32 +# define HAVE_CRYPT 1 +# define HAVE_DECL_FDATASYNC 1 +# define HAVE_DECL_RTLD_GLOBAL 1 +# define HAVE_DECL_RTLD_NOW 1 +# define HAVE_FDATASYNC 1 +# define HAVE_GETADDRINFO 1 +# define HAVE_GETIFADDRS 1 +# define HAVE_IFADDRS_H 1 +# define HAVE_GETPWUID_R 1 +# define HAVE_INET_ATON 1 +# define HAVE_LANGINFO_H 1 +# define HAVE_MKDTEMP 1 +# define HAVE_NETINET_TCP_H 1 +# define HAVE_NET_IF_H 1 +# define HAVE_DECL_POSIX_FADVISE 1 +# define HAVE_POSIX_FADVISE 1 +# define HAVE_RANDOM 1 +# define HAVE_SRANDOM 1 +# define HAVE_STRERROR_R 1 +# define HAVE_STRINGS_H 1 +# define HAVE_SYS_IOCTL_H 1 +# define HAVE_POLL 1 +# define HAVE_POLL_H 1 +# define HAVE_SYS_POLL_H 1 +# define HAVE_SYS_SELECT_H 1 +# define HAVE_SYS_UN_H 1 +# define HAVE_TERMIOS_H 1 +# define HAVE_UNIX_SOCKETS 1 +# define HAVE_UNSETENV 1 +# define USE_INTEGER_DATETIMES 1 +# define HAVE_DLOPEN 1 +# define HAVE_PREAD 1 +# define HAVE_PWRITE 1 +/* + * Specific for Windows. + */ +#else +# define HAVE_DECL_FDATASYNC 0 +# define HAVE_DECL_RTLD_GLOBAL 0 +# define HAVE_DECL_RTLD_NOW 0 +# define HAVE_DECL_POSIX_FADVISE 0 +# define HAVE_GETTIMEOFDAY 1 +# define HAVE_ISINF 1 +# define HAVE_FUNCNAME__FUNCTION 1 +# define USE_REPL_SNPRINTF 1 +#endif + +/* + * Specific for GNU C Library. + */ +#ifdef __GLIBC__ +# define HAVE_GETHOSTBYNAME_R 1 +#endif + +/* + * Specific for (non-) VC. + */ +#ifndef _MSC_VER +# define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1 +# define HAVE__BUILTIN_UNREACHABLE 1 +# define HAVE__BUILTIN_BSWAP16 1 +# define HAVE__BUILTIN_BSWAP32 1 +# define HAVE__BUILTIN_BSWAP64 1 +# define HAVE__BUILTIN_OP_OVERFLOW 1 +#endif + +/* + * Relates to the enabled OpenSSL. + */ +#define USE_OPENSSL 1 +#define HAVE_OPENSSL_INIT_SSL 1 +#define HAVE_ASN1_STRING_GET0_DATA 1 +#define HAVE_BIO_GET_DATA 1 +#define HAVE_BIO_METH_NEW 1 +#define HAVE_SSL_CLEAR_OPTIONS 1 + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +# define HAVE_CRYPTO_LOCK 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +# define HAVE_X509_GET_SIGNATURE_NID 1 +#endif + +#define USE_OPENSSL_RANDOM 1 +#undef USE_DEV_URANDOM +#undef USE_WIN32_RANDOM + +/* + * Common for all supported OSes/compilers. + */ +#define ENABLE_THREAD_SAFETY 1 +#define HAVE_MEMMOVE 1 +#define HAVE_RINT 1 +#define HAVE_DECL_SNPRINTF 1 +#define HAVE_DECL_VSNPRINTF 1 +#define HAVE_DECL_STRNLEN 1 +#define HAVE_DECL_STRTOLL 1 +#define HAVE_DECL_STRTOULL 1 +#define HAVE_FSEEKO 1 +#define HAVE_FUNCNAME__FUNC 1 +#define HAVE_IPV6 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDBOOL_H 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRTOULL 1 +#define HAVE_STRTOF 1 +#define HAVE_TOWLOWER 1 +#define HAVE_WCSTOMBS 1 +#define HAVE_SSL_GET_CURRENT_COMPRESSION 1 +#define HAVE_STRUCT_ADDRINFO 1 +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 +#define BLCKSZ 8192 +#define XLOG_BLCKSZ 8192 +#define PG_KRB_SRVNAM "postgres" +#define PG_PRINTF_ATTRIBUTE printf +#define FLEXIBLE_ARRAY_MEMBER +#define MEMSET_LOOP_LIMIT 1024 +#define DEF_PGPORT 5432 +#define DEF_PGPORT_STR "5432" + +/* + * _Static_assert() was introduced in C11. However, all the latest major + * compilers support it for C99 as well. + */ +#define HAVE__STATIC_ASSERT 1 + +/* + * Undefined macros. + */ + +/* + * The following features are disabled. + */ +#undef USE_ASSERT_CHECKING +#undef ENABLE_NLS +#undef ENABLE_GSS +#undef USE_LDAP + +/* + * Is meaningless if NLS support is disabled (see above and libpq/buildfile for + * details). + */ +#undef LOCALEDIR + +/* + * Is meaningless if GSSAPI support is disabled (see above). It also seems that + * for modern systems including or will work both + * ( just includes ). + */ +#undef HAVE_GSSAPI_H + +/* + * Integer literal LL suffix is optional for C99. + */ +#undef HAVE_LL_CONSTANTS + +/* + * Windows-specific. is included for the latest (>= 1400) VC + * unconditionally. + */ +#undef HAVE_CRTDEFS_H + +/* + * Solaris-specific (getpeerucred() function). + */ +#undef HAVE_GETPEERUCRED + +/* + * Hard to even find any records of these types. + */ +#undef HAVE_INT64 +#undef HAVE_INT8 +#undef HAVE_UINT64 +#undef HAVE_UINT8 + +/* + * Something optimization-related for PowerPC machines (see + * libpq/include/pg_config_manual.h for more details). + */ +#undef HAVE_PPC_LWARX_MUTEX_HINT + +/* + * None of the supported platforms has the '__' prefix for the mentioned + * sockaddr_storage struct members. + */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY +#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN + +/* + * Let's follow Linux man page advise for sync_file_range() function: + * + * This system call is Linux-specific, and should be avoided in portable + * programs. + * + * The macro also seems to be backend-specific. + */ +#undef HAVE_SYNC_FILE_RANGE + +/* + * None of the supported OSes have . FreeBSD and Mac OS have + * (HAVE_SYS_UCRED_H macro). + */ +#undef HAVE_UCRED_H + +/* + * Meaningless as HAVE_STRTOULL and HAVE_STRTOULL are always defined. + */ +#undef HAVE___STRTOLL +#undef HAVE___STRTOULL diff --git a/libpq/libpq/pg_config.h.in.orig b/libpq/libpq/pg_config.h.in.orig new file mode 120000 index 0000000..0232148 --- /dev/null +++ b/libpq/libpq/pg_config.h.in.orig @@ -0,0 +1 @@ +../../upstream/src/include/pg_config.h.in \ No newline at end of file diff --git a/libpq/libpq/pg_config.h.win32.orig b/libpq/libpq/pg_config.h.win32.orig new file mode 120000 index 0000000..9c4d1e1 --- /dev/null +++ b/libpq/libpq/pg_config.h.win32.orig @@ -0,0 +1 @@ +../../upstream/src/include/pg_config.h.win32 \ No newline at end of file diff --git a/libpq/libpq/pg_config_ext.h b/libpq/libpq/pg_config_ext.h new file mode 100644 index 0000000..e3a9abe --- /dev/null +++ b/libpq/libpq/pg_config_ext.h @@ -0,0 +1,19 @@ +/* file : libpq/pg_config_ext.h -*- C -*- + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * For the semantics of the following macros refer to pg_config_ext.h.in.orig, + * pg_config_ext.h.win32.orig, and the upstream's configure.in. + */ + +/* + * Note that is invented by C99 and we can't expect that the libpq + * client is compiled according to this standard. However, when compile with + * GCC, Clang or VC, even requesting C90 standard explicitly, then the header + * and int64_t type are both available. + */ +#include + +#define PG_INT64_TYPE int64_t diff --git a/libpq/libpq/pg_config_ext.h.in.orig b/libpq/libpq/pg_config_ext.h.in.orig new file mode 120000 index 0000000..22f6198 --- /dev/null +++ b/libpq/libpq/pg_config_ext.h.in.orig @@ -0,0 +1 @@ +../../upstream/src/include/pg_config_ext.h.in \ No newline at end of file diff --git a/libpq/libpq/pg_config_ext.h.win32.orig b/libpq/libpq/pg_config_ext.h.win32.orig new file mode 120000 index 0000000..e401e39 --- /dev/null +++ b/libpq/libpq/pg_config_ext.h.win32.orig @@ -0,0 +1 @@ +../../upstream/src/include/pg_config_ext.h.win32 \ No newline at end of file diff --git a/libpq/libpq/pg_config_os.h b/libpq/libpq/pg_config_os.h new file mode 100644 index 0000000..e616265 --- /dev/null +++ b/libpq/libpq/pg_config_os.h @@ -0,0 +1,21 @@ +/* file : libpq/pg_config_os.h -*- C -*- + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * The upstream package makefile creates this file as a symlink to the + * target-specific header in src/include/port/. + */ + +#if defined(__linux__) +# include +#elif defined(__FreeBSD__) +# include +#elif defined(__APPLE__) +# include +#elif defined(_WIN32) +# include +#else +# error this OS is not supported +#endif diff --git a/libpq/libpq/pg_config_paths.h b/libpq/libpq/pg_config_paths.h new file mode 100644 index 0000000..2e67511 --- /dev/null +++ b/libpq/libpq/pg_config_paths.h @@ -0,0 +1,11 @@ +/* file : libpq/pg_config_paths.h -*- C -*- + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * The upstream package makefile creates this file on the fly, dumping a + * number of macro definitions. The libpq source files only use the SYSCONFDIR + * macro (for the configuration we package against) which we define via the -D + * preprocessor option (see buildfile for details). + */ diff --git a/libpq/libpq/port/chklocale.c b/libpq/libpq/port/chklocale.c new file mode 120000 index 0000000..8447432 --- /dev/null +++ b/libpq/libpq/port/chklocale.c @@ -0,0 +1 @@ +../../../upstream/src/port/chklocale.c \ No newline at end of file diff --git a/libpq/libpq/port/getaddrinfo.c b/libpq/libpq/port/getaddrinfo.c new file mode 120000 index 0000000..ca07fe4 --- /dev/null +++ b/libpq/libpq/port/getaddrinfo.c @@ -0,0 +1 @@ +../../../upstream/src/port/getaddrinfo.c \ No newline at end of file diff --git a/libpq/libpq/port/getpeereid.c b/libpq/libpq/port/getpeereid.c new file mode 120000 index 0000000..88e09de --- /dev/null +++ b/libpq/libpq/port/getpeereid.c @@ -0,0 +1 @@ +../../../upstream/src/port/getpeereid.c \ No newline at end of file diff --git a/libpq/libpq/port/inet_aton.c b/libpq/libpq/port/inet_aton.c new file mode 120000 index 0000000..dec85cf --- /dev/null +++ b/libpq/libpq/port/inet_aton.c @@ -0,0 +1 @@ +../../../upstream/src/port/inet_aton.c \ No newline at end of file diff --git a/libpq/libpq/port/inet_net_ntop.c b/libpq/libpq/port/inet_net_ntop.c new file mode 120000 index 0000000..342abc2 --- /dev/null +++ b/libpq/libpq/port/inet_net_ntop.c @@ -0,0 +1 @@ +../../../upstream/src/port/inet_net_ntop.c \ No newline at end of file diff --git a/libpq/libpq/port/noblock.c b/libpq/libpq/port/noblock.c new file mode 120000 index 0000000..912f287 --- /dev/null +++ b/libpq/libpq/port/noblock.c @@ -0,0 +1 @@ +../../../upstream/src/port/noblock.c \ No newline at end of file diff --git a/libpq/libpq/port/open.c b/libpq/libpq/port/open.c new file mode 120000 index 0000000..6cac9e0 --- /dev/null +++ b/libpq/libpq/port/open.c @@ -0,0 +1 @@ +../../../upstream/src/port/open.c \ No newline at end of file diff --git a/libpq/libpq/port/pg_strong_random.c b/libpq/libpq/port/pg_strong_random.c new file mode 120000 index 0000000..911f1c2 --- /dev/null +++ b/libpq/libpq/port/pg_strong_random.c @@ -0,0 +1 @@ +../../../upstream/src/port/pg_strong_random.c \ No newline at end of file diff --git a/libpq/libpq/port/pgsleep.c b/libpq/libpq/port/pgsleep.c new file mode 120000 index 0000000..36040ee --- /dev/null +++ b/libpq/libpq/port/pgsleep.c @@ -0,0 +1 @@ +../../../upstream/src/port/pgsleep.c \ No newline at end of file diff --git a/libpq/libpq/port/pgstrcasecmp.c b/libpq/libpq/port/pgstrcasecmp.c new file mode 120000 index 0000000..7e5b081 --- /dev/null +++ b/libpq/libpq/port/pgstrcasecmp.c @@ -0,0 +1 @@ +../../../upstream/src/port/pgstrcasecmp.c \ No newline at end of file diff --git a/libpq/libpq/port/pthread-win32.h b/libpq/libpq/port/pthread-win32.h new file mode 120000 index 0000000..a4a445d --- /dev/null +++ b/libpq/libpq/port/pthread-win32.h @@ -0,0 +1 @@ +../../../upstream/src/port/pthread-win32.h \ No newline at end of file diff --git a/libpq/libpq/port/snprintf.c b/libpq/libpq/port/snprintf.c new file mode 120000 index 0000000..a73fb8e --- /dev/null +++ b/libpq/libpq/port/snprintf.c @@ -0,0 +1 @@ +../../../upstream/src/port/snprintf.c \ No newline at end of file diff --git a/libpq/libpq/port/strerror.c b/libpq/libpq/port/strerror.c new file mode 120000 index 0000000..733a98c --- /dev/null +++ b/libpq/libpq/port/strerror.c @@ -0,0 +1 @@ +../../../upstream/src/port/strerror.c \ No newline at end of file diff --git a/libpq/libpq/port/strlcpy.c b/libpq/libpq/port/strlcpy.c new file mode 120000 index 0000000..0f3db74 --- /dev/null +++ b/libpq/libpq/port/strlcpy.c @@ -0,0 +1 @@ +../../../upstream/src/port/strlcpy.c \ No newline at end of file diff --git a/libpq/libpq/port/system.c b/libpq/libpq/port/system.c new file mode 120000 index 0000000..80c33eb --- /dev/null +++ b/libpq/libpq/port/system.c @@ -0,0 +1 @@ +../../../upstream/src/port/system.c \ No newline at end of file diff --git a/libpq/libpq/port/thread.c b/libpq/libpq/port/thread.c new file mode 120000 index 0000000..c8f5fbf --- /dev/null +++ b/libpq/libpq/port/thread.c @@ -0,0 +1 @@ +../../../upstream/src/port/thread.c \ No newline at end of file diff --git a/libpq/libpq/port/win32error.c b/libpq/libpq/port/win32error.c new file mode 120000 index 0000000..02fd874 --- /dev/null +++ b/libpq/libpq/port/win32error.c @@ -0,0 +1 @@ +../../../upstream/src/port/win32error.c \ No newline at end of file diff --git a/libpq/libpq/port/win32setlocale.c b/libpq/libpq/port/win32setlocale.c new file mode 120000 index 0000000..ab72c17 --- /dev/null +++ b/libpq/libpq/port/win32setlocale.c @@ -0,0 +1 @@ +../../../upstream/src/port/win32setlocale.c \ No newline at end of file diff --git a/libpq/libpq/pq b/libpq/libpq/pq new file mode 120000 index 0000000..1f95366 --- /dev/null +++ b/libpq/libpq/pq @@ -0,0 +1 @@ +../../upstream/src/interfaces/libpq \ No newline at end of file diff --git a/libpq/libpq/version.h.in b/libpq/libpq/version.h.in new file mode 100644 index 0000000..0dec491 --- /dev/null +++ b/libpq/libpq/version.h.in @@ -0,0 +1,17 @@ +/* file : libpq/version.h.in -*- C -*- + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +#ifndef PG_MAJORVERSION /* Note: using the version macro itself. */ + +#define PG_VERSION "$libpq.version.major$.$libpq.version.minor$" + +/* + * For example, 120001 for 12.1. + */ +#define PG_VERSION_NUM (10000 * $libpq.version.major$ + $libpq.version.minor$) + +#define PG_MAJORVERSION "$libpq.version.major$" + +#endif /* PG_MAJORVERSION */ diff --git a/libpq/manifest b/libpq/manifest new file mode 100644 index 0000000..211af02 --- /dev/null +++ b/libpq/manifest @@ -0,0 +1,25 @@ +: 1 +name: libpq + +# Note: remember to update doc-url below! +# +version: 12.1.0-a.0.z +upstream-version: 12.1 + +project: postgresql +summary: PostgreSQL C API client library +license: PostgreSQL License ; Permissive free software license. +topics: C, PostgreSQL, SQL, relational database +description-file: README +url: https://www.postgresql.org/ +doc-url: https://www.postgresql.org/docs/12/libpq.html +src-url: https://git.build2.org/cgit/packaging/postgresql/postgresql/tree/libpq/ +package-url: https://git.build2.org/cgit/packaging/postgresql/ +email: pgsql-general@postgresql.org ; Mailing list. +package-email: packaging@build2.org ; Mailing list. +build-email: builds@build2.org +builds: all +depends: * build2 >= 0.12.0 +depends: * bpkg >= 0.12.0 +depends: libcrypto >= 1.1.1 +depends: libssl >= 1.1.1 diff --git a/libpq/md5.c b/libpq/md5.c deleted file mode 100644 index 5af54e6..0000000 --- a/libpq/md5.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * md5.c - * - * Implements the MD5 Message-Digest Algorithm as specified in - * RFC 1321. This implementation is a simple one, in that it - * needs every input byte to be buffered before doing any - * calculations. I do not expect this file to be used for - * general purpose MD5'ing of large amounts of data, only for - * generating hashed passwords from limited input. - * - * Sverre H. Huseby - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * src/backend/libpq/md5.c - */ - -/* This is intended to be used in both frontend and backend, so use c.h */ -#include "c.h" - -#include "libpq/md5.h" - - -/* - * PRIVATE FUNCTIONS - */ - - -/* - * The returned array is allocated using malloc. the caller should free it - * when it is no longer needed. - */ -static uint8 * -createPaddedCopyWithLength(const uint8 *b, uint32 *l) -{ - uint8 *ret; - uint32 q; - uint32 len, - newLen448; - uint32 len_high, - len_low; /* 64-bit value split into 32-bit sections */ - - len = ((b == NULL) ? 0 : *l); - newLen448 = len + 64 - (len % 64) - 8; - if (newLen448 <= len) - newLen448 += 64; - - *l = newLen448 + 8; - if ((ret = (uint8 *) malloc(sizeof(uint8) * *l)) == NULL) - return NULL; - - if (b != NULL) - memcpy(ret, b, sizeof(uint8) * len); - - /* pad */ - ret[len] = 0x80; - for (q = len + 1; q < newLen448; q++) - ret[q] = 0x00; - - /* append length as a 64 bit bitcount */ - len_low = len; - /* split into two 32-bit values */ - /* we only look at the bottom 32-bits */ - len_high = len >> 29; - len_low <<= 3; - q = newLen448; - ret[q++] = (len_low & 0xff); - len_low >>= 8; - ret[q++] = (len_low & 0xff); - len_low >>= 8; - ret[q++] = (len_low & 0xff); - len_low >>= 8; - ret[q++] = (len_low & 0xff); - ret[q++] = (len_high & 0xff); - len_high >>= 8; - ret[q++] = (len_high & 0xff); - len_high >>= 8; - ret[q++] = (len_high & 0xff); - len_high >>= 8; - ret[q] = (len_high & 0xff); - - return ret; -} - -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define ROT_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - -static void -doTheRounds(uint32 X[16], uint32 state[4]) -{ - uint32 a, - b, - c, - d; - - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - - /* round 1 */ - a = b + ROT_LEFT((a + F(b, c, d) + X[0] + 0xd76aa478), 7); /* 1 */ - d = a + ROT_LEFT((d + F(a, b, c) + X[1] + 0xe8c7b756), 12); /* 2 */ - c = d + ROT_LEFT((c + F(d, a, b) + X[2] + 0x242070db), 17); /* 3 */ - b = c + ROT_LEFT((b + F(c, d, a) + X[3] + 0xc1bdceee), 22); /* 4 */ - a = b + ROT_LEFT((a + F(b, c, d) + X[4] + 0xf57c0faf), 7); /* 5 */ - d = a + ROT_LEFT((d + F(a, b, c) + X[5] + 0x4787c62a), 12); /* 6 */ - c = d + ROT_LEFT((c + F(d, a, b) + X[6] + 0xa8304613), 17); /* 7 */ - b = c + ROT_LEFT((b + F(c, d, a) + X[7] + 0xfd469501), 22); /* 8 */ - a = b + ROT_LEFT((a + F(b, c, d) + X[8] + 0x698098d8), 7); /* 9 */ - d = a + ROT_LEFT((d + F(a, b, c) + X[9] + 0x8b44f7af), 12); /* 10 */ - c = d + ROT_LEFT((c + F(d, a, b) + X[10] + 0xffff5bb1), 17); /* 11 */ - b = c + ROT_LEFT((b + F(c, d, a) + X[11] + 0x895cd7be), 22); /* 12 */ - a = b + ROT_LEFT((a + F(b, c, d) + X[12] + 0x6b901122), 7); /* 13 */ - d = a + ROT_LEFT((d + F(a, b, c) + X[13] + 0xfd987193), 12); /* 14 */ - c = d + ROT_LEFT((c + F(d, a, b) + X[14] + 0xa679438e), 17); /* 15 */ - b = c + ROT_LEFT((b + F(c, d, a) + X[15] + 0x49b40821), 22); /* 16 */ - - /* round 2 */ - a = b + ROT_LEFT((a + G(b, c, d) + X[1] + 0xf61e2562), 5); /* 17 */ - d = a + ROT_LEFT((d + G(a, b, c) + X[6] + 0xc040b340), 9); /* 18 */ - c = d + ROT_LEFT((c + G(d, a, b) + X[11] + 0x265e5a51), 14); /* 19 */ - b = c + ROT_LEFT((b + G(c, d, a) + X[0] + 0xe9b6c7aa), 20); /* 20 */ - a = b + ROT_LEFT((a + G(b, c, d) + X[5] + 0xd62f105d), 5); /* 21 */ - d = a + ROT_LEFT((d + G(a, b, c) + X[10] + 0x02441453), 9); /* 22 */ - c = d + ROT_LEFT((c + G(d, a, b) + X[15] + 0xd8a1e681), 14); /* 23 */ - b = c + ROT_LEFT((b + G(c, d, a) + X[4] + 0xe7d3fbc8), 20); /* 24 */ - a = b + ROT_LEFT((a + G(b, c, d) + X[9] + 0x21e1cde6), 5); /* 25 */ - d = a + ROT_LEFT((d + G(a, b, c) + X[14] + 0xc33707d6), 9); /* 26 */ - c = d + ROT_LEFT((c + G(d, a, b) + X[3] + 0xf4d50d87), 14); /* 27 */ - b = c + ROT_LEFT((b + G(c, d, a) + X[8] + 0x455a14ed), 20); /* 28 */ - a = b + ROT_LEFT((a + G(b, c, d) + X[13] + 0xa9e3e905), 5); /* 29 */ - d = a + ROT_LEFT((d + G(a, b, c) + X[2] + 0xfcefa3f8), 9); /* 30 */ - c = d + ROT_LEFT((c + G(d, a, b) + X[7] + 0x676f02d9), 14); /* 31 */ - b = c + ROT_LEFT((b + G(c, d, a) + X[12] + 0x8d2a4c8a), 20); /* 32 */ - - /* round 3 */ - a = b + ROT_LEFT((a + H(b, c, d) + X[5] + 0xfffa3942), 4); /* 33 */ - d = a + ROT_LEFT((d + H(a, b, c) + X[8] + 0x8771f681), 11); /* 34 */ - c = d + ROT_LEFT((c + H(d, a, b) + X[11] + 0x6d9d6122), 16); /* 35 */ - b = c + ROT_LEFT((b + H(c, d, a) + X[14] + 0xfde5380c), 23); /* 36 */ - a = b + ROT_LEFT((a + H(b, c, d) + X[1] + 0xa4beea44), 4); /* 37 */ - d = a + ROT_LEFT((d + H(a, b, c) + X[4] + 0x4bdecfa9), 11); /* 38 */ - c = d + ROT_LEFT((c + H(d, a, b) + X[7] + 0xf6bb4b60), 16); /* 39 */ - b = c + ROT_LEFT((b + H(c, d, a) + X[10] + 0xbebfbc70), 23); /* 40 */ - a = b + ROT_LEFT((a + H(b, c, d) + X[13] + 0x289b7ec6), 4); /* 41 */ - d = a + ROT_LEFT((d + H(a, b, c) + X[0] + 0xeaa127fa), 11); /* 42 */ - c = d + ROT_LEFT((c + H(d, a, b) + X[3] + 0xd4ef3085), 16); /* 43 */ - b = c + ROT_LEFT((b + H(c, d, a) + X[6] + 0x04881d05), 23); /* 44 */ - a = b + ROT_LEFT((a + H(b, c, d) + X[9] + 0xd9d4d039), 4); /* 45 */ - d = a + ROT_LEFT((d + H(a, b, c) + X[12] + 0xe6db99e5), 11); /* 46 */ - c = d + ROT_LEFT((c + H(d, a, b) + X[15] + 0x1fa27cf8), 16); /* 47 */ - b = c + ROT_LEFT((b + H(c, d, a) + X[2] + 0xc4ac5665), 23); /* 48 */ - - /* round 4 */ - a = b + ROT_LEFT((a + I(b, c, d) + X[0] + 0xf4292244), 6); /* 49 */ - d = a + ROT_LEFT((d + I(a, b, c) + X[7] + 0x432aff97), 10); /* 50 */ - c = d + ROT_LEFT((c + I(d, a, b) + X[14] + 0xab9423a7), 15); /* 51 */ - b = c + ROT_LEFT((b + I(c, d, a) + X[5] + 0xfc93a039), 21); /* 52 */ - a = b + ROT_LEFT((a + I(b, c, d) + X[12] + 0x655b59c3), 6); /* 53 */ - d = a + ROT_LEFT((d + I(a, b, c) + X[3] + 0x8f0ccc92), 10); /* 54 */ - c = d + ROT_LEFT((c + I(d, a, b) + X[10] + 0xffeff47d), 15); /* 55 */ - b = c + ROT_LEFT((b + I(c, d, a) + X[1] + 0x85845dd1), 21); /* 56 */ - a = b + ROT_LEFT((a + I(b, c, d) + X[8] + 0x6fa87e4f), 6); /* 57 */ - d = a + ROT_LEFT((d + I(a, b, c) + X[15] + 0xfe2ce6e0), 10); /* 58 */ - c = d + ROT_LEFT((c + I(d, a, b) + X[6] + 0xa3014314), 15); /* 59 */ - b = c + ROT_LEFT((b + I(c, d, a) + X[13] + 0x4e0811a1), 21); /* 60 */ - a = b + ROT_LEFT((a + I(b, c, d) + X[4] + 0xf7537e82), 6); /* 61 */ - d = a + ROT_LEFT((d + I(a, b, c) + X[11] + 0xbd3af235), 10); /* 62 */ - c = d + ROT_LEFT((c + I(d, a, b) + X[2] + 0x2ad7d2bb), 15); /* 63 */ - b = c + ROT_LEFT((b + I(c, d, a) + X[9] + 0xeb86d391), 21); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; -} - -static int -calculateDigestFromBuffer(const uint8 *b, uint32 len, uint8 sum[16]) -{ - register uint32 i, - j, - k, - newI; - uint32 l; - uint8 *input; - register uint32 *wbp; - uint32 workBuff[16], - state[4]; - - l = len; - - state[0] = 0x67452301; - state[1] = 0xEFCDAB89; - state[2] = 0x98BADCFE; - state[3] = 0x10325476; - - if ((input = createPaddedCopyWithLength(b, &l)) == NULL) - return 0; - - for (i = 0;;) - { - if ((newI = i + 16 * 4) > l) - break; - k = i + 3; - for (j = 0; j < 16; j++) - { - wbp = (workBuff + j); - *wbp = input[k--]; - *wbp <<= 8; - *wbp |= input[k--]; - *wbp <<= 8; - *wbp |= input[k--]; - *wbp <<= 8; - *wbp |= input[k]; - k += 7; - } - doTheRounds(workBuff, state); - i = newI; - } - free(input); - - j = 0; - for (i = 0; i < 4; i++) - { - k = state[i]; - sum[j++] = (k & 0xff); - k >>= 8; - sum[j++] = (k & 0xff); - k >>= 8; - sum[j++] = (k & 0xff); - k >>= 8; - sum[j++] = (k & 0xff); - } - return 1; -} - -static void -bytesToHex(uint8 b[16], char *s) -{ - static const char *hex = "0123456789abcdef"; - int q, - w; - - for (q = 0, w = 0; q < 16; q++) - { - s[w++] = hex[(b[q] >> 4) & 0x0F]; - s[w++] = hex[b[q] & 0x0F]; - } - s[w] = '\0'; -} - -/* - * PUBLIC FUNCTIONS - */ - -/* - * pg_md5_hash - * - * Calculates the MD5 sum of the bytes in a buffer. - * - * SYNOPSIS #include "md5.h" - * int pg_md5_hash(const void *buff, size_t len, char *hexsum) - * - * INPUT buff the buffer containing the bytes that you want - * the MD5 sum of. - * len number of bytes in the buffer. - * - * OUTPUT hexsum the MD5 sum as a '\0'-terminated string of - * hexadecimal digits. an MD5 sum is 16 bytes long. - * each byte is represented by two heaxadecimal - * characters. you thus need to provide an array - * of 33 characters, including the trailing '\0'. - * - * RETURNS false on failure (out of memory for internal buffers) or - * true on success. - * - * STANDARDS MD5 is described in RFC 1321. - * - * AUTHOR Sverre H. Huseby - * - */ -bool -pg_md5_hash(const void *buff, size_t len, char *hexsum) -{ - uint8 sum[16]; - - if (!calculateDigestFromBuffer(buff, len, sum)) - return false; - - bytesToHex(sum, hexsum); - return true; -} - -bool -pg_md5_binary(const void *buff, size_t len, void *outbuf) -{ - if (!calculateDigestFromBuffer(buff, len, outbuf)) - return false; - return true; -} - - -/* - * Computes MD5 checksum of "passwd" (a null-terminated string) followed - * by "salt" (which need not be null-terminated). - * - * Output format is "md5" followed by a 32-hex-digit MD5 checksum. - * Hence, the output buffer "buf" must be at least 36 bytes long. - * - * Returns TRUE if okay, FALSE on error (out of memory). - */ -bool -pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, - char *buf) -{ - size_t passwd_len = strlen(passwd); - - /* +1 here is just to avoid risk of unportable malloc(0) */ - char *crypt_buf = malloc(passwd_len + salt_len + 1); - bool ret; - - if (!crypt_buf) - return false; - - /* - * Place salt at the end because it may be known by users trying to crack - * the MD5 output. - */ - memcpy(crypt_buf, passwd, passwd_len); - memcpy(crypt_buf + passwd_len, salt, salt_len); - - strcpy(buf, "md5"); - ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3); - - free(crypt_buf); - - return ret; -} diff --git a/libpq/noblock.c b/libpq/noblock.c deleted file mode 100644 index 959d3ad..0000000 --- a/libpq/noblock.c +++ /dev/null @@ -1,66 +0,0 @@ -/*------------------------------------------------------------------------- - * - * noblock.c - * set a file descriptor as blocking or non-blocking - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * src/port/noblock.c - * - *------------------------------------------------------------------------- - */ - -#include "c.h" - -#include - - -/* - * Put socket into nonblock mode. - * Returns true on success, false on failure. - */ -bool -pg_set_noblock(pgsocket sock) -{ -#if !defined(WIN32) - int flags; - - flags = fcntl(sock, F_GETFL); - if (flags < 0) - return false; - if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) == -1) - return false; - return true; -#else - unsigned long ioctlsocket_ret = 1; - - /* Returns non-0 on failure, while fcntl() returns -1 on failure */ - return (ioctlsocket(sock, FIONBIO, &ioctlsocket_ret) == 0); -#endif -} - -/* - * Put socket into blocking mode. - * Returns true on success, false on failure. - */ -bool -pg_set_block(pgsocket sock) -{ -#if !defined(WIN32) - int flags; - - flags = fcntl(sock, F_GETFL); - if (flags < 0) - return false; - if (fcntl(sock, F_SETFL, (flags & ~O_NONBLOCK)) == -1) - return false; - return true; -#else - unsigned long ioctlsocket_ret = 0; - - /* Returns non-0 on failure, while fcntl() returns -1 on failure */ - return (ioctlsocket(sock, FIONBIO, &ioctlsocket_ret) == 0); -#endif -} diff --git a/libpq/non-bsd/strlcpy.c b/libpq/non-bsd/strlcpy.c deleted file mode 100644 index 6aff65c..0000000 --- a/libpq/non-bsd/strlcpy.c +++ /dev/null @@ -1,71 +0,0 @@ -/*------------------------------------------------------------------------- - * - * strlcpy.c - * strncpy done right - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * - * IDENTIFICATION - * src/port/strlcpy.c - * - * This file was taken from OpenBSD and is used on platforms that don't - * provide strlcpy(). The OpenBSD copyright terms follow. - *------------------------------------------------------------------------- - */ - -/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "c.h" - - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - * Function creation history: http://www.gratisoft.us/todd/papers/strlcpy.html - */ -size_t -strlcpy(char *dst, const char *src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) - { - while (--n != 0) - { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) - { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return (s - src - 1); /* count does not include NUL */ -} diff --git a/libpq/pg_service.conf.sample b/libpq/pg_service.conf.sample deleted file mode 100644 index 5a1c083..0000000 --- a/libpq/pg_service.conf.sample +++ /dev/null @@ -1,17 +0,0 @@ -# -# Connection configuration file -# -# A service is a set of named connection parameters. You may specify -# multiple services in this file. Each starts with a service name in -# brackets. Subsequent lines have connection configuration parameters of -# the pattern "param=value" or LDAP URLs starting with "ldap://" -# to look up such parameters. A sample configuration for postgres is -# included in this file. Lines beginning with '#' are comments. -# -# Copy this to your sysconf directory (typically /usr/local/pgsql/etc) and -# rename it pg_service.conf. -# -# -#[postgres] -#dbname=postgres -#user=postgres diff --git a/libpq/pgstrcasecmp.c b/libpq/pgstrcasecmp.c deleted file mode 100644 index ee87a65..0000000 --- a/libpq/pgstrcasecmp.c +++ /dev/null @@ -1,151 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pgstrcasecmp.c - * Portable SQL-like case-independent comparisons and conversions. - * - * SQL99 specifies Unicode-aware case normalization, which we don't yet - * have the infrastructure for. Instead we use tolower() to provide a - * locale-aware translation. However, there are some locales where this - * is not right either (eg, Turkish may do strange things with 'i' and - * 'I'). Our current compromise is to use tolower() for characters with - * the high bit set, and use an ASCII-only downcasing for 7-bit - * characters. - * - * NB: this code should match downcase_truncate_identifier() in scansup.c. - * - * We also provide strict ASCII-only case conversion functions, which can - * be used to implement C/POSIX case folding semantics no matter what the - * C library thinks the locale is. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * src/port/pgstrcasecmp.c - * - *------------------------------------------------------------------------- - */ -#include "c.h" - -#include - - -/* - * Case-independent comparison of two null-terminated strings. - */ -int -pg_strcasecmp(const char *s1, const char *s2) -{ - for (;;) - { - unsigned char ch1 = (unsigned char) *s1++; - unsigned char ch2 = (unsigned char) *s2++; - - if (ch1 != ch2) - { - if (ch1 >= 'A' && ch1 <= 'Z') - ch1 += 'a' - 'A'; - else if (IS_HIGHBIT_SET(ch1) && isupper(ch1)) - ch1 = tolower(ch1); - - if (ch2 >= 'A' && ch2 <= 'Z') - ch2 += 'a' - 'A'; - else if (IS_HIGHBIT_SET(ch2) && isupper(ch2)) - ch2 = tolower(ch2); - - if (ch1 != ch2) - return (int) ch1 - (int) ch2; - } - if (ch1 == 0) - break; - } - return 0; -} - -/* - * Case-independent comparison of two not-necessarily-null-terminated strings. - * At most n bytes will be examined from each string. - */ -int -pg_strncasecmp(const char *s1, const char *s2, size_t n) -{ - while (n-- > 0) - { - unsigned char ch1 = (unsigned char) *s1++; - unsigned char ch2 = (unsigned char) *s2++; - - if (ch1 != ch2) - { - if (ch1 >= 'A' && ch1 <= 'Z') - ch1 += 'a' - 'A'; - else if (IS_HIGHBIT_SET(ch1) && isupper(ch1)) - ch1 = tolower(ch1); - - if (ch2 >= 'A' && ch2 <= 'Z') - ch2 += 'a' - 'A'; - else if (IS_HIGHBIT_SET(ch2) && isupper(ch2)) - ch2 = tolower(ch2); - - if (ch1 != ch2) - return (int) ch1 - (int) ch2; - } - if (ch1 == 0) - break; - } - return 0; -} - -/* - * Fold a character to upper case. - * - * Unlike some versions of toupper(), this is safe to apply to characters - * that aren't lower case letters. Note however that the whole thing is - * a bit bogus for multibyte character sets. - */ -unsigned char -pg_toupper(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'z') - ch += 'A' - 'a'; - else if (IS_HIGHBIT_SET(ch) && islower(ch)) - ch = toupper(ch); - return ch; -} - -/* - * Fold a character to lower case. - * - * Unlike some versions of tolower(), this is safe to apply to characters - * that aren't upper case letters. Note however that the whole thing is - * a bit bogus for multibyte character sets. - */ -unsigned char -pg_tolower(unsigned char ch) -{ - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - else if (IS_HIGHBIT_SET(ch) && isupper(ch)) - ch = tolower(ch); - return ch; -} - -/* - * Fold a character to upper case, following C/POSIX locale rules. - */ -unsigned char -pg_ascii_toupper(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'z') - ch += 'A' - 'a'; - return ch; -} - -/* - * Fold a character to lower case, following C/POSIX locale rules. - */ -unsigned char -pg_ascii_tolower(unsigned char ch) -{ - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - return ch; -} diff --git a/libpq/postgresql/c.h b/libpq/postgresql/c.h deleted file mode 100644 index 726f0f3..0000000 --- a/libpq/postgresql/c.h +++ /dev/null @@ -1,1107 +0,0 @@ -/*------------------------------------------------------------------------- - * - * c.h - * Fundamental C definitions. This is included by every .c file in - * PostgreSQL (via either postgres.h or postgres_fe.h, as appropriate). - * - * Note that the definitions here are not intended to be exposed to clients - * of the frontend interface libraries --- so we don't worry much about - * polluting the namespace with lots of stuff... - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/c.h - * - *------------------------------------------------------------------------- - */ -/* - *---------------------------------------------------------------- - * TABLE OF CONTENTS - * - * When adding stuff to this file, please try to put stuff - * into the relevant section, or add new sections as appropriate. - * - * section description - * ------- ------------------------------------------------ - * 0) pg_config.h and standard system headers - * 1) hacks to cope with non-ANSI C compilers - * 2) bool, true, false, TRUE, FALSE, NULL - * 3) standard system types - * 4) IsValid macros for system types - * 5) offsetof, lengthof, endof, alignment - * 6) assertions - * 7) widely useful macros - * 8) random stuff - * 9) system-specific hacks - * - * NOTE: since this file is included by both frontend and backend modules, it's - * almost certainly wrong to put an "extern" declaration here. typedefs and - * macros are the kind of thing that might go here. - * - *---------------------------------------------------------------- - */ -#ifndef C_H -#define C_H - -#include "postgres_ext.h" - -/* Must undef pg_config_ext.h symbols before including pg_config.h */ -#undef PG_INT64_TYPE - -#include "pg_config.h" -#include "pg_config_manual.h" /* must be after pg_config.h */ - -/* - * We always rely on the WIN32 macro being set by our build system, - * but _WIN32 is the compiler pre-defined macro. So make sure we define - * WIN32 whenever _WIN32 is set, to facilitate standalone building. - */ -#if defined(_WIN32) && !defined(WIN32) -#define WIN32 -#endif - -#if !defined(WIN32) && !defined(__CYGWIN__) /* win32 includes further down */ -#include "pg_config_os.h" /* must be before any system header files */ -#endif - -#if _MSC_VER >= 1400 || defined(HAVE_CRTDEFS_H) -#define errcode __msvc_errcode -#include -#undef errcode -#endif - -/* - * We have to include stdlib.h here because it defines many of these macros - * on some platforms, and we only want our definitions used if stdlib.h doesn't - * have its own. The same goes for stddef and stdarg if present. - */ - -#include -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif -#ifdef HAVE_STDINT_H -#include -#endif -#include - -#include -#if defined(WIN32) || defined(__CYGWIN__) -#include /* ensure O_BINARY is available */ -#endif - -#if defined(WIN32) || defined(__CYGWIN__) -/* We have to redefine some system functions after they are included above. */ -#include "pg_config_os.h" -#endif - -/* - * Force disable inlining if PG_FORCE_DISABLE_INLINE is defined. This is used - * to work around compiler bugs and might also be useful for investigatory - * purposes by defining the symbol in the platform's header.. - * - * This is done early (in slightly the wrong section) as functionality later - * in this file might want to rely on inline functions. - */ -#ifdef PG_FORCE_DISABLE_INLINE -#undef inline -#define inline -#endif - -/* Must be before gettext() games below */ -#include - -#define _(x) gettext(x) - -#ifdef ENABLE_NLS -#include -#else -#define gettext(x) (x) -#define dgettext(d,x) (x) -#define ngettext(s,p,n) ((n) == 1 ? (s) : (p)) -#define dngettext(d,s,p,n) ((n) == 1 ? (s) : (p)) -#endif - -/* - * Use this to mark string constants as needing translation at some later - * time, rather than immediately. This is useful for cases where you need - * access to the original string and translated string, and for cases where - * immediate translation is not possible, like when initializing global - * variables. - * http://www.gnu.org/software/autoconf/manual/gettext/Special-cases.html - */ -#define gettext_noop(x) (x) - - -/* ---------------------------------------------------------------- - * Section 1: hacks to cope with non-ANSI C compilers - * - * type prefixes (const, signed, volatile, inline) are handled in pg_config.h. - * ---------------------------------------------------------------- - */ - -/* - * CppAsString - * Convert the argument to a string, using the C preprocessor. - * CppConcat - * Concatenate two arguments together, using the C preprocessor. - * - * Note: There used to be support here for pre-ANSI C compilers that didn't - * support # and ##. Nowadays, these macros are just for clarity and/or - * backward compatibility with existing PostgreSQL code. - */ -#define CppAsString(identifier) #identifier -#define CppConcat(x, y) x##y - -/* - * dummyret is used to set return values in macros that use ?: to make - * assignments. gcc wants these to be void, other compilers like char - */ -#ifdef __GNUC__ /* GNU cc */ -#define dummyret void -#else -#define dummyret char -#endif - -/* Which __func__ symbol do we have, if any? */ -#ifdef HAVE_FUNCNAME__FUNC -#define PG_FUNCNAME_MACRO __func__ -#else -#ifdef HAVE_FUNCNAME__FUNCTION -#define PG_FUNCNAME_MACRO __FUNCTION__ -#else -#define PG_FUNCNAME_MACRO NULL -#endif -#endif - -/* ---------------------------------------------------------------- - * Section 2: bool, true, false, TRUE, FALSE, NULL - * ---------------------------------------------------------------- - */ - -/* - * bool - * Boolean value, either true or false. - * - * XXX for C++ compilers, we assume the compiler has a compatible - * built-in definition of bool. - */ - -#ifndef __cplusplus - -#ifndef bool -typedef char bool; -#endif - -#ifndef true -#define true ((bool) 1) -#endif - -#ifndef false -#define false ((bool) 0) -#endif -#endif /* not C++ */ - -typedef bool *BoolPtr; - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/* - * NULL - * Null pointer. - */ -#ifndef NULL -#define NULL ((void *) 0) -#endif - - -/* ---------------------------------------------------------------- - * Section 3: standard system types - * ---------------------------------------------------------------- - */ - -/* - * Pointer - * Variable holding address of any memory resident object. - * - * XXX Pointer arithmetic is done with this, so it can't be void * - * under "true" ANSI compilers. - */ -typedef char *Pointer; - -/* - * intN - * Signed integer, EXACTLY N BITS IN SIZE, - * used for numerical computations and the - * frontend/backend protocol. - */ -#ifndef HAVE_INT8 -typedef signed char int8; /* == 8 bits */ -typedef signed short int16; /* == 16 bits */ -typedef signed int int32; /* == 32 bits */ -#endif /* not HAVE_INT8 */ - -/* - * uintN - * Unsigned integer, EXACTLY N BITS IN SIZE, - * used for numerical computations and the - * frontend/backend protocol. - */ -#ifndef HAVE_UINT8 -typedef unsigned char uint8; /* == 8 bits */ -typedef unsigned short uint16; /* == 16 bits */ -typedef unsigned int uint32; /* == 32 bits */ -#endif /* not HAVE_UINT8 */ - -/* - * bitsN - * Unit of bitwise operation, AT LEAST N BITS IN SIZE. - */ -typedef uint8 bits8; /* >= 8 bits */ -typedef uint16 bits16; /* >= 16 bits */ -typedef uint32 bits32; /* >= 32 bits */ - -/* - * 64-bit integers - */ -#ifdef HAVE_LONG_INT_64 -/* Plain "long int" fits, use it */ - -#ifndef HAVE_INT64 -typedef long int int64; -#endif -#ifndef HAVE_UINT64 -typedef unsigned long int uint64; -#endif -#elif defined(HAVE_LONG_LONG_INT_64) -/* We have working support for "long long int", use that */ - -#ifndef HAVE_INT64 -typedef long long int int64; -#endif -#ifndef HAVE_UINT64 -typedef unsigned long long int uint64; -#endif -#else -/* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */ -#error must have a working 64-bit integer datatype -#endif - -/* Decide if we need to decorate 64-bit constants */ -#ifdef HAVE_LL_CONSTANTS -#define INT64CONST(x) ((int64) x##LL) -#define UINT64CONST(x) ((uint64) x##ULL) -#else -#define INT64CONST(x) ((int64) x) -#define UINT64CONST(x) ((uint64) x) -#endif - -/* snprintf format strings to use for 64-bit integers */ -#define INT64_FORMAT "%" INT64_MODIFIER "d" -#define UINT64_FORMAT "%" INT64_MODIFIER "u" - -/* - * 128-bit signed and unsigned integers - * There currently is only a limited support for the type. E.g. 128bit - * literals and snprintf are not supported; but math is. - */ -#if defined(PG_INT128_TYPE) -#define HAVE_INT128 -typedef PG_INT128_TYPE int128; -typedef unsigned PG_INT128_TYPE uint128; -#endif - -/* - * stdint.h limits aren't guaranteed to be present and aren't guaranteed to - * have compatible types with our fixed width types. So just define our own. - */ -#define PG_INT8_MIN (-0x7F-1) -#define PG_INT8_MAX (0x7F) -#define PG_UINT8_MAX (0xFF) -#define PG_INT16_MIN (-0x7FFF-1) -#define PG_INT16_MAX (0x7FFF) -#define PG_UINT16_MAX (0xFFFF) -#define PG_INT32_MIN (-0x7FFFFFFF-1) -#define PG_INT32_MAX (0x7FFFFFFF) -#define PG_UINT32_MAX (0xFFFFFFFF) -#define PG_INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1) -#define PG_INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF) -#define PG_UINT64_MAX UINT64CONST(0xFFFFFFFFFFFFFFFF) - -/* Select timestamp representation (float8 or int64) */ -#ifdef USE_INTEGER_DATETIMES -#define HAVE_INT64_TIMESTAMP -#endif - -/* - * Size - * Size of any memory resident object, as returned by sizeof. - */ -typedef size_t Size; - -/* - * Index - * Index into any memory resident array. - * - * Note: - * Indices are non negative. - */ -typedef unsigned int Index; - -/* - * Offset - * Offset into any memory resident array. - * - * Note: - * This differs from an Index in that an Index is always - * non negative, whereas Offset may be negative. - */ -typedef signed int Offset; - -/* - * Common Postgres datatype names (as used in the catalogs) - */ -typedef float float4; -typedef double float8; - -/* - * Oid, RegProcedure, TransactionId, SubTransactionId, MultiXactId, - * CommandId - */ - -/* typedef Oid is in postgres_ext.h */ - -/* - * regproc is the type name used in the include/catalog headers, but - * RegProcedure is the preferred name in C code. - */ -typedef Oid regproc; -typedef regproc RegProcedure; - -typedef uint32 TransactionId; - -typedef uint32 LocalTransactionId; - -typedef uint32 SubTransactionId; - -#define InvalidSubTransactionId ((SubTransactionId) 0) -#define TopSubTransactionId ((SubTransactionId) 1) - -/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */ -typedef TransactionId MultiXactId; - -typedef uint32 MultiXactOffset; - -typedef uint32 CommandId; - -#define FirstCommandId ((CommandId) 0) -#define InvalidCommandId (~(CommandId)0) - -/* - * Array indexing support - */ -#define MAXDIM 6 -typedef struct -{ - int indx[MAXDIM]; -} IntArray; - -/* ---------------- - * Variable-length datatypes all share the 'struct varlena' header. - * - * NOTE: for TOASTable types, this is an oversimplification, since the value - * may be compressed or moved out-of-line. However datatype-specific routines - * are mostly content to deal with de-TOASTed values only, and of course - * client-side routines should never see a TOASTed value. But even in a - * de-TOASTed value, beware of touching vl_len_ directly, as its representation - * is no longer convenient. It's recommended that code always use the VARDATA, - * VARSIZE, and SET_VARSIZE macros instead of relying on direct mentions of - * the struct fields. See postgres.h for details of the TOASTed form. - * ---------------- - */ -struct varlena -{ - char vl_len_[4]; /* Do not touch this field directly! */ - char vl_dat[FLEXIBLE_ARRAY_MEMBER]; /* Data content is here */ -}; - -#define VARHDRSZ ((int32) sizeof(int32)) - -/* - * These widely-used datatypes are just a varlena header and the data bytes. - * There is no terminating null or anything like that --- the data length is - * always VARSIZE(ptr) - VARHDRSZ. - */ -typedef struct varlena bytea; -typedef struct varlena text; -typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */ -typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */ - -/* - * Specialized array types. These are physically laid out just the same - * as regular arrays (so that the regular array subscripting code works - * with them). They exist as distinct types mostly for historical reasons: - * they have nonstandard I/O behavior which we don't want to change for fear - * of breaking applications that look at the system catalogs. There is also - * an implementation issue for oidvector: it's part of the primary key for - * pg_proc, and we can't use the normal btree array support routines for that - * without circularity. - */ -typedef struct -{ - int32 vl_len_; /* these fields must match ArrayType! */ - int ndim; /* always 1 for int2vector */ - int32 dataoffset; /* always 0 for int2vector */ - Oid elemtype; - int dim1; - int lbound1; - int16 values[FLEXIBLE_ARRAY_MEMBER]; -} int2vector; - -typedef struct -{ - int32 vl_len_; /* these fields must match ArrayType! */ - int ndim; /* always 1 for oidvector */ - int32 dataoffset; /* always 0 for oidvector */ - Oid elemtype; - int dim1; - int lbound1; - Oid values[FLEXIBLE_ARRAY_MEMBER]; -} oidvector; - -/* - * Representation of a Name: effectively just a C string, but null-padded to - * exactly NAMEDATALEN bytes. The use of a struct is historical. - */ -typedef struct nameData -{ - char data[NAMEDATALEN]; -} NameData; -typedef NameData *Name; - -#define NameStr(name) ((name).data) - -/* - * Support macros for escaping strings. escape_backslash should be TRUE - * if generating a non-standard-conforming string. Prefixing a string - * with ESCAPE_STRING_SYNTAX guarantees it is non-standard-conforming. - * Beware of multiple evaluation of the "ch" argument! - */ -#define SQL_STR_DOUBLE(ch, escape_backslash) \ - ((ch) == '\'' || ((ch) == '\\' && (escape_backslash))) - -#define ESCAPE_STRING_SYNTAX 'E' - -/* ---------------------------------------------------------------- - * Section 4: IsValid macros for system types - * ---------------------------------------------------------------- - */ -/* - * BoolIsValid - * True iff bool is valid. - */ -#define BoolIsValid(boolean) ((boolean) == false || (boolean) == true) - -/* - * PointerIsValid - * True iff pointer is valid. - */ -#define PointerIsValid(pointer) ((const void*)(pointer) != NULL) - -/* - * PointerIsAligned - * True iff pointer is properly aligned to point to the given type. - */ -#define PointerIsAligned(pointer, type) \ - (((uintptr_t)(pointer) % (sizeof (type))) == 0) - -#define OidIsValid(objectId) ((bool) ((objectId) != InvalidOid)) - -#define RegProcedureIsValid(p) OidIsValid(p) - - -/* ---------------------------------------------------------------- - * Section 5: offsetof, lengthof, endof, alignment - * ---------------------------------------------------------------- - */ -/* - * offsetof - * Offset of a structure/union field within that structure/union. - * - * XXX This is supposed to be part of stddef.h, but isn't on - * some systems (like SunOS 4). - */ -#ifndef offsetof -#define offsetof(type, field) ((long) &((type *)0)->field) -#endif /* offsetof */ - -/* - * lengthof - * Number of elements in an array. - */ -#define lengthof(array) (sizeof (array) / sizeof ((array)[0])) - -/* - * endof - * Address of the element one past the last in an array. - */ -#define endof(array) (&(array)[lengthof(array)]) - -/* ---------------- - * Alignment macros: align a length or address appropriately for a given type. - * The fooALIGN() macros round up to a multiple of the required alignment, - * while the fooALIGN_DOWN() macros round down. The latter are more useful - * for problems like "how many X-sized structures will fit in a page?". - * - * NOTE: TYPEALIGN[_DOWN] will not work if ALIGNVAL is not a power of 2. - * That case seems extremely unlikely to be needed in practice, however. - * ---------------- - */ - -#define TYPEALIGN(ALIGNVAL,LEN) \ - (((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((uintptr_t) ((ALIGNVAL) - 1))) - -#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN)) -#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN)) -#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN)) -#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN)) -#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN)) -/* MAXALIGN covers only built-in types, not buffers */ -#define BUFFERALIGN(LEN) TYPEALIGN(ALIGNOF_BUFFER, (LEN)) -#define CACHELINEALIGN(LEN) TYPEALIGN(PG_CACHE_LINE_SIZE, (LEN)) - -#define TYPEALIGN_DOWN(ALIGNVAL,LEN) \ - (((uintptr_t) (LEN)) & ~((uintptr_t) ((ALIGNVAL) - 1))) - -#define SHORTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN)) -#define INTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_INT, (LEN)) -#define LONGALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN)) -#define DOUBLEALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN)) -#define MAXALIGN_DOWN(LEN) TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN)) - -/* - * The above macros will not work with types wider than uintptr_t, like with - * uint64 on 32-bit platforms. That's not problem for the usual use where a - * pointer or a length is aligned, but for the odd case that you need to - * align something (potentially) wider, use TYPEALIGN64. - */ -#define TYPEALIGN64(ALIGNVAL,LEN) \ - (((uint64) (LEN) + ((ALIGNVAL) - 1)) & ~((uint64) ((ALIGNVAL) - 1))) - -/* we don't currently need wider versions of the other ALIGN macros */ -#define MAXALIGN64(LEN) TYPEALIGN64(MAXIMUM_ALIGNOF, (LEN)) - -/* ---------------- - * Attribute macros - * - * GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html - * GCC: https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html - * Sunpro: https://docs.oracle.com/cd/E18659_01/html/821-1384/gjzke.html - * XLC: http://www-01.ibm.com/support/knowledgecenter/SSGH2K_11.1.0/com.ibm.xlc111.aix.doc/language_ref/function_attributes.html - * XLC: http://www-01.ibm.com/support/knowledgecenter/SSGH2K_11.1.0/com.ibm.xlc111.aix.doc/language_ref/type_attrib.html - * ---------------- - */ - -/* only GCC supports the unused attribute */ -#ifdef __GNUC__ -#define pg_attribute_unused() __attribute__((unused)) -#else -#define pg_attribute_unused() -#endif - -/* GCC and XLC support format attributes */ -#if defined(__GNUC__) || defined(__IBMC__) -#define pg_attribute_format_arg(a) __attribute__((format_arg(a))) -#define pg_attribute_printf(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE, f, a))) -#else -#define pg_attribute_format_arg(a) -#define pg_attribute_printf(f,a) -#endif - -/* GCC, Sunpro and XLC support aligned, packed and noreturn */ -#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) -#define pg_attribute_aligned(a) __attribute__((aligned(a))) -#define pg_attribute_noreturn() __attribute__((noreturn)) -#define pg_attribute_packed() __attribute__((packed)) -#define HAVE_PG_ATTRIBUTE_NORETURN 1 -#else -/* - * NB: aligned and packed are not given default definitions because they - * affect code functionality; they *must* be implemented by the compiler - * if they are to be used. - */ -#define pg_attribute_noreturn() -#endif - -/* ---------------------------------------------------------------- - * Section 6: assertions - * ---------------------------------------------------------------- - */ - -/* - * USE_ASSERT_CHECKING, if defined, turns on all the assertions. - * - plai 9/5/90 - * - * It should _NOT_ be defined in releases or in benchmark copies - */ - -/* - * Assert() can be used in both frontend and backend code. In frontend code it - * just calls the standard assert, if it's available. If use of assertions is - * not configured, it does nothing. - */ -#ifndef USE_ASSERT_CHECKING - -#define Assert(condition) ((void)true) -#define AssertMacro(condition) ((void)true) -#define AssertArg(condition) ((void)true) -#define AssertState(condition) ((void)true) -#define AssertPointerAlignment(ptr, bndr) ((void)true) -#define Trap(condition, errorType) ((void)true) -#define TrapMacro(condition, errorType) (true) - -#elif defined(FRONTEND) - -#include -#define Assert(p) assert(p) -#define AssertMacro(p) ((void) assert(p)) -#define AssertArg(condition) assert(condition) -#define AssertState(condition) assert(condition) -#define AssertPointerAlignment(ptr, bndr) ((void)true) -#else /* USE_ASSERT_CHECKING && !FRONTEND */ - -/* - * Trap - * Generates an exception if the given condition is true. - */ -#define Trap(condition, errorType) \ - do { \ - if (condition) \ - ExceptionalCondition(CppAsString(condition), (errorType), \ - __FILE__, __LINE__); \ - } while (0) - -/* - * TrapMacro is the same as Trap but it's intended for use in macros: - * - * #define foo(x) (AssertMacro(x != 0), bar(x)) - * - * Isn't CPP fun? - */ -#define TrapMacro(condition, errorType) \ - ((bool) (! (condition) || \ - (ExceptionalCondition(CppAsString(condition), (errorType), \ - __FILE__, __LINE__), 0))) - -#define Assert(condition) \ - Trap(!(condition), "FailedAssertion") - -#define AssertMacro(condition) \ - ((void) TrapMacro(!(condition), "FailedAssertion")) - -#define AssertArg(condition) \ - Trap(!(condition), "BadArgument") - -#define AssertState(condition) \ - Trap(!(condition), "BadState") - -/* - * Check that `ptr' is `bndr' aligned. - */ -#define AssertPointerAlignment(ptr, bndr) \ - Trap(TYPEALIGN(bndr, (uintptr_t)(ptr)) != (uintptr_t)(ptr), \ - "UnalignedPointer") - -#endif /* USE_ASSERT_CHECKING && !FRONTEND */ - -/* - * Macros to support compile-time assertion checks. - * - * If the "condition" (a compile-time-constant expression) evaluates to false, - * throw a compile error using the "errmessage" (a string literal). - * - * gcc 4.6 and up supports _Static_assert(), but there are bizarre syntactic - * placement restrictions. These macros make it safe to use as a statement - * or in an expression, respectively. - * - * Otherwise we fall back on a kluge that assumes the compiler will complain - * about a negative width for a struct bit-field. This will not include a - * helpful error message, but it beats not getting an error at all. - */ -#ifdef HAVE__STATIC_ASSERT -#define StaticAssertStmt(condition, errmessage) \ - do { _Static_assert(condition, errmessage); } while(0) -#define StaticAssertExpr(condition, errmessage) \ - ({ StaticAssertStmt(condition, errmessage); true; }) -#else /* !HAVE__STATIC_ASSERT */ -#define StaticAssertStmt(condition, errmessage) \ - ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; })) -#define StaticAssertExpr(condition, errmessage) \ - StaticAssertStmt(condition, errmessage) -#endif /* HAVE__STATIC_ASSERT */ - - -/* - * Compile-time checks that a variable (or expression) has the specified type. - * - * AssertVariableIsOfType() can be used as a statement. - * AssertVariableIsOfTypeMacro() is intended for use in macros, eg - * #define foo(x) (AssertVariableIsOfTypeMacro(x, int), bar(x)) - * - * If we don't have __builtin_types_compatible_p, we can still assert that - * the types have the same size. This is far from ideal (especially on 32-bit - * platforms) but it provides at least some coverage. - */ -#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P -#define AssertVariableIsOfType(varname, typename) \ - StaticAssertStmt(__builtin_types_compatible_p(__typeof__(varname), typename), \ - CppAsString(varname) " does not have type " CppAsString(typename)) -#define AssertVariableIsOfTypeMacro(varname, typename) \ - ((void) StaticAssertExpr(__builtin_types_compatible_p(__typeof__(varname), typename), \ - CppAsString(varname) " does not have type " CppAsString(typename))) -#else /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */ -#define AssertVariableIsOfType(varname, typename) \ - StaticAssertStmt(sizeof(varname) == sizeof(typename), \ - CppAsString(varname) " does not have type " CppAsString(typename)) -#define AssertVariableIsOfTypeMacro(varname, typename) \ - ((void) StaticAssertExpr(sizeof(varname) == sizeof(typename), \ - CppAsString(varname) " does not have type " CppAsString(typename))) -#endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */ - - -/* ---------------------------------------------------------------- - * Section 7: widely useful macros - * ---------------------------------------------------------------- - */ -/* - * Max - * Return the maximum of two numbers. - */ -#define Max(x, y) ((x) > (y) ? (x) : (y)) - -/* - * Min - * Return the minimum of two numbers. - */ -#define Min(x, y) ((x) < (y) ? (x) : (y)) - -/* - * Abs - * Return the absolute value of the argument. - */ -#define Abs(x) ((x) >= 0 ? (x) : -(x)) - -/* - * StrNCpy - * Like standard library function strncpy(), except that result string - * is guaranteed to be null-terminated --- that is, at most N-1 bytes - * of the source string will be kept. - * Also, the macro returns no result (too hard to do that without - * evaluating the arguments multiple times, which seems worse). - * - * BTW: when you need to copy a non-null-terminated string (like a text - * datum) and add a null, do not do it with StrNCpy(..., len+1). That - * might seem to work, but it fetches one byte more than there is in the - * text object. One fine day you'll have a SIGSEGV because there isn't - * another byte before the end of memory. Don't laugh, we've had real - * live bug reports from real live users over exactly this mistake. - * Do it honestly with "memcpy(dst,src,len); dst[len] = '\0';", instead. - */ -#define StrNCpy(dst,src,len) \ - do \ - { \ - char * _dst = (dst); \ - Size _len = (len); \ -\ - if (_len > 0) \ - { \ - strncpy(_dst, (src), _len); \ - _dst[_len-1] = '\0'; \ - } \ - } while (0) - - -/* Get a bit mask of the bits set in non-long aligned addresses */ -#define LONG_ALIGN_MASK (sizeof(long) - 1) - -/* - * MemSet - * Exactly the same as standard library function memset(), but considerably - * faster for zeroing small word-aligned structures (such as parsetree nodes). - * This has to be a macro because the main point is to avoid function-call - * overhead. However, we have also found that the loop is faster than - * native libc memset() on some platforms, even those with assembler - * memset() functions. More research needs to be done, perhaps with - * MEMSET_LOOP_LIMIT tests in configure. - */ -#define MemSet(start, val, len) \ - do \ - { \ - /* must be void* because we don't know if it is integer aligned yet */ \ - void *_vstart = (void *) (start); \ - int _val = (val); \ - Size _len = (len); \ -\ - if ((((uintptr_t) _vstart) & LONG_ALIGN_MASK) == 0 && \ - (_len & LONG_ALIGN_MASK) == 0 && \ - _val == 0 && \ - _len <= MEMSET_LOOP_LIMIT && \ - /* \ - * If MEMSET_LOOP_LIMIT == 0, optimizer should find \ - * the whole "if" false at compile time. \ - */ \ - MEMSET_LOOP_LIMIT != 0) \ - { \ - long *_start = (long *) _vstart; \ - long *_stop = (long *) ((char *) _start + _len); \ - while (_start < _stop) \ - *_start++ = 0; \ - } \ - else \ - memset(_vstart, _val, _len); \ - } while (0) - -/* - * MemSetAligned is the same as MemSet except it omits the test to see if - * "start" is word-aligned. This is okay to use if the caller knows a-priori - * that the pointer is suitably aligned (typically, because he just got it - * from palloc(), which always delivers a max-aligned pointer). - */ -#define MemSetAligned(start, val, len) \ - do \ - { \ - long *_start = (long *) (start); \ - int _val = (val); \ - Size _len = (len); \ -\ - if ((_len & LONG_ALIGN_MASK) == 0 && \ - _val == 0 && \ - _len <= MEMSET_LOOP_LIMIT && \ - MEMSET_LOOP_LIMIT != 0) \ - { \ - long *_stop = (long *) ((char *) _start + _len); \ - while (_start < _stop) \ - *_start++ = 0; \ - } \ - else \ - memset(_start, _val, _len); \ - } while (0) - - -/* - * MemSetTest/MemSetLoop are a variant version that allow all the tests in - * MemSet to be done at compile time in cases where "val" and "len" are - * constants *and* we know the "start" pointer must be word-aligned. - * If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use - * MemSetAligned. Beware of multiple evaluations of the arguments when using - * this approach. - */ -#define MemSetTest(val, len) \ - ( ((len) & LONG_ALIGN_MASK) == 0 && \ - (len) <= MEMSET_LOOP_LIMIT && \ - MEMSET_LOOP_LIMIT != 0 && \ - (val) == 0 ) - -#define MemSetLoop(start, val, len) \ - do \ - { \ - long * _start = (long *) (start); \ - long * _stop = (long *) ((char *) _start + (Size) (len)); \ - \ - while (_start < _stop) \ - *_start++ = 0; \ - } while (0) - - -/* - * Mark a point as unreachable in a portable fashion. This should preferably - * be something that the compiler understands, to aid code generation. - * In assert-enabled builds, we prefer abort() for debugging reasons. - */ -#if defined(HAVE__BUILTIN_UNREACHABLE) && !defined(USE_ASSERT_CHECKING) -#define pg_unreachable() __builtin_unreachable() -#elif defined(_MSC_VER) && !defined(USE_ASSERT_CHECKING) -#define pg_unreachable() __assume(0) -#else -#define pg_unreachable() abort() -#endif - - -/* ---------------------------------------------------------------- - * Section 8: random stuff - * ---------------------------------------------------------------- - */ - -/* msb for char */ -#define HIGHBIT (0x80) -#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT) - -#define STATUS_OK (0) -#define STATUS_ERROR (-1) -#define STATUS_EOF (-2) -#define STATUS_FOUND (1) -#define STATUS_WAITING (2) - - -/* - * Append PG_USED_FOR_ASSERTS_ONLY to definitions of variables that are only - * used in assert-enabled builds, to avoid compiler warnings about unused - * variables in assert-disabled builds. - */ -#ifdef USE_ASSERT_CHECKING -#define PG_USED_FOR_ASSERTS_ONLY -#else -#define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused() -#endif - - -/* gettext domain name mangling */ - -/* - * To better support parallel installations of major PostgreSQL - * versions as well as parallel installations of major library soname - * versions, we mangle the gettext domain name by appending those - * version numbers. The coding rule ought to be that wherever the - * domain name is mentioned as a literal, it must be wrapped into - * PG_TEXTDOMAIN(). The macros below do not work on non-literals; but - * that is somewhat intentional because it avoids having to worry - * about multiple states of premangling and postmangling as the values - * are being passed around. - * - * Make sure this matches the installation rules in nls-global.mk. - */ - -/* need a second indirection because we want to stringize the macro value, not the name */ -#define CppAsString2(x) CppAsString(x) - -#ifdef SO_MAJOR_VERSION -#define PG_TEXTDOMAIN(domain) (domain CppAsString2(SO_MAJOR_VERSION) "-" PG_MAJORVERSION) -#else -#define PG_TEXTDOMAIN(domain) (domain "-" PG_MAJORVERSION) -#endif - - -/* ---------------------------------------------------------------- - * Section 9: system-specific hacks - * - * This should be limited to things that absolutely have to be - * included in every source file. The port-specific header file - * is usually a better place for this sort of thing. - * ---------------------------------------------------------------- - */ - -/* - * NOTE: this is also used for opening text files. - * WIN32 treats Control-Z as EOF in files opened in text mode. - * Therefore, we open files in binary mode on Win32 so we can read - * literal control-Z. The other affect is that we see CRLF, but - * that is OK because we can already handle those cleanly. - */ -#if defined(WIN32) || defined(__CYGWIN__) -#define PG_BINARY O_BINARY -#define PG_BINARY_A "ab" -#define PG_BINARY_R "rb" -#define PG_BINARY_W "wb" -#else -#define PG_BINARY 0 -#define PG_BINARY_A "a" -#define PG_BINARY_R "r" -#define PG_BINARY_W "w" -#endif - -/* - * Provide prototypes for routines not present in a particular machine's - * standard C library. - */ - -#if !HAVE_DECL_SNPRINTF -extern int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); -#endif - -#if !HAVE_DECL_VSNPRINTF -extern int vsnprintf(char *str, size_t count, const char *fmt, va_list args); -#endif - -#if !defined(HAVE_MEMMOVE) && !defined(memmove) -#define memmove(d, s, c) bcopy(s, d, c) -#endif - -/* no special DLL markers on most ports */ -#ifndef PGDLLIMPORT -#define PGDLLIMPORT -#endif -#ifndef PGDLLEXPORT -#define PGDLLEXPORT -#endif - -/* - * The following is used as the arg list for signal handlers. Any ports - * that take something other than an int argument should override this in - * their pg_config_os.h file. Note that variable names are required - * because it is used in both the prototypes as well as the definitions. - * Note also the long name. We expect that this won't collide with - * other names causing compiler warnings. - */ - -#ifndef SIGNAL_ARGS -#define SIGNAL_ARGS int postgres_signal_arg -#endif - -/* - * When there is no sigsetjmp, its functionality is provided by plain - * setjmp. Incidentally, nothing provides setjmp's functionality in - * that case. We now support the case only on Windows. - */ -#ifdef WIN32 -#define sigjmp_buf jmp_buf -#define sigsetjmp(x,y) setjmp(x) -#define siglongjmp longjmp -#endif - -#if defined(HAVE_FDATASYNC) && !HAVE_DECL_FDATASYNC -extern int fdatasync(int fildes); -#endif - -/* If strtoq() exists, rename it to the more standard strtoll() */ -#if defined(HAVE_LONG_LONG_INT_64) && !defined(HAVE_STRTOLL) && defined(HAVE_STRTOQ) -#define strtoll strtoq -#define HAVE_STRTOLL 1 -#endif - -/* If strtouq() exists, rename it to the more standard strtoull() */ -#if defined(HAVE_LONG_LONG_INT_64) && !defined(HAVE_STRTOULL) && defined(HAVE_STRTOUQ) -#define strtoull strtouq -#define HAVE_STRTOULL 1 -#endif - -/* - * We assume if we have these two functions, we have their friends too, and - * can use the wide-character functions. - */ -#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER) -#define USE_WIDE_UPPER_LOWER -#endif - -/* EXEC_BACKEND defines */ -#ifdef EXEC_BACKEND -#define NON_EXEC_STATIC -#else -#define NON_EXEC_STATIC static -#endif - -/* /port compatibility functions */ -#include "port.h" - -#endif /* C_H */ diff --git a/libpq/postgresql/common/fe_memutils.h b/libpq/postgresql/common/fe_memutils.h deleted file mode 100644 index b4ce3d4..0000000 --- a/libpq/postgresql/common/fe_memutils.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * fe_memutils.h - * memory management support for frontend code - * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group - * - * src/include/common/fe_memutils.h - */ -#ifndef FE_MEMUTILS_H -#define FE_MEMUTILS_H - -/* - * Flags for pg_malloc_extended and palloc_extended, deliberately named - * the same as the backend flags. - */ -#define MCXT_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) not - * actually used for frontends */ -#define MCXT_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ -#define MCXT_ALLOC_ZERO 0x04 /* zero allocated memory */ - -/* - * "Safe" memory allocation functions --- these exit(1) on failure - * (except pg_malloc_extended with MCXT_ALLOC_NO_OOM) - */ -extern char *pg_strdup(const char *in); -extern void *pg_malloc(size_t size); -extern void *pg_malloc0(size_t size); -extern void *pg_malloc_extended(size_t size, int flags); -extern void *pg_realloc(void *pointer, size_t size); -extern void pg_free(void *pointer); - -/* Equivalent functions, deliberately named the same as backend functions */ -extern char *pstrdup(const char *in); -extern void *palloc(Size size); -extern void *palloc0(Size size); -extern void *palloc_extended(Size size, int flags); -extern void *repalloc(void *pointer, Size size); -extern void pfree(void *pointer); - -/* sprintf into a palloc'd buffer --- these are in psprintf.c */ -extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2); -extern size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) pg_attribute_printf(3, 0); - -#endif /* FE_MEMUTILS_H */ diff --git a/libpq/postgresql/getaddrinfo.h b/libpq/postgresql/getaddrinfo.h deleted file mode 100644 index 46aad59..0000000 --- a/libpq/postgresql/getaddrinfo.h +++ /dev/null @@ -1,164 +0,0 @@ -/*------------------------------------------------------------------------- - * - * getaddrinfo.h - * Support getaddrinfo() on platforms that don't have it. - * - * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, - * whether or not the library routine getaddrinfo() can be found. This - * policy is needed because on some platforms a manually installed libbind.a - * may provide getaddrinfo(), yet the system headers may not provide the - * struct definitions needed to call it. To avoid conflict with the libbind - * definition in such cases, we rename our routines to pg_xxx() via macros. - * - * This code will also work on platforms where struct addrinfo is defined - * in the system headers but no getaddrinfo() can be located. - * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group - * - * src/include/getaddrinfo.h - * - *------------------------------------------------------------------------- - */ -#ifndef GETADDRINFO_H -#define GETADDRINFO_H - -#include -#include - - -/* Various macros that ought to be in , but might not be */ - -#ifndef EAI_FAIL -#ifndef WIN32 -#define EAI_BADFLAGS (-1) -#define EAI_NONAME (-2) -#define EAI_AGAIN (-3) -#define EAI_FAIL (-4) -#define EAI_FAMILY (-6) -#define EAI_SOCKTYPE (-7) -#define EAI_SERVICE (-8) -#define EAI_MEMORY (-10) -#define EAI_SYSTEM (-11) -#else /* WIN32 */ -#ifdef WIN32_ONLY_COMPILER -#ifndef WSA_NOT_ENOUGH_MEMORY -#define WSA_NOT_ENOUGH_MEMORY (WSAENOBUFS) -#endif -#ifndef __BORLANDC__ -#define WSATYPE_NOT_FOUND (WSABASEERR+109) -#endif -#endif -#define EAI_AGAIN WSATRY_AGAIN -#define EAI_BADFLAGS WSAEINVAL -#define EAI_FAIL WSANO_RECOVERY -#define EAI_FAMILY WSAEAFNOSUPPORT -#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY -#define EAI_NODATA WSANO_DATA -#define EAI_NONAME WSAHOST_NOT_FOUND -#define EAI_SERVICE WSATYPE_NOT_FOUND -#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT -#endif /* !WIN32 */ -#endif /* !EAI_FAIL */ - -#ifndef AI_PASSIVE -#define AI_PASSIVE 0x0001 -#endif - -#ifndef AI_NUMERICHOST -/* - * some platforms don't support AI_NUMERICHOST; define as zero if using - * the system version of getaddrinfo... - */ -#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) -#define AI_NUMERICHOST 0 -#else -#define AI_NUMERICHOST 0x0004 -#endif -#endif - -#ifndef NI_NUMERICHOST -#define NI_NUMERICHOST 1 -#endif -#ifndef NI_NUMERICSERV -#define NI_NUMERICSERV 2 -#endif -#ifndef NI_NAMEREQD -#define NI_NAMEREQD 4 -#endif - -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif -#ifndef NI_MAXSERV -#define NI_MAXSERV 32 -#endif - - -#ifndef HAVE_STRUCT_ADDRINFO - -#ifndef WIN32 -struct addrinfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; - struct addrinfo *ai_next; -}; -#else -/* - * The order of the structure elements on Win32 doesn't match the - * order specified in the standard, but we have to match it for - * IPv6 to work. - */ -struct addrinfo -{ - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - char *ai_canonname; - struct sockaddr *ai_addr; - struct addrinfo *ai_next; -}; -#endif -#endif /* HAVE_STRUCT_ADDRINFO */ - - -#ifndef HAVE_GETADDRINFO - -/* Rename private copies per comments above */ -#ifdef getaddrinfo -#undef getaddrinfo -#endif -#define getaddrinfo pg_getaddrinfo - -#ifdef freeaddrinfo -#undef freeaddrinfo -#endif -#define freeaddrinfo pg_freeaddrinfo - -#ifdef gai_strerror -#undef gai_strerror -#endif -#define gai_strerror pg_gai_strerror - -#ifdef getnameinfo -#undef getnameinfo -#endif -#define getnameinfo pg_getnameinfo - -extern int getaddrinfo(const char *node, const char *service, - const struct addrinfo * hints, struct addrinfo ** res); -extern void freeaddrinfo(struct addrinfo * res); -extern const char *gai_strerror(int errcode); -extern int getnameinfo(const struct sockaddr * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, int flags); -#endif /* HAVE_GETADDRINFO */ - -#endif /* GETADDRINFO_H */ diff --git a/libpq/postgresql/libpq/ip.h b/libpq/postgresql/libpq/ip.h deleted file mode 100644 index ce9bc6e..0000000 --- a/libpq/postgresql/libpq/ip.h +++ /dev/null @@ -1,51 +0,0 @@ -/*------------------------------------------------------------------------- - * - * ip.h - * Definitions for IPv6-aware network access. - * - * These definitions are used by both frontend and backend code. Be careful - * what you include here! - * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group - * - * src/include/libpq/ip.h - * - *------------------------------------------------------------------------- - */ -#ifndef IP_H -#define IP_H - -#include "getaddrinfo.h" /* pgrminclude ignore */ -#include "libpq/pqcomm.h" /* pgrminclude ignore */ - - -#ifdef HAVE_UNIX_SOCKETS -#define IS_AF_UNIX(fam) ((fam) == AF_UNIX) -#else -#define IS_AF_UNIX(fam) (0) -#endif - -typedef void (*PgIfAddrCallback) (struct sockaddr * addr, - struct sockaddr * netmask, - void *cb_data); - -extern int pg_getaddrinfo_all(const char *hostname, const char *servname, - const struct addrinfo * hintp, - struct addrinfo ** result); -extern void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai); - -extern int pg_getnameinfo_all(const struct sockaddr_storage * addr, int salen, - char *node, int nodelen, - char *service, int servicelen, - int flags); - -extern int pg_range_sockaddr(const struct sockaddr_storage * addr, - const struct sockaddr_storage * netaddr, - const struct sockaddr_storage * netmask); - -extern int pg_sockaddr_cidr_mask(struct sockaddr_storage * mask, - char *numbits, int family); - -extern int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data); - -#endif /* IP_H */ diff --git a/libpq/postgresql/libpq/libpq-fs.h b/libpq/postgresql/libpq/libpq-fs.h deleted file mode 100644 index 5134ce6..0000000 --- a/libpq/postgresql/libpq/libpq-fs.h +++ /dev/null @@ -1,24 +0,0 @@ -/*------------------------------------------------------------------------- - * - * libpq-fs.h - * definitions for using Inversion file system routines (ie, large objects) - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/libpq/libpq-fs.h - * - *------------------------------------------------------------------------- - */ -#ifndef LIBPQ_FS_H -#define LIBPQ_FS_H - -/* - * Read/write mode flags for inversion (large object) calls - */ - -#define INV_WRITE 0x00020000 -#define INV_READ 0x00040000 - -#endif /* LIBPQ_FS_H */ diff --git a/libpq/postgresql/libpq/md5.h b/libpq/postgresql/libpq/md5.h deleted file mode 100644 index f3eec8b..0000000 --- a/libpq/postgresql/libpq/md5.h +++ /dev/null @@ -1,30 +0,0 @@ -/*------------------------------------------------------------------------- - * - * md5.h - * Interface to libpq/md5.c - * - * These definitions are needed by both frontend and backend code to work - * with MD5-encrypted passwords. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/libpq/md5.h - * - *------------------------------------------------------------------------- - */ -#ifndef PG_MD5_H -#define PG_MD5_H - -#define MD5_PASSWD_LEN 35 - -#define isMD5(passwd) (strncmp(passwd, "md5", 3) == 0 && \ - strlen(passwd) == MD5_PASSWD_LEN) - - -extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum); -extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf); -extern bool pg_md5_encrypt(const char *passwd, const char *salt, - size_t salt_len, char *buf); - -#endif diff --git a/libpq/postgresql/libpq/pqcomm.h b/libpq/postgresql/libpq/pqcomm.h deleted file mode 100644 index 1d063d1..0000000 --- a/libpq/postgresql/libpq/pqcomm.h +++ /dev/null @@ -1,206 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pqcomm.h - * Definitions common to frontends and backends. - * - * NOTE: for historical reasons, this does not correspond to pqcomm.c. - * pqcomm.c's routines are declared in libpq.h. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/libpq/pqcomm.h - * - *------------------------------------------------------------------------- - */ -#ifndef PQCOMM_H -#define PQCOMM_H - -#include -#include -#ifdef HAVE_SYS_UN_H -#include -#endif -#include - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE - -#ifndef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY -#define ss_family __ss_family -#else -#error struct sockaddr_storage does not provide an ss_family member -#endif -#endif - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN -#define ss_len __ss_len -#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 -#endif -#else /* !HAVE_STRUCT_SOCKADDR_STORAGE */ - -/* Define a struct sockaddr_storage if we don't have one. */ - -struct sockaddr_storage -{ - union - { - struct sockaddr sa; /* get the system-dependent fields */ - int64 ss_align; /* ensures struct is properly aligned */ - char ss_pad[128]; /* ensures struct has desired size */ - } ss_stuff; -}; - -#define ss_family ss_stuff.sa.sa_family -/* It should have an ss_len field if sockaddr has sa_len. */ -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN -#define ss_len ss_stuff.sa.sa_len -#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 -#endif -#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */ - -typedef struct -{ - struct sockaddr_storage addr; - ACCEPT_TYPE_ARG3 salen; -} SockAddr; - -/* Configure the UNIX socket location for the well known port. */ - -#define UNIXSOCK_PATH(path, port, sockdir) \ - snprintf(path, sizeof(path), "%s/.s.PGSQL.%d", \ - ((sockdir) && *(sockdir) != '\0') ? (sockdir) : \ - DEFAULT_PGSOCKET_DIR, \ - (port)) - -/* - * The maximum workable length of a socket path is what will fit into - * struct sockaddr_un. This is usually only 100 or so bytes :-(. - * - * For consistency, always pass a MAXPGPATH-sized buffer to UNIXSOCK_PATH(), - * then complain if the resulting string is >= UNIXSOCK_PATH_BUFLEN bytes. - * (Because the standard API for getaddrinfo doesn't allow it to complain in - * a useful way when the socket pathname is too long, we have to test for - * this explicitly, instead of just letting the subroutine return an error.) - */ -#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path) - - -/* - * These manipulate the frontend/backend protocol version number. - * - * The major number should be incremented for incompatible changes. The minor - * number should be incremented for compatible changes (eg. additional - * functionality). - * - * If a backend supports version m.n of the protocol it must actually support - * versions m.[0..n]. Backend support for version m-1 can be dropped after a - * `reasonable' length of time. - * - * A frontend isn't required to support anything other than the current - * version. - */ - -#define PG_PROTOCOL_MAJOR(v) ((v) >> 16) -#define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff) -#define PG_PROTOCOL(m,n) (((m) << 16) | (n)) - -/* The earliest and latest frontend/backend protocol version supported. */ - -#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) -#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0) - -typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ - -typedef ProtocolVersion MsgType; - - -/* - * Packet lengths are 4 bytes in network byte order. - * - * The initial length is omitted from the packet layouts appearing below. - */ - -typedef uint32 PacketLen; - - -/* - * Old-style startup packet layout with fixed-width fields. This is used in - * protocol 1.0 and 2.0, but not in later versions. Note that the fields - * in this layout are '\0' terminated only if there is room. - */ - -#define SM_DATABASE 64 -#define SM_USER 32 -/* We append database name if db_user_namespace true. */ -#define SM_DATABASE_USER (SM_DATABASE+SM_USER+1) /* +1 for @ */ -#define SM_OPTIONS 64 -#define SM_UNUSED 64 -#define SM_TTY 64 - -typedef struct StartupPacket -{ - ProtocolVersion protoVersion; /* Protocol version */ - char database[SM_DATABASE]; /* Database name */ - /* Db_user_namespace appends dbname */ - char user[SM_USER]; /* User name */ - char options[SM_OPTIONS]; /* Optional additional args */ - char unused[SM_UNUSED]; /* Unused */ - char tty[SM_TTY]; /* Tty for debug output */ -} StartupPacket; - -extern bool Db_user_namespace; - -/* - * In protocol 3.0 and later, the startup packet length is not fixed, but - * we set an arbitrary limit on it anyway. This is just to prevent simple - * denial-of-service attacks via sending enough data to run the server - * out of memory. - */ -#define MAX_STARTUP_PACKET_LENGTH 10000 - - -/* These are the authentication request codes sent by the backend. */ - -#define AUTH_REQ_OK 0 /* User is authenticated */ -#define AUTH_REQ_KRB4 1 /* Kerberos V4. Not supported any more. */ -#define AUTH_REQ_KRB5 2 /* Kerberos V5. Not supported any more. */ -#define AUTH_REQ_PASSWORD 3 /* Password */ -#define AUTH_REQ_CRYPT 4 /* crypt password. Not supported any more. */ -#define AUTH_REQ_MD5 5 /* md5 password */ -#define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */ -#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */ -#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */ -#define AUTH_REQ_SSPI 9 /* SSPI negotiate without wrap() */ -#define AUTH_REQ_SASL 10 /* SASL authentication. Not supported before - * libpq version 10. */ - -typedef uint32 AuthRequest; - - -/* - * A client can also send a cancel-current-operation request to the postmaster. - * This is uglier than sending it directly to the client's backend, but it - * avoids depending on out-of-band communication facilities. - * - * The cancel request code must not match any protocol version number - * we're ever likely to use. This random choice should do. - */ -#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678) - -typedef struct CancelRequestPacket -{ - /* Note that each field is stored in network byte order! */ - MsgType cancelRequestCode; /* code to identify a cancel request */ - uint32 backendPID; /* PID of client's backend */ - uint32 cancelAuthCode; /* secret key to authorize cancel */ -} CancelRequestPacket; - - -/* - * A client can also start by sending a SSL negotiation request, to get a - * secure channel. - */ -#define NEGOTIATE_SSL_CODE PG_PROTOCOL(1234,5679) - -#endif /* PQCOMM_H */ diff --git a/libpq/postgresql/mb/pg_wchar.h b/libpq/postgresql/mb/pg_wchar.h deleted file mode 100644 index 24e8d0d..0000000 --- a/libpq/postgresql/mb/pg_wchar.h +++ /dev/null @@ -1,561 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pg_wchar.h - * multibyte-character support - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/mb/pg_wchar.h - * - * NOTES - * This is used both by the backend and by libpq, but should not be - * included by libpq client programs. In particular, a libpq client - * should not assume that the encoding IDs used by the version of libpq - * it's linked to match up with the IDs declared here. - * - *------------------------------------------------------------------------- - */ -#ifndef PG_WCHAR_H -#define PG_WCHAR_H - -/* - * The pg_wchar type - */ -typedef unsigned int pg_wchar; - -/* - * Maximum byte length of multibyte characters in any backend encoding - */ -#define MAX_MULTIBYTE_CHAR_LEN 4 - -/* - * various definitions for EUC - */ -#define SS2 0x8e /* single shift 2 (JIS0201) */ -#define SS3 0x8f /* single shift 3 (JIS0212) */ - -/* - * SJIS validation macros - */ -#define ISSJISHEAD(c) (((c) >= 0x81 && (c) <= 0x9f) || ((c) >= 0xe0 && (c) <= 0xfc)) -#define ISSJISTAIL(c) (((c) >= 0x40 && (c) <= 0x7e) || ((c) >= 0x80 && (c) <= 0xfc)) - -/*---------------------------------------------------- - * MULE Internal Encoding (MIC) - * - * This encoding follows the design used within XEmacs; it is meant to - * subsume many externally-defined character sets. Each character includes - * identification of the character set it belongs to, so the encoding is - * general but somewhat bulky. - * - * Currently PostgreSQL supports 5 types of MULE character sets: - * - * 1) 1-byte ASCII characters. Each byte is below 0x80. - * - * 2) "Official" single byte charsets such as ISO-8859-1 (Latin1). - * Each MULE character consists of 2 bytes: LC1 + C1, where LC1 is - * an identifier for the charset (in the range 0x81 to 0x8d) and C1 - * is the character code (in the range 0xa0 to 0xff). - * - * 3) "Private" single byte charsets such as SISHENG. Each MULE - * character consists of 3 bytes: LCPRV1 + LC12 + C1, where LCPRV1 - * is a private-charset flag, LC12 is an identifier for the charset, - * and C1 is the character code (in the range 0xa0 to 0xff). - * LCPRV1 is either 0x9a (if LC12 is in the range 0xa0 to 0xdf) - * or 0x9b (if LC12 is in the range 0xe0 to 0xef). - * - * 4) "Official" multibyte charsets such as JIS X0208. Each MULE - * character consists of 3 bytes: LC2 + C1 + C2, where LC2 is - * an identifier for the charset (in the range 0x90 to 0x99) and C1 - * and C2 form the character code (each in the range 0xa0 to 0xff). - * - * 5) "Private" multibyte charsets such as CNS 11643-1992 Plane 3. - * Each MULE character consists of 4 bytes: LCPRV2 + LC22 + C1 + C2, - * where LCPRV2 is a private-charset flag, LC22 is an identifier for - * the charset, and C1 and C2 form the character code (each in the range - * 0xa0 to 0xff). LCPRV2 is either 0x9c (if LC22 is in the range 0xf0 - * to 0xf4) or 0x9d (if LC22 is in the range 0xf5 to 0xfe). - * - * "Official" encodings are those that have been assigned code numbers by - * the XEmacs project; "private" encodings have Postgres-specific charset - * identifiers. - * - * See the "XEmacs Internals Manual", available at http://www.xemacs.org, - * for more details. Note that for historical reasons, Postgres' - * private-charset flag values do not match what XEmacs says they should be, - * so this isn't really exactly MULE (not that private charsets would be - * interoperable anyway). - * - * Note that XEmacs's implementation is different from what emacs does. - * We follow emacs's implementation, rather than XEmacs's. - *---------------------------------------------------- - */ - -/* - * Charset identifiers (also called "leading bytes" in the MULE documentation) - */ - -/* - * Charset IDs for official single byte encodings (0x81-0x8e) - */ -#define LC_ISO8859_1 0x81 /* ISO8859 Latin 1 */ -#define LC_ISO8859_2 0x82 /* ISO8859 Latin 2 */ -#define LC_ISO8859_3 0x83 /* ISO8859 Latin 3 */ -#define LC_ISO8859_4 0x84 /* ISO8859 Latin 4 */ -#define LC_TIS620 0x85 /* Thai (not supported yet) */ -#define LC_ISO8859_7 0x86 /* Greek (not supported yet) */ -#define LC_ISO8859_6 0x87 /* Arabic (not supported yet) */ -#define LC_ISO8859_8 0x88 /* Hebrew (not supported yet) */ -#define LC_JISX0201K 0x89 /* Japanese 1 byte kana */ -#define LC_JISX0201R 0x8a /* Japanese 1 byte Roman */ -/* Note that 0x8b seems to be unused as of Emacs 20.7. - * However, there might be a chance that 0x8b could be used - * in later versions of Emacs. - */ -#define LC_KOI8_R 0x8b /* Cyrillic KOI8-R */ -#define LC_ISO8859_5 0x8c /* ISO8859 Cyrillic */ -#define LC_ISO8859_9 0x8d /* ISO8859 Latin 5 (not supported yet) */ -#define LC_ISO8859_15 0x8e /* ISO8859 Latin 15 (not supported yet) */ -/* #define CONTROL_1 0x8f control characters (unused) */ - -/* Is a leading byte for "official" single byte encodings? */ -#define IS_LC1(c) ((unsigned char)(c) >= 0x81 && (unsigned char)(c) <= 0x8d) - -/* - * Charset IDs for official multibyte encodings (0x90-0x99) - * 0x9a-0x9d are free. 0x9e and 0x9f are reserved. - */ -#define LC_JISX0208_1978 0x90 /* Japanese Kanji, old JIS (not supported) */ -#define LC_GB2312_80 0x91 /* Chinese */ -#define LC_JISX0208 0x92 /* Japanese Kanji (JIS X 0208) */ -#define LC_KS5601 0x93 /* Korean */ -#define LC_JISX0212 0x94 /* Japanese Kanji (JIS X 0212) */ -#define LC_CNS11643_1 0x95 /* CNS 11643-1992 Plane 1 */ -#define LC_CNS11643_2 0x96 /* CNS 11643-1992 Plane 2 */ -#define LC_JISX0213_1 0x97/* Japanese Kanji (JIS X 0213 Plane 1) (not - * supported) */ -#define LC_BIG5_1 0x98 /* Plane 1 Chinese traditional (not supported) */ -#define LC_BIG5_2 0x99 /* Plane 1 Chinese traditional (not supported) */ - -/* Is a leading byte for "official" multibyte encodings? */ -#define IS_LC2(c) ((unsigned char)(c) >= 0x90 && (unsigned char)(c) <= 0x99) - -/* - * Postgres-specific prefix bytes for "private" single byte encodings - * (According to the MULE docs, we should be using 0x9e for this) - */ -#define LCPRV1_A 0x9a -#define LCPRV1_B 0x9b -#define IS_LCPRV1(c) ((unsigned char)(c) == LCPRV1_A || (unsigned char)(c) == LCPRV1_B) -#define IS_LCPRV1_A_RANGE(c) \ - ((unsigned char)(c) >= 0xa0 && (unsigned char)(c) <= 0xdf) -#define IS_LCPRV1_B_RANGE(c) \ - ((unsigned char)(c) >= 0xe0 && (unsigned char)(c) <= 0xef) - -/* - * Postgres-specific prefix bytes for "private" multibyte encodings - * (According to the MULE docs, we should be using 0x9f for this) - */ -#define LCPRV2_A 0x9c -#define LCPRV2_B 0x9d -#define IS_LCPRV2(c) ((unsigned char)(c) == LCPRV2_A || (unsigned char)(c) == LCPRV2_B) -#define IS_LCPRV2_A_RANGE(c) \ - ((unsigned char)(c) >= 0xf0 && (unsigned char)(c) <= 0xf4) -#define IS_LCPRV2_B_RANGE(c) \ - ((unsigned char)(c) >= 0xf5 && (unsigned char)(c) <= 0xfe) - -/* - * Charset IDs for private single byte encodings (0xa0-0xef) - */ -#define LC_SISHENG 0xa0/* Chinese SiSheng characters for - * PinYin/ZhuYin (not supported) */ -#define LC_IPA 0xa1/* IPA (International Phonetic Association) - * (not supported) */ -#define LC_VISCII_LOWER 0xa2/* Vietnamese VISCII1.1 lower-case (not - * supported) */ -#define LC_VISCII_UPPER 0xa3/* Vietnamese VISCII1.1 upper-case (not - * supported) */ -#define LC_ARABIC_DIGIT 0xa4 /* Arabic digit (not supported) */ -#define LC_ARABIC_1_COLUMN 0xa5 /* Arabic 1-column (not supported) */ -#define LC_ASCII_RIGHT_TO_LEFT 0xa6 /* ASCII (left half of ISO8859-1) with - * right-to-left direction (not - * supported) */ -#define LC_LAO 0xa7/* Lao characters (ISO10646 0E80..0EDF) (not - * supported) */ -#define LC_ARABIC_2_COLUMN 0xa8 /* Arabic 1-column (not supported) */ - -/* - * Charset IDs for private multibyte encodings (0xf0-0xff) - */ -#define LC_INDIAN_1_COLUMN 0xf0/* Indian charset for 1-column width glyphs - * (not supported) */ -#define LC_TIBETAN_1_COLUMN 0xf1/* Tibetan 1-column width glyphs (not - * supported) */ -#define LC_UNICODE_SUBSET_2 0xf2/* Unicode characters of the range - * U+2500..U+33FF. (not supported) */ -#define LC_UNICODE_SUBSET_3 0xf3/* Unicode characters of the range - * U+E000..U+FFFF. (not supported) */ -#define LC_UNICODE_SUBSET 0xf4/* Unicode characters of the range - * U+0100..U+24FF. (not supported) */ -#define LC_ETHIOPIC 0xf5 /* Ethiopic characters (not supported) */ -#define LC_CNS11643_3 0xf6 /* CNS 11643-1992 Plane 3 */ -#define LC_CNS11643_4 0xf7 /* CNS 11643-1992 Plane 4 */ -#define LC_CNS11643_5 0xf8 /* CNS 11643-1992 Plane 5 */ -#define LC_CNS11643_6 0xf9 /* CNS 11643-1992 Plane 6 */ -#define LC_CNS11643_7 0xfa /* CNS 11643-1992 Plane 7 */ -#define LC_INDIAN_2_COLUMN 0xfb/* Indian charset for 2-column width glyphs - * (not supported) */ -#define LC_TIBETAN 0xfc /* Tibetan (not supported) */ -/* #define FREE 0xfd free (unused) */ -/* #define FREE 0xfe free (unused) */ -/* #define FREE 0xff free (unused) */ - -/*---------------------------------------------------- - * end of MULE stuff - *---------------------------------------------------- - */ - -/* - * PostgreSQL encoding identifiers - * - * WARNING: the order of this enum must be same as order of entries - * in the pg_enc2name_tbl[] array (in mb/encnames.c), and - * in the pg_wchar_table[] array (in mb/wchar.c)! - * - * If you add some encoding don't forget to check - * PG_ENCODING_BE_LAST macro. - * - * PG_SQL_ASCII is default encoding and must be = 0. - * - * XXX We must avoid renumbering any backend encoding until libpq's major - * version number is increased beyond 5; it turns out that the backend - * encoding IDs are effectively part of libpq's ABI as far as 8.2 initdb and - * psql are concerned. - */ -typedef enum pg_enc -{ - PG_SQL_ASCII = 0, /* SQL/ASCII */ - PG_EUC_JP, /* EUC for Japanese */ - PG_EUC_CN, /* EUC for Chinese */ - PG_EUC_KR, /* EUC for Korean */ - PG_EUC_TW, /* EUC for Taiwan */ - PG_EUC_JIS_2004, /* EUC-JIS-2004 */ - PG_UTF8, /* Unicode UTF8 */ - PG_MULE_INTERNAL, /* Mule internal code */ - PG_LATIN1, /* ISO-8859-1 Latin 1 */ - PG_LATIN2, /* ISO-8859-2 Latin 2 */ - PG_LATIN3, /* ISO-8859-3 Latin 3 */ - PG_LATIN4, /* ISO-8859-4 Latin 4 */ - PG_LATIN5, /* ISO-8859-9 Latin 5 */ - PG_LATIN6, /* ISO-8859-10 Latin6 */ - PG_LATIN7, /* ISO-8859-13 Latin7 */ - PG_LATIN8, /* ISO-8859-14 Latin8 */ - PG_LATIN9, /* ISO-8859-15 Latin9 */ - PG_LATIN10, /* ISO-8859-16 Latin10 */ - PG_WIN1256, /* windows-1256 */ - PG_WIN1258, /* Windows-1258 */ - PG_WIN866, /* (MS-DOS CP866) */ - PG_WIN874, /* windows-874 */ - PG_KOI8R, /* KOI8-R */ - PG_WIN1251, /* windows-1251 */ - PG_WIN1252, /* windows-1252 */ - PG_ISO_8859_5, /* ISO-8859-5 */ - PG_ISO_8859_6, /* ISO-8859-6 */ - PG_ISO_8859_7, /* ISO-8859-7 */ - PG_ISO_8859_8, /* ISO-8859-8 */ - PG_WIN1250, /* windows-1250 */ - PG_WIN1253, /* windows-1253 */ - PG_WIN1254, /* windows-1254 */ - PG_WIN1255, /* windows-1255 */ - PG_WIN1257, /* windows-1257 */ - PG_KOI8U, /* KOI8-U */ - /* PG_ENCODING_BE_LAST points to the above entry */ - - /* followings are for client encoding only */ - PG_SJIS, /* Shift JIS (Windows-932) */ - PG_BIG5, /* Big5 (Windows-950) */ - PG_GBK, /* GBK (Windows-936) */ - PG_UHC, /* UHC (Windows-949) */ - PG_GB18030, /* GB18030 */ - PG_JOHAB, /* EUC for Korean JOHAB */ - PG_SHIFT_JIS_2004, /* Shift-JIS-2004 */ - _PG_LAST_ENCODING_ /* mark only */ - -} pg_enc; - -#define PG_ENCODING_BE_LAST PG_KOI8U - -/* - * Please use these tests before access to pg_encconv_tbl[] - * or to other places... - */ -#define PG_VALID_BE_ENCODING(_enc) \ - ((_enc) >= 0 && (_enc) <= PG_ENCODING_BE_LAST) - -#define PG_ENCODING_IS_CLIENT_ONLY(_enc) \ - ((_enc) > PG_ENCODING_BE_LAST && (_enc) < _PG_LAST_ENCODING_) - -#define PG_VALID_ENCODING(_enc) \ - ((_enc) >= 0 && (_enc) < _PG_LAST_ENCODING_) - -/* On FE are possible all encodings */ -#define PG_VALID_FE_ENCODING(_enc) PG_VALID_ENCODING(_enc) - -/* - * Table for mapping an encoding number to official encoding name and - * possibly other subsidiary data. Be careful to check encoding number - * before accessing a table entry! - * - * if (PG_VALID_ENCODING(encoding)) - * pg_enc2name_tbl[ encoding ]; - */ -typedef struct pg_enc2name -{ - const char *name; - pg_enc encoding; -#ifdef WIN32 - unsigned codepage; /* codepage for WIN32 */ -#endif -} pg_enc2name; - -extern const pg_enc2name pg_enc2name_tbl[]; - -/* - * Encoding names for gettext - */ -typedef struct pg_enc2gettext -{ - pg_enc encoding; - const char *name; -} pg_enc2gettext; - -extern const pg_enc2gettext pg_enc2gettext_tbl[]; - -/* - * pg_wchar stuff - */ -typedef int (*mb2wchar_with_len_converter) (const unsigned char *from, - pg_wchar *to, - int len); - -typedef int (*wchar2mb_with_len_converter) (const pg_wchar *from, - unsigned char *to, - int len); - -typedef int (*mblen_converter) (const unsigned char *mbstr); - -typedef int (*mbdisplaylen_converter) (const unsigned char *mbstr); - -typedef bool (*mbcharacter_incrementer) (unsigned char *mbstr, int len); - -typedef int (*mbverifier) (const unsigned char *mbstr, int len); - -typedef struct -{ - mb2wchar_with_len_converter mb2wchar_with_len; /* convert a multibyte - * string to a wchar */ - wchar2mb_with_len_converter wchar2mb_with_len; /* convert a wchar - * string to a multibyte */ - mblen_converter mblen; /* get byte length of a char */ - mbdisplaylen_converter dsplen; /* get display width of a char */ - mbverifier mbverify; /* verify multibyte sequence */ - int maxmblen; /* max bytes for a char in this encoding */ -} pg_wchar_tbl; - -extern const pg_wchar_tbl pg_wchar_table[]; - -/* - * Data structures for conversions between UTF-8 and other encodings - * (UtfToLocal() and LocalToUtf()). In these data structures, characters of - * either encoding are represented by uint32 words; hence we can only support - * characters up to 4 bytes long. For example, the byte sequence 0xC2 0x89 - * would be represented by 0x0000C289, and 0xE8 0xA2 0xB4 by 0x00E8A2B4. - * - * Maps are arrays of these structs, which must be in order by the lookup key - * (so that bsearch() can be used). - * - * UTF-8 to local code conversion map - */ -typedef struct -{ - uint32 utf; /* UTF-8 */ - uint32 code; /* local code */ -} pg_utf_to_local; - -/* - * local code to UTF-8 conversion map - */ -typedef struct -{ - uint32 code; /* local code */ - uint32 utf; /* UTF-8 */ -} pg_local_to_utf; - -/* - * UTF-8 to local code conversion map (for combined characters) - */ -typedef struct -{ - uint32 utf1; /* UTF-8 code 1 */ - uint32 utf2; /* UTF-8 code 2 */ - uint32 code; /* local code */ -} pg_utf_to_local_combined; - -/* - * local code to UTF-8 conversion map (for combined characters) - */ -typedef struct -{ - uint32 code; /* local code */ - uint32 utf1; /* UTF-8 code 1 */ - uint32 utf2; /* UTF-8 code 2 */ -} pg_local_to_utf_combined; - -/* - * callback function for algorithmic encoding conversions (in either direction) - * - * if function returns zero, it does not know how to convert the code - */ -typedef uint32 (*utf_local_conversion_func) (uint32 code); - -/* - * Support macro for encoding conversion functions to validate their - * arguments. (This could be made more compact if we included fmgr.h - * here, but we don't want to do that because this header file is also - * used by frontends.) - */ -#define CHECK_ENCODING_CONVERSION_ARGS(srcencoding,destencoding) \ - check_encoding_conversion_args(PG_GETARG_INT32(0), \ - PG_GETARG_INT32(1), \ - PG_GETARG_INT32(4), \ - (srcencoding), \ - (destencoding)) - - -/* - * These functions are considered part of libpq's exported API and - * are also declared in libpq-fe.h. - */ -extern int pg_char_to_encoding(const char *name); -extern const char *pg_encoding_to_char(int encoding); -extern int pg_valid_server_encoding_id(int encoding); - -/* - * Remaining functions are not considered part of libpq's API, though many - * of them do exist inside libpq. - */ -extern int pg_mb2wchar(const char *from, pg_wchar *to); -extern int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len); -extern int pg_encoding_mb2wchar_with_len(int encoding, - const char *from, pg_wchar *to, int len); -extern int pg_wchar2mb(const pg_wchar *from, char *to); -extern int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len); -extern int pg_encoding_wchar2mb_with_len(int encoding, - const pg_wchar *from, char *to, int len); -extern int pg_char_and_wchar_strcmp(const char *s1, const pg_wchar *s2); -extern int pg_wchar_strncmp(const pg_wchar *s1, const pg_wchar *s2, size_t n); -extern int pg_char_and_wchar_strncmp(const char *s1, const pg_wchar *s2, size_t n); -extern size_t pg_wchar_strlen(const pg_wchar *wstr); -extern int pg_mblen(const char *mbstr); -extern int pg_dsplen(const char *mbstr); -extern int pg_encoding_mblen(int encoding, const char *mbstr); -extern int pg_encoding_dsplen(int encoding, const char *mbstr); -extern int pg_encoding_verifymb(int encoding, const char *mbstr, int len); -extern int pg_mule_mblen(const unsigned char *mbstr); -extern int pg_mic_mblen(const unsigned char *mbstr); -extern int pg_mbstrlen(const char *mbstr); -extern int pg_mbstrlen_with_len(const char *mbstr, int len); -extern int pg_mbcliplen(const char *mbstr, int len, int limit); -extern int pg_encoding_mbcliplen(int encoding, const char *mbstr, - int len, int limit); -extern int pg_mbcharcliplen(const char *mbstr, int len, int imit); -extern int pg_encoding_max_length(int encoding); -extern int pg_database_encoding_max_length(void); -extern mbcharacter_incrementer pg_database_encoding_character_incrementer(void); - -extern int PrepareClientEncoding(int encoding); -extern int SetClientEncoding(int encoding); -extern void InitializeClientEncoding(void); -extern int pg_get_client_encoding(void); -extern const char *pg_get_client_encoding_name(void); - -extern void SetDatabaseEncoding(int encoding); -extern int GetDatabaseEncoding(void); -extern const char *GetDatabaseEncodingName(void); -extern void SetMessageEncoding(int encoding); -extern int GetMessageEncoding(void); - -#ifdef ENABLE_NLS -extern int pg_bind_textdomain_codeset(const char *domainname); -#endif - -extern int pg_valid_client_encoding(const char *name); -extern int pg_valid_server_encoding(const char *name); - -extern unsigned char *unicode_to_utf8(pg_wchar c, unsigned char *utf8string); -extern pg_wchar utf8_to_unicode(const unsigned char *c); -extern int pg_utf_mblen(const unsigned char *); -extern unsigned char *pg_do_encoding_conversion(unsigned char *src, int len, - int src_encoding, - int dest_encoding); - -extern char *pg_client_to_server(const char *s, int len); -extern char *pg_server_to_client(const char *s, int len); -extern char *pg_any_to_server(const char *s, int len, int encoding); -extern char *pg_server_to_any(const char *s, int len, int encoding); - -extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc); -extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc); - -extern void UtfToLocal(const unsigned char *utf, int len, - unsigned char *iso, - const pg_utf_to_local *map, int mapsize, - const pg_utf_to_local_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); -extern void LocalToUtf(const unsigned char *iso, int len, - unsigned char *utf, - const pg_local_to_utf *map, int mapsize, - const pg_local_to_utf_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); - -extern bool pg_verifymbstr(const char *mbstr, int len, bool noError); -extern bool pg_verify_mbstr(int encoding, const char *mbstr, int len, - bool noError); -extern int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, - bool noError); - -extern void check_encoding_conversion_args(int src_encoding, - int dest_encoding, - int len, - int expected_src_encoding, - int expected_dest_encoding); - -extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn(); -extern void report_untranslatable_char(int src_encoding, int dest_encoding, - const char *mbstr, int len) pg_attribute_noreturn(); - -extern void local2local(const unsigned char *l, unsigned char *p, int len, - int src_encoding, int dest_encoding, const unsigned char *tab); -extern void pg_ascii2mic(const unsigned char *l, unsigned char *p, int len); -extern void pg_mic2ascii(const unsigned char *mic, unsigned char *p, int len); -extern void latin2mic(const unsigned char *l, unsigned char *p, int len, - int lc, int encoding); -extern void mic2latin(const unsigned char *mic, unsigned char *p, int len, - int lc, int encoding); -extern void latin2mic_with_table(const unsigned char *l, unsigned char *p, - int len, int lc, int encoding, - const unsigned char *tab); -extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p, - int len, int lc, int encoding, - const unsigned char *tab); - -extern bool pg_utf8_islegal(const unsigned char *source, int length); - -#ifdef WIN32 -extern WCHAR *pgwin32_message_to_UTF16(const char *str, int len, int *utf16len); -#endif - -#endif /* PG_WCHAR_H */ diff --git a/libpq/postgresql/pg_config.h b/libpq/postgresql/pg_config.h deleted file mode 100644 index 4d38fba..0000000 --- a/libpq/postgresql/pg_config.h +++ /dev/null @@ -1,280 +0,0 @@ -/* file : libpq/postgresql/pg_config.h -*- C -*- - * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd - * license : PostgreSQL License; see accompanying COPYRIGHT file - */ - -/* - * For the semantics of the following macros refer to - * libpq/postgresql/pg_config.h.in.orig and - * libpq/postgresql/pg_config.h.win32.orig files. - * - * Note that we will explicitly undefine macros that are present in the libpq - * source code but should not be defined. While this is not technically - * required, it simplifies the change tracking (see README-DEV). As a bonus we - * also make sure that they are not get eventually defined by some system - * headers. - */ - -#include /* offsetof() */ - -/* - * Version. - */ -#undef PG_MAJORVERSION -#undef PG_VERSION_NUM -#include - -/* - * Types, type sizes and alignments. - */ -#define ALIGNOF_(type) offsetof (struct {char c; type m;}, m) -#define ALIGNOF_DOUBLE ALIGNOF_ (double) -#define ALIGNOF_INT ALIGNOF_ (int) -#define ALIGNOF_LONG ALIGNOF_ (long) -#define ALIGNOF_SHORT ALIGNOF_ (short) - -/* - * GCC and Clang provide __SIZEOF_*__ and __*_TYPE__ predefined macros that we - * use to define the required libpq macros. Note that on Windows long and - * long long types are always of 32 and 64 bits width respectively. - */ -#ifndef _WIN32 -# if __SIZEOF_LONG__ == 8 -# define HAVE_LONG_INT_64 1 -# endif -# if __SIZEOF_LONG_LONG__ == 8 -# define HAVE_LONG_LONG_INT_64 1 -# endif -# if __SIZEOF_LONG_LONG__ > __SIZEOF_DOUBLE__ -# define MAXIMUM_ALIGNOF __SIZEOF_LONG_LONG__ -# else -# define MAXIMUM_ALIGNOF __SIZEOF_DOUBLE__ -# endif -# ifdef __SIZEOF_INT128__ -# define PG_INT128_TYPE __int128 -# endif -# define PG_INT64_TYPE __INT64_TYPE__ -# define ACCEPT_TYPE_ARG3 socklen_t -# define SIZEOF_SIZE_T __SIZEOF_SIZE_T__ -#else -# define HAVE_LONG_LONG_INT_64 1 -# define MAXIMUM_ALIGNOF 8 -# define PG_INT64_TYPE long long int -# define ACCEPT_TYPE_ARG3 int -# ifdef _WIN64 -# define SIZEOF_SIZE_T 8 -# else -# define SIZEOF_SIZE_T 4 -# endif -#endif - -#define INT64_MODIFIER "ll" - -/* - * Specific for FreeBSD. - */ -#ifdef __FreeBSD__ -# define HAVE_STRUCT_CMSGCRED 1 -#endif - -/* - * Specific for Mac OS. - */ -#ifdef __APPLE__ -# define HAVE_DECL_F_FULLFSYNC 1 -#else -# define HAVE_DECL_F_FULLFSYNC 0 -#endif - -/* - * Specific for FreeBSD and Mac OS. - */ -#if defined(__FreeBSD__) || defined(__APPLE__) -# define HAVE_DECL_STRLCAT 1 -# define HAVE_DECL_STRLCPY 1 -# define STRERROR_R_INT 1 -# define HAVE_FLS 1 -# define HAVE_GETPEEREID 1 -# define HAVE_STRTOQ 1 -# define HAVE_STRTOUQ 1 -# define HAVE_STRUCT_SOCKADDR_SA_LEN 1 -# define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 -# define HAVE_SYS_SOCKIO_H 1 -# define HAVE_SYS_UCRED_H 1 -# define HAVE_UNION_SEMUN 1 -#else -# define HAVE_DECL_STRLCAT 0 -# define HAVE_DECL_STRLCPY 0 -#endif - -/* - * Specific for POSIX. - */ -#ifndef _WIN32 -# define HAVE_CRYPT 1 -# define HAVE_DECL_FDATASYNC 1 -# define HAVE_FDATASYNC 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETIFADDRS 1 -# define HAVE_IFADDRS_H 1 -# define HAVE_GETPWUID_R 1 -# define HAVE_INET_ATON 1 -# define HAVE_LANGINFO_H 1 -# define HAVE_MKDTEMP 1 -# define HAVE_NETINET_TCP_H 1 -# define HAVE_NET_IF_H 1 -# define HAVE_DECL_POSIX_FADVISE 1 -# define HAVE_POSIX_FADVISE 1 -# define HAVE_RANDOM 1 -# define HAVE_SRANDOM 1 -# define HAVE_STRERROR_R 1 -# define HAVE_STRINGS_H 1 -# define HAVE_SYS_IOCTL_H 1 -# define HAVE_POLL 1 -# define HAVE_POLL_H 1 -# define HAVE_SYS_POLL_H 1 -# define HAVE_SYS_SELECT_H 1 -# define HAVE_SYS_UN_H 1 -# define HAVE_TERMIOS_H 1 -# define HAVE_UNIX_SOCKETS 1 -# define HAVE_UNSETENV 1 -# define USE_INTEGER_DATETIMES 1 -/* - * Specific for Windows. - */ -#else -# define HAVE_DECL_FDATASYNC 0 -# define HAVE_DECL_POSIX_FADVISE 0 -# define HAVE_GETTIMEOFDAY 1 -# define HAVE_ISINF 1 -# define HAVE_FUNCNAME__FUNCTION 1 -# define USE_REPL_SNPRINTF 1 -#endif - -/* - * Specific for GNU C Library. - */ -#ifdef __GLIBC__ -# define HAVE_GETHOSTBYNAME_R 1 -#endif - -/* - * Specific for (non-) VC. - */ -#ifndef _MSC_VER -# define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1 -# define HAVE__BUILTIN_UNREACHABLE 1 -#endif - -/* - * Common for all supported OSes/compilers. - */ -#define ENABLE_THREAD_SAFETY 1 -#define HAVE_MEMMOVE 1 -#define HAVE_RINT 1 -#define HAVE_DECL_SNPRINTF 1 -#define HAVE_DECL_VSNPRINTF 1 -#define HAVE_FSEEKO 1 -#define HAVE_FUNCNAME__FUNC 1 -#define HAVE_IPV6 1 -#define HAVE_STDINT_H 1 -#define HAVE_STRTOLL 1 -#define HAVE_STRTOULL 1 -#define HAVE_TOWLOWER 1 -#define HAVE_WCSTOMBS 1 -#define HAVE_SSL_GET_CURRENT_COMPRESSION 1 -#define HAVE_STRUCT_ADDRINFO 1 -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 -#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 -#define BLCKSZ 8192 -#define PG_KRB_SRVNAM "postgres" -#define PG_PRINTF_ATTRIBUTE printf -#define FLEXIBLE_ARRAY_MEMBER -#define MEMSET_LOOP_LIMIT 1024 -#define DEF_PGPORT 5432 -#define DEF_PGPORT_STR "5432" - -/* - * _Static_assert() was introduced in C11. However, all the latest major - * compilers support it for C99 as well. - */ -#define HAVE__STATIC_ASSERT 1 - -/* - * Undefined macros. - */ - -/* - * The following features are disabled by default, so we also disable them. - */ -#undef USE_ASSERT_CHECKING -#undef ENABLE_NLS -#undef ENABLE_GSS -#undef USE_OPENSSL -#undef USE_LDAP - -/* - * Is meaningless if NLS support is disabled (see above and libpq/buildfile for - * details). - */ -#undef LOCALEDIR - -/* - * Is meaningless if GSSAPI support is disabled (see above). It also seems that - * for modern systems including or will work both - * ( just includes ). - */ -#undef HAVE_GSSAPI_H - -/* - * Integer literal LL suffix is optional for C99. - */ -#undef HAVE_LL_CONSTANTS - -/* - * Windows-specific. is included for the latest (>= 1400) VC - * unconditionally. - */ -#undef HAVE_CRTDEFS_H - -/* - * Solaris-specific (getpeerucred() function). - */ -#undef HAVE_GETPEERUCRED - -/* - * Hard to even find any records of these types. - */ -#undef HAVE_INT64 -#undef HAVE_INT8 -#undef HAVE_UINT64 -#undef HAVE_UINT8 - -/* - * Something optimization-related for PowerPC machines (see - * libpq/postgresql/pg_config_manual.h for more details). - */ -#undef HAVE_PPC_LWARX_MUTEX_HINT - -/* - * None of the supported platforms has the '__' prefix for the mentioned - * sockaddr_storage struct members. - */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY -#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN - -/* - * Let's follow Linux man page advise for sync_file_range() function: - * - * This system call is Linux-specific, and should be avoided in portable - * programs. - * - * The macro also seems to be backend-specific. - */ -#undef HAVE_SYNC_FILE_RANGE - -/* - * None of the supported OSes have . FreeBSD and Mac OS have - * (HAVE_SYS_UCRED_H macro). - */ -#undef HAVE_UCRED_H diff --git a/libpq/postgresql/pg_config.h.in.orig b/libpq/postgresql/pg_config.h.in.orig deleted file mode 100644 index 7dbfa90..0000000 --- a/libpq/postgresql/pg_config.h.in.orig +++ /dev/null @@ -1,931 +0,0 @@ -/* src/include/pg_config.h.in. Generated from configure.in by autoheader. */ - -/* Define to the type of arg 1 of 'accept' */ -#undef ACCEPT_TYPE_ARG1 - -/* Define to the type of arg 2 of 'accept' */ -#undef ACCEPT_TYPE_ARG2 - -/* Define to the type of arg 3 of 'accept' */ -#undef ACCEPT_TYPE_ARG3 - -/* Define to the return type of 'accept' */ -#undef ACCEPT_TYPE_RETURN - -/* Define if building universal (internal helper macro) */ -#undef AC_APPLE_UNIVERSAL_BUILD - -/* The normal alignment of `double', in bytes. */ -#undef ALIGNOF_DOUBLE - -/* The normal alignment of `int', in bytes. */ -#undef ALIGNOF_INT - -/* The normal alignment of `long', in bytes. */ -#undef ALIGNOF_LONG - -/* The normal alignment of `long long int', in bytes. */ -#undef ALIGNOF_LONG_LONG_INT - -/* The normal alignment of `short', in bytes. */ -#undef ALIGNOF_SHORT - -/* Size of a disk block --- this also limits the size of a tuple. You can set - it bigger if you need bigger tuples (although TOAST should reduce the need - to have large tuples, since fields can be spread across multiple tuples). - BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is - currently 2^15 (32768). This is determined by the 15-bit widths of the - lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h). - Changing BLCKSZ requires an initdb. */ -#undef BLCKSZ - -/* Define to the default TCP port number on which the server listens and to - which clients will try to connect. This can be overridden at run-time, but - it's convenient if your clients have the right default compiled in. - (--with-pgport=PORTNUM) */ -#undef DEF_PGPORT - -/* Define to the default TCP port number as a string constant. */ -#undef DEF_PGPORT_STR - -/* Define to build with GSSAPI support. (--with-gssapi) */ -#undef ENABLE_GSS - -/* Define to 1 if you want National Language Support. (--enable-nls) */ -#undef ENABLE_NLS - -/* Define to 1 to build client libraries as thread-safe code. - (--enable-thread-safety) */ -#undef ENABLE_THREAD_SAFETY - -/* Define to nothing if C supports flexible array members, and to 1 if it does - not. That way, with a declaration like `struct s { int n; double - d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 - compilers. When computing the size of such an object, don't use 'sizeof - (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' - instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with - MSVC and with C++ compilers. */ -#undef FLEXIBLE_ARRAY_MEMBER - -/* float4 values are passed by value if 'true', by reference if 'false' */ -#undef FLOAT4PASSBYVAL - -/* float8, int8, and related values are passed by value if 'true', by - reference if 'false' */ -#undef FLOAT8PASSBYVAL - -/* Define to 1 if gettimeofday() takes only 1 argument. */ -#undef GETTIMEOFDAY_1ARG - -#ifdef GETTIMEOFDAY_1ARG -# define gettimeofday(a,b) gettimeofday(a) -#endif - -/* Define to 1 if you have the `append_history' function. */ -#undef HAVE_APPEND_HISTORY - -/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ -#undef HAVE_ASN1_STRING_GET0_DATA - -/* Define to 1 if you want to use atomics if available. */ -#undef HAVE_ATOMICS - -/* Define to 1 if you have the header file. */ -#undef HAVE_ATOMIC_H - -/* Define to 1 if you have the `BIO_get_data' function. */ -#undef HAVE_BIO_GET_DATA - -/* Define to 1 if you have the `BIO_meth_new' function. */ -#undef HAVE_BIO_METH_NEW - -/* Define to 1 if you have the `cbrt' function. */ -#undef HAVE_CBRT - -/* Define to 1 if you have the `class' function. */ -#undef HAVE_CLASS - -/* Define to 1 if you have the header file. */ -#undef HAVE_CRTDEFS_H - -/* Define to 1 if you have the `crypt' function. */ -#undef HAVE_CRYPT - -/* Define to 1 if you have the `CRYPTO_lock' function. */ -#undef HAVE_CRYPTO_LOCK - -/* Define to 1 if you have the header file. */ -#undef HAVE_CRYPT_H - -/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you - don't. */ -#undef HAVE_DECL_FDATASYNC - -/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you - don't. */ -#undef HAVE_DECL_F_FULLFSYNC - -/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you - don't. */ -#undef HAVE_DECL_POSIX_FADVISE - -/* Define to 1 if you have the declaration of `snprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_SNPRINTF - -/* Define to 1 if you have the declaration of `strlcat', and to 0 if you - don't. */ -#undef HAVE_DECL_STRLCAT - -/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you - don't. */ -#undef HAVE_DECL_STRLCPY - -/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you - don't. */ -#undef HAVE_DECL_SYS_SIGLIST - -/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you - don't. */ -#undef HAVE_DECL_VSNPRINTF - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLD_H - -/* Define to 1 if you have the `dlopen' function. */ -#undef HAVE_DLOPEN - -/* Define to 1 if you have the header file. */ -#undef HAVE_EDITLINE_HISTORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_EDITLINE_READLINE_H - -/* Define to 1 if you have the `fdatasync' function. */ -#undef HAVE_FDATASYNC - -/* Define to 1 if you have the `fls' function. */ -#undef HAVE_FLS - -/* Define to 1 if you have the `fpclass' function. */ -#undef HAVE_FPCLASS - -/* Define to 1 if you have the `fp_class' function. */ -#undef HAVE_FP_CLASS - -/* Define to 1 if you have the `fp_class_d' function. */ -#undef HAVE_FP_CLASS_D - -/* Define to 1 if you have the header file. */ -#undef HAVE_FP_CLASS_H - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#undef HAVE_FSEEKO - -/* Define to 1 if your compiler understands __func__. */ -#undef HAVE_FUNCNAME__FUNC - -/* Define to 1 if your compiler understands __FUNCTION__. */ -#undef HAVE_FUNCNAME__FUNCTION - -/* Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int). */ -#undef HAVE_GCC__ATOMIC_INT32_CAS - -/* Define to 1 if you have __atomic_compare_exchange_n(int64 *, int *, int64). - */ -#undef HAVE_GCC__ATOMIC_INT64_CAS - -/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */ -#undef HAVE_GCC__SYNC_CHAR_TAS - -/* Define to 1 if you have __sync_compare_and_swap(int *, int, int). */ -#undef HAVE_GCC__SYNC_INT32_CAS - -/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */ -#undef HAVE_GCC__SYNC_INT32_TAS - -/* Define to 1 if you have __sync_compare_and_swap(int64 *, int64, int64). */ -#undef HAVE_GCC__SYNC_INT64_CAS - -/* Define to 1 if you have the `getaddrinfo' function. */ -#undef HAVE_GETADDRINFO - -/* Define to 1 if you have the `gethostbyname_r' function. */ -#undef HAVE_GETHOSTBYNAME_R - -/* Define to 1 if you have the `getifaddrs' function. */ -#undef HAVE_GETIFADDRS - -/* Define to 1 if you have the `getopt' function. */ -#undef HAVE_GETOPT - -/* Define to 1 if you have the header file. */ -#undef HAVE_GETOPT_H - -/* Define to 1 if you have the `getopt_long' function. */ -#undef HAVE_GETOPT_LONG - -/* Define to 1 if you have the `getpeereid' function. */ -#undef HAVE_GETPEEREID - -/* Define to 1 if you have the `getpeerucred' function. */ -#undef HAVE_GETPEERUCRED - -/* Define to 1 if you have the `getpwuid_r' function. */ -#undef HAVE_GETPWUID_R - -/* Define to 1 if you have the `getrlimit' function. */ -#undef HAVE_GETRLIMIT - -/* Define to 1 if you have the `getrusage' function. */ -#undef HAVE_GETRUSAGE - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_GSSAPI_GSSAPI_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_GSSAPI_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_HISTORY_H - -/* Define to 1 if you have the `history_truncate_file' function. */ -#undef HAVE_HISTORY_TRUNCATE_FILE - -/* Define to 1 if you have the header file. */ -#undef HAVE_IEEEFP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_IFADDRS_H - -/* Define to 1 if you have the `inet_aton' function. */ -#undef HAVE_INET_ATON - -/* Define to 1 if the system has the type `int64'. */ -#undef HAVE_INT64 - -/* Define to 1 if the system has the type `int8'. */ -#undef HAVE_INT8 - -/* Define to 1 if the system has the type `intptr_t'. */ -#undef HAVE_INTPTR_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the global variable 'int opterr'. */ -#undef HAVE_INT_OPTERR - -/* Define to 1 if you have the global variable 'int optreset'. */ -#undef HAVE_INT_OPTRESET - -/* Define to 1 if you have the global variable 'int timezone'. */ -#undef HAVE_INT_TIMEZONE - -/* Define to 1 if you have support for IPv6. */ -#undef HAVE_IPV6 - -/* Define to 1 if you have isinf(). */ -#undef HAVE_ISINF - -/* Define to 1 if you have the header file. */ -#undef HAVE_LANGINFO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LDAP_H - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -#undef HAVE_LIBCRYPTO - -/* Define to 1 if you have the `ldap' library (-lldap). */ -#undef HAVE_LIBLDAP - -/* Define to 1 if you have the `ldap_r' library (-lldap_r). */ -#undef HAVE_LIBLDAP_R - -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - -/* Define to 1 if you have the `pam' library (-lpam). */ -#undef HAVE_LIBPAM - -/* Define if you have a function readline library */ -#undef HAVE_LIBREADLINE - -/* Define to 1 if you have the `selinux' library (-lselinux). */ -#undef HAVE_LIBSELINUX - -/* Define to 1 if you have the `ssl' library (-lssl). */ -#undef HAVE_LIBSSL - -/* Define to 1 if you have the `wldap32' library (-lwldap32). */ -#undef HAVE_LIBWLDAP32 - -/* Define to 1 if you have the `xml2' library (-lxml2). */ -#undef HAVE_LIBXML2 - -/* Define to 1 if you have the `xslt' library (-lxslt). */ -#undef HAVE_LIBXSLT - -/* Define to 1 if you have the `z' library (-lz). */ -#undef HAVE_LIBZ - -/* Define to 1 if constants of type 'long long int' should have the suffix LL. - */ -#undef HAVE_LL_CONSTANTS - -/* Define to 1 if the system has the type `locale_t'. */ -#undef HAVE_LOCALE_T - -/* Define to 1 if `long int' works and is 64 bits. */ -#undef HAVE_LONG_INT_64 - -/* Define to 1 if the system has the type `long long int'. */ -#undef HAVE_LONG_LONG_INT - -/* Define to 1 if `long long int' works and is 64 bits. */ -#undef HAVE_LONG_LONG_INT_64 - -/* Define to 1 if you have the header file. */ -#undef HAVE_MBARRIER_H - -/* Define to 1 if you have the `mbstowcs_l' function. */ -#undef HAVE_MBSTOWCS_L - -/* Define to 1 if you have the `memmove' function. */ -#undef HAVE_MEMMOVE - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */ -#undef HAVE_MINIDUMP_TYPE - -/* Define to 1 if you have the `mkdtemp' function. */ -#undef HAVE_MKDTEMP - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_TCP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_IF_H - -/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ -#undef HAVE_OPENSSL_INIT_SSL - -/* Define to 1 if you have the header file. */ -#undef HAVE_OSSP_UUID_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PAM_PAM_APPL_H - -/* Define to 1 if you have the `poll' function. */ -#undef HAVE_POLL - -/* Define to 1 if you have the header file. */ -#undef HAVE_POLL_H - -/* Define to 1 if you have the `posix_fadvise' function. */ -#undef HAVE_POSIX_FADVISE - -/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */ -#undef HAVE_PPC_LWARX_MUTEX_HINT - -/* Define to 1 if you have the `pstat' function. */ -#undef HAVE_PSTAT - -/* Define to 1 if the PS_STRINGS thing exists. */ -#undef HAVE_PS_STRINGS - -/* Define if you have POSIX threads libraries and header files. */ -#undef HAVE_PTHREAD - -/* Define to 1 if you have the `pthread_is_threaded_np' function. */ -#undef HAVE_PTHREAD_IS_THREADED_NP - -/* Have PTHREAD_PRIO_INHERIT. */ -#undef HAVE_PTHREAD_PRIO_INHERIT - -/* Define to 1 if you have the header file. */ -#undef HAVE_PWD_H - -/* Define to 1 if you have the `random' function. */ -#undef HAVE_RANDOM - -/* Define to 1 if you have the `RAND_OpenSSL' function. */ -#undef HAVE_RAND_OPENSSL - -/* Define to 1 if you have the header file. */ -#undef HAVE_READLINE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_READLINE_HISTORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_READLINE_READLINE_H - -/* Define to 1 if you have the `readlink' function. */ -#undef HAVE_READLINK - -/* Define to 1 if you have the `rint' function. */ -#undef HAVE_RINT - -/* Define to 1 if you have the global variable - 'rl_completion_append_character'. */ -#undef HAVE_RL_COMPLETION_APPEND_CHARACTER - -/* Define to 1 if you have the `rl_completion_matches' function. */ -#undef HAVE_RL_COMPLETION_MATCHES - -/* Define to 1 if you have the `rl_filename_completion_function' function. */ -#undef HAVE_RL_FILENAME_COMPLETION_FUNCTION - -/* Define to 1 if you have the `rl_reset_screen_size' function. */ -#undef HAVE_RL_RESET_SCREEN_SIZE - -/* Define to 1 if you have the header file. */ -#undef HAVE_SECURITY_PAM_APPL_H - -/* Define to 1 if you have the `setproctitle' function. */ -#undef HAVE_SETPROCTITLE - -/* Define to 1 if you have the `setsid' function. */ -#undef HAVE_SETSID - -/* Define to 1 if you have the `shm_open' function. */ -#undef HAVE_SHM_OPEN - -/* Define to 1 if you have the `snprintf' function. */ -#undef HAVE_SNPRINTF - -/* Define to 1 if you have spinlocks. */ -#undef HAVE_SPINLOCKS - -/* Define to 1 if you have the `srandom' function. */ -#undef HAVE_SRANDOM - -/* Define to 1 if you have the `SSL_get_current_compression' function. */ -#undef HAVE_SSL_GET_CURRENT_COMPRESSION - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the `strerror_r' function. */ -#undef HAVE_STRERROR_R - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strlcat' function. */ -#undef HAVE_STRLCAT - -/* Define to 1 if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - -/* Define to 1 if you have the `strtoll' function. */ -#undef HAVE_STRTOLL - -/* Define to 1 if you have the `strtoq' function. */ -#undef HAVE_STRTOQ - -/* Define to 1 if you have the `strtoull' function. */ -#undef HAVE_STRTOULL - -/* Define to 1 if you have the `strtouq' function. */ -#undef HAVE_STRTOUQ - -/* Define to 1 if the system has the type `struct addrinfo'. */ -#undef HAVE_STRUCT_ADDRINFO - -/* Define to 1 if the system has the type `struct cmsgcred'. */ -#undef HAVE_STRUCT_CMSGCRED - -/* Define to 1 if the system has the type `struct option'. */ -#undef HAVE_STRUCT_OPTION - -/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ -#undef HAVE_STRUCT_SOCKADDR_SA_LEN - -/* Define to 1 if the system has the type `struct sockaddr_storage'. */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE - -/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY - -/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN - -/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY - -/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */ -#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN - -/* Define to 1 if `tm_zone' is a member of `struct tm'. */ -#undef HAVE_STRUCT_TM_TM_ZONE - -/* Define to 1 if you have the `symlink' function. */ -#undef HAVE_SYMLINK - -/* Define to 1 if you have the `sync_file_range' function. */ -#undef HAVE_SYNC_FILE_RANGE - -/* Define to 1 if you have the syslog interface. */ -#undef HAVE_SYSLOG - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_EPOLL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IPC_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_POLL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PSTAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SEM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SHM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TAS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UCRED_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use - `HAVE_STRUCT_TM_TM_ZONE' instead. */ -#undef HAVE_TM_ZONE - -/* Define to 1 if you have the `towlower' function. */ -#undef HAVE_TOWLOWER - -/* Define to 1 if you have the external array `tzname'. */ -#undef HAVE_TZNAME - -/* Define to 1 if you have the header file. */ -#undef HAVE_UCRED_H - -/* Define to 1 if the system has the type `uint64'. */ -#undef HAVE_UINT64 - -/* Define to 1 if the system has the type `uint8'. */ -#undef HAVE_UINT8 - -/* Define to 1 if the system has the type `uintptr_t'. */ -#undef HAVE_UINTPTR_T - -/* Define to 1 if the system has the type `union semun'. */ -#undef HAVE_UNION_SEMUN - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have unix sockets. */ -#undef HAVE_UNIX_SOCKETS - -/* Define to 1 if you have the `unsetenv' function. */ -#undef HAVE_UNSETENV - -/* Define to 1 if the system has the type `unsigned long long int'. */ -#undef HAVE_UNSIGNED_LONG_LONG_INT - -/* Define to 1 if you have the `utime' function. */ -#undef HAVE_UTIME - -/* Define to 1 if you have the `utimes' function. */ -#undef HAVE_UTIMES - -/* 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 - -/* Define to 1 if you have the header file. */ -#undef HAVE_WCHAR_H - -/* Define to 1 if you have the `wcstombs' function. */ -#undef HAVE_WCSTOMBS - -/* Define to 1 if you have the `wcstombs_l' function. */ -#undef HAVE_WCSTOMBS_L - -/* Define to 1 if you have the header file. */ -#undef HAVE_WCTYPE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WINLDAP_H - -/* Define to 1 if your compiler understands __builtin_bswap32. */ -#undef HAVE__BUILTIN_BSWAP32 - -/* Define to 1 if your compiler understands __builtin_bswap64. */ -#undef HAVE__BUILTIN_BSWAP64 - -/* Define to 1 if your compiler understands __builtin_constant_p. */ -#undef HAVE__BUILTIN_CONSTANT_P - -/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ -#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P - -/* Define to 1 if your compiler understands __builtin_unreachable. */ -#undef HAVE__BUILTIN_UNREACHABLE - -/* Define to 1 if you have __cpuid. */ -#undef HAVE__CPUID - -/* Define to 1 if you have __get_cpuid. */ -#undef HAVE__GET_CPUID - -/* Define to 1 if your compiler understands _Static_assert. */ -#undef HAVE__STATIC_ASSERT - -/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */ -#undef HAVE__VA_ARGS - -/* Define to the appropriate snprintf length modifier for 64-bit ints. */ -#undef INT64_MODIFIER - -/* Define to 1 if `locale_t' requires . */ -#undef LOCALE_T_IN_XLOCALE - -/* Define as the maximum alignment requirement of any C data type. */ -#undef MAXIMUM_ALIGNOF - -/* Define bytes to use libc memset(). */ -#undef MEMSET_LOOP_LIMIT - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to the name of a signed 128-bit integer type. */ -#undef PG_INT128_TYPE - -/* Define to the name of a signed 64-bit integer type. */ -#undef PG_INT64_TYPE - -/* Define to the name of the default PostgreSQL service principal in Kerberos - (GSSAPI). (--with-krb-srvnam=NAME) */ -#undef PG_KRB_SRVNAM - -/* PostgreSQL major version as a string */ -#undef PG_MAJORVERSION - -/* Define to gnu_printf if compiler supports it, else printf. */ -#undef PG_PRINTF_ATTRIBUTE - -/* PostgreSQL version as a string */ -#undef PG_VERSION - -/* PostgreSQL version as a number */ -#undef PG_VERSION_NUM - -/* A string containing the version number, platform, and C compiler */ -#undef PG_VERSION_STR - -/* Define to 1 to allow profiling output to be saved separately for each - process. */ -#undef PROFILE_PID_DIR - -/* Define to necessary symbol if this constant uses a non-standard name on - your system. */ -#undef PTHREAD_CREATE_JOINABLE - -/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus, - the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger - than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be - less than your OS' limit on file size. This is often 2 GB or 4GB in a - 32-bit operating system, unless you have large file support enabled. By - default, we make the limit 1 GB to avoid any possible integer-overflow - problems within the OS. A limit smaller than necessary only means we divide - a large relation into more chunks than necessary, so it seems best to err - in the direction of a small limit. A power-of-2 value is recommended to - save a few cycles in md.c, but is not absolutely required. Changing - RELSEG_SIZE requires an initdb. */ -#undef RELSEG_SIZE - -/* The size of `long', as computed by sizeof. */ -#undef SIZEOF_LONG - -/* The size of `off_t', as computed by sizeof. */ -#undef SIZEOF_OFF_T - -/* The size of `size_t', as computed by sizeof. */ -#undef SIZEOF_SIZE_T - -/* The size of `void *', as computed by sizeof. */ -#undef SIZEOF_VOID_P - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to 1 if strerror_r() returns a int. */ -#undef STRERROR_R_INT - -/* Define to 1 if your declares `struct tm'. */ -#undef TM_IN_SYS_TIME - -/* Define to 1 to build with assertion checks. (--enable-cassert) */ -#undef USE_ASSERT_CHECKING - -/* Define to 1 to build with Bonjour support. (--with-bonjour) */ -#undef USE_BONJOUR - -/* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ -#undef USE_BSD_AUTH - -/* Define to 1 if you want float4 values to be passed by value. - (--enable-float4-byval) */ -#undef USE_FLOAT4_BYVAL - -/* Define to 1 if you want float8, int8, etc values to be passed by value. - (--enable-float8-byval) */ -#undef USE_FLOAT8_BYVAL - -/* Define to 1 if you want 64-bit integer timestamp and interval support. - (--enable-integer-datetimes) */ -#undef USE_INTEGER_DATETIMES - -/* Define to 1 to build with LDAP support. (--with-ldap) */ -#undef USE_LDAP - -/* Define to 1 to build with XML support. (--with-libxml) */ -#undef USE_LIBXML - -/* Define to 1 to use XSLT support when building contrib/xml2. - (--with-libxslt) */ -#undef USE_LIBXSLT - -/* Define to select named POSIX semaphores. */ -#undef USE_NAMED_POSIX_SEMAPHORES - -/* Define to build with OpenSSL support. (--with-openssl) */ -#undef USE_OPENSSL - -/* Define to 1 to build with PAM support. (--with-pam) */ -#undef USE_PAM - -/* Use replacement snprintf() functions. */ -#undef USE_REPL_SNPRINTF - -/* Define to 1 to use Intel SSE 4.2 CRC instructions with a runtime check. */ -#undef USE_SLICING_BY_8_CRC32C - -/* Define to 1 use Intel SSE 4.2 CRC instructions. */ -#undef USE_SSE42_CRC32C - -/* Define to 1 to use Intel SSSE 4.2 CRC instructions with a runtime check. */ -#undef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK - -/* Define to build with systemd support. (--with-systemd) */ -#undef USE_SYSTEMD - -/* Define to select SysV-style semaphores. */ -#undef USE_SYSV_SEMAPHORES - -/* Define to select SysV-style shared memory. */ -#undef USE_SYSV_SHARED_MEMORY - -/* Define to select unnamed POSIX semaphores. */ -#undef USE_UNNAMED_POSIX_SEMAPHORES - -/* Define to select Win32-style semaphores. */ -#undef USE_WIN32_SEMAPHORES - -/* Define to select Win32-style shared memory. */ -#undef USE_WIN32_SHARED_MEMORY - -/* Define to 1 if `wcstombs_l' requires . */ -#undef WCSTOMBS_L_IN_XLOCALE - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif - -/* Size of a WAL file block. This need have no particular relation to BLCKSZ. - XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O, - XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O - buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb. - */ -#undef XLOG_BLCKSZ - -/* XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2 - and larger than XLOG_BLCKSZ (preferably, a great deal larger than - XLOG_BLCKSZ). Changing XLOG_SEG_SIZE requires an initdb. */ -#undef XLOG_SEG_SIZE - - - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -#undef _LARGEFILE_SOURCE - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to the type of a signed integer type wide enough to hold a pointer, - if such a type exists, and if the system does not define it. */ -#undef intptr_t - -/* Define to empty if the C compiler does not understand signed types. */ -#undef signed - -/* Define to the type of an unsigned integer type wide enough to hold a - pointer, if such a type exists, and if the system does not define it. */ -#undef uintptr_t diff --git a/libpq/postgresql/pg_config.h.win32.orig b/libpq/postgresql/pg_config.h.win32.orig deleted file mode 100644 index 0e17ccb..0000000 --- a/libpq/postgresql/pg_config.h.win32.orig +++ /dev/null @@ -1,682 +0,0 @@ -/* src/include/pg_config.h. Generated by configure. */ -/* src/include/pg_config.h.in. Generated from configure.in by autoheader. */ - -/* This file is generated from MingW ./configure, and with the following - * changes to be valid for Visual C++ (and compatible): - * - * HAVE_CBRT, HAVE_FUNCNAME_FUNC, HAVE_GETOPT, HAVE_GETOPT_H, HAVE_INTTYPES_H, - * HAVE_GETOPT_LONG, HAVE_LOCALE_T, HAVE_RINT, HAVE_STRINGS_H, HAVE_STRTOLL, - * HAVE_STRTOULL, HAVE_STRUCT_OPTION, ENABLE_THREAD_SAFETY, - * inline, USE_SSE42_CRC32C_WITH_RUNTIME_CHECK - */ - -/* Define to the type of arg 1 of 'accept' */ -#define ACCEPT_TYPE_ARG1 unsigned int - -/* Define to the type of arg 2 of 'accept' */ -#define ACCEPT_TYPE_ARG2 struct sockaddr * - -/* Define to the type of arg 3 of 'accept' */ -#define ACCEPT_TYPE_ARG3 int - -/* Define to the return type of 'accept' */ -#define ACCEPT_TYPE_RETURN unsigned int PASCAL - -/* The alignment requirement of a `double'. */ -#define ALIGNOF_DOUBLE 8 - -/* The alignment requirement of a `int'. */ -#define ALIGNOF_INT 4 - -/* The alignment requirement of a `long'. */ -#define ALIGNOF_LONG 4 - -/* The alignment requirement of a `long long int'. */ -#define ALIGNOF_LONG_LONG_INT 8 - -/* The alignment requirement of a `short'. */ -#define ALIGNOF_SHORT 2 - -/* Define to the default TCP port number on which the server listens and to - which clients will try to connect. This can be overridden at run-time, but - it's convenient if your clients have the right default compiled in. - (--with-pgport=PORTNUM) */ -#define DEF_PGPORT 5432 - -/* Define to the default TCP port number as a string constant. */ -#define DEF_PGPORT_STR "5432" - -/* Define to nothing if C supports flexible array members, and to 1 if it does - not. That way, with a declaration like `struct s { int n; double - d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 - compilers. When computing the size of such an object, don't use 'sizeof - (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' - instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with - MSVC and with C++ compilers. */ -#define FLEXIBLE_ARRAY_MEMBER - -/* Define to 1 if you want National Language Support. (--enable-nls) */ -/* #undef ENABLE_NLS */ - -/* Define to 1 to build client libraries as thread-safe code. - (--enable-thread-safety) */ -#define ENABLE_THREAD_SAFETY 1 - -/* Define to 1 if gettimeofday() takes only 1 argument. */ -/* #undef GETTIMEOFDAY_1ARG */ - -#ifdef GETTIMEOFDAY_1ARG -# define gettimeofday(a,b) gettimeofday(a) -#endif - -/* Define to 1 if you have the `cbrt' function. */ -//#define HAVE_CBRT 1 - -/* Define to 1 if you have the `class' function. */ -/* #undef HAVE_CLASS */ - -/* Define to 1 if you have the `crypt' function. */ -/* #undef HAVE_CRYPT */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_CRYPT_H */ - -/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you - don't. */ -#define HAVE_DECL_FDATASYNC 0 - -/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you - don't. */ -#define HAVE_DECL_F_FULLFSYNC 0 - -/* Define to 1 if you have the declaration of `snprintf', and to 0 if you - don't. */ -#define HAVE_DECL_SNPRINTF 1 - -/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you - don't. */ -#define HAVE_DECL_VSNPRINTF 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DLD_H */ - -/* Define to 1 if you have the `dlopen' function. */ -/* #undef HAVE_DLOPEN */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EDITLINE_HISTORY_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EDITLINE_READLINE_H */ - -/* Define to 1 if you have the `fcvt' function. */ -#define HAVE_FCVT 1 - -/* Define to 1 if you have the `fdatasync' function. */ -/* #undef HAVE_FDATASYNC */ - -/* Define to 1 if you have finite(). */ -#define HAVE_FINITE 1 - -/* Define to 1 if you have the `fpclass' function. */ -/* #undef HAVE_FPCLASS */ - -/* Define to 1 if you have the `fp_class' function. */ -/* #undef HAVE_FP_CLASS */ - -/* Define to 1 if you have the `fp_class_d' function. */ -/* #undef HAVE_FP_CLASS_D */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_FP_CLASS_H */ - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if your compiler understands __func__. */ -//#define HAVE_FUNCNAME__FUNC 1 - -/* Define to 1 if your compiler understands __FUNCTION__. */ -#define HAVE_FUNCNAME__FUNCTION 1 - -/* Define to 1 if you have getaddrinfo(). */ -/* #undef HAVE_GETADDRINFO */ - -/* Define to 1 if you have the `gethostbyname_r' function. */ -/* #undef HAVE_GETHOSTBYNAME_R */ - -/* Define to 1 if you have the `getopt' function. */ -//#define HAVE_GETOPT 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_GETOPT_H 1 - -/* Define to 1 if you have the `getopt_long' function. */ -//#define HAVE_GETOPT_LONG 1 - -/* Define to 1 if you have the `getpeereid' function. */ -/* #undef HAVE_GETPEEREID */ - -/* Define to 1 if you have the `getpwuid_r' function. */ -/* #undef HAVE_GETPWUID_R */ - -/* Define to 1 if you have the `getrusage' function. */ -/* #undef HAVE_GETRUSAGE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_HISTORY_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_IEEEFP_H */ - -/* Define to 1 if you have the `inet_aton' function. */ -/* #undef HAVE_INET_ATON */ - -/* Define to 1 if the system has the type `int64'. */ -/* #undef HAVE_INT64 */ - -/* Define to 1 if the system has the type `int8'. */ -/* #undef HAVE_INT8 */ - -/* Define to 1 if you have the header file. */ -//#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the global variable 'int timezone'. */ -#define HAVE_INT_TIMEZONE 1 - -/* Define to 1 if you have support for IPv6. */ -#define HAVE_IPV6 1 - -/* Define to 1 if you have isinf(). */ -#define HAVE_ISINF 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LANGINFO_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_LDAP_H */ - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -/* #undef HAVE_LIBCRYPTO */ - -/* Define to 1 if you have the `ldap' library (-lldap). */ -/* #undef HAVE_LIBLDAP */ - -/* Define to 1 if you have the `pam' library (-lpam). */ -/* #undef HAVE_LIBPAM */ - -/* Define if you have a function readline library */ -/* #undef HAVE_LIBREADLINE */ - -/* Define to 1 if you have the `ssl' library (-lssl). */ -/* #undef HAVE_LIBSSL */ - -/* Define to 1 if you have the `wldap32' library (-lwldap32). */ -/* #undef HAVE_LIBWLDAP32 */ - -/* Define to 1 if you have the `z' library (-lz). */ -/* #undef HAVE_LIBZ */ - -/* Define to 1 if constants of type 'long long int' should have the suffix LL. - */ -#if (_MSC_VER > 1200) -#define HAVE_LL_CONSTANTS 1 -#endif - -/* Define to 1 if the system has the type `locale_t'. */ -#define HAVE_LOCALE_T 1 - -/* Define to 1 if `long int' works and is 64 bits. */ -/* #undef HAVE_LONG_INT_64 */ - -/* Define to 1 if `long long int' works and is 64 bits. */ -#if (_MSC_VER > 1200) -#define HAVE_LONG_LONG_INT_64 -#endif - -/* Define to 1 if you have the `mbstowcs_l' function. */ -#define HAVE_MBSTOWCS_L 1 - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */ -#define HAVE_MINIDUMP_TYPE 1 - -/* Define to 1 if you have the `mkdtemp' function. */ -/* #undef HAVE_MKDTEMP */ - -/* Define to 1 if you have the header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETINET_TCP_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PAM_PAM_APPL_H */ - -/* Define to 1 if you have the `poll' function. */ -/* #undef HAVE_POLL */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_POLL_H */ - -/* Define to 1 if you have the `pstat' function. */ -/* #undef HAVE_PSTAT */ - -/* Define to 1 if the PS_STRINGS thing exists. */ -/* #undef HAVE_PS_STRINGS */ - -/* Define to 1 if you have the header file. */ -#define HAVE_PWD_H 1 - -/* Define to 1 if you have the `random' function. */ -/* #undef HAVE_RANDOM */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_HISTORY_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_READLINE_H */ - -/* Define to 1 if you have the `readlink' function. */ -/* #undef HAVE_READLINK */ - -/* Define to 1 if you have the `rint' function. */ -#if (_MSC_VER >= 1800) -#define HAVE_RINT 1 -#endif - - -/* Define to 1 if you have the global variable - 'rl_completion_append_character'. */ -/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */ - -/* Define to 1 if you have the `rl_completion_matches' function. */ -/* #undef HAVE_RL_COMPLETION_MATCHES */ - -/* Define to 1 if you have the `rl_filename_completion_function' function. */ -/* #undef HAVE_RL_FILENAME_COMPLETION_FUNCTION */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SECURITY_PAM_APPL_H */ - -/* Define to 1 if you have the `setproctitle' function. */ -/* #undef HAVE_SETPROCTITLE */ - -/* Define to 1 if you have the `setsid' function. */ -/* #undef HAVE_SETSID */ - -/* Define to 1 if you have the `snprintf' function. */ -/* #undef HAVE_SNPRINTF */ - -/* Define to 1 if you have spinlocks. */ -#define HAVE_SPINLOCKS 1 - -/* Define to 1 if you have atomics. */ -#define HAVE_ATOMICS 1 - -/* Define to 1 if you have the `srandom' function. */ -/* #undef HAVE_SRANDOM */ - -/* Define to 1 if you have the `SSL_get_current_compression' function. */ -#define HAVE_SSL_GET_CURRENT_COMPRESSION 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_STDINT_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strerror' function. */ -#ifndef HAVE_STRERROR -#define HAVE_STRERROR 1 -#endif - -/* Define to 1 if you have the `strerror_r' function. */ -/* #undef HAVE_STRERROR_R */ - -/* Define to 1 if you have the header file. */ -/*#define HAVE_STRINGS_H 1 */ - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strtoll' function. */ -//#define HAVE_STRTOLL 1 - -/* Define to 1 if you have the `strtoq' function. */ -/* #undef HAVE_STRTOQ */ - -/* Define to 1 if you have the `strtoull' function. */ -//#define HAVE_STRTOULL 1 - -/* Define to 1 if you have the `strtouq' function. */ -/* #undef HAVE_STRTOUQ */ - -/* Define to 1 if the system has the type `struct addrinfo'. */ -#if (_MSC_VER > 1200) -#define HAVE_STRUCT_ADDRINFO 1 -#endif - -/* Define to 1 if the system has the type `struct cmsgcred'. */ -/* #undef HAVE_STRUCT_CMSGCRED */ - -/* Define to 1 if the system has the type `struct option'. */ -//#define HAVE_STRUCT_OPTION 1 - -/* Define to 1 if `sa_len' is member of `struct sockaddr'. */ -/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ - -/* Define to 1 if the system has the type `struct sockaddr_storage'. */ -#if (_MSC_VER > 1200) -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 -#endif - -/* Define to 1 if `ss_family' is member of `struct sockaddr_storage'. */ -#if (_MSC_VER > 1200) -#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1 -#endif - -/* Define to 1 if `ss_len' is member of `struct sockaddr_storage'. */ -/* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ - -/* Define to 1 if `__ss_family' is member of `struct sockaddr_storage'. */ -/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */ - -/* Define to 1 if `__ss_len' is member of `struct sockaddr_storage'. */ -/* #undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */ - -/* Define to 1 if the system has the type `struct sockaddr_un'. */ -/* #undef HAVE_STRUCT_SOCKADDR_UN */ - -/* Define to 1 if `tm_zone' is member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM_TM_ZONE */ - -/* Define to 1 if you have the `symlink' function. */ -#define HAVE_SYMLINK 1 - -/* Define to 1 if you have the `sync_file_range' function. */ -/* #undef HAVE_SYNC_FILE_RANGE */ - -/* Define to 1 if you have the `sysconf' function. */ -/* #undef HAVE_SYSCONF */ - -/* Define to 1 if you have the syslog interface. */ -/* #undef HAVE_SYSLOG */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_IPC_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PSTAT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SELECT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SEM_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SHM_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UCRED_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_UN_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_TERMIOS_H */ - -/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use - `HAVE_STRUCT_TM_TM_ZONE' instead. */ -/* #undef HAVE_TM_ZONE */ - -/* Define to 1 if you have the `towlower' function. */ -#define HAVE_TOWLOWER 1 - -/* Define to 1 if you have the external array `tzname'. */ -/* #undef HAVE_TZNAME */ - -/* Define to 1 if the system has the type `uint64'. */ -/* #undef HAVE_UINT64 */ - -/* Define to 1 if the system has the type `uint8'. */ -/* #undef HAVE_UINT8 */ - -/* Define to 1 if the system has the type `union semun'. */ -/* #undef HAVE_UNION_SEMUN */ - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have unix sockets. */ -/* #undef HAVE_UNIX_SOCKETS */ - -/* Define to 1 if you have the `unsetenv' function. */ -/* #undef HAVE_UNSETENV */ - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimes' function. */ -/* #undef HAVE_UTIMES */ - -/* Define to 1 if you have the header file. */ -#define HAVE_UTIME_H 1 - -/* Define to 1 if you have the `vsnprintf' function. */ -#define HAVE_VSNPRINTF 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if you have the `wcstombs' function. */ -#define HAVE_WCSTOMBS 1 - -/* Define to 1 if you have the `wcstombs_l' function. */ -#define HAVE_WCSTOMBS_L 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_WCTYPE_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_WINLDAP_H */ - -/* Define to 1 if your compiler understands __builtin_bswap32. */ -/* #undef HAVE__BUILTIN_BSWAP32 */ - -/* Define to 1 if your compiler understands __builtin_bswap64. */ -/* #undef HAVE__BUILTIN_BSWAP64 */ - -/* Define to 1 if your compiler understands __builtin_constant_p. */ -/* #undef HAVE__BUILTIN_CONSTANT_P */ - -/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ -/* #undef HAVE__BUILTIN_TYPES_COMPATIBLE_P */ - -/* Define to 1 if your compiler understands __builtin_unreachable. */ -/* #undef HAVE__BUILTIN_UNREACHABLE */ - -/* Define to 1 if you have __cpuid. */ -#define HAVE__CPUID 1 - -/* Define to 1 if you have __get_cpuid. */ -#undef HAVE__GET_CPUID - -/* Define to 1 if your compiler understands _Static_assert. */ -/* #undef HAVE__STATIC_ASSERT */ - -/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */ -#define HAVE__VA_ARGS 1 - -/* Define to the appropriate snprintf length modifier for 64-bit ints. */ -#define INT64_MODIFIER "ll" - -/* Define to 1 if `locale_t' requires . */ -/* #undef LOCALE_T_IN_XLOCALE */ - -/* Define to the location of locale files. */ -/* #undef LOCALEDIR */ - -/* Define as the maximum alignment requirement of any C data type. */ -#define MAXIMUM_ALIGNOF 8 - -/* Define bytes to use libc memset(). */ -#define MEMSET_LOOP_LIMIT 1024 - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "pgsql-bugs@postgresql.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "PostgreSQL" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PostgreSQL 9.6.5" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "9.6.5" - -/* Define to the name of a signed 128-bit integer type. */ -#undef PG_INT128_TYPE - -/* Define to the name of a signed 64-bit integer type. */ -#define PG_INT64_TYPE long long int - -/* PostgreSQL version as a string */ -#define PG_VERSION "9.6.5" - -/* PostgreSQL version as a number */ -#define PG_VERSION_NUM 90605 - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "postgresql" - -/* Define to the name of the default PostgreSQL service principal in Kerberos. - (--with-krb-srvnam=NAME) */ -#define PG_KRB_SRVNAM "postgres" - -/* A string containing the version number, platform, and C compiler */ -#define PG_VERSION_STR "Uninitialized version string (win32)" - -/* The size of `long', as computed by sizeof. */ -#define SIZEOF_LONG 4 - -/* The size of `size_t', as computed by sizeof. */ -#ifndef _WIN64 -#define SIZEOF_SIZE_T 4 -#else -#define SIZEOF_SIZE_T 8 -#endif - -/* The size of `void *', as computed by sizeof. */ -#ifndef _WIN64 -#define SIZEOF_VOID_P 4 -#else -#define SIZEOF_VOID_P 8 -#endif - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if strerror_r() returns a int. */ -/* #undef STRERROR_R_INT */ - -/* Define to 1 if your declares `struct tm'. */ -/* #undef TM_IN_SYS_TIME */ - -/* Define to 1 to build with assertion checks. (--enable-cassert) */ -/* #undef USE_ASSERT_CHECKING */ - -/* Define to 1 to build with Bonjour support. (--with-bonjour) */ -/* #undef USE_BONJOUR */ - -/* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ -/* #undef USE_BSD_AUTH */ - -/* Define to 1 if you want 64-bit integer timestamp and interval support. - (--enable-integer-datetimes) */ -/* #undef USE_INTEGER_DATETIMES */ - -/* Define to 1 to build with LDAP support. (--with-ldap) */ -/* #undef USE_LDAP */ - -/* Define to select named POSIX semaphores. */ -/* #undef USE_NAMED_POSIX_SEMAPHORES */ - -/* Define to build with OpenSSL support. (--with-openssl) */ -/* #undef USE_OPENSSL */ - -/* Define to 1 to build with PAM support. (--with-pam) */ -/* #undef USE_PAM */ - -/* Use replacement snprintf() functions. */ -#define USE_REPL_SNPRINTF 1 - -/* Define to 1 to use Intel SSE 4.2 CRC instructions with a runtime check. */ -#if (_MSC_VER < 1500) -#define USE_SLICING_BY_8_CRC32C 1 -#endif - -/* Define to 1 use Intel SSE 4.2 CRC instructions. */ -/* #undef USE_SSE42_CRC32C */ - -/* Define to 1 to use Intel SSSE 4.2 CRC instructions with a runtime check. */ -#if (_MSC_VER >= 1500) -#define USE_SSE42_CRC32C_WITH_RUNTIME_CHECK -#endif - -/* Define to select SysV-style semaphores. */ -/* #undef USE_SYSV_SEMAPHORES */ - -/* Define to select SysV-style shared memory. */ -#define USE_SYSV_SHARED_MEMORY 1 - -/* Define to select unnamed POSIX semaphores. */ -/* #undef USE_UNNAMED_POSIX_SEMAPHORES */ - -/* Define to select Win32-style semaphores. */ -#define USE_WIN32_SEMAPHORES 1 - -/* Define to 1 if `wcstombs_l' requires . */ -/* #undef WCSTOMBS_L_IN_XLOCALE */ - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#define inline __inline -#endif - -/* Define to empty if the C compiler does not understand signed types. */ -/* #undef signed */ diff --git a/libpq/postgresql/pg_config_ext.h b/libpq/postgresql/pg_config_ext.h deleted file mode 100644 index f1fd0f5..0000000 --- a/libpq/postgresql/pg_config_ext.h +++ /dev/null @@ -1,20 +0,0 @@ -/* file : libpq/postgresql/pg_config_ext.h -*- C -*- - * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd - * license : PostgreSQL License; see accompanying COPYRIGHT file - */ - -/* - * For the semanics of the following macros refer to the - * libpq/postgresql/pg_config_ext.h.in.orig and - * libpq/postgresql/pg_config_ext.h.win32.orig file. - */ - -/* - * Note that is invented by C99 and we can't expect that the libpq - * client is compiled according to this standard. However, when compile with - * GCC, Clang or VC, even requesting C90 standard explicitly, then the header - * and int64_t type are both available. - */ -#include - -#define PG_INT64_TYPE int64_t diff --git a/libpq/postgresql/pg_config_ext.h.in.orig b/libpq/postgresql/pg_config_ext.h.in.orig deleted file mode 100644 index 8acadbd..0000000 --- a/libpq/postgresql/pg_config_ext.h.in.orig +++ /dev/null @@ -1,7 +0,0 @@ -/* - * src/include/pg_config_ext.h.in. This is generated manually, not by - * autoheader, since we want to limit which symbols get defined here. - */ - -/* Define to the name of a signed 64-bit integer type. */ -#undef PG_INT64_TYPE diff --git a/libpq/postgresql/pg_config_ext.h.win32.orig b/libpq/postgresql/pg_config_ext.h.win32.orig deleted file mode 100644 index 65bbb5d..0000000 --- a/libpq/postgresql/pg_config_ext.h.win32.orig +++ /dev/null @@ -1,7 +0,0 @@ -/* - * src/include/pg_config_ext.h.win32. This is generated manually, not by - * autoheader, since we want to limit which symbols get defined here. - */ - -/* Define to the name of a signed 64-bit integer type. */ -#define PG_INT64_TYPE long long int diff --git a/libpq/postgresql/pg_config_manual.h b/libpq/postgresql/pg_config_manual.h deleted file mode 100644 index 96885bb..0000000 --- a/libpq/postgresql/pg_config_manual.h +++ /dev/null @@ -1,327 +0,0 @@ -/*------------------------------------------------------------------------ - * PostgreSQL manual configuration settings - * - * This file contains various configuration symbols and limits. In - * all cases, changing them is only useful in very rare situations or - * for developers. If you edit any of these, be sure to do a *full* - * rebuild (and an initdb if noted). - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/pg_config_manual.h - *------------------------------------------------------------------------ - */ - -/* - * Maximum length for identifiers (e.g. table names, column names, - * function names). Names actually are limited to one less byte than this, - * because the length must include a trailing zero byte. - * - * Changing this requires an initdb. - */ -#define NAMEDATALEN 64 - -/* - * Maximum number of arguments to a function. - * - * The minimum value is 8 (GIN indexes use 8-argument support functions). - * The maximum possible value is around 600 (limited by index tuple size in - * pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger - * than needed will waste memory and processing time, but do not directly - * cost disk space. - * - * Changing this does not require an initdb, but it does require a full - * backend recompile (including any user-defined C functions). - */ -#define FUNC_MAX_ARGS 100 - -/* - * Maximum number of columns in an index. There is little point in making - * this anything but a multiple of 32, because the main cost is associated - * with index tuple header size (see access/itup.h). - * - * Changing this requires an initdb. - */ -#define INDEX_MAX_KEYS 32 - -/* - * Set the upper and lower bounds of sequence values. - */ -#define SEQ_MAXVALUE PG_INT64_MAX -#define SEQ_MINVALUE (-SEQ_MAXVALUE) - -/* - * When we don't have native spinlocks, we use semaphores to simulate them. - * Decreasing this value reduces consumption of OS resources; increasing it - * may improve performance, but supplying a real spinlock implementation is - * probably far better. - */ -#define NUM_SPINLOCK_SEMAPHORES 128 - -/* - * When we have neither spinlocks nor atomic operations support we're - * implementing atomic operations on top of spinlock on top of semaphores. To - * be safe against atomic operations while holding a spinlock separate - * semaphores have to be used. - */ -#define NUM_ATOMICS_SEMAPHORES 64 - -/* - * Define this if you want to allow the lo_import and lo_export SQL - * functions to be executed by ordinary users. By default these - * functions are only available to the Postgres superuser. CAUTION: - * These functions are SECURITY HOLES since they can read and write - * any file that the PostgreSQL server has permission to access. If - * you turn this on, don't say we didn't warn you. - */ -/* #define ALLOW_DANGEROUS_LO_FUNCTIONS */ - -/* - * MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence, - * maximum usable pathname length is one less). - * - * We'd use a standard system header symbol for this, if there weren't - * so many to choose from: MAXPATHLEN, MAX_PATH, PATH_MAX are all - * defined by different "standards", and often have different values - * on the same platform! So we just punt and use a reasonably - * generous setting here. - */ -#define MAXPGPATH 1024 - -/* - * PG_SOMAXCONN: maximum accept-queue length limit passed to - * listen(2). You'd think we should use SOMAXCONN from - * , but on many systems that symbol is much smaller - * than the kernel's actual limit. In any case, this symbol need be - * twiddled only if you have a kernel that refuses large limit values, - * rather than silently reducing the value to what it can handle - * (which is what most if not all Unixen do). - */ -#define PG_SOMAXCONN 10000 - -/* - * You can try changing this if you have a machine with bytes of - * another size, but no guarantee... - */ -#define BITS_PER_BYTE 8 - -/* - * Preferred alignment for disk I/O buffers. On some CPUs, copies between - * user space and kernel space are significantly faster if the user buffer - * is aligned on a larger-than-MAXALIGN boundary. Ideally this should be - * a platform-dependent value, but for now we just hard-wire it. - */ -#define ALIGNOF_BUFFER 32 - -/* - * Disable UNIX sockets for certain operating systems. - */ -#if defined(WIN32) -#undef HAVE_UNIX_SOCKETS -#endif - -/* - * Define this if your operating system supports link() - */ -#if !defined(WIN32) && !defined(__CYGWIN__) -#define HAVE_WORKING_LINK 1 -#endif - -/* - * USE_POSIX_FADVISE controls whether Postgres will attempt to use the - * posix_fadvise() kernel call. Usually the automatic configure tests are - * sufficient, but some older Linux distributions had broken versions of - * posix_fadvise(). If necessary you can remove the #define here. - */ -#if HAVE_DECL_POSIX_FADVISE && defined(HAVE_POSIX_FADVISE) -#define USE_POSIX_FADVISE -#endif - -/* - * USE_PREFETCH code should be compiled only if we have a way to implement - * prefetching. (This is decoupled from USE_POSIX_FADVISE because there - * might in future be support for alternative low-level prefetch APIs.) - */ -#ifdef USE_POSIX_FADVISE -#define USE_PREFETCH -#endif - -/* - * Default and maximum values for backend_flush_after, bgwriter_flush_after - * and checkpoint_flush_after; measured in blocks. Currently, these are - * enabled by default if sync_file_range() exists, ie, only on Linux. Perhaps - * we could also enable by default if we have mmap and msync(MS_ASYNC)? - */ -#ifdef HAVE_SYNC_FILE_RANGE -#define DEFAULT_BACKEND_FLUSH_AFTER 0 /* never enabled by default */ -#define DEFAULT_BGWRITER_FLUSH_AFTER 64 -#define DEFAULT_CHECKPOINT_FLUSH_AFTER 32 -#else -#define DEFAULT_BACKEND_FLUSH_AFTER 0 -#define DEFAULT_BGWRITER_FLUSH_AFTER 0 -#define DEFAULT_CHECKPOINT_FLUSH_AFTER 0 -#endif -/* upper limit for all three variables */ -#define WRITEBACK_MAX_PENDING_FLUSHES 256 - -/* - * USE_SSL code should be compiled only when compiling with an SSL - * implementation. (Currently, only OpenSSL is supported, but we might add - * more implementations in the future.) - */ -#ifdef USE_OPENSSL -#define USE_SSL -#endif - -/* - * This is the default directory in which AF_UNIX socket files are - * placed. Caution: changing this risks breaking your existing client - * applications, which are likely to continue to look in the old - * directory. But if you just hate the idea of sockets in /tmp, - * here's where to twiddle it. You can also override this at runtime - * with the postmaster's -k switch. - */ -#define DEFAULT_PGSOCKET_DIR "/tmp" - -/* - * This is the default event source for Windows event log. - */ -#define DEFAULT_EVENT_SOURCE "PostgreSQL" - -/* - * The random() function is expected to yield values between 0 and - * MAX_RANDOM_VALUE. Currently, all known implementations yield - * 0..2^31-1, so we just hardwire this constant. We could do a - * configure test if it proves to be necessary. CAUTION: Think not to - * replace this with RAND_MAX. RAND_MAX defines the maximum value of - * the older rand() function, which is often different from --- and - * considerably inferior to --- random(). - */ -#define MAX_RANDOM_VALUE PG_INT32_MAX - -/* - * On PPC machines, decide whether to use the mutex hint bit in LWARX - * instructions. Setting the hint bit will slightly improve spinlock - * performance on POWER6 and later machines, but does nothing before that, - * and will result in illegal-instruction failures on some pre-POWER4 - * machines. By default we use the hint bit when building for 64-bit PPC, - * which should be safe in nearly all cases. You might want to override - * this if you are building 32-bit code for a known-recent PPC machine. - */ -#ifdef HAVE_PPC_LWARX_MUTEX_HINT /* must have assembler support in any case */ -#if defined(__ppc64__) || defined(__powerpc64__) -#define USE_PPC_LWARX_MUTEX_HINT -#endif -#endif - -/* - * On PPC machines, decide whether to use LWSYNC instructions in place of - * ISYNC and SYNC. This provides slightly better performance, but will - * result in illegal-instruction failures on some pre-POWER4 machines. - * By default we use LWSYNC when building for 64-bit PPC, which should be - * safe in nearly all cases. - */ -#if defined(__ppc64__) || defined(__powerpc64__) -#define USE_PPC_LWSYNC -#endif - -/* - * Assumed cache line size. This doesn't affect correctness, but can be used - * for low-level optimizations. Currently, this is used to pad some data - * structures in xlog.c, to ensure that highly-contended fields are on - * different cache lines. Too small a value can hurt performance due to false - * sharing, while the only downside of too large a value is a few bytes of - * wasted memory. The default is 128, which should be large enough for all - * supported platforms. - */ -#define PG_CACHE_LINE_SIZE 128 - -/* - *------------------------------------------------------------------------ - * The following symbols are for enabling debugging code, not for - * controlling user-visible features or resource limits. - *------------------------------------------------------------------------ - */ - -/* - * Include Valgrind "client requests", mostly in the memory allocator, so - * Valgrind understands PostgreSQL memory contexts. This permits detecting - * memory errors that Valgrind would not detect on a vanilla build. See also - * src/tools/valgrind.supp. "make installcheck" runs 20-30x longer under - * Valgrind. Note that USE_VALGRIND slowed older versions of Valgrind by an - * additional order of magnitude; Valgrind 3.8.1 does not have this problem. - * The client requests fall in hot code paths, so USE_VALGRIND also slows - * native execution by a few percentage points. - * - * You should normally use MEMORY_CONTEXT_CHECKING with USE_VALGRIND; - * instrumentation of repalloc() is inferior without it. - */ -/* #define USE_VALGRIND */ - -/* - * Define this to cause pfree()'d memory to be cleared immediately, to - * facilitate catching bugs that refer to already-freed values. - * Right now, this gets defined automatically if --enable-cassert. - */ -#ifdef USE_ASSERT_CHECKING -#define CLOBBER_FREED_MEMORY -#endif - -/* - * Define this to check memory allocation errors (scribbling on more - * bytes than were allocated). Right now, this gets defined - * automatically if --enable-cassert or USE_VALGRIND. - */ -#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND) -#define MEMORY_CONTEXT_CHECKING -#endif - -/* - * Define this to cause palloc()'d memory to be filled with random data, to - * facilitate catching code that depends on the contents of uninitialized - * memory. Caution: this is horrendously expensive. - */ -/* #define RANDOMIZE_ALLOCATED_MEMORY */ - -/* - * Define this to force all parse and plan trees to be passed through - * copyObject(), to facilitate catching errors and omissions in - * copyObject(). - */ -/* #define COPY_PARSE_PLAN_TREES */ - -/* - * Define this to force all raw parse trees for DML statements to be scanned - * by raw_expression_tree_walker(), to facilitate catching errors and - * omissions in that function. - */ -/* #define RAW_EXPRESSION_COVERAGE_TEST */ - -/* - * Enable debugging print statements for lock-related operations. - */ -/* #define LOCK_DEBUG */ - -/* - * Enable debugging print statements for WAL-related operations; see - * also the wal_debug GUC var. - */ -/* #define WAL_DEBUG */ - -/* - * Enable tracing of resource consumption during sort operations; - * see also the trace_sort GUC var. For 8.1 this is enabled by default. - */ -#define TRACE_SORT 1 - -/* - * Enable tracing of syncscan operations (see also the trace_syncscan GUC var). - */ -/* #define TRACE_SYNCSCAN */ - -/* - * Other debug #defines (documentation, anyone?) - */ -/* #define HEAPDEBUGALL */ -/* #define ACLDEBUG */ diff --git a/libpq/postgresql/pg_config_paths.h b/libpq/postgresql/pg_config_paths.h deleted file mode 100644 index 8b13789..0000000 --- a/libpq/postgresql/pg_config_paths.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libpq/postgresql/port.h b/libpq/postgresql/port.h deleted file mode 100644 index a61e59c..0000000 --- a/libpq/postgresql/port.h +++ /dev/null @@ -1,477 +0,0 @@ -/*------------------------------------------------------------------------- - * - * port.h - * Header for src/port/ compatibility functions. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/include/port.h - * - *------------------------------------------------------------------------- - */ -#ifndef PG_PORT_H -#define PG_PORT_H - -#include -#include -#include - -/* socket has a different definition on WIN32 */ -#ifndef WIN32 -typedef int pgsocket; - -#define PGINVALID_SOCKET (-1) -#else -typedef SOCKET pgsocket; - -#define PGINVALID_SOCKET INVALID_SOCKET -#endif - -/* non-blocking */ -extern bool pg_set_noblock(pgsocket sock); -extern bool pg_set_block(pgsocket sock); - -/* Portable path handling for Unix/Win32 (in path.c) */ - -extern bool has_drive_prefix(const char *filename); -extern char *first_dir_separator(const char *filename); -extern char *last_dir_separator(const char *filename); -extern char *first_path_var_separator(const char *pathlist); -extern void join_path_components(char *ret_path, - const char *head, const char *tail); -extern void canonicalize_path(char *path); -extern void make_native_path(char *path); -extern void cleanup_path(char *path); -extern bool path_contains_parent_reference(const char *path); -extern bool path_is_relative_and_below_cwd(const char *path); -extern bool path_is_prefix_of_path(const char *path1, const char *path2); -extern char *make_absolute_path(const char *path); -extern const char *get_progname(const char *argv0); -extern void get_share_path(const char *my_exec_path, char *ret_path); -extern void get_etc_path(const char *my_exec_path, char *ret_path); -extern void get_include_path(const char *my_exec_path, char *ret_path); -extern void get_pkginclude_path(const char *my_exec_path, char *ret_path); -extern void get_includeserver_path(const char *my_exec_path, char *ret_path); -extern void get_lib_path(const char *my_exec_path, char *ret_path); -extern void get_pkglib_path(const char *my_exec_path, char *ret_path); -extern void get_locale_path(const char *my_exec_path, char *ret_path); -extern void get_doc_path(const char *my_exec_path, char *ret_path); -extern void get_html_path(const char *my_exec_path, char *ret_path); -extern void get_man_path(const char *my_exec_path, char *ret_path); -extern bool get_home_path(char *ret_path); -extern void get_parent_directory(char *path); - -/* common/pgfnames.c */ -extern char **pgfnames(const char *path); -extern void pgfnames_cleanup(char **filenames); - -/* - * is_absolute_path - * - * By making this a macro we avoid needing to include path.c in libpq. - */ -#ifndef WIN32 -#define IS_DIR_SEP(ch) ((ch) == '/') - -#define is_absolute_path(filename) \ -( \ - IS_DIR_SEP((filename)[0]) \ -) -#else -#define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') - -/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ -#define is_absolute_path(filename) \ -( \ - IS_DIR_SEP((filename)[0]) || \ - (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ - IS_DIR_SEP((filename)[2])) \ -) -#endif - -/* Portable locale initialization (in exec.c) */ -extern void set_pglocale_pgservice(const char *argv0, const char *app); - -/* Portable way to find binaries (in exec.c) */ -extern int find_my_exec(const char *argv0, char *retpath); -extern int find_other_exec(const char *argv0, const char *target, - const char *versionstr, char *retpath); - -/* Windows security token manipulation (in exec.c) */ -#ifdef WIN32 -extern BOOL AddUserToTokenDacl(HANDLE hToken); -#endif - - -#if defined(WIN32) || defined(__CYGWIN__) -#define EXE ".exe" -#else -#define EXE "" -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) -#define DEVNULL "nul" -#else -#define DEVNULL "/dev/null" -#endif - -/* Portable delay handling */ -extern void pg_usleep(long microsec); - -/* Portable SQL-like case-independent comparisons and conversions */ -extern int pg_strcasecmp(const char *s1, const char *s2); -extern int pg_strncasecmp(const char *s1, const char *s2, size_t n); -extern unsigned char pg_toupper(unsigned char ch); -extern unsigned char pg_tolower(unsigned char ch); -extern unsigned char pg_ascii_toupper(unsigned char ch); -extern unsigned char pg_ascii_tolower(unsigned char ch); - -#ifdef USE_REPL_SNPRINTF - -/* - * Versions of libintl >= 0.13 try to replace printf() and friends with - * macros to their own versions that understand the %$ format. We do the - * same, so disable their macros, if they exist. - */ -#ifdef vsnprintf -#undef vsnprintf -#endif -#ifdef snprintf -#undef snprintf -#endif -#ifdef sprintf -#undef sprintf -#endif -#ifdef vfprintf -#undef vfprintf -#endif -#ifdef fprintf -#undef fprintf -#endif -#ifdef printf -#undef printf -#endif - -extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); -extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); -extern int pg_sprintf(char *str, const char *fmt,...) pg_attribute_printf(2, 3); -extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); -extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); -extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); - -/* - * The GCC-specific code below prevents the pg_attribute_printf above from - * being replaced, and this is required because gcc doesn't know anything - * about pg_printf. - */ -#ifdef __GNUC__ -#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) -#define snprintf(...) pg_snprintf(__VA_ARGS__) -#define sprintf(...) pg_sprintf(__VA_ARGS__) -#define vfprintf(...) pg_vfprintf(__VA_ARGS__) -#define fprintf(...) pg_fprintf(__VA_ARGS__) -#define printf(...) pg_printf(__VA_ARGS__) -#else -#define vsnprintf pg_vsnprintf -#define snprintf pg_snprintf -#define sprintf pg_sprintf -#define vfprintf pg_vfprintf -#define fprintf pg_fprintf -#define printf pg_printf -#endif -#endif /* USE_REPL_SNPRINTF */ - -#if defined(WIN32) -/* - * Versions of libintl >= 0.18? try to replace setlocale() with a macro - * to their own versions. Remove the macro, if it exists, because it - * ends up calling the wrong version when the backend and libintl use - * different versions of msvcrt. - */ -#if defined(setlocale) -#undef setlocale -#endif - -/* - * Define our own wrapper macro around setlocale() to work around bugs in - * Windows' native setlocale() function. - */ -extern char *pgwin32_setlocale(int category, const char *locale); - -#define setlocale(a,b) pgwin32_setlocale(a,b) -#endif /* WIN32 */ - -/* Portable prompt handling */ -extern char *simple_prompt(const char *prompt, int maxlen, bool echo); - -#ifdef WIN32 -#define PG_SIGNAL_COUNT 32 -#define kill(pid,sig) pgkill(pid,sig) -extern int pgkill(int pid, int sig); -#endif - -extern int pclose_check(FILE *stream); - -/* Global variable holding time zone information. */ -#if defined(WIN32) || defined(__CYGWIN__) -#define TIMEZONE_GLOBAL _timezone -#define TZNAME_GLOBAL _tzname -#else -#define TIMEZONE_GLOBAL timezone -#define TZNAME_GLOBAL tzname -#endif - -#if defined(WIN32) || defined(__CYGWIN__) -/* - * Win32 doesn't have reliable rename/unlink during concurrent access. - */ -extern int pgrename(const char *from, const char *to); -extern int pgunlink(const char *path); - -/* Include this first so later includes don't see these defines */ -#ifdef WIN32_ONLY_COMPILER -#include -#endif - -#define rename(from, to) pgrename(from, to) -#define unlink(path) pgunlink(path) -#endif /* defined(WIN32) || defined(__CYGWIN__) */ - -/* - * Win32 also doesn't have symlinks, but we can emulate them with - * junction points on newer Win32 versions. - * - * Cygwin has its own symlinks which work on Win95/98/ME where - * junction points don't, so use those instead. We have no way of - * knowing what type of system Cygwin binaries will be run on. - * Note: Some CYGWIN includes might #define WIN32. - */ -#if defined(WIN32) && !defined(__CYGWIN__) -extern int pgsymlink(const char *oldpath, const char *newpath); -extern int pgreadlink(const char *path, char *buf, size_t size); -extern bool pgwin32_is_junction(char *path); - -#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) -#define readlink(path, buf, size) pgreadlink(path, buf, size) -#endif - -extern bool rmtree(const char *path, bool rmtopdir); - -/* - * stat() is not guaranteed to set the st_size field on win32, so we - * redefine it to our own implementation that is. - * - * We must pull in sys/stat.h here so the system header definition - * goes in first, and we redefine that, and not the other way around. - * - * Some frontends don't need the size from stat, so if UNSAFE_STAT_OK - * is defined we don't bother with this. - */ -#if defined(WIN32) && !defined(__CYGWIN__) && !defined(UNSAFE_STAT_OK) -#include -extern int pgwin32_safestat(const char *path, struct stat * buf); - -#define stat(a,b) pgwin32_safestat(a,b) -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) - -/* - * open() and fopen() replacements to allow deletion of open files and - * passing of other special options. - */ -#define O_DIRECT 0x80000000 -extern int pgwin32_open(const char *, int,...); -extern FILE *pgwin32_fopen(const char *, const char *); - -#ifndef FRONTEND -#define open(a,b,c) pgwin32_open(a,b,c) -#define fopen(a,b) pgwin32_fopen(a,b) -#endif - -/* - * Mingw-w64 headers #define popen and pclose to _popen and _pclose. We want - * to use our popen wrapper, rather than plain _popen, so override that. For - * consistency, use our version of pclose, too. - */ -#ifdef popen -#undef popen -#endif -#ifdef pclose -#undef pclose -#endif - -/* - * system() and popen() replacements to enclose the command in an extra - * pair of quotes. - */ -extern int pgwin32_system(const char *command); -extern FILE *pgwin32_popen(const char *command, const char *type); - -#define system(a) pgwin32_system(a) -#define popen(a,b) pgwin32_popen(a,b) -#define pclose(a) _pclose(a) - -/* New versions of MingW have gettimeofday, old mingw and msvc don't */ -#ifndef HAVE_GETTIMEOFDAY -/* Last parameter not used */ -extern int gettimeofday(struct timeval * tp, struct timezone * tzp); -#endif -#else /* !WIN32 */ - -/* - * Win32 requires a special close for sockets and pipes, while on Unix - * close() does them all. - */ -#define closesocket close -#endif /* WIN32 */ - -/* - * On Windows, setvbuf() does not support _IOLBF mode, and interprets that - * as _IOFBF. To add insult to injury, setvbuf(file, NULL, _IOFBF, 0) - * crashes outright if "parameter validation" is enabled. Therefore, in - * places where we'd like to select line-buffered mode, we fall back to - * unbuffered mode instead on Windows. Always use PG_IOLBF not _IOLBF - * directly in order to implement this behavior. - */ -#ifndef WIN32 -#define PG_IOLBF _IOLBF -#else -#define PG_IOLBF _IONBF -#endif - -/* - * Default "extern" declarations or macro substitutes for library routines. - * When necessary, these routines are provided by files in src/port/. - */ -#ifndef HAVE_CRYPT -extern char *crypt(const char *key, const char *setting); -#endif - -/* WIN32 handled in port/win32.h */ -#ifndef WIN32 -#define pgoff_t off_t -#ifdef __NetBSD__ -extern int fseeko(FILE *stream, off_t offset, int whence); -extern off_t ftello(FILE *stream); -#endif -#endif - -extern double pg_erand48(unsigned short xseed[3]); -extern long pg_lrand48(void); -extern void pg_srand48(long seed); - -#ifndef HAVE_FLS -extern int fls(int mask); -#endif - -#ifndef HAVE_FSEEKO -#define fseeko(a, b, c) fseek(a, b, c) -#define ftello(a) ftell(a) -#endif - -#if !defined(HAVE_GETPEEREID) && !defined(WIN32) -extern int getpeereid(int sock, uid_t *uid, gid_t *gid); -#endif - -#ifndef HAVE_ISINF -extern int isinf(double x); -#endif - -#ifndef HAVE_MKDTEMP -extern char *mkdtemp(char *path); -#endif - -#ifndef HAVE_RINT -extern double rint(double x); -#endif - -#ifndef HAVE_INET_ATON -#include -#include -extern int inet_aton(const char *cp, struct in_addr * addr); -#endif - -#if !HAVE_DECL_STRLCAT -extern size_t strlcat(char *dst, const char *src, size_t siz); -#endif - -#if !HAVE_DECL_STRLCPY -extern size_t strlcpy(char *dst, const char *src, size_t siz); -#endif - -#if !defined(HAVE_RANDOM) && !defined(__BORLANDC__) -extern long random(void); -#endif - -#ifndef HAVE_UNSETENV -extern void unsetenv(const char *name); -#endif - -#ifndef HAVE_SRANDOM -extern void srandom(unsigned int seed); -#endif - -#ifndef HAVE_SSL_GET_CURRENT_COMPRESSION -#define SSL_get_current_compression(x) 0 -#endif - -/* thread.h */ -extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen); - -#ifndef WIN32 -extern int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer, - size_t buflen, struct passwd ** result); -#endif - -extern int pqGethostbyname(const char *name, - struct hostent * resultbuf, - char *buffer, size_t buflen, - struct hostent ** result, - int *herrno); - -extern void pg_qsort(void *base, size_t nel, size_t elsize, - int (*cmp) (const void *, const void *)); -extern int pg_qsort_strcmp(const void *a, const void *b); - -#define qsort(a,b,c,d) pg_qsort(a,b,c,d) - -typedef int (*qsort_arg_comparator) (const void *a, const void *b, void *arg); - -extern void qsort_arg(void *base, size_t nel, size_t elsize, - qsort_arg_comparator cmp, void *arg); - -/* port/chklocale.c */ -extern int pg_get_encoding_from_locale(const char *ctype, bool write_message); - -#if defined(WIN32) && !defined(FRONTEND) -extern int pg_codepage_to_encoding(UINT cp); -#endif - -/* port/inet_net_ntop.c */ -extern char *inet_net_ntop(int af, const void *src, int bits, - char *dst, size_t size); - -/* port/pgcheckdir.c */ -extern int pg_check_dir(const char *dir); - -/* port/pgmkdirp.c */ -extern int pg_mkdir_p(char *path, int omode); - -/* port/pqsignal.c */ -typedef void (*pqsigfunc) (int signo); -extern pqsigfunc pqsignal(int signo, pqsigfunc func); -#ifndef WIN32 -extern pqsigfunc pqsignal_no_restart(int signo, pqsigfunc func); -#else -#define pqsignal_no_restart(signo, func) pqsignal(signo, func) -#endif - -/* port/quotes.c */ -extern char *escape_single_quotes_ascii(const char *src); - -/* port/wait_error.c */ -extern char *wait_result_to_str(int exit_status); - -#endif /* PG_PORT_H */ diff --git a/libpq/postgresql/port/bsd/pg_config_os.h b/libpq/postgresql/port/bsd/pg_config_os.h deleted file mode 100644 index e69de29..0000000 diff --git a/libpq/postgresql/port/darwin/pg_config_os.h b/libpq/postgresql/port/darwin/pg_config_os.h deleted file mode 100644 index 29c4b91..0000000 --- a/libpq/postgresql/port/darwin/pg_config_os.h +++ /dev/null @@ -1,8 +0,0 @@ -/* src/include/port/darwin.h */ - -#define __darwin__ 1 - -#if HAVE_DECL_F_FULLFSYNC /* not present before OS X 10.3 */ -#define HAVE_FSYNC_WRITETHROUGH - -#endif diff --git a/libpq/postgresql/port/linux/pg_config_os.h b/libpq/postgresql/port/linux/pg_config_os.h deleted file mode 100644 index 7a6e46c..0000000 --- a/libpq/postgresql/port/linux/pg_config_os.h +++ /dev/null @@ -1,22 +0,0 @@ -/* src/include/port/linux.h */ - -/* - * As of July 2007, all known versions of the Linux kernel will sometimes - * return EIDRM for a shmctl() operation when EINVAL is correct (it happens - * when the low-order 15 bits of the supplied shm ID match the slot number - * assigned to a newer shmem segment). We deal with this by assuming that - * EIDRM means EINVAL in PGSharedMemoryIsInUse(). This is reasonably safe - * since in fact Linux has no excuse for ever returning EIDRM; it doesn't - * track removed segments in a way that would allow distinguishing them from - * private ones. But someday that code might get upgraded, and we'd have - * to have a kernel version test here. - */ -#define HAVE_LINUX_EIDRM_BUG - -/* - * Set the default wal_sync_method to fdatasync. With recent Linux versions, - * xlogdefs.h's normal rules will prefer open_datasync, which (a) doesn't - * perform better and (b) causes outright failures on ext4 data=journal - * filesystems, because those don't support O_DIRECT. - */ -#define PLATFORM_DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC diff --git a/libpq/postgresql/port/win32/arpa/inet.h b/libpq/postgresql/port/win32/arpa/inet.h deleted file mode 100644 index ad18031..0000000 --- a/libpq/postgresql/port/win32/arpa/inet.h +++ /dev/null @@ -1,3 +0,0 @@ -/* src/include/port/win32/arpa/inet.h */ - -#include diff --git a/libpq/postgresql/port/win32/netdb.h b/libpq/postgresql/port/win32/netdb.h deleted file mode 100644 index ad0627e..0000000 --- a/libpq/postgresql/port/win32/netdb.h +++ /dev/null @@ -1 +0,0 @@ -/* src/include/port/win32/netdb.h */ diff --git a/libpq/postgresql/port/win32/netinet/in.h b/libpq/postgresql/port/win32/netinet/in.h deleted file mode 100644 index a4e22f8..0000000 --- a/libpq/postgresql/port/win32/netinet/in.h +++ /dev/null @@ -1,3 +0,0 @@ -/* src/include/port/win32/netinet/in.h */ - -#include diff --git a/libpq/postgresql/port/win32/pg_config_os.h b/libpq/postgresql/port/win32/pg_config_os.h deleted file mode 100644 index 4453c90..0000000 --- a/libpq/postgresql/port/win32/pg_config_os.h +++ /dev/null @@ -1,486 +0,0 @@ -/* src/include/port/win32.h */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define WIN32_ONLY_COMPILER -#endif - -/* - * Make sure _WIN32_WINNT has the minimum required value. - * Leave a higher value in place. When building with at least Visual - * Studio 2015 the minimum requirement is Windows Vista (0x0600) to - * get support for GetLocaleInfoEx() with locales. For everything else - * the minimum version is Windows XP (0x0501). - * Also for VS2015, add a define that stops compiler complaints about - * using the old Winsock API. - */ -#if defined(_MSC_VER) && _MSC_VER >= 1900 -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#define MIN_WINNT 0x0600 -#else -#define MIN_WINNT 0x0501 -#endif - -#if defined(_WIN32_WINNT) && _WIN32_WINNT < MIN_WINNT -#undef _WIN32_WINNT -#endif - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT MIN_WINNT -#endif - -/* - * Always build with SSPI support. Keep it as a #define in case - * we want a switch to disable it sometime in the future. - */ -#ifndef __BORLANDC__ -#define ENABLE_SSPI 1 -#endif - -/* undefine and redefine after #include */ -#undef mkdir - -#undef ERROR - -/* - * The Mingw64 headers choke if this is already defined - they - * define it themselves. - */ -#if !defined(__MINGW64_VERSION_MAJOR) || defined(WIN32_ONLY_COMPILER) -#define _WINSOCKAPI_ -#endif -#include -#include -#include -#undef small -#include -#include -#include -#include -#ifndef __BORLANDC__ -#include /* for non-unicode version */ -#endif -#undef near - -/* Must be here to avoid conflicting with prototype in windows.h */ -#define mkdir(a,b) mkdir(a) - -#define ftruncate(a,b) chsize(a,b) - -/* Windows doesn't have fsync() as such, use _commit() */ -#define fsync(fd) _commit(fd) - -/* - * For historical reasons, we allow setting wal_sync_method to - * fsync_writethrough on Windows, even though it's really identical to fsync - * (both code paths wind up at _commit()). - */ -#define HAVE_FSYNC_WRITETHROUGH -#define FSYNC_WRITETHROUGH_IS_FSYNC - -#define USES_WINSOCK - -/* defines for dynamic linking on Win32 platform - * - * http://support.microsoft.com/kb/132044 - * http://msdn.microsoft.com/en-us/library/8fskxacy(v=vs.80).aspx - * http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx - */ - -#if defined(WIN32) || defined(__CYGWIN__) - -#ifdef BUILDING_DLL -#define PGDLLIMPORT __declspec (dllexport) -#else /* not BUILDING_DLL */ -#define PGDLLIMPORT __declspec (dllimport) -#endif - -#ifdef _MSC_VER -#define PGDLLEXPORT __declspec (dllexport) -#else -#define PGDLLEXPORT -#endif -#else /* not CYGWIN, not MSVC, not MingW */ -#define PGDLLIMPORT -#define PGDLLEXPORT -#endif - - -/* - * IPC defines - */ -#undef HAVE_UNION_SEMUN -#define HAVE_UNION_SEMUN 1 - -#define IPC_RMID 256 -#define IPC_CREAT 512 -#define IPC_EXCL 1024 -#define IPC_PRIVATE 234564 -#define IPC_NOWAIT 2048 -#define IPC_STAT 4096 - -#define EACCESS 2048 -#ifndef EIDRM -#define EIDRM 4096 -#endif - -#define SETALL 8192 -#define GETNCNT 16384 -#define GETVAL 65536 -#define SETVAL 131072 -#define GETPID 262144 - - -/* - * Signal stuff - * - * For WIN32, there is no wait() call so there are no wait() macros - * to interpret the return value of system(). Instead, system() - * return values < 0x100 are used for exit() termination, and higher - * values are used to indicated non-exit() termination, which is - * similar to a unix-style signal exit (think SIGSEGV == - * STATUS_ACCESS_VIOLATION). Return values are broken up into groups: - * - * http://msdn2.microsoft.com/en-gb/library/aa489609.aspx - * - * NT_SUCCESS 0 - 0x3FFFFFFF - * NT_INFORMATION 0x40000000 - 0x7FFFFFFF - * NT_WARNING 0x80000000 - 0xBFFFFFFF - * NT_ERROR 0xC0000000 - 0xFFFFFFFF - * - * Effectively, we don't care on the severity of the return value from - * system(), we just need to know if it was because of exit() or generated - * by the system, and it seems values >= 0x100 are system-generated. - * See this URL for a list of WIN32 STATUS_* values: - * - * Wine (URL used in our error messages) - - * http://source.winehq.org/source/include/ntstatus.h - * Descriptions - http://www.comp.nus.edu.sg/~wuyongzh/my_doc/ntstatus.txt - * MS SDK - http://www.nologs.com/ntstatus.html - * - * It seems the exception lists are in both ntstatus.h and winnt.h, but - * ntstatus.h has a more comprehensive list, and it only contains - * exception values, rather than winnt, which contains lots of other - * things: - * - * http://www.microsoft.com/msj/0197/exception/exception.aspx - * - * The ExceptionCode parameter is the number that the operating system - * assigned to the exception. You can see a list of various exception codes - * in WINNT.H by searching for #defines that start with "STATUS_". For - * example, the code for the all-too-familiar STATUS_ACCESS_VIOLATION is - * 0xC0000005. A more complete set of exception codes can be found in - * NTSTATUS.H from the Windows NT DDK. - * - * Some day we might want to print descriptions for the most common - * exceptions, rather than printing an include file name. We could use - * RtlNtStatusToDosError() and pass to FormatMessage(), which can print - * the text of error values, but MinGW does not support - * RtlNtStatusToDosError(). - */ -#define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0) -#define WIFSIGNALED(w) (!WIFEXITED(w)) -#define WEXITSTATUS(w) (w) -#define WTERMSIG(w) (w) - -#define sigmask(sig) ( 1 << ((sig)-1) ) - -/* Signal function return values */ -#undef SIG_DFL -#undef SIG_ERR -#undef SIG_IGN -#define SIG_DFL ((pqsigfunc)0) -#define SIG_ERR ((pqsigfunc)-1) -#define SIG_IGN ((pqsigfunc)1) - -/* Some extra signals */ -#define SIGHUP 1 -#define SIGQUIT 3 -#define SIGTRAP 5 -#define SIGABRT 22 /* Set to match W32 value -- not UNIX value */ -#define SIGKILL 9 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGSTOP 17 -#define SIGTSTP 18 -#define SIGCONT 19 -#define SIGCHLD 20 -#define SIGTTIN 21 -#define SIGTTOU 22 /* Same as SIGABRT -- no problem, I hope */ -#define SIGWINCH 28 -#ifndef __BORLANDC__ -#define SIGUSR1 30 -#define SIGUSR2 31 -#endif - -/* - * New versions of mingw have gettimeofday() and also declare - * struct timezone to support it. - */ -#ifndef HAVE_GETTIMEOFDAY -struct timezone -{ - int tz_minuteswest; /* Minutes west of GMT. */ - int tz_dsttime; /* Nonzero if DST is ever in effect. */ -}; -#endif - -/* for setitimer in backend/port/win32/timer.c */ -#define ITIMER_REAL 0 -struct itimerval -{ - struct timeval it_interval; - struct timeval it_value; -}; - -int setitimer(int which, const struct itimerval * value, struct itimerval * ovalue); - -/* - * WIN32 does not provide 64-bit off_t, but does provide the functions operating - * with 64-bit offsets. - */ -#define pgoff_t __int64 -#ifdef WIN32_ONLY_COMPILER -#define fseeko(stream, offset, origin) _fseeki64(stream, offset, origin) -#define ftello(stream) _ftelli64(stream) -#else -#ifndef fseeko -#define fseeko(stream, offset, origin) fseeko64(stream, offset, origin) -#endif -#ifndef ftello -#define ftello(stream) ftello64(stream) -#endif -#endif - -/* - * Supplement to . - * - * Perl already has typedefs for uid_t and gid_t. - */ -#ifndef PLPERL_HAVE_UID_GID -typedef int uid_t; -typedef int gid_t; -#endif -typedef long key_t; - -#ifdef WIN32_ONLY_COMPILER -typedef int pid_t; -#endif - -/* - * Supplement to . - */ -#define lstat(path, sb) stat((path), (sb)) - -/* - * Supplement to . - * This is the same value as _O_NOINHERIT in the MS header file. This is - * to ensure that we don't collide with a future definition. It means - * we cannot use _O_NOINHERIT ourselves. - */ -#define O_DSYNC 0x0080 - -/* - * Supplement to . - * - * We redefine network-related Berkeley error symbols as the corresponding WSA - * constants. This allows elog.c to recognize them as being in the Winsock - * error code range and pass them off to pgwin32_socket_strerror(), since - * Windows' version of plain strerror() won't cope. Note that this will break - * if these names are used for anything else besides Windows Sockets errors. - * See TranslateSocketError() when changing this list. - */ -#undef EAGAIN -#define EAGAIN WSAEWOULDBLOCK -#undef EINTR -#define EINTR WSAEINTR -#undef EMSGSIZE -#define EMSGSIZE WSAEMSGSIZE -#undef EAFNOSUPPORT -#define EAFNOSUPPORT WSAEAFNOSUPPORT -#undef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#undef ECONNABORTED -#define ECONNABORTED WSAECONNABORTED -#undef ECONNRESET -#define ECONNRESET WSAECONNRESET -#undef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#undef EISCONN -#define EISCONN WSAEISCONN -#undef ENOBUFS -#define ENOBUFS WSAENOBUFS -#undef EPROTONOSUPPORT -#define EPROTONOSUPPORT WSAEPROTONOSUPPORT -#undef ECONNREFUSED -#define ECONNREFUSED WSAECONNREFUSED -#undef ENOTSOCK -#define ENOTSOCK WSAENOTSOCK -#undef EOPNOTSUPP -#define EOPNOTSUPP WSAEOPNOTSUPP -#undef EADDRINUSE -#define EADDRINUSE WSAEADDRINUSE -#undef EADDRNOTAVAIL -#define EADDRNOTAVAIL WSAEADDRNOTAVAIL -#undef EHOSTUNREACH -#define EHOSTUNREACH WSAEHOSTUNREACH -#undef ENOTCONN -#define ENOTCONN WSAENOTCONN - -/* - * Extended locale functions with gratuitous underscore prefixes. - * (These APIs are nevertheless fully documented by Microsoft.) - */ -#define locale_t _locale_t -#define tolower_l _tolower_l -#define toupper_l _toupper_l -#define towlower_l _towlower_l -#define towupper_l _towupper_l -#define isdigit_l _isdigit_l -#define iswdigit_l _iswdigit_l -#define isalpha_l _isalpha_l -#define iswalpha_l _iswalpha_l -#define isalnum_l _isalnum_l -#define iswalnum_l _iswalnum_l -#define isupper_l _isupper_l -#define iswupper_l _iswupper_l -#define islower_l _islower_l -#define iswlower_l _iswlower_l -#define isgraph_l _isgraph_l -#define iswgraph_l _iswgraph_l -#define isprint_l _isprint_l -#define iswprint_l _iswprint_l -#define ispunct_l _ispunct_l -#define iswpunct_l _iswpunct_l -#define isspace_l _isspace_l -#define iswspace_l _iswspace_l -#define strcoll_l _strcoll_l -#define strxfrm_l _strxfrm_l -#define wcscoll_l _wcscoll_l -#define wcstombs_l _wcstombs_l -#define mbstowcs_l _mbstowcs_l - - -/* In backend/port/win32/signal.c */ -extern PGDLLIMPORT volatile int pg_signal_queue; -extern PGDLLIMPORT int pg_signal_mask; -extern HANDLE pgwin32_signal_event; -extern HANDLE pgwin32_initial_signal_pipe; - -#define UNBLOCKED_SIGNAL_QUEUE() (pg_signal_queue & ~pg_signal_mask) - - -void pgwin32_signal_initialize(void); -HANDLE pgwin32_create_signal_listener(pid_t pid); -void pgwin32_dispatch_queued_signals(void); -void pg_queue_signal(int signum); - -/* In backend/port/win32/socket.c */ -#ifndef FRONTEND -#define socket(af, type, protocol) pgwin32_socket(af, type, protocol) -#define bind(s, addr, addrlen) pgwin32_bind(s, addr, addrlen) -#define listen(s, backlog) pgwin32_listen(s, backlog) -#define accept(s, addr, addrlen) pgwin32_accept(s, addr, addrlen) -#define connect(s, name, namelen) pgwin32_connect(s, name, namelen) -#define select(n, r, w, e, timeout) pgwin32_select(n, r, w, e, timeout) -#define recv(s, buf, len, flags) pgwin32_recv(s, buf, len, flags) -#define send(s, buf, len, flags) pgwin32_send(s, buf, len, flags) - -SOCKET pgwin32_socket(int af, int type, int protocol); -int pgwin32_bind(SOCKET s, struct sockaddr * addr, int addrlen); -int pgwin32_listen(SOCKET s, int backlog); -SOCKET pgwin32_accept(SOCKET s, struct sockaddr * addr, int *addrlen); -int pgwin32_connect(SOCKET s, const struct sockaddr * name, int namelen); -int pgwin32_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds, const struct timeval * timeout); -int pgwin32_recv(SOCKET s, char *buf, int len, int flags); -int pgwin32_send(SOCKET s, const void *buf, int len, int flags); - -const char *pgwin32_socket_strerror(int err); -int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); - -extern int pgwin32_noblock; - -#endif - -/* in backend/port/win32_shmem.c */ -extern int pgwin32_ReserveSharedMemoryRegion(HANDLE); - -/* in backend/port/win32/crashdump.c */ -extern void pgwin32_install_crashdump_handler(void); - -/* in port/win32error.c */ -extern void _dosmaperr(unsigned long); - -/* in port/win32env.c */ -extern int pgwin32_putenv(const char *); -extern void pgwin32_unsetenv(const char *); - -/* in port/win32security.c */ -extern int pgwin32_is_service(void); -extern int pgwin32_is_admin(void); - -#define putenv(x) pgwin32_putenv(x) -#define unsetenv(x) pgwin32_unsetenv(x) - -/* Things that exist in MingW headers, but need to be added to MSVC & BCC */ -#ifdef WIN32_ONLY_COMPILER - -#ifndef _WIN64 -typedef long ssize_t; -#else -typedef __int64 ssize_t; -#endif - -#ifndef __BORLANDC__ -typedef unsigned short mode_t; - -#define S_IRUSR _S_IREAD -#define S_IWUSR _S_IWRITE -#define S_IXUSR _S_IEXEC -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -/* see also S_IRGRP etc below */ -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif /* __BORLANDC__ */ - -#define F_OK 0 -#define W_OK 2 -#define R_OK 4 - -#if (_MSC_VER < 1800) -#define isinf(x) ((_fpclass(x) == _FPCLASS_PINF) || (_fpclass(x) == _FPCLASS_NINF)) -#define isnan(x) _isnan(x) -#endif - -/* Pulled from Makefile.port in mingw */ -#define DLSUFFIX ".dll" - -#ifdef __BORLANDC__ - -/* for port/dirent.c */ -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD) -1) -#endif - -/* for port/open.c */ -#ifndef O_RANDOM -#define O_RANDOM 0x0010 /* File access is primarily random */ -#define O_SEQUENTIAL 0x0020 /* File access is primarily sequential */ -#define O_TEMPORARY 0x0040 /* Temporary file bit */ -#define O_SHORT_LIVED 0x1000 /* Temporary storage file, try not to flush */ -#define _O_SHORT_LIVED O_SHORT_LIVED -#endif /* ifndef O_RANDOM */ -#endif /* __BORLANDC__ */ -#endif /* WIN32_ONLY_COMPILER */ - -/* These aren't provided by either MingW or MSVC */ -#ifndef __BORLANDC__ -#define S_IRGRP 0 -#define S_IWGRP 0 -#define S_IXGRP 0 -#define S_IRWXG 0 -#define S_IROTH 0 -#define S_IWOTH 0 -#define S_IXOTH 0 -#define S_IRWXO 0 - -#endif /* __BORLANDC__ */ diff --git a/libpq/postgresql/port/win32/pthread-win32.h b/libpq/postgresql/port/win32/pthread-win32.h deleted file mode 100644 index 97ccc17..0000000 --- a/libpq/postgresql/port/win32/pthread-win32.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * src/port/pthread-win32.h - */ -#ifndef __PTHREAD_H -#define __PTHREAD_H - -typedef ULONG pthread_key_t; -typedef CRITICAL_SECTION *pthread_mutex_t; -typedef int pthread_once_t; - -DWORD pthread_self(void); - -void pthread_setspecific(pthread_key_t, void *); -void *pthread_getspecific(pthread_key_t); - -int pthread_mutex_init(pthread_mutex_t *, void *attr); -int pthread_mutex_lock(pthread_mutex_t *); - -/* blocking */ -int pthread_mutex_unlock(pthread_mutex_t *); - -#endif diff --git a/libpq/postgresql/port/win32/pwd.h b/libpq/postgresql/port/win32/pwd.h deleted file mode 100644 index b8c7178..0000000 --- a/libpq/postgresql/port/win32/pwd.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * src/include/port/win32/pwd.h - */ diff --git a/libpq/postgresql/port/win32/sys/socket.h b/libpq/postgresql/port/win32/sys/socket.h deleted file mode 100644 index edaee6a..0000000 --- a/libpq/postgresql/port/win32/sys/socket.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * src/include/port/win32/sys/socket.h - */ -#ifndef WIN32_SYS_SOCKET_H -#define WIN32_SYS_SOCKET_H - -/* - * Unfortunately, of VC++ also defines ERROR. - * To avoid the conflict, we include here and undefine ERROR - * immediately. - * - * Note: Don't include directly. It causes compile errors. - */ -#include -#include -#include - -#undef ERROR -#undef small - -/* Restore old ERROR value */ -#ifdef PGERROR -#define ERROR PGERROR -#endif - -/* - * we can't use the windows gai_strerror{AW} functions because - * they are defined inline in the MS header files. So we'll use our - * own - */ -#undef gai_strerror - -#endif /* WIN32_SYS_SOCKET_H */ diff --git a/libpq/postgresql/port/win32/sys/wait.h b/libpq/postgresql/port/win32/sys/wait.h deleted file mode 100644 index eaeb566..0000000 --- a/libpq/postgresql/port/win32/sys/wait.h +++ /dev/null @@ -1,3 +0,0 @@ -/* - * src/include/port/win32/sys/wait.h - */ diff --git a/libpq/postgresql/port/win32_msvc/sys/file.h b/libpq/postgresql/port/win32_msvc/sys/file.h deleted file mode 100644 index 76be3e7..0000000 --- a/libpq/postgresql/port/win32_msvc/sys/file.h +++ /dev/null @@ -1 +0,0 @@ -/* src/include/port/win32_msvc/sys/file.h */ diff --git a/libpq/postgresql/port/win32_msvc/sys/param.h b/libpq/postgresql/port/win32_msvc/sys/param.h deleted file mode 100644 index 160df3b..0000000 --- a/libpq/postgresql/port/win32_msvc/sys/param.h +++ /dev/null @@ -1 +0,0 @@ -/* src/include/port/win32_msvc/sys/param.h */ diff --git a/libpq/postgresql/port/win32_msvc/sys/time.h b/libpq/postgresql/port/win32_msvc/sys/time.h deleted file mode 100644 index 9d943ec..0000000 --- a/libpq/postgresql/port/win32_msvc/sys/time.h +++ /dev/null @@ -1 +0,0 @@ -/* src/include/port/win32_msvc/sys/time.h */ diff --git a/libpq/postgresql/port/win32_msvc/unistd.h b/libpq/postgresql/port/win32_msvc/unistd.h deleted file mode 100644 index b63f477..0000000 --- a/libpq/postgresql/port/win32_msvc/unistd.h +++ /dev/null @@ -1 +0,0 @@ -/* src/include/port/win32_msvc/unistd.h */ diff --git a/libpq/postgresql/postgres_ext.h b/libpq/postgresql/postgres_ext.h deleted file mode 100644 index ae2f087..0000000 --- a/libpq/postgresql/postgres_ext.h +++ /dev/null @@ -1,70 +0,0 @@ -/*------------------------------------------------------------------------- - * - * postgres_ext.h - * - * This file contains declarations of things that are visible everywhere - * in PostgreSQL *and* are visible to clients of frontend interface libraries. - * For example, the Oid type is part of the API of libpq and other libraries. - * - * Declarations which are specific to a particular interface should - * go in the header file for that interface (such as libpq-fe.h). This - * file is only for fundamental Postgres declarations. - * - * User-written C functions don't count as "external to Postgres." - * Those function much as local modifications to the backend itself, and - * use header files that are otherwise internal to Postgres to interface - * with the backend. - * - * src/include/postgres_ext.h - * - *------------------------------------------------------------------------- - */ - -#ifndef POSTGRES_EXT_H -#define POSTGRES_EXT_H - -#include "pg_config_ext.h" - -/* - * Object ID is a fundamental type in Postgres. - */ -typedef unsigned int Oid; - -#ifdef __cplusplus -#define InvalidOid (Oid(0)) -#else -#define InvalidOid ((Oid) 0) -#endif - -#define OID_MAX UINT_MAX -/* you will need to include to use the above #define */ - -/* Define a signed 64-bit integer type for use in client API declarations. */ -typedef PG_INT64_TYPE pg_int64; - - -/* - * Identifiers of error message fields. Kept here to keep common - * between frontend and backend, and also to export them to libpq - * applications. - */ -#define PG_DIAG_SEVERITY 'S' -#define PG_DIAG_SEVERITY_NONLOCALIZED 'V' -#define PG_DIAG_SQLSTATE 'C' -#define PG_DIAG_MESSAGE_PRIMARY 'M' -#define PG_DIAG_MESSAGE_DETAIL 'D' -#define PG_DIAG_MESSAGE_HINT 'H' -#define PG_DIAG_STATEMENT_POSITION 'P' -#define PG_DIAG_INTERNAL_POSITION 'p' -#define PG_DIAG_INTERNAL_QUERY 'q' -#define PG_DIAG_CONTEXT 'W' -#define PG_DIAG_SCHEMA_NAME 's' -#define PG_DIAG_TABLE_NAME 't' -#define PG_DIAG_COLUMN_NAME 'c' -#define PG_DIAG_DATATYPE_NAME 'd' -#define PG_DIAG_CONSTRAINT_NAME 'n' -#define PG_DIAG_SOURCE_FILE 'F' -#define PG_DIAG_SOURCE_LINE 'L' -#define PG_DIAG_SOURCE_FUNCTION 'R' - -#endif /* POSTGRES_EXT_H */ diff --git a/libpq/postgresql/postgres_fe.h b/libpq/postgresql/postgres_fe.h deleted file mode 100644 index 69c0ad8..0000000 --- a/libpq/postgresql/postgres_fe.h +++ /dev/null @@ -1,29 +0,0 @@ -/*------------------------------------------------------------------------- - * - * postgres_fe.h - * Primary include file for PostgreSQL client-side .c files - * - * This should be the first file included by PostgreSQL client libraries and - * application programs --- but not by backend modules, which should include - * postgres.h. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1995, Regents of the University of California - * - * src/include/postgres_fe.h - * - *------------------------------------------------------------------------- - */ -#ifndef POSTGRES_FE_H -#define POSTGRES_FE_H - -#ifndef FRONTEND -#define FRONTEND 1 -#endif - -#include "c.h" - -#include "common/fe_memutils.h" - -#endif /* POSTGRES_FE_H */ diff --git a/libpq/pqexpbuffer.c b/libpq/pqexpbuffer.c deleted file mode 100644 index 8d82d5c..0000000 --- a/libpq/pqexpbuffer.c +++ /dev/null @@ -1,430 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pqexpbuffer.c - * - * PQExpBuffer provides an indefinitely-extensible string data type. - * It can be used to buffer either ordinary C strings (null-terminated text) - * or arbitrary binary data. All storage is allocated with malloc(). - * - * This module is essentially the same as the backend's StringInfo data type, - * but it is intended for use in frontend libpq and client applications. - * Thus, it does not rely on palloc() nor elog(), nor psprintf.c which - * will exit() on error. - * - * It does rely on vsnprintf(); if configure finds that libc doesn't provide - * a usable vsnprintf(), then a copy of our own implementation of it will - * be linked into libpq. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/pqexpbuffer.c - * - *------------------------------------------------------------------------- - */ - -#include "postgres_fe.h" - -#include - -#include "pqexpbuffer.h" - -#ifdef WIN32 -#include "win32.h" -#endif - - -/* All "broken" PQExpBuffers point to this string. */ -static const char oom_buffer[1] = ""; - -static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0); - - -/* - * markPQExpBufferBroken - * - * Put a PQExpBuffer in "broken" state if it isn't already. - */ -static void -markPQExpBufferBroken(PQExpBuffer str) -{ - if (str->data != oom_buffer) - free(str->data); - - /* - * Casting away const here is a bit ugly, but it seems preferable to not - * marking oom_buffer const. We want to do that to encourage the compiler - * to put oom_buffer in read-only storage, so that anyone who tries to - * scribble on a broken PQExpBuffer will get a failure. - */ - str->data = (char *) oom_buffer; - str->len = 0; - str->maxlen = 0; -} - -/* - * createPQExpBuffer - * - * Create an empty 'PQExpBufferData' & return a pointer to it. - */ -PQExpBuffer -createPQExpBuffer(void) -{ - PQExpBuffer res; - - res = (PQExpBuffer) malloc(sizeof(PQExpBufferData)); - if (res != NULL) - initPQExpBuffer(res); - - return res; -} - -/* - * initPQExpBuffer - * - * Initialize a PQExpBufferData struct (with previously undefined contents) - * to describe an empty string. - */ -void -initPQExpBuffer(PQExpBuffer str) -{ - str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE); - if (str->data == NULL) - { - str->data = (char *) oom_buffer; /* see comment above */ - str->maxlen = 0; - str->len = 0; - } - else - { - str->maxlen = INITIAL_EXPBUFFER_SIZE; - str->len = 0; - str->data[0] = '\0'; - } -} - -/* - * destroyPQExpBuffer(str); - * - * free()s both the data buffer and the PQExpBufferData. - * This is the inverse of createPQExpBuffer(). - */ -void -destroyPQExpBuffer(PQExpBuffer str) -{ - if (str) - { - termPQExpBuffer(str); - free(str); - } -} - -/* - * termPQExpBuffer(str) - * free()s the data buffer but not the PQExpBufferData itself. - * This is the inverse of initPQExpBuffer(). - */ -void -termPQExpBuffer(PQExpBuffer str) -{ - if (str->data != oom_buffer) - free(str->data); - /* just for luck, make the buffer validly empty. */ - str->data = (char *) oom_buffer; /* see comment above */ - str->maxlen = 0; - str->len = 0; -} - -/* - * resetPQExpBuffer - * Reset a PQExpBuffer to empty - * - * Note: if possible, a "broken" PQExpBuffer is returned to normal. - */ -void -resetPQExpBuffer(PQExpBuffer str) -{ - if (str) - { - if (str->data != oom_buffer) - { - str->len = 0; - str->data[0] = '\0'; - } - else - { - /* try to reinitialize to valid state */ - initPQExpBuffer(str); - } - } -} - -/* - * enlargePQExpBuffer - * Make sure there is enough space for 'needed' more bytes in the buffer - * ('needed' does not include the terminating null). - * - * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case - * the buffer is left in "broken" state.) - */ -int -enlargePQExpBuffer(PQExpBuffer str, size_t needed) -{ - size_t newlen; - char *newdata; - - if (PQExpBufferBroken(str)) - return 0; /* already failed */ - - /* - * Guard against ridiculous "needed" values, which can occur if we're fed - * bogus data. Without this, we can get an overflow or infinite loop in - * the following. - */ - if (needed >= ((size_t) INT_MAX - str->len)) - { - markPQExpBufferBroken(str); - return 0; - } - - needed += str->len + 1; /* total space required now */ - - /* Because of the above test, we now have needed <= INT_MAX */ - - if (needed <= str->maxlen) - return 1; /* got enough space already */ - - /* - * We don't want to allocate just a little more space with each append; - * for efficiency, double the buffer size each time it overflows. - * Actually, we might need to more than double it if 'needed' is big... - */ - newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64; - while (needed > newlen) - newlen = 2 * newlen; - - /* - * Clamp to INT_MAX in case we went past it. Note we are assuming here - * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We - * will still have newlen >= needed. - */ - if (newlen > (size_t) INT_MAX) - newlen = (size_t) INT_MAX; - - newdata = (char *) realloc(str->data, newlen); - if (newdata != NULL) - { - str->data = newdata; - str->maxlen = newlen; - return 1; - } - - markPQExpBufferBroken(str); - return 0; -} - -/* - * printfPQExpBuffer - * Format text data under the control of fmt (an sprintf-like format string) - * and insert it into str. More space is allocated to str if necessary. - * This is a convenience routine that does the same thing as - * resetPQExpBuffer() followed by appendPQExpBuffer(). - */ -void -printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) -{ - va_list args; - bool done; - - resetPQExpBuffer(str); - - if (PQExpBufferBroken(str)) - return; /* already failed */ - - /* Loop in case we have to retry after enlarging the buffer. */ - do - { - va_start(args, fmt); - done = appendPQExpBufferVA(str, fmt, args); - va_end(args); - } while (!done); -} - -/* - * appendPQExpBuffer - * - * Format text data under the control of fmt (an sprintf-like format string) - * and append it to whatever is already in str. More space is allocated - * to str if necessary. This is sort of like a combination of sprintf and - * strcat. - */ -void -appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) -{ - va_list args; - bool done; - - if (PQExpBufferBroken(str)) - return; /* already failed */ - - /* Loop in case we have to retry after enlarging the buffer. */ - do - { - va_start(args, fmt); - done = appendPQExpBufferVA(str, fmt, args); - va_end(args); - } while (!done); -} - -/* - * appendPQExpBufferVA - * Shared guts of printfPQExpBuffer/appendPQExpBuffer. - * Attempt to format data and append it to str. Returns true if done - * (either successful or hard failure), false if need to retry. - */ -static bool -appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) -{ - size_t avail; - size_t needed; - int nprinted; - - /* - * Try to format the given string into the available space; but if there's - * hardly any space, don't bother trying, just enlarge the buffer first. - */ - if (str->maxlen > str->len + 16) - { - /* - * Note: we intentionally leave one byte unused, as a guard against - * old broken versions of vsnprintf. - */ - avail = str->maxlen - str->len - 1; - - errno = 0; - - nprinted = vsnprintf(str->data + str->len, avail, fmt, args); - - /* - * If vsnprintf reports an error other than ENOMEM, fail. - */ - if (nprinted < 0 && errno != 0 && errno != ENOMEM) - { - markPQExpBufferBroken(str); - return true; - } - - /* - * Note: some versions of vsnprintf return the number of chars - * actually stored, not the total space needed as C99 specifies. And - * at least one returns -1 on failure. Be conservative about - * believing whether the print worked. - */ - if (nprinted >= 0 && (size_t) nprinted < avail - 1) - { - /* Success. Note nprinted does not include trailing null. */ - str->len += nprinted; - return true; - } - - if (nprinted >= 0 && (size_t) nprinted > avail) - { - /* - * This appears to be a C99-compliant vsnprintf, so believe its - * estimate of the required space. (If it's wrong, the logic will - * still work, but we may loop multiple times.) Note that the - * space needed should be only nprinted+1 bytes, but we'd better - * allocate one more than that so that the test above will succeed - * next time. - * - * In the corner case where the required space just barely - * overflows, fail. - */ - if (nprinted > INT_MAX - 2) - { - markPQExpBufferBroken(str); - return true; - } - needed = nprinted + 2; - } - else - { - /* - * Buffer overrun, and we don't know how much space is needed. - * Estimate twice the previous buffer size, but not more than - * INT_MAX. - */ - if (avail >= INT_MAX / 2) - needed = INT_MAX; - else - needed = avail * 2; - } - } - else - { - /* - * We have to guess at how much to enlarge, since we're skipping the - * formatting work. - */ - needed = 32; - } - - /* Increase the buffer size and try again. */ - if (!enlargePQExpBuffer(str, needed)) - return true; /* oops, out of memory */ - - return false; -} - -/* - * appendPQExpBufferStr - * Append the given string to a PQExpBuffer, allocating more space - * if necessary. - */ -void -appendPQExpBufferStr(PQExpBuffer str, const char *data) -{ - appendBinaryPQExpBuffer(str, data, strlen(data)); -} - -/* - * appendPQExpBufferChar - * Append a single byte to str. - * Like appendPQExpBuffer(str, "%c", ch) but much faster. - */ -void -appendPQExpBufferChar(PQExpBuffer str, char ch) -{ - /* Make more room if needed */ - if (!enlargePQExpBuffer(str, 1)) - return; - - /* OK, append the character */ - str->data[str->len] = ch; - str->len++; - str->data[str->len] = '\0'; -} - -/* - * appendBinaryPQExpBuffer - * - * Append arbitrary binary data to a PQExpBuffer, allocating more space - * if necessary. - */ -void -appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen) -{ - /* Make more room if needed */ - if (!enlargePQExpBuffer(str, datalen)) - return; - - /* OK, append the data */ - memcpy(str->data + str->len, data, datalen); - str->len += datalen; - - /* - * Keep a trailing null in place, even though it's probably useless for - * binary data... - */ - str->data[str->len] = '\0'; -} diff --git a/libpq/pqexpbuffer.h b/libpq/pqexpbuffer.h deleted file mode 100644 index ce87cd5..0000000 --- a/libpq/pqexpbuffer.h +++ /dev/null @@ -1,182 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pqexpbuffer.h - * Declarations/definitions for "PQExpBuffer" functions. - * - * PQExpBuffer provides an indefinitely-extensible string data type. - * It can be used to buffer either ordinary C strings (null-terminated text) - * or arbitrary binary data. All storage is allocated with malloc(). - * - * This module is essentially the same as the backend's StringInfo data type, - * but it is intended for use in frontend libpq and client applications. - * Thus, it does not rely on palloc() nor elog(). - * - * It does rely on vsnprintf(); if configure finds that libc doesn't provide - * a usable vsnprintf(), then a copy of our own implementation of it will - * be linked into libpq. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * src/interfaces/libpq/pqexpbuffer.h - * - *------------------------------------------------------------------------- - */ -#ifndef PQEXPBUFFER_H -#define PQEXPBUFFER_H - -/*------------------------- - * PQExpBufferData holds information about an extensible string. - * data is the current buffer for the string (allocated with malloc). - * len is the current string length. There is guaranteed to be - * a terminating '\0' at data[len], although this is not very - * useful when the string holds binary data rather than text. - * maxlen is the allocated size in bytes of 'data', i.e. the maximum - * string size (including the terminating '\0' char) that we can - * currently store in 'data' without having to reallocate - * more space. We must always have maxlen > len. - * - * An exception occurs if we failed to allocate enough memory for the string - * buffer. In that case data points to a statically allocated empty string, - * and len = maxlen = 0. - *------------------------- - */ -typedef struct PQExpBufferData -{ - char *data; - size_t len; - size_t maxlen; -} PQExpBufferData; - -typedef PQExpBufferData *PQExpBuffer; - -/*------------------------ - * Test for a broken (out of memory) PQExpBuffer. - * When a buffer is "broken", all operations except resetting or deleting it - * are no-ops. - *------------------------ - */ -#define PQExpBufferBroken(str) \ - ((str) == NULL || (str)->maxlen == 0) - -/*------------------------ - * Same, but for use when using a static or local PQExpBufferData struct. - * For that, a null-pointer test is useless and may draw compiler warnings. - *------------------------ - */ -#define PQExpBufferDataBroken(buf) \ - ((buf).maxlen == 0) - -/*------------------------ - * Initial size of the data buffer in a PQExpBuffer. - * NB: this must be large enough to hold error messages that might - * be returned by PQrequestCancel(). - *------------------------ - */ -#define INITIAL_EXPBUFFER_SIZE 256 - -/*------------------------ - * There are two ways to create a PQExpBuffer object initially: - * - * PQExpBuffer stringptr = createPQExpBuffer(); - * Both the PQExpBufferData and the data buffer are malloc'd. - * - * PQExpBufferData string; - * initPQExpBuffer(&string); - * The data buffer is malloc'd but the PQExpBufferData is presupplied. - * This is appropriate if the PQExpBufferData is a field of another - * struct. - *------------------------- - */ - -/*------------------------ - * createPQExpBuffer - * Create an empty 'PQExpBufferData' & return a pointer to it. - */ -extern PQExpBuffer createPQExpBuffer(void); - -/*------------------------ - * initPQExpBuffer - * Initialize a PQExpBufferData struct (with previously undefined contents) - * to describe an empty string. - */ -extern void initPQExpBuffer(PQExpBuffer str); - -/*------------------------ - * To destroy a PQExpBuffer, use either: - * - * destroyPQExpBuffer(str); - * free()s both the data buffer and the PQExpBufferData. - * This is the inverse of createPQExpBuffer(). - * - * termPQExpBuffer(str) - * free()s the data buffer but not the PQExpBufferData itself. - * This is the inverse of initPQExpBuffer(). - * - * NOTE: some routines build up a string using PQExpBuffer, and then - * release the PQExpBufferData but return the data string itself to their - * caller. At that point the data string looks like a plain malloc'd - * string. - */ -extern void destroyPQExpBuffer(PQExpBuffer str); -extern void termPQExpBuffer(PQExpBuffer str); - -/*------------------------ - * resetPQExpBuffer - * Reset a PQExpBuffer to empty - * - * Note: if possible, a "broken" PQExpBuffer is returned to normal. - */ -extern void resetPQExpBuffer(PQExpBuffer str); - -/*------------------------ - * enlargePQExpBuffer - * Make sure there is enough space for 'needed' more bytes in the buffer - * ('needed' does not include the terminating null). - * - * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case - * the buffer is left in "broken" state.) - */ -extern int enlargePQExpBuffer(PQExpBuffer str, size_t needed); - -/*------------------------ - * printfPQExpBuffer - * Format text data under the control of fmt (an sprintf-like format string) - * and insert it into str. More space is allocated to str if necessary. - * This is a convenience routine that does the same thing as - * resetPQExpBuffer() followed by appendPQExpBuffer(). - */ -extern void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) pg_attribute_printf(2, 3); - -/*------------------------ - * appendPQExpBuffer - * Format text data under the control of fmt (an sprintf-like format string) - * and append it to whatever is already in str. More space is allocated - * to str if necessary. This is sort of like a combination of sprintf and - * strcat. - */ -extern void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) pg_attribute_printf(2, 3); - -/*------------------------ - * appendPQExpBufferStr - * Append the given string to a PQExpBuffer, allocating more space - * if necessary. - */ -extern void appendPQExpBufferStr(PQExpBuffer str, const char *data); - -/*------------------------ - * appendPQExpBufferChar - * Append a single byte to str. - * Like appendPQExpBuffer(str, "%c", ch) but much faster. - */ -extern void appendPQExpBufferChar(PQExpBuffer str, char ch); - -/*------------------------ - * appendBinaryPQExpBuffer - * Append arbitrary binary data to a PQExpBuffer, allocating more space - * if necessary. - */ -extern void appendBinaryPQExpBuffer(PQExpBuffer str, - const char *data, size_t datalen); - -#endif /* PQEXPBUFFER_H */ diff --git a/libpq/pqsignal.c b/libpq/pqsignal.c deleted file mode 100644 index 07797f9..0000000 --- a/libpq/pqsignal.c +++ /dev/null @@ -1,90 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pqsignal.c - * reliable BSD-style signal(2) routine stolen from RWW who stole it - * from Stevens... - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * src/port/pqsignal.c - * - * We now assume that all Unix-oid systems have POSIX sigaction(2) - * with support for restartable signals (SA_RESTART). We used to also - * support BSD-style signal(2), but there really shouldn't be anything - * out there anymore that doesn't have the POSIX API. - * - * Windows, of course, is resolutely in a class by itself. In the backend, - * we don't use this file at all; src/backend/port/win32/signal.c provides - * pqsignal() for the backend environment. Frontend programs can use - * this version of pqsignal() if they wish, but beware that this does - * not provide restartable signals on Windows. - * - * ------------------------------------------------------------------------ - */ - -#include "c.h" - -#include - -#if !defined(WIN32) || defined(FRONTEND) - -/* - * Set up a signal handler, with SA_RESTART, for signal "signo" - * - * Returns the previous handler. - */ -pqsigfunc -pqsignal(int signo, pqsigfunc func) -{ -#ifndef WIN32 - struct sigaction act, - oact; - - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; -#ifdef SA_NOCLDSTOP - if (signo == SIGCHLD) - act.sa_flags |= SA_NOCLDSTOP; -#endif - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; - return oact.sa_handler; -#else /* WIN32 */ - return signal(signo, func); -#endif -} - -/* - * Set up a signal handler, without SA_RESTART, for signal "signo" - * - * Returns the previous handler. - * - * On Windows, this would be identical to pqsignal(), so don't bother. - */ -#ifndef WIN32 - -pqsigfunc -pqsignal_no_restart(int signo, pqsigfunc func) -{ - struct sigaction act, - oact; - - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_NOCLDSTOP - if (signo == SIGCHLD) - act.sa_flags |= SA_NOCLDSTOP; -#endif - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; - return oact.sa_handler; -} - -#endif /* !WIN32 */ - -#endif /* !defined(WIN32) || defined(FRONTEND) */ diff --git a/libpq/tests/.gitignore b/libpq/tests/.gitignore new file mode 100644 index 0000000..2e508a9 --- /dev/null +++ b/libpq/tests/.gitignore @@ -0,0 +1,3 @@ +driver +test/ +test-*/ diff --git a/libpq/tests/build/.gitignore b/libpq/tests/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/libpq/tests/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/libpq/tests/build/bootstrap.build b/libpq/tests/build/bootstrap.build new file mode 100644 index 0000000..6212d9b --- /dev/null +++ b/libpq/tests/build/bootstrap.build @@ -0,0 +1,9 @@ +# file : tests/build/bootstrap.build +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +project = # Unnamed subproject. + +using config +using dist +using test diff --git a/libpq/tests/build/root.build b/libpq/tests/build/root.build new file mode 100644 index 0000000..e374ddd --- /dev/null +++ b/libpq/tests/build/root.build @@ -0,0 +1,22 @@ +# file : tests/build/root.build +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +using c + +h{*}: extension = h +c{*}: extension = c + +if ($c.target.system == 'win32-msvc') + c.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($c.class == 'msvc') + c.coptions += /wd4251 /wd4275 /wd4800 + +# Every exe{} in this subproject is by default a test. +# +exe{*}: test = true + +# Specify the test target for cross-testing. +# +test.target = $c.target diff --git a/libpq/tests/buildfile b/libpq/tests/buildfile new file mode 100644 index 0000000..098486c --- /dev/null +++ b/libpq/tests/buildfile @@ -0,0 +1,5 @@ +# file : tests/buildfile +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +./: {*/ -build/} diff --git a/libpq/tests/conninfo/buildfile b/libpq/tests/conninfo/buildfile new file mode 100644 index 0000000..d9d4bab --- /dev/null +++ b/libpq/tests/conninfo/buildfile @@ -0,0 +1,13 @@ +# file : tests/conninfo/buildfile +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +# Here we reproduce the upstream's libpq test. See the +# src/interfaces/libpq/test/ in the upstream package for details. +# +import libs = libpq%lib{pq} + +exe{driver}: {h c}{* -uri-regress} $libs testscript \ + file{uri-regress.c regress.in expected.out} + +c.poptions =+ "-I$src_base" diff --git a/libpq/tests/conninfo/driver.c b/libpq/tests/conninfo/driver.c new file mode 100644 index 0000000..1a13af2 --- /dev/null +++ b/libpq/tests/conninfo/driver.c @@ -0,0 +1,74 @@ +/* file : tests/conninfo/driver.c + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * Include the upstream package test and rename it's main() function to test() + * (see below for details). + */ +#define main test +#include +#undef main + +/* + * Enable assertions. + */ +#ifdef NDEBUG +# undef NDEBUG +#endif + +#include +#include +#include /* strlen() */ + +/* + * Usage: argv[0] + * + * Read connection info strings from STDIN and call upstream test main() + * function for each of them. The function prints the parsed connection info to + * stdout on success or error message to stderr on failure. + */ +int +main (int argc, char* argv[]) +{ + assert (argc == 1); + + char s[1024]; + + while (fgets (s, sizeof(s), stdin) != NULL) + { + /* + * Print the conninfo string that will be tested. + */ + printf ("trying %s", s); + + /* + * Strip the newline character and make sure it is printed to stdout. + */ + size_t n = strlen (s); + if (n != 0 && s[n - 1] == '\n') + s[n - 1] = '\0'; + else + printf ("\n"); + + /* + * Make sure the output make sense if stderr is redirected to stdout (and + * vice versa). + */ + fflush (stdout); + + /* + * Run the test. + * + * Note that we need to print the trailing newline character ourselves. + */ + char* args[] = {argv[0], s, NULL}; + int r = test (2, args); + + fprintf (r == 0 ? stdout : stderr, "\n"); + fflush (r == 0 ? stdout : stderr); + } + + return 0; +} diff --git a/libpq/tests/conninfo/expected.out b/libpq/tests/conninfo/expected.out new file mode 100644 index 0000000..d375e82 --- /dev/null +++ b/libpq/tests/conninfo/expected.out @@ -0,0 +1,171 @@ +trying postgresql://uri-user:secret@host:12345/db +user='uri-user' password='secret' dbname='db' host='host' port='12345' (inet) + +trying postgresql://uri-user@host:12345/db +user='uri-user' dbname='db' host='host' port='12345' (inet) + +trying postgresql://uri-user@host/db +user='uri-user' dbname='db' host='host' (inet) + +trying postgresql://host:12345/db +dbname='db' host='host' port='12345' (inet) + +trying postgresql://host/db +dbname='db' host='host' (inet) + +trying postgresql://uri-user@host:12345/ +user='uri-user' host='host' port='12345' (inet) + +trying postgresql://uri-user@host/ +user='uri-user' host='host' (inet) + +trying postgresql://uri-user@ +user='uri-user' (local) + +trying postgresql://host:12345/ +host='host' port='12345' (inet) + +trying postgresql://host:12345 +host='host' port='12345' (inet) + +trying postgresql://host/db +dbname='db' host='host' (inet) + +trying postgresql://host/ +host='host' (inet) + +trying postgresql://host +host='host' (inet) + +trying postgresql:// +(local) + +trying postgresql://?hostaddr=127.0.0.1 +hostaddr='127.0.0.1' (inet) + +trying postgresql://example.com?hostaddr=63.1.2.4 +host='example.com' hostaddr='63.1.2.4' (inet) + +trying postgresql://%68ost/ +host='host' (inet) + +trying postgresql://host/db?user=uri-user +user='uri-user' dbname='db' host='host' (inet) + +trying postgresql://host/db?user=uri-user&port=12345 +user='uri-user' dbname='db' host='host' port='12345' (inet) + +trying postgresql://host/db?u%73er=someotheruser&port=12345 +user='someotheruser' dbname='db' host='host' port='12345' (inet) + +trying postgresql://host/db?u%7aer=someotheruser&port=12345 +uri-regress: invalid URI query parameter: "uzer" + +trying postgresql://host:12345?user=uri-user +user='uri-user' host='host' port='12345' (inet) + +trying postgresql://host?user=uri-user +user='uri-user' host='host' (inet) + +trying postgresql://host? +host='host' (inet) + +trying postgresql://[::1]:12345/db +dbname='db' host='::1' port='12345' (inet) + +trying postgresql://[::1]/db +dbname='db' host='::1' (inet) + +trying postgresql://[2001:db8::1234]/ +host='2001:db8::1234' (inet) + +trying postgresql://[200z:db8::1234]/ +host='200z:db8::1234' (inet) + +trying postgresql://[::1] +host='::1' (inet) + +trying postgres:// +(local) + +trying postgres:/// +(local) + +trying postgres:///db +dbname='db' (local) + +trying postgres://uri-user@/db +user='uri-user' dbname='db' (local) + +trying postgres://?host=/path/to/socket/dir +host='/path/to/socket/dir' (local) + +trying postgresql://host?uzer= +uri-regress: invalid URI query parameter: "uzer" + +trying postgre:// +uri-regress: missing "=" after "postgre://" in connection info string + +trying postgres://[::1 +uri-regress: end of string reached when looking for matching "]" in IPv6 host address in URI: "postgres://[::1" + +trying postgres://[] +uri-regress: IPv6 host address may not be empty in URI: "postgres://[]" + +trying postgres://[::1]z +uri-regress: unexpected character "z" at position 17 in URI (expected ":" or "/"): "postgres://[::1]z" + +trying postgresql://host?zzz +uri-regress: missing key/value separator "=" in URI query parameter: "zzz" + +trying postgresql://host?value1&value2 +uri-regress: missing key/value separator "=" in URI query parameter: "value1" + +trying postgresql://host?key=key=value +uri-regress: extra key/value separator "=" in URI query parameter: "key" + +trying postgres://host?dbname=%XXfoo +uri-regress: invalid percent-encoded token: "%XXfoo" + +trying postgresql://a%00b +uri-regress: forbidden value %00 in percent-encoded value: "a%00b" + +trying postgresql://%zz +uri-regress: invalid percent-encoded token: "%zz" + +trying postgresql://%1 +uri-regress: invalid percent-encoded token: "%1" + +trying postgresql://% +uri-regress: invalid percent-encoded token: "%" + +trying postgres://@host +host='host' (inet) + +trying postgres://host:/ +host='host' (inet) + +trying postgres://:12345/ +port='12345' (local) + +trying postgres://otheruser@?host=/no/such/directory +user='otheruser' host='/no/such/directory' (local) + +trying postgres://otheruser@/?host=/no/such/directory +user='otheruser' host='/no/such/directory' (local) + +trying postgres://otheruser@:12345?host=/no/such/socket/path +user='otheruser' host='/no/such/socket/path' port='12345' (local) + +trying postgres://otheruser@:12345/db?host=/path/to/socket +user='otheruser' dbname='db' host='/path/to/socket' port='12345' (local) + +trying postgres://:12345/db?host=/path/to/socket +dbname='db' host='/path/to/socket' port='12345' (local) + +trying postgres://:12345?host=/path/to/socket +host='/path/to/socket' port='12345' (local) + +trying postgres://%2Fvar%2Flib%2Fpostgresql/dbname +dbname='dbname' host='/var/lib/postgresql' (local) + diff --git a/libpq/tests/conninfo/postgres_fe.h b/libpq/tests/conninfo/postgres_fe.h new file mode 100644 index 0000000..0dd2ed2 --- /dev/null +++ b/libpq/tests/conninfo/postgres_fe.h @@ -0,0 +1,19 @@ +/* file : tests/conninfo/postgres_fe.h + * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd + * license : PostgreSQL License; see accompanying COPYRIGHT file + */ + +/* + * The upstream's uri-regress.c includes src/include/postgres_fe.h that is + * located in libpq/include/ in our source tree. This file is not installed, + * so to keep the test as a subproject and be able to test against the + * installed libpq library we replace it with the header stub, containing the + * bare minimum that is required the test to compile. + */ +#ifndef TESTS_CONNINFO_POSTGRES_FE_H +#define TESTS_CONNINFO_POSTGRES_FE_H + +#include +#include + +#endif /* TESTS_CONNINFO_POSTGRES_FE_H */ diff --git a/libpq/tests/conninfo/regress.in b/libpq/tests/conninfo/regress.in new file mode 100644 index 0000000..de034f3 --- /dev/null +++ b/libpq/tests/conninfo/regress.in @@ -0,0 +1,57 @@ +postgresql://uri-user:secret@host:12345/db +postgresql://uri-user@host:12345/db +postgresql://uri-user@host/db +postgresql://host:12345/db +postgresql://host/db +postgresql://uri-user@host:12345/ +postgresql://uri-user@host/ +postgresql://uri-user@ +postgresql://host:12345/ +postgresql://host:12345 +postgresql://host/db +postgresql://host/ +postgresql://host +postgresql:// +postgresql://?hostaddr=127.0.0.1 +postgresql://example.com?hostaddr=63.1.2.4 +postgresql://%68ost/ +postgresql://host/db?user=uri-user +postgresql://host/db?user=uri-user&port=12345 +postgresql://host/db?u%73er=someotheruser&port=12345 +postgresql://host/db?u%7aer=someotheruser&port=12345 +postgresql://host:12345?user=uri-user +postgresql://host?user=uri-user +postgresql://host? +postgresql://[::1]:12345/db +postgresql://[::1]/db +postgresql://[2001:db8::1234]/ +postgresql://[200z:db8::1234]/ +postgresql://[::1] +postgres:// +postgres:/// +postgres:///db +postgres://uri-user@/db +postgres://?host=/path/to/socket/dir +postgresql://host?uzer= +postgre:// +postgres://[::1 +postgres://[] +postgres://[::1]z +postgresql://host?zzz +postgresql://host?value1&value2 +postgresql://host?key=key=value +postgres://host?dbname=%XXfoo +postgresql://a%00b +postgresql://%zz +postgresql://%1 +postgresql://% +postgres://@host +postgres://host:/ +postgres://:12345/ +postgres://otheruser@?host=/no/such/directory +postgres://otheruser@/?host=/no/such/directory +postgres://otheruser@:12345?host=/no/such/socket/path +postgres://otheruser@:12345/db?host=/path/to/socket +postgres://:12345/db?host=/path/to/socket +postgres://:12345?host=/path/to/socket +postgres://%2Fvar%2Flib%2Fpostgresql/dbname diff --git a/libpq/tests/conninfo/testscript b/libpq/tests/conninfo/testscript new file mode 100644 index 0000000..bf278ae --- /dev/null +++ b/libpq/tests/conninfo/testscript @@ -0,0 +1,5 @@ +# file : tests/conninfo/testscript +# copyright : Copyright (c) 2016-2019 Code Synthesis Ltd +# license : PostgreSQL License; see accompanying COPYRIGHT file + +$* <<<$src_base/regress.in >>>$src_base/expected.out 2>&1 diff --git a/libpq/tests/conninfo/uri-regress.c b/libpq/tests/conninfo/uri-regress.c new file mode 120000 index 0000000..fbab965 --- /dev/null +++ b/libpq/tests/conninfo/uri-regress.c @@ -0,0 +1 @@ +../../../upstream/src/interfaces/libpq/test/uri-regress.c \ No newline at end of file diff --git a/libpq/thread.c b/libpq/thread.c deleted file mode 100644 index ed908ba..0000000 --- a/libpq/thread.c +++ /dev/null @@ -1,146 +0,0 @@ -/*------------------------------------------------------------------------- - * - * thread.c - * - * Prototypes and macros around system calls, used to help make - * threaded libraries reentrant and safe to use from threaded applications. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * src/port/thread.c - * - *------------------------------------------------------------------------- - */ - -#include "c.h" - -#include - - -/* - * Threading sometimes requires specially-named versions of functions - * that return data in static buffers, like strerror_r() instead of - * strerror(). Other operating systems use pthread_setspecific() - * and pthread_getspecific() internally to allow standard library - * functions to return static data to threaded applications. And some - * operating systems have neither. - * - * Additional confusion exists because many operating systems that - * use pthread_setspecific/pthread_getspecific() also have *_r versions - * of standard library functions for compatibility with operating systems - * that require them. However, internally, these *_r functions merely - * call the thread-safe standard library functions. - * - * For example, BSD/OS 4.3 uses Bind 8.2.3 for getpwuid(). Internally, - * getpwuid() calls pthread_setspecific/pthread_getspecific() to return - * static data to the caller in a thread-safe manner. However, BSD/OS - * also has getpwuid_r(), which merely calls getpwuid() and shifts - * around the arguments to match the getpwuid_r() function declaration. - * Therefore, while BSD/OS has getpwuid_r(), it isn't required. It also - * doesn't have strerror_r(), so we can't fall back to only using *_r - * functions for threaded programs. - * - * The current setup is to try threading in this order: - * - * use *_r function names if they exit - * (*_THREADSAFE=yes) - * use non-*_r functions if they are thread-safe - * - * One thread-safe solution for gethostbyname() might be to use getaddrinfo(). - * - * Run src/test/thread to test if your operating system has thread-safe - * non-*_r functions. - */ - - -/* - * Wrapper around strerror and strerror_r to use the former if it is - * available and also return a more useful value (the error string). - */ -char * -pqStrerror(int errnum, char *strerrbuf, size_t buflen) -{ -#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_STRERROR_R) - /* reentrant strerror_r is available */ -#ifdef STRERROR_R_INT - /* SUSv3 version */ - if (strerror_r(errnum, strerrbuf, buflen) == 0) - return strerrbuf; - else - return "Unknown error"; -#else - /* GNU libc */ - return strerror_r(errnum, strerrbuf, buflen); -#endif -#else - /* no strerror_r() available, just use strerror */ - strlcpy(strerrbuf, strerror(errnum), buflen); - - return strerrbuf; -#endif -} - -/* - * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r() - * behaviour, if that function is not available or required. - * - * Per POSIX, the possible cases are: - * success: returns zero, *result is non-NULL - * uid not found: returns zero, *result is NULL - * error during lookup: returns an errno code, *result is NULL - * (caller should *not* assume that the errno variable is set) - */ -#ifndef WIN32 -int -pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer, - size_t buflen, struct passwd ** result) -{ -#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETPWUID_R) - return getpwuid_r(uid, resultbuf, buffer, buflen, result); -#else - /* no getpwuid_r() available, just use getpwuid() */ - errno = 0; - *result = getpwuid(uid); - /* paranoia: ensure we return zero on success */ - return (*result == NULL) ? errno : 0; -#endif -} -#endif - -/* - * Wrapper around gethostbyname() or gethostbyname_r() to mimic - * POSIX gethostbyname_r() behaviour, if it is not available or required. - * This function is called _only_ by our getaddinfo() portability function. - */ -#ifndef HAVE_GETADDRINFO -int -pqGethostbyname(const char *name, - struct hostent * resultbuf, - char *buffer, size_t buflen, - struct hostent ** result, - int *herrno) -{ -#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R) - - /* - * broken (well early POSIX draft) gethostbyname_r() which returns 'struct - * hostent *' - */ - *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno); - return (*result == NULL) ? -1 : 0; -#else - - /* no gethostbyname_r(), just use gethostbyname() */ - *result = gethostbyname(name); - - if (*result != NULL) - *herrno = h_errno; - - if (*result != NULL) - return 0; - else - return -1; -#endif -} - -#endif diff --git a/libpq/version.h.in b/libpq/version.h.in deleted file mode 100644 index af772da..0000000 --- a/libpq/version.h.in +++ /dev/null @@ -1,26 +0,0 @@ -/* file : libpq/version.h.in -*- C -*- - * copyright : Copyright (c) 2016-2019 Code Synthesis Ltd - * license : PostgreSQL License; see accompanying COPYRIGHT file - */ - -#ifndef PG_MAJORVERSION /* Note: using the version macro itself. */ - -/* - * Note that staring PostgreSQL 10 the release version schema changed (see - * build/bootstrap.build for details). - */ -#if $libpq.version.major$ < 10 -# define PG_MAJORVERSION "$libpq.version.major$.$libpq.version.minor$" -#else -# error "change PG_MAJORVERSION macro definition" -# define PG_MAJORVERSION "$libpq.version.major$" -#endif - -/* - * Is valid for both old and new version schemes (see above). - */ -#define PG_VERSION_NUM (10000 * $libpq.version.major$ + \ - 100 * $libpq.version.minor$ + \ - $libpq.version.patch$) - -#endif /* PG_MAJORVERSION */ diff --git a/libpq/wchar.c b/libpq/wchar.c deleted file mode 100644 index fd51eed..0000000 --- a/libpq/wchar.c +++ /dev/null @@ -1,2054 +0,0 @@ -/* - * conversion functions between pg_wchar and multibyte streams. - * Tatsuo Ishii - * src/backend/utils/mb/wchar.c - * - */ -/* can be used in either frontend or backend */ -#ifdef FRONTEND -#include "postgres_fe.h" -#else -#include "postgres.h" -#endif - -#include "mb/pg_wchar.h" - - -/* - * conversion to pg_wchar is done by "table driven." - * to add an encoding support, define mb2wchar_with_len(), mblen(), dsplen() - * for the particular encoding. Note that if the encoding is only - * supported in the client, you don't need to define - * mb2wchar_with_len() function (SJIS is the case). - * - * These functions generally assume that their input is validly formed. - * The "verifier" functions, further down in the file, have to be more - * paranoid. We expect that mblen() does not need to examine more than - * the first byte of the character to discover the correct length. - * - * Note: for the display output of psql to work properly, the return values - * of the dsplen functions must conform to the Unicode standard. In particular - * the NUL character is zero width and control characters are generally - * width -1. It is recommended that non-ASCII encodings refer their ASCII - * subset to the ASCII routines to ensure consistency. - */ - -/* - * SQL/ASCII - */ -static int -pg_ascii2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - *to++ = *from++; - len--; - cnt++; - } - *to = 0; - return cnt; -} - -static int -pg_ascii_mblen(const unsigned char *s) -{ - return 1; -} - -static int -pg_ascii_dsplen(const unsigned char *s) -{ - if (*s == '\0') - return 0; - if (*s < 0x20 || *s == 0x7f) - return -1; - - return 1; -} - -/* - * EUC - */ -static int -pg_euc2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - if (*from == SS2 && len >= 2) /* JIS X 0201 (so called "1 byte - * KANA") */ - { - from++; - *to = (SS2 << 8) | *from++; - len -= 2; - } - else if (*from == SS3 && len >= 3) /* JIS X 0212 KANJI */ - { - from++; - *to = (SS3 << 16) | (*from++ << 8); - *to |= *from++; - len -= 3; - } - else if (IS_HIGHBIT_SET(*from) && len >= 2) /* JIS X 0208 KANJI */ - { - *to = *from++ << 8; - *to |= *from++; - len -= 2; - } - else /* must be ASCII */ - { - *to = *from++; - len--; - } - to++; - cnt++; - } - *to = 0; - return cnt; -} - -static inline int -pg_euc_mblen(const unsigned char *s) -{ - int len; - - if (*s == SS2) - len = 2; - else if (*s == SS3) - len = 3; - else if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = 1; - return len; -} - -static inline int -pg_euc_dsplen(const unsigned char *s) -{ - int len; - - if (*s == SS2) - len = 2; - else if (*s == SS3) - len = 2; - else if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = pg_ascii_dsplen(s); - return len; -} - -/* - * EUC_JP - */ -static int -pg_eucjp2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - return pg_euc2wchar_with_len(from, to, len); -} - -static int -pg_eucjp_mblen(const unsigned char *s) -{ - return pg_euc_mblen(s); -} - -static int -pg_eucjp_dsplen(const unsigned char *s) -{ - int len; - - if (*s == SS2) - len = 1; - else if (*s == SS3) - len = 2; - else if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = pg_ascii_dsplen(s); - return len; -} - -/* - * EUC_KR - */ -static int -pg_euckr2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - return pg_euc2wchar_with_len(from, to, len); -} - -static int -pg_euckr_mblen(const unsigned char *s) -{ - return pg_euc_mblen(s); -} - -static int -pg_euckr_dsplen(const unsigned char *s) -{ - return pg_euc_dsplen(s); -} - -/* - * EUC_CN - * - */ -static int -pg_euccn2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - if (*from == SS2 && len >= 3) /* code set 2 (unused?) */ - { - from++; - *to = (SS2 << 16) | (*from++ << 8); - *to |= *from++; - len -= 3; - } - else if (*from == SS3 && len >= 3) /* code set 3 (unused ?) */ - { - from++; - *to = (SS3 << 16) | (*from++ << 8); - *to |= *from++; - len -= 3; - } - else if (IS_HIGHBIT_SET(*from) && len >= 2) /* code set 1 */ - { - *to = *from++ << 8; - *to |= *from++; - len -= 2; - } - else - { - *to = *from++; - len--; - } - to++; - cnt++; - } - *to = 0; - return cnt; -} - -static int -pg_euccn_mblen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = 1; - return len; -} - -static int -pg_euccn_dsplen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = pg_ascii_dsplen(s); - return len; -} - -/* - * EUC_TW - * - */ -static int -pg_euctw2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - if (*from == SS2 && len >= 4) /* code set 2 */ - { - from++; - *to = (((uint32) SS2) << 24) | (*from++ << 16); - *to |= *from++ << 8; - *to |= *from++; - len -= 4; - } - else if (*from == SS3 && len >= 3) /* code set 3 (unused?) */ - { - from++; - *to = (SS3 << 16) | (*from++ << 8); - *to |= *from++; - len -= 3; - } - else if (IS_HIGHBIT_SET(*from) && len >= 2) /* code set 2 */ - { - *to = *from++ << 8; - *to |= *from++; - len -= 2; - } - else - { - *to = *from++; - len--; - } - to++; - cnt++; - } - *to = 0; - return cnt; -} - -static int -pg_euctw_mblen(const unsigned char *s) -{ - int len; - - if (*s == SS2) - len = 4; - else if (*s == SS3) - len = 3; - else if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = 1; - return len; -} - -static int -pg_euctw_dsplen(const unsigned char *s) -{ - int len; - - if (*s == SS2) - len = 2; - else if (*s == SS3) - len = 2; - else if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = pg_ascii_dsplen(s); - return len; -} - -/* - * Convert pg_wchar to EUC_* encoding. - * caller must allocate enough space for "to", including a trailing zero! - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_wchar2euc_with_len(const pg_wchar *from, unsigned char *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - unsigned char c; - - if ((c = (*from >> 24))) - { - *to++ = c; - *to++ = (*from >> 16) & 0xff; - *to++ = (*from >> 8) & 0xff; - *to++ = *from & 0xff; - cnt += 4; - } - else if ((c = (*from >> 16))) - { - *to++ = c; - *to++ = (*from >> 8) & 0xff; - *to++ = *from & 0xff; - cnt += 3; - } - else if ((c = (*from >> 8))) - { - *to++ = c; - *to++ = *from & 0xff; - cnt += 2; - } - else - { - *to++ = *from; - cnt++; - } - from++; - len--; - } - *to = 0; - return cnt; -} - - -/* - * JOHAB - */ -static int -pg_johab_mblen(const unsigned char *s) -{ - return pg_euc_mblen(s); -} - -static int -pg_johab_dsplen(const unsigned char *s) -{ - return pg_euc_dsplen(s); -} - -/* - * convert UTF8 string to pg_wchar (UCS-4) - * caller must allocate enough space for "to", including a trailing zero! - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_utf2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - uint32 c1, - c2, - c3, - c4; - - while (len > 0 && *from) - { - if ((*from & 0x80) == 0) - { - *to = *from++; - len--; - } - else if ((*from & 0xe0) == 0xc0) - { - if (len < 2) - break; /* drop trailing incomplete char */ - c1 = *from++ & 0x1f; - c2 = *from++ & 0x3f; - *to = (c1 << 6) | c2; - len -= 2; - } - else if ((*from & 0xf0) == 0xe0) - { - if (len < 3) - break; /* drop trailing incomplete char */ - c1 = *from++ & 0x0f; - c2 = *from++ & 0x3f; - c3 = *from++ & 0x3f; - *to = (c1 << 12) | (c2 << 6) | c3; - len -= 3; - } - else if ((*from & 0xf8) == 0xf0) - { - if (len < 4) - break; /* drop trailing incomplete char */ - c1 = *from++ & 0x07; - c2 = *from++ & 0x3f; - c3 = *from++ & 0x3f; - c4 = *from++ & 0x3f; - *to = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; - len -= 4; - } - else - { - /* treat a bogus char as length 1; not ours to raise error */ - *to = *from++; - len--; - } - to++; - cnt++; - } - *to = 0; - return cnt; -} - - -/* - * Map a Unicode code point to UTF-8. utf8string must have 4 bytes of - * space allocated. - */ -unsigned char * -unicode_to_utf8(pg_wchar c, unsigned char *utf8string) -{ - if (c <= 0x7F) - { - utf8string[0] = c; - } - else if (c <= 0x7FF) - { - utf8string[0] = 0xC0 | ((c >> 6) & 0x1F); - utf8string[1] = 0x80 | (c & 0x3F); - } - else if (c <= 0xFFFF) - { - utf8string[0] = 0xE0 | ((c >> 12) & 0x0F); - utf8string[1] = 0x80 | ((c >> 6) & 0x3F); - utf8string[2] = 0x80 | (c & 0x3F); - } - else - { - utf8string[0] = 0xF0 | ((c >> 18) & 0x07); - utf8string[1] = 0x80 | ((c >> 12) & 0x3F); - utf8string[2] = 0x80 | ((c >> 6) & 0x3F); - utf8string[3] = 0x80 | (c & 0x3F); - } - - return utf8string; -} - -/* - * Trivial conversion from pg_wchar to UTF-8. - * caller should allocate enough space for "to" - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_wchar2utf_with_len(const pg_wchar *from, unsigned char *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - int char_len; - - unicode_to_utf8(*from, to); - char_len = pg_utf_mblen(to); - cnt += char_len; - to += char_len; - from++; - len--; - } - *to = 0; - return cnt; -} - -/* - * Return the byte length of a UTF8 character pointed to by s - * - * Note: in the current implementation we do not support UTF8 sequences - * of more than 4 bytes; hence do NOT return a value larger than 4. - * We return "1" for any leading byte that is either flat-out illegal or - * indicates a length larger than we support. - * - * pg_utf2wchar_with_len(), utf8_to_unicode(), pg_utf8_islegal(), and perhaps - * other places would need to be fixed to change this. - */ -int -pg_utf_mblen(const unsigned char *s) -{ - int len; - - if ((*s & 0x80) == 0) - len = 1; - else if ((*s & 0xe0) == 0xc0) - len = 2; - else if ((*s & 0xf0) == 0xe0) - len = 3; - else if ((*s & 0xf8) == 0xf0) - len = 4; -#ifdef NOT_USED - else if ((*s & 0xfc) == 0xf8) - len = 5; - else if ((*s & 0xfe) == 0xfc) - len = 6; -#endif - else - len = 1; - return len; -} - -/* - * This is an implementation of wcwidth() and wcswidth() as defined in - * "The Single UNIX Specification, Version 2, The Open Group, 1997" - * - * - * Markus Kuhn -- 2001-09-08 -- public domain - * - * customised for PostgreSQL - * - * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ - -struct mbinterval -{ - unsigned short first; - unsigned short last; -}; - -/* auxiliary function for binary search in interval table */ -static int -mbbisearch(pg_wchar ucs, const struct mbinterval * table, int max) -{ - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) - { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} - - -/* The following functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * FullWidth (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded - * in ISO 10646. - */ - -static int -ucs_wcwidth(pg_wchar ucs) -{ - /* sorted list of non-overlapping intervals of non-spacing characters */ - static const struct mbinterval combining[] = { - {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486}, - {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9}, - {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, - {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670}, - {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, - {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, - {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C}, - {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954}, - {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, - {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, - {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, - {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, - {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, - {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01}, - {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, - {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, - {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, - {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, - {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, - {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, - {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, - {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, - {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, - {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, - {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, - {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, - {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032}, - {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, - {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6}, - {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9}, - {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F}, - {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A}, - {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, - {0xFFF9, 0xFFFB} - }; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - - if (ucs < 0x20 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff) - return -1; - - /* binary search in table of non-spacing characters */ - if (mbbisearch(ucs, combining, - sizeof(combining) / sizeof(struct mbinterval) - 1)) - return 0; - - /* - * if we arrive here, ucs is not a combining or C0/C1 control character - */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility - * Ideographs */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2ffff))); -} - -/* - * Convert a UTF-8 character to a Unicode code point. - * This is a one-character version of pg_utf2wchar_with_len. - * - * No error checks here, c must point to a long-enough string. - */ -pg_wchar -utf8_to_unicode(const unsigned char *c) -{ - if ((*c & 0x80) == 0) - return (pg_wchar) c[0]; - else if ((*c & 0xe0) == 0xc0) - return (pg_wchar) (((c[0] & 0x1f) << 6) | - (c[1] & 0x3f)); - else if ((*c & 0xf0) == 0xe0) - return (pg_wchar) (((c[0] & 0x0f) << 12) | - ((c[1] & 0x3f) << 6) | - (c[2] & 0x3f)); - else if ((*c & 0xf8) == 0xf0) - return (pg_wchar) (((c[0] & 0x07) << 18) | - ((c[1] & 0x3f) << 12) | - ((c[2] & 0x3f) << 6) | - (c[3] & 0x3f)); - else - /* that is an invalid code on purpose */ - return 0xffffffff; -} - -static int -pg_utf_dsplen(const unsigned char *s) -{ - return ucs_wcwidth(utf8_to_unicode(s)); -} - -/* - * convert mule internal code to pg_wchar - * caller should allocate enough space for "to" - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_mule2wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - if (IS_LC1(*from) && len >= 2) - { - *to = *from++ << 16; - *to |= *from++; - len -= 2; - } - else if (IS_LCPRV1(*from) && len >= 3) - { - from++; - *to = *from++ << 16; - *to |= *from++; - len -= 3; - } - else if (IS_LC2(*from) && len >= 3) - { - *to = *from++ << 16; - *to |= *from++ << 8; - *to |= *from++; - len -= 3; - } - else if (IS_LCPRV2(*from) && len >= 4) - { - from++; - *to = *from++ << 16; - *to |= *from++ << 8; - *to |= *from++; - len -= 4; - } - else - { /* assume ASCII */ - *to = (unsigned char) *from++; - len--; - } - to++; - cnt++; - } - *to = 0; - return cnt; -} - -/* - * convert pg_wchar to mule internal code - * caller should allocate enough space for "to" - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_wchar2mule_with_len(const pg_wchar *from, unsigned char *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - unsigned char lb; - - lb = (*from >> 16) & 0xff; - if (IS_LC1(lb)) - { - *to++ = lb; - *to++ = *from & 0xff; - cnt += 2; - } - else if (IS_LC2(lb)) - { - *to++ = lb; - *to++ = (*from >> 8) & 0xff; - *to++ = *from & 0xff; - cnt += 3; - } - else if (IS_LCPRV1_A_RANGE(lb)) - { - *to++ = LCPRV1_A; - *to++ = lb; - *to++ = *from & 0xff; - cnt += 3; - } - else if (IS_LCPRV1_B_RANGE(lb)) - { - *to++ = LCPRV1_B; - *to++ = lb; - *to++ = *from & 0xff; - cnt += 3; - } - else if (IS_LCPRV2_A_RANGE(lb)) - { - *to++ = LCPRV2_A; - *to++ = lb; - *to++ = (*from >> 8) & 0xff; - *to++ = *from & 0xff; - cnt += 4; - } - else if (IS_LCPRV2_B_RANGE(lb)) - { - *to++ = LCPRV2_B; - *to++ = lb; - *to++ = (*from >> 8) & 0xff; - *to++ = *from & 0xff; - cnt += 4; - } - else - { - *to++ = *from & 0xff; - cnt += 1; - } - from++; - len--; - } - *to = 0; - return cnt; -} - -int -pg_mule_mblen(const unsigned char *s) -{ - int len; - - if (IS_LC1(*s)) - len = 2; - else if (IS_LCPRV1(*s)) - len = 3; - else if (IS_LC2(*s)) - len = 3; - else if (IS_LCPRV2(*s)) - len = 4; - else - len = 1; /* assume ASCII */ - return len; -} - -static int -pg_mule_dsplen(const unsigned char *s) -{ - int len; - - /* - * Note: it's not really appropriate to assume that all multibyte charsets - * are double-wide on screen. But this seems an okay approximation for - * the MULE charsets we currently support. - */ - - if (IS_LC1(*s)) - len = 1; - else if (IS_LCPRV1(*s)) - len = 1; - else if (IS_LC2(*s)) - len = 2; - else if (IS_LCPRV2(*s)) - len = 2; - else - len = 1; /* assume ASCII */ - - return len; -} - -/* - * ISO8859-1 - */ -static int -pg_latin12wchar_with_len(const unsigned char *from, pg_wchar *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - *to++ = *from++; - len--; - cnt++; - } - *to = 0; - return cnt; -} - -/* - * Trivial conversion from pg_wchar to single byte encoding. Just ignores - * high bits. - * caller should allocate enough space for "to" - * len: length of from. - * "from" not necessarily null terminated. - */ -static int -pg_wchar2single_with_len(const pg_wchar *from, unsigned char *to, int len) -{ - int cnt = 0; - - while (len > 0 && *from) - { - *to++ = *from++; - len--; - cnt++; - } - *to = 0; - return cnt; -} - -static int -pg_latin1_mblen(const unsigned char *s) -{ - return 1; -} - -static int -pg_latin1_dsplen(const unsigned char *s) -{ - return pg_ascii_dsplen(s); -} - -/* - * SJIS - */ -static int -pg_sjis_mblen(const unsigned char *s) -{ - int len; - - if (*s >= 0xa1 && *s <= 0xdf) - len = 1; /* 1 byte kana? */ - else if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = 1; /* should be ASCII */ - return len; -} - -static int -pg_sjis_dsplen(const unsigned char *s) -{ - int len; - - if (*s >= 0xa1 && *s <= 0xdf) - len = 1; /* 1 byte kana? */ - else if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = pg_ascii_dsplen(s); /* should be ASCII */ - return len; -} - -/* - * Big5 - */ -static int -pg_big5_mblen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = 1; /* should be ASCII */ - return len; -} - -static int -pg_big5_dsplen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = pg_ascii_dsplen(s); /* should be ASCII */ - return len; -} - -/* - * GBK - */ -static int -pg_gbk_mblen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = 1; /* should be ASCII */ - return len; -} - -static int -pg_gbk_dsplen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* kanji? */ - else - len = pg_ascii_dsplen(s); /* should be ASCII */ - return len; -} - -/* - * UHC - */ -static int -pg_uhc_mblen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* 2byte? */ - else - len = 1; /* should be ASCII */ - return len; -} - -static int -pg_uhc_dsplen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; /* 2byte? */ - else - len = pg_ascii_dsplen(s); /* should be ASCII */ - return len; -} - -/* - * GB18030 - * Added by Bill Huang , - */ -static int -pg_gb18030_mblen(const unsigned char *s) -{ - int len; - - if (!IS_HIGHBIT_SET(*s)) - len = 1; /* ASCII */ - else if (*(s + 1) >= 0x30 && *(s + 1) <= 0x39) - len = 4; - else - len = 2; - return len; -} - -static int -pg_gb18030_dsplen(const unsigned char *s) -{ - int len; - - if (IS_HIGHBIT_SET(*s)) - len = 2; - else - len = pg_ascii_dsplen(s); /* ASCII */ - return len; -} - -/* - *------------------------------------------------------------------- - * multibyte sequence validators - * - * These functions accept "s", a pointer to the first byte of a string, - * and "len", the remaining length of the string. If there is a validly - * encoded character beginning at *s, return its length in bytes; else - * return -1. - * - * The functions can assume that len > 0 and that *s != '\0', but they must - * test for and reject zeroes in any additional bytes of a multibyte character. - * - * Note that this definition allows the function for a single-byte - * encoding to be just "return 1". - *------------------------------------------------------------------- - */ - -static int -pg_ascii_verifier(const unsigned char *s, int len) -{ - return 1; -} - -#define IS_EUC_RANGE_VALID(c) ((c) >= 0xa1 && (c) <= 0xfe) - -static int -pg_eucjp_verifier(const unsigned char *s, int len) -{ - int l; - unsigned char c1, - c2; - - c1 = *s++; - - switch (c1) - { - case SS2: /* JIS X 0201 */ - l = 2; - if (l > len) - return -1; - c2 = *s++; - if (c2 < 0xa1 || c2 > 0xdf) - return -1; - break; - - case SS3: /* JIS X 0212 */ - l = 3; - if (l > len) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - break; - - default: - if (IS_HIGHBIT_SET(c1)) /* JIS X 0208? */ - { - l = 2; - if (l > len) - return -1; - if (!IS_EUC_RANGE_VALID(c1)) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - } - else - /* must be ASCII */ - { - l = 1; - } - break; - } - - return l; -} - -static int -pg_euckr_verifier(const unsigned char *s, int len) -{ - int l; - unsigned char c1, - c2; - - c1 = *s++; - - if (IS_HIGHBIT_SET(c1)) - { - l = 2; - if (l > len) - return -1; - if (!IS_EUC_RANGE_VALID(c1)) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - } - else - /* must be ASCII */ - { - l = 1; - } - - return l; -} - -/* EUC-CN byte sequences are exactly same as EUC-KR */ -#define pg_euccn_verifier pg_euckr_verifier - -static int -pg_euctw_verifier(const unsigned char *s, int len) -{ - int l; - unsigned char c1, - c2; - - c1 = *s++; - - switch (c1) - { - case SS2: /* CNS 11643 Plane 1-7 */ - l = 4; - if (l > len) - return -1; - c2 = *s++; - if (c2 < 0xa1 || c2 > 0xa7) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - break; - - case SS3: /* unused */ - return -1; - - default: - if (IS_HIGHBIT_SET(c1)) /* CNS 11643 Plane 1 */ - { - l = 2; - if (l > len) - return -1; - /* no further range check on c1? */ - c2 = *s++; - if (!IS_EUC_RANGE_VALID(c2)) - return -1; - } - else - /* must be ASCII */ - { - l = 1; - } - break; - } - return l; -} - -static int -pg_johab_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - unsigned char c; - - l = mbl = pg_johab_mblen(s); - - if (len < l) - return -1; - - if (!IS_HIGHBIT_SET(*s)) - return mbl; - - while (--l > 0) - { - c = *++s; - if (!IS_EUC_RANGE_VALID(c)) - return -1; - } - return mbl; -} - -static int -pg_mule_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - unsigned char c; - - l = mbl = pg_mule_mblen(s); - - if (len < l) - return -1; - - while (--l > 0) - { - c = *++s; - if (!IS_HIGHBIT_SET(c)) - return -1; - } - return mbl; -} - -static int -pg_latin1_verifier(const unsigned char *s, int len) -{ - return 1; -} - -static int -pg_sjis_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - unsigned char c1, - c2; - - l = mbl = pg_sjis_mblen(s); - - if (len < l) - return -1; - - if (l == 1) /* pg_sjis_mblen already verified it */ - return mbl; - - c1 = *s++; - c2 = *s; - if (!ISSJISHEAD(c1) || !ISSJISTAIL(c2)) - return -1; - return mbl; -} - -static int -pg_big5_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - - l = mbl = pg_big5_mblen(s); - - if (len < l) - return -1; - - while (--l > 0) - { - if (*++s == '\0') - return -1; - } - - return mbl; -} - -static int -pg_gbk_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - - l = mbl = pg_gbk_mblen(s); - - if (len < l) - return -1; - - while (--l > 0) - { - if (*++s == '\0') - return -1; - } - - return mbl; -} - -static int -pg_uhc_verifier(const unsigned char *s, int len) -{ - int l, - mbl; - - l = mbl = pg_uhc_mblen(s); - - if (len < l) - return -1; - - while (--l > 0) - { - if (*++s == '\0') - return -1; - } - - return mbl; -} - -static int -pg_gb18030_verifier(const unsigned char *s, int len) -{ - int l; - - if (!IS_HIGHBIT_SET(*s)) - l = 1; /* ASCII */ - else if (len >= 4 && *(s + 1) >= 0x30 && *(s + 1) <= 0x39) - { - /* Should be 4-byte, validate remaining bytes */ - if (*s >= 0x81 && *s <= 0xfe && - *(s + 2) >= 0x81 && *(s + 2) <= 0xfe && - *(s + 3) >= 0x30 && *(s + 3) <= 0x39) - l = 4; - else - l = -1; - } - else if (len >= 2 && *s >= 0x81 && *s <= 0xfe) - { - /* Should be 2-byte, validate */ - if ((*(s + 1) >= 0x40 && *(s + 1) <= 0x7e) || - (*(s + 1) >= 0x80 && *(s + 1) <= 0xfe)) - l = 2; - else - l = -1; - } - else - l = -1; - return l; -} - -static int -pg_utf8_verifier(const unsigned char *s, int len) -{ - int l = pg_utf_mblen(s); - - if (len < l) - return -1; - - if (!pg_utf8_islegal(s, l)) - return -1; - - return l; -} - -/* - * Check for validity of a single UTF-8 encoded character - * - * This directly implements the rules in RFC3629. The bizarre-looking - * restrictions on the second byte are meant to ensure that there isn't - * more than one encoding of a given Unicode character point; that is, - * you may not use a longer-than-necessary byte sequence with high order - * zero bits to represent a character that would fit in fewer bytes. - * To do otherwise is to create security hazards (eg, create an apparent - * non-ASCII character that decodes to plain ASCII). - * - * length is assumed to have been obtained by pg_utf_mblen(), and the - * caller must have checked that that many bytes are present in the buffer. - */ -bool -pg_utf8_islegal(const unsigned char *source, int length) -{ - unsigned char a; - - switch (length) - { - default: - /* reject lengths 5 and 6 for now */ - return false; - case 4: - a = source[3]; - if (a < 0x80 || a > 0xBF) - return false; - /* FALL THRU */ - case 3: - a = source[2]; - if (a < 0x80 || a > 0xBF) - return false; - /* FALL THRU */ - case 2: - a = source[1]; - switch (*source) - { - case 0xE0: - if (a < 0xA0 || a > 0xBF) - return false; - break; - case 0xED: - if (a < 0x80 || a > 0x9F) - return false; - break; - case 0xF0: - if (a < 0x90 || a > 0xBF) - return false; - break; - case 0xF4: - if (a < 0x80 || a > 0x8F) - return false; - break; - default: - if (a < 0x80 || a > 0xBF) - return false; - break; - } - /* FALL THRU */ - case 1: - a = *source; - if (a >= 0x80 && a < 0xC2) - return false; - if (a > 0xF4) - return false; - break; - } - return true; -} - -#ifndef FRONTEND - -/* - * Generic character incrementer function. - * - * Not knowing anything about the properties of the encoding in use, we just - * keep incrementing the last byte until we get a validly-encoded result, - * or we run out of values to try. We don't bother to try incrementing - * higher-order bytes, so there's no growth in runtime for wider characters. - * (If we did try to do that, we'd need to consider the likelihood that 255 - * is not a valid final byte in the encoding.) - */ -static bool -pg_generic_charinc(unsigned char *charptr, int len) -{ - unsigned char *lastbyte = charptr + len - 1; - mbverifier mbverify; - - /* We can just invoke the character verifier directly. */ - mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverify; - - while (*lastbyte < (unsigned char) 255) - { - (*lastbyte)++; - if ((*mbverify) (charptr, len) == len) - return true; - } - - return false; -} - -/* - * UTF-8 character incrementer function. - * - * For a one-byte character less than 0x7F, we just increment the byte. - * - * For a multibyte character, every byte but the first must fall between 0x80 - * and 0xBF; and the first byte must be between 0xC0 and 0xF4. We increment - * the last byte that's not already at its maximum value. If we can't find a - * byte that's less than the maximum allowable value, we simply fail. We also - * need some special-case logic to skip regions used for surrogate pair - * handling, as those should not occur in valid UTF-8. - * - * Note that we don't reset lower-order bytes back to their minimums, since - * we can't afford to make an exhaustive search (see make_greater_string). - */ -static bool -pg_utf8_increment(unsigned char *charptr, int length) -{ - unsigned char a; - unsigned char limit; - - switch (length) - { - default: - /* reject lengths 5 and 6 for now */ - return false; - case 4: - a = charptr[3]; - if (a < 0xBF) - { - charptr[3]++; - break; - } - /* FALL THRU */ - case 3: - a = charptr[2]; - if (a < 0xBF) - { - charptr[2]++; - break; - } - /* FALL THRU */ - case 2: - a = charptr[1]; - switch (*charptr) - { - case 0xED: - limit = 0x9F; - break; - case 0xF4: - limit = 0x8F; - break; - default: - limit = 0xBF; - break; - } - if (a < limit) - { - charptr[1]++; - break; - } - /* FALL THRU */ - case 1: - a = *charptr; - if (a == 0x7F || a == 0xDF || a == 0xEF || a == 0xF4) - return false; - charptr[0]++; - break; - } - - return true; -} - -/* - * EUC-JP character incrementer function. - * - * If the sequence starts with SS2 (0x8e), it must be a two-byte sequence - * representing JIS X 0201 characters with the second byte ranging between - * 0xa1 and 0xdf. We just increment the last byte if it's less than 0xdf, - * and otherwise rewrite the whole sequence to 0xa1 0xa1. - * - * If the sequence starts with SS3 (0x8f), it must be a three-byte sequence - * in which the last two bytes range between 0xa1 and 0xfe. The last byte - * is incremented if possible, otherwise the second-to-last byte. - * - * If the sequence starts with a value other than the above and its MSB - * is set, it must be a two-byte sequence representing JIS X 0208 characters - * with both bytes ranging between 0xa1 and 0xfe. The last byte is - * incremented if possible, otherwise the second-to-last byte. - * - * Otherwise, the sequence is a single-byte ASCII character. It is - * incremented up to 0x7f. - */ -static bool -pg_eucjp_increment(unsigned char *charptr, int length) -{ - unsigned char c1, - c2; - int i; - - c1 = *charptr; - - switch (c1) - { - case SS2: /* JIS X 0201 */ - if (length != 2) - return false; - - c2 = charptr[1]; - - if (c2 >= 0xdf) - charptr[0] = charptr[1] = 0xa1; - else if (c2 < 0xa1) - charptr[1] = 0xa1; - else - charptr[1]++; - break; - - case SS3: /* JIS X 0212 */ - if (length != 3) - return false; - - for (i = 2; i > 0; i--) - { - c2 = charptr[i]; - if (c2 < 0xa1) - { - charptr[i] = 0xa1; - return true; - } - else if (c2 < 0xfe) - { - charptr[i]++; - return true; - } - } - - /* Out of 3-byte code region */ - return false; - - default: - if (IS_HIGHBIT_SET(c1)) /* JIS X 0208? */ - { - if (length != 2) - return false; - - for (i = 1; i >= 0; i--) - { - c2 = charptr[i]; - if (c2 < 0xa1) - { - charptr[i] = 0xa1; - return true; - } - else if (c2 < 0xfe) - { - charptr[i]++; - return true; - } - } - - /* Out of 2 byte code region */ - return false; - } - else - { /* ASCII, single byte */ - if (c1 > 0x7e) - return false; - (*charptr)++; - } - break; - } - - return true; -} -#endif /* !FRONTEND */ - - -/* - *------------------------------------------------------------------- - * encoding info table - * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) - *------------------------------------------------------------------- - */ -const pg_wchar_tbl pg_wchar_table[] = { - {pg_ascii2wchar_with_len, pg_wchar2single_with_len, pg_ascii_mblen, pg_ascii_dsplen, pg_ascii_verifier, 1}, /* PG_SQL_ASCII */ - {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JP */ - {pg_euccn2wchar_with_len, pg_wchar2euc_with_len, pg_euccn_mblen, pg_euccn_dsplen, pg_euccn_verifier, 2}, /* PG_EUC_CN */ - {pg_euckr2wchar_with_len, pg_wchar2euc_with_len, pg_euckr_mblen, pg_euckr_dsplen, pg_euckr_verifier, 3}, /* PG_EUC_KR */ - {pg_euctw2wchar_with_len, pg_wchar2euc_with_len, pg_euctw_mblen, pg_euctw_dsplen, pg_euctw_verifier, 4}, /* PG_EUC_TW */ - {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifier, 3}, /* PG_EUC_JIS_2004 */ - {pg_utf2wchar_with_len, pg_wchar2utf_with_len, pg_utf_mblen, pg_utf_dsplen, pg_utf8_verifier, 4}, /* PG_UTF8 */ - {pg_mule2wchar_with_len, pg_wchar2mule_with_len, pg_mule_mblen, pg_mule_dsplen, pg_mule_verifier, 4}, /* PG_MULE_INTERNAL */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN1 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN2 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN3 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN4 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN5 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN6 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN7 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN8 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN9 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_LATIN10 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1256 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1258 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN866 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN874 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8R */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1251 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1252 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-5 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-6 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-7 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* ISO-8859-8 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1250 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1253 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1254 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1255 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_WIN1257 */ - {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifier, 1}, /* PG_KOI8U */ - {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2}, /* PG_SJIS */ - {0, 0, pg_big5_mblen, pg_big5_dsplen, pg_big5_verifier, 2}, /* PG_BIG5 */ - {0, 0, pg_gbk_mblen, pg_gbk_dsplen, pg_gbk_verifier, 2}, /* PG_GBK */ - {0, 0, pg_uhc_mblen, pg_uhc_dsplen, pg_uhc_verifier, 2}, /* PG_UHC */ - {0, 0, pg_gb18030_mblen, pg_gb18030_dsplen, pg_gb18030_verifier, 4}, /* PG_GB18030 */ - {0, 0, pg_johab_mblen, pg_johab_dsplen, pg_johab_verifier, 3}, /* PG_JOHAB */ - {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifier, 2} /* PG_SHIFT_JIS_2004 */ -}; - -/* returns the byte length of a word for mule internal code */ -int -pg_mic_mblen(const unsigned char *mbstr) -{ - return pg_mule_mblen(mbstr); -} - -/* - * Returns the byte length of a multibyte character. - */ -int -pg_encoding_mblen(int encoding, const char *mbstr) -{ - return (PG_VALID_ENCODING(encoding) ? - ((*pg_wchar_table[encoding].mblen) ((const unsigned char *) mbstr)) : - ((*pg_wchar_table[PG_SQL_ASCII].mblen) ((const unsigned char *) mbstr))); -} - -/* - * Returns the display length of a multibyte character. - */ -int -pg_encoding_dsplen(int encoding, const char *mbstr) -{ - return (PG_VALID_ENCODING(encoding) ? - ((*pg_wchar_table[encoding].dsplen) ((const unsigned char *) mbstr)) : - ((*pg_wchar_table[PG_SQL_ASCII].dsplen) ((const unsigned char *) mbstr))); -} - -/* - * Verify the first multibyte character of the given string. - * Return its byte length if good, -1 if bad. (See comments above for - * full details of the mbverify API.) - */ -int -pg_encoding_verifymb(int encoding, const char *mbstr, int len) -{ - return (PG_VALID_ENCODING(encoding) ? - ((*pg_wchar_table[encoding].mbverify) ((const unsigned char *) mbstr, len)) : - ((*pg_wchar_table[PG_SQL_ASCII].mbverify) ((const unsigned char *) mbstr, len))); -} - -/* - * fetch maximum length of a given encoding - */ -int -pg_encoding_max_length(int encoding) -{ - Assert(PG_VALID_ENCODING(encoding)); - - return pg_wchar_table[encoding].maxmblen; -} - -#ifndef FRONTEND - -/* - * fetch maximum length of the encoding for the current database - */ -int -pg_database_encoding_max_length(void) -{ - return pg_wchar_table[GetDatabaseEncoding()].maxmblen; -} - -/* - * get the character incrementer for the encoding for the current database - */ -mbcharacter_incrementer -pg_database_encoding_character_incrementer(void) -{ - /* - * Eventually it might be best to add a field to pg_wchar_table[], but for - * now we just use a switch. - */ - switch (GetDatabaseEncoding()) - { - case PG_UTF8: - return pg_utf8_increment; - - case PG_EUC_JP: - return pg_eucjp_increment; - - default: - return pg_generic_charinc; - } -} - -/* - * Verify mbstr to make sure that it is validly encoded in the current - * database encoding. Otherwise same as pg_verify_mbstr(). - */ -bool -pg_verifymbstr(const char *mbstr, int len, bool noError) -{ - return - pg_verify_mbstr_len(GetDatabaseEncoding(), mbstr, len, noError) >= 0; -} - -/* - * Verify mbstr to make sure that it is validly encoded in the specified - * encoding. - */ -bool -pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError) -{ - return pg_verify_mbstr_len(encoding, mbstr, len, noError) >= 0; -} - -/* - * Verify mbstr to make sure that it is validly encoded in the specified - * encoding. - * - * mbstr is not necessarily zero terminated; length of mbstr is - * specified by len. - * - * If OK, return length of string in the encoding. - * If a problem is found, return -1 when noError is - * true; when noError is false, ereport() a descriptive message. - */ -int -pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError) -{ - mbverifier mbverify; - int mb_len; - - Assert(PG_VALID_ENCODING(encoding)); - - /* - * In single-byte encodings, we need only reject nulls (\0). - */ - if (pg_encoding_max_length(encoding) <= 1) - { - const char *nullpos = memchr(mbstr, 0, len); - - if (nullpos == NULL) - return len; - if (noError) - return -1; - report_invalid_encoding(encoding, nullpos, 1); - } - - /* fetch function pointer just once */ - mbverify = pg_wchar_table[encoding].mbverify; - - mb_len = 0; - - while (len > 0) - { - int l; - - /* fast path for ASCII-subset characters */ - if (!IS_HIGHBIT_SET(*mbstr)) - { - if (*mbstr != '\0') - { - mb_len++; - mbstr++; - len--; - continue; - } - if (noError) - return -1; - report_invalid_encoding(encoding, mbstr, len); - } - - l = (*mbverify) ((const unsigned char *) mbstr, len); - - if (l < 0) - { - if (noError) - return -1; - report_invalid_encoding(encoding, mbstr, len); - } - - mbstr += l; - len -= l; - mb_len++; - } - return mb_len; -} - -/* - * check_encoding_conversion_args: check arguments of a conversion function - * - * "expected" arguments can be either an encoding ID or -1 to indicate that - * the caller will check whether it accepts the ID. - * - * Note: the errors here are not really user-facing, so elog instead of - * ereport seems sufficient. Also, we trust that the "expected" encoding - * arguments are valid encoding IDs, but we don't trust the actuals. - */ -void -check_encoding_conversion_args(int src_encoding, - int dest_encoding, - int len, - int expected_src_encoding, - int expected_dest_encoding) -{ - if (!PG_VALID_ENCODING(src_encoding)) - elog(ERROR, "invalid source encoding ID: %d", src_encoding); - if (src_encoding != expected_src_encoding && expected_src_encoding >= 0) - elog(ERROR, "expected source encoding \"%s\", but got \"%s\"", - pg_enc2name_tbl[expected_src_encoding].name, - pg_enc2name_tbl[src_encoding].name); - if (!PG_VALID_ENCODING(dest_encoding)) - elog(ERROR, "invalid destination encoding ID: %d", dest_encoding); - if (dest_encoding != expected_dest_encoding && expected_dest_encoding >= 0) - elog(ERROR, "expected destination encoding \"%s\", but got \"%s\"", - pg_enc2name_tbl[expected_dest_encoding].name, - pg_enc2name_tbl[dest_encoding].name); - if (len < 0) - elog(ERROR, "encoding conversion length must not be negative"); -} - -/* - * report_invalid_encoding: complain about invalid multibyte character - * - * note: len is remaining length of string, not length of character; - * len must be greater than zero, as we always examine the first byte. - */ -void -report_invalid_encoding(int encoding, const char *mbstr, int len) -{ - int l = pg_encoding_mblen(encoding, mbstr); - char buf[8 * 5 + 1]; - char *p = buf; - int j, - jlimit; - - jlimit = Min(l, len); - jlimit = Min(jlimit, 8); /* prevent buffer overrun */ - - for (j = 0; j < jlimit; j++) - { - p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]); - if (j < jlimit - 1) - p += sprintf(p, " "); - } - - ereport(ERROR, - (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), - errmsg("invalid byte sequence for encoding \"%s\": %s", - pg_enc2name_tbl[encoding].name, - buf))); -} - -/* - * report_untranslatable_char: complain about untranslatable character - * - * note: len is remaining length of string, not length of character; - * len must be greater than zero, as we always examine the first byte. - */ -void -report_untranslatable_char(int src_encoding, int dest_encoding, - const char *mbstr, int len) -{ - int l = pg_encoding_mblen(src_encoding, mbstr); - char buf[8 * 5 + 1]; - char *p = buf; - int j, - jlimit; - - jlimit = Min(l, len); - jlimit = Min(jlimit, 8); /* prevent buffer overrun */ - - for (j = 0; j < jlimit; j++) - { - p += sprintf(p, "0x%02x", (unsigned char) mbstr[j]); - if (j < jlimit - 1) - p += sprintf(p, " "); - } - - ereport(ERROR, - (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER), - errmsg("character with byte sequence %s in encoding \"%s\" has no equivalent in encoding \"%s\"", - buf, - pg_enc2name_tbl[src_encoding].name, - pg_enc2name_tbl[dest_encoding].name))); -} - -#endif /* !FRONTEND */ diff --git a/libpq/win32/crypt.c b/libpq/win32/crypt.c deleted file mode 100644 index 6a902ef..0000000 --- a/libpq/win32/crypt.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* src/port/crypt.c */ -/* $NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Tom Truscott. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)crypt.c 8.1.1.1 (Berkeley) 8/18/93"; -#else -__RCSID("$NetBSD: crypt.c,v 1.18 2001/03/01 14:37:35 wiz Exp $"); -#endif -#endif /* not lint */ - -#include "c.h" - -#include - -#ifndef WIN32 -#include -#endif - -static int des_setkey(const char *key); -static int des_cipher(const char *in, char *out, long salt, int num_iter); - -/* - * UNIX password, and DES, encryption. - * By Tom Truscott, trt@rti.rti.org, - * from algorithms by Robert W. Baldwin and James Gillogly. - * - * References: - * "Mathematical Cryptology for Computer Scientists and Mathematicians," - * by Wayne Patterson, 1987, ISBN 0-8476-7438-X. - * - * "Password Security: A Case History," R. Morris and Ken Thompson, - * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979. - * - * "DES will be Totally Insecure within Ten Years," M.E. Hellman, - * IEEE Spectrum, vol. 16, pp. 32-39, July 1979. - */ - -/* ===== Configuration ==================== */ - -/* - * define "MUST_ALIGN" if your compiler cannot load/store - * long integers at arbitrary (e.g. odd) memory locations. - * (Either that or never pass unaligned addresses to des_cipher!) - */ -/* #define MUST_ALIGN */ - -#ifdef CHAR_BITS -#if CHAR_BITS != 8 -#error C_block structure assumes 8 bit characters -#endif -#endif - -/* - * define "B64" to be the declaration for a 64 bit integer. - * XXX this feature is currently unused, see "endian" comment below. - */ -/* #define B64 int64 */ - -/* - * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes - * of lookup tables. This speeds up des_setkey() and des_cipher(), but has - * little effect on crypt(). - */ -/* #define LARGEDATA */ - -/* compile with "-DSTATIC=void" when profiling */ -#ifndef STATIC -#define STATIC static void -#endif - -/* - * Define the "int32_t" type for integral type with a width of at least - * 32 bits. - */ -typedef int int32_t; - -/* ==================================== */ - -#define _PASSWORD_EFMT1 '_' /* extended encryption format */ - -/* - * Cipher-block representation (Bob Baldwin): - * - * DES operates on groups of 64 bits, numbered 1..64 (sigh). One - * representation is to store one bit per byte in an array of bytes. Bit N of - * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array. - * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the - * first byte, 9..16 in the second, and so on. The DES spec apparently has - * bit 1 in the MSB of the first byte, but that is particularly noxious so we - * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is - * the MSB of the first byte. Specifically, the 64-bit input data and key are - * converted to LSB format, and the output 64-bit block is converted back into - * MSB format. - * - * DES operates internally on groups of 32 bits which are expanded to 48 bits - * by permutation E and shrunk back to 32 bits by the S boxes. To speed up - * the computation, the expansion is applied only once, the expanded - * representation is maintained during the encryption, and a compression - * permutation is applied only at the end. To speed up the S-box lookups, - * the 48 bits are maintained as eight 6 bit groups, one per byte, which - * directly feed the eight S-boxes. Within each byte, the 6 bits are the - * most significant ones. The low two bits of each byte are zero. (Thus, - * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the - * first byte in the eight byte representation, bit 2 of the 48 bit value is - * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is - * used, in which the output is the 64 bit result of an S-box lookup which - * has been permuted by P and expanded by E, and is ready for use in the next - * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this - * lookup. Since each byte in the 48 bit path is a multiple of four, indexed - * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and - * "salt" are also converted to this 8*(6+2) format. The SPE table size is - * 8*64*8 = 4K bytes. - * - * To speed up bit-parallel operations (such as XOR), the 8 byte - * representation is "union"ed with 32 bit values "i0" and "i1", and, on - * machines which support it, a 64 bit value "b64". This data structure, - * "C_block", has two problems. First, alignment restrictions must be - * honored. Second, the byte-order (e.g. little-endian or big-endian) of - * the architecture becomes visible. - * - * The byte-order problem is unfortunate, since on the one hand it is good - * to have a machine-independent C_block representation (bits 1..8 in the - * first byte, etc.), and on the other hand it is good for the LSB of the - * first byte to be the LSB of i0. We cannot have both these things, so we - * currently use the "little-endian" representation and avoid any multi-byte - * operations that depend on byte order. This largely precludes use of the - * 64-bit datatype since the relative order of i0 and i1 are unknown. It - * also inhibits grouping the SPE table to look up 12 bits at a time. (The - * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1 - * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the - * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup - * requires a 128 kilobyte table, so perhaps this is not a big loss. - * - * Permutation representation (Jim Gillogly): - * - * A transformation is defined by its effect on each of the 8 bytes of the - * 64-bit input. For each byte we give a 64-bit output that has the bits in - * the input distributed appropriately. The transformation is then the OR - * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for - * each transformation. Unless LARGEDATA is defined, however, a more compact - * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks. - * The smaller table uses 16*16*8 = 2K bytes for each transformation. This - * is slower but tolerable, particularly for password encryption in which - * the SPE transformation is iterated many times. The small tables total 9K - * bytes, the large tables total 72K bytes. - * - * The transformations used are: - * IE3264: MSB->LSB conversion, initial permutation, and expansion. - * This is done by collecting the 32 even-numbered bits and applying - * a 32->64 bit transformation, and then collecting the 32 odd-numbered - * bits and applying the same transformation. Since there are only - * 32 input bits, the IE3264 transformation table is half the size of - * the usual table. - * CF6464: Compression, final permutation, and LSB->MSB conversion. - * This is done by two trivial 48->32 bit compressions to obtain - * a 64-bit block (the bit numbering is given in the "CIFP" table) - * followed by a 64->64 bit "cleanup" transformation. (It would - * be possible to group the bits in the 64-bit block so that 2 - * identical 32->32 bit transformations could be used instead, - * saving a factor of 4 in space and possibly 2 in time, but - * byte-ordering and other complications rear their ugly head. - * Similar opportunities/problems arise in the key schedule - * transforms.) - * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation. - * This admittedly baroque 64->64 bit transformation is used to - * produce the first code (in 8*(6+2) format) of the key schedule. - * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation. - * It would be possible to define 15 more transformations, each - * with a different rotation, to generate the entire key schedule. - * To save space, however, we instead permute each code into the - * next by using a transformation that "undoes" the PC2 permutation, - * rotates the code, and then applies PC2. Unfortunately, PC2 - * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not - * invertible. We get around that problem by using a modified PC2 - * which retains the 8 otherwise-lost bits in the unused low-order - * bits of each byte. The low-order bits are cleared when the - * codes are stored into the key schedule. - * PC2ROT[1]: Same as PC2ROT[0], but with two rotations. - * This is faster than applying PC2ROT[0] twice, - * - * The Bell Labs "salt" (Bob Baldwin): - * - * The salting is a simple permutation applied to the 48-bit result of E. - * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and - * i+24 of the result are swapped. The salt is thus a 24 bit number, with - * 16777216 possible values. (The original salt was 12 bits and could not - * swap bits 13..24 with 36..48.) - * - * It is possible, but ugly, to warp the SPE table to account for the salt - * permutation. Fortunately, the conditional bit swapping requires only - * about four machine instructions and can be done on-the-fly with about an - * 8% performance penalty. - */ - -typedef union -{ - unsigned char b[8]; - struct - { - int32_t i0; - int32_t i1; - } b32; -#if defined(B64) - B64 b64; -#endif -} C_block; - -/* - * Convert twenty-four-bit long in host-order - * to six bits (and 2 low-order zeroes) per char little-endian format. - */ -#define TO_SIX_BIT(rslt, src) { \ - C_block cvt; \ - cvt.b[0] = src; src >>= 6; \ - cvt.b[1] = src; src >>= 6; \ - cvt.b[2] = src; src >>= 6; \ - cvt.b[3] = src; \ - rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ - } - -/* - * These macros may someday permit efficient use of 64-bit integers. - */ -#define ZERO(d,d0,d1) d0 = 0, d1 = 0 -#define LOAD(d,d0,d1,bl) d0 = (bl).b32.i0, d1 = (bl).b32.i1 -#define LOADREG(d,d0,d1,s,s0,s1) d0 = s0, d1 = s1 -#define OR(d,d0,d1,bl) d0 |= (bl).b32.i0, d1 |= (bl).b32.i1 -#define STORE(s,s0,s1,bl) (bl).b32.i0 = s0, (bl).b32.i1 = s1 -#define DCL_BLOCK(d,d0,d1) int32_t d0, d1 - -#if defined(LARGEDATA) - /* Waste memory like crazy. Also, do permutations in line */ -#define LGCHUNKBITS 3 -#define CHUNKBITS (1<> 4]; - OR(D, D0, D1, *tp); - p += (1 << CHUNKBITS); - } while (--chars_in > 0); - STORE(D, D0, D1, *out); -} -#endif /* LARGEDATA */ - - -/* ===== (mostly) Standard DES Tables ==================== */ - -static const unsigned char IP[] = { /* initial permutation */ - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, -}; - -/* The final permutation is the inverse of IP - no table is necessary */ - -static const unsigned char ExpandTr[] = { /* expansion operation */ - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1, -}; - -static const unsigned char PC1[] = { /* permuted choice table 1 */ - 57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36, - - 63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4, -}; - -static const unsigned char Rotates[] = { /* PC1 rotation schedule */ - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, -}; - -/* note: each "row" of PC2 is left-padded with bits that make it invertible */ -static const unsigned char PC2[] = { /* permuted choice table 2 */ - 9, 18, 14, 17, 11, 24, 1, 5, - 22, 25, 3, 28, 15, 6, 21, 10, - 35, 38, 23, 19, 12, 4, 26, 8, - 43, 54, 16, 7, 27, 20, 13, 2, - - 0, 0, 41, 52, 31, 37, 47, 55, - 0, 0, 30, 40, 51, 45, 33, 48, - 0, 0, 44, 49, 39, 56, 34, 53, - 0, 0, 46, 42, 50, 36, 29, 32, -}; - -static const unsigned char S[8][64] = { /* 48->32 bit substitution tables */ - /* S[1] */ - {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, - 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, - 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, - 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}, - /* S[2] */ - {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, - 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, - 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, - 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}, - /* S[3] */ - {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, - 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, - 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, - 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}, - /* S[4] */ - {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, - 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, - 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, - 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}, - /* S[5] */ - {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, - 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, - 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, - 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}, - /* S[6] */ - {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, - 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, - 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, - 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}, - /* S[7] */ - {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, - 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, - 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, - 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, - /* S[8] */ - {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, - 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, - 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, - 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} -}; - -static const unsigned char P32Tr[] = { /* 32-bit permutation function */ - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25, -}; - -static const unsigned char CIFP[] = { /* compressed/interleaved permutation */ - 1, 2, 3, 4, 17, 18, 19, 20, - 5, 6, 7, 8, 21, 22, 23, 24, - 9, 10, 11, 12, 25, 26, 27, 28, - 13, 14, 15, 16, 29, 30, 31, 32, - - 33, 34, 35, 36, 49, 50, 51, 52, - 37, 38, 39, 40, 53, 54, 55, 56, - 41, 42, 43, 44, 57, 58, 59, 60, - 45, 46, 47, 48, 61, 62, 63, 64, -}; - -static const unsigned char itoa64[] = /* 0..63 => ascii-64 */ -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - -/* ===== Tables that are initialized at run time ==================== */ - - -static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ - -/* Initial key schedule permutation */ -static C_block PC1ROT[64 / CHUNKBITS][1 << CHUNKBITS]; - -/* Subsequent key schedule rotation permutations */ -static C_block PC2ROT[2][64 / CHUNKBITS][1 << CHUNKBITS]; - -/* Initial permutation/expansion table */ -static C_block IE3264[32 / CHUNKBITS][1 << CHUNKBITS]; - -/* Table that combines the S, P, and E operations. */ -static int32_t SPE[2][8][64]; - -/* compressed/interleaved => final permutation table */ -static C_block CF6464[64 / CHUNKBITS][1 << CHUNKBITS]; - - -/* ==================================== */ - - -static C_block constdatablock; /* encryption constant */ -static char cryptresult[1 + 4 + 4 + 11 + 1]; /* encrypted result */ - -extern char *__md5crypt(const char *, const char *); /* XXX */ -extern char *__bcrypt(const char *, const char *); /* XXX */ - - -/* - * Return a pointer to static data consisting of the "setting" - * followed by an encryption produced by the "key" and "setting". - */ -char * -crypt(key, setting) -const char *key; -const char *setting; -{ - char *encp; - int32_t i; - int t; - int32_t salt; - int num_iter, - salt_size; - C_block keyblock, - rsltblock; - -#if 0 - /* Non-DES encryption schemes hook in here. */ - if (setting[0] == _PASSWORD_NONDES) - { - switch (setting[1]) - { - case '2': - return (__bcrypt(key, setting)); - case '1': - default: - return (__md5crypt(key, setting)); - } - } -#endif - - for (i = 0; i < 8; i++) - { - if ((t = 2 * (unsigned char) (*key)) != 0) - key++; - keyblock.b[i] = t; - } - if (des_setkey((char *) keyblock.b)) /* also initializes "a64toi" */ - return (NULL); - - encp = &cryptresult[0]; - switch (*setting) - { - case _PASSWORD_EFMT1: - - /* - * Involve the rest of the password 8 characters at a time. - */ - while (*key) - { - if (des_cipher((char *) (void *) &keyblock, - (char *) (void *) &keyblock, 0L, 1)) - return (NULL); - for (i = 0; i < 8; i++) - { - if ((t = 2 * (unsigned char) (*key)) != 0) - key++; - keyblock.b[i] ^= t; - } - if (des_setkey((char *) keyblock.b)) - return (NULL); - } - - *encp++ = *setting++; - - /* get iteration count */ - num_iter = 0; - for (i = 4; --i >= 0;) - { - if ((t = (unsigned char) setting[i]) == '\0') - t = '.'; - encp[i] = t; - num_iter = (num_iter << 6) | a64toi[t]; - } - setting += 4; - encp += 4; - salt_size = 4; - break; - default: - num_iter = 25; - salt_size = 2; - } - - salt = 0; - for (i = salt_size; --i >= 0;) - { - if ((t = (unsigned char) setting[i]) == '\0') - t = '.'; - encp[i] = t; - salt = (salt << 6) | a64toi[t]; - } - encp += salt_size; - if (des_cipher((char *) (void *) &constdatablock, - (char *) (void *) &rsltblock, salt, num_iter)) - return (NULL); - - /* - * Encode the 64 cipher bits as 11 ascii characters. - */ - i = ((int32_t) ((rsltblock.b[0] << 8) | rsltblock.b[1]) << 8) | - rsltblock.b[2]; - encp[3] = itoa64[i & 0x3f]; - i >>= 6; - encp[2] = itoa64[i & 0x3f]; - i >>= 6; - encp[1] = itoa64[i & 0x3f]; - i >>= 6; - encp[0] = itoa64[i]; - encp += 4; - i = ((int32_t) ((rsltblock.b[3] << 8) | rsltblock.b[4]) << 8) | - rsltblock.b[5]; - encp[3] = itoa64[i & 0x3f]; - i >>= 6; - encp[2] = itoa64[i & 0x3f]; - i >>= 6; - encp[1] = itoa64[i & 0x3f]; - i >>= 6; - encp[0] = itoa64[i]; - encp += 4; - i = ((int32_t) ((rsltblock.b[6]) << 8) | rsltblock.b[7]) << 2; - encp[2] = itoa64[i & 0x3f]; - i >>= 6; - encp[1] = itoa64[i & 0x3f]; - i >>= 6; - encp[0] = itoa64[i]; - - encp[3] = 0; - - return (cryptresult); -} - - -/* - * The Key Schedule, filled in by des_setkey() or setkey(). - */ -#define KS_SIZE 16 -static C_block KS[KS_SIZE]; - -static volatile int des_ready = 0; - -/* - * Set up the key schedule from the key. - */ -static int -des_setkey(key) -const char *key; -{ - DCL_BLOCK(K, K0, K1); - C_block *ptabp; - int i; - - if (!des_ready) - init_des(); - - PERM6464(K, K0, K1, (unsigned char *) key, (C_block *) PC1ROT); - key = (char *) &KS[0]; - STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key); - for (i = 1; i < 16; i++) - { - key += sizeof(C_block); - STORE(K, K0, K1, *(C_block *) key); - ptabp = (C_block *) PC2ROT[Rotates[i] - 1]; - PERM6464(K, K0, K1, (unsigned char *) key, ptabp); - STORE(K & ~0x03030303L, K0 & ~0x03030303L, K1, *(C_block *) key); - } - return (0); -} - -/* - * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter) - * iterations of DES, using the given 24-bit salt and the pre-computed key - * schedule, and store the resulting 8 chars at "out" (in == out is permitted). - * - * NOTE: the performance of this routine is critically dependent on your - * compiler and machine architecture. - */ -static int -des_cipher(in, out, salt, num_iter) -const char *in; -char *out; -long salt; -int num_iter; -{ - /* variables that we want in registers, most important first */ -#if defined(pdp11) - int j; -#endif - int32_t L0, - L1, - R0, - R1, - k; - C_block *kp; - int ks_inc, - loop_count; - C_block B; - - L0 = salt; - TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */ - -#if defined(__vax__) || defined(pdp11) - salt = ~salt; /* "x &~ y" is faster than "x & y". */ -#define SALT (~salt) -#else -#define SALT salt -#endif - -#if defined(MUST_ALIGN) - B.b[0] = in[0]; - B.b[1] = in[1]; - B.b[2] = in[2]; - B.b[3] = in[3]; - B.b[4] = in[4]; - B.b[5] = in[5]; - B.b[6] = in[6]; - B.b[7] = in[7]; - LOAD(L, L0, L1, B); -#else - LOAD(L, L0, L1, *(C_block *) in); -#endif - LOADREG(R, R0, R1, L, L0, L1); - L0 &= 0x55555555L; - L1 &= 0x55555555L; - L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */ - R0 &= 0xaaaaaaaaL; - R1 = (R1 >> 1) & 0x55555555L; - L1 = R0 | R1; /* L1 is the odd-numbered input bits */ - STORE(L, L0, L1, B); - PERM3264(L, L0, L1, B.b, (C_block *) IE3264); /* even bits */ - PERM3264(R, R0, R1, B.b + 4, (C_block *) IE3264); /* odd bits */ - - if (num_iter >= 0) - { /* encryption */ - kp = &KS[0]; - ks_inc = sizeof(*kp); - } - else - { /* decryption */ - num_iter = -num_iter; - kp = &KS[KS_SIZE - 1]; - ks_inc = -(long) sizeof(*kp); - } - - while (--num_iter >= 0) - { - loop_count = 8; - do - { - -#define SPTAB(t, i) \ - (*(int32_t *)((unsigned char *)(t) + (i)*(sizeof(int32_t)/4))) -#if defined(gould) - /* use this if B.b[i] is evaluated just once ... */ -#define DOXOR(x,y,i) x^=SPTAB(SPE[0][i],B.b[i]); y^=SPTAB(SPE[1][i],B.b[i]); -#else -#if defined(pdp11) - /* use this if your "long" int indexing is slow */ -#define DOXOR(x,y,i) j=B.b[i]; x^=SPTAB(SPE[0][i],j); y^=SPTAB(SPE[1][i],j); -#else - /* use this if "k" is allocated to a register ... */ -#define DOXOR(x,y,i) k=B.b[i]; x^=SPTAB(SPE[0][i],k); y^=SPTAB(SPE[1][i],k); -#endif -#endif - -#define CRUNCH(p0, p1, q0, q1) \ - k = ((q0) ^ (q1)) & SALT; \ - B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \ - B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \ - kp = (C_block *)((char *)kp+ks_inc); \ - \ - DOXOR(p0, p1, 0); \ - DOXOR(p0, p1, 1); \ - DOXOR(p0, p1, 2); \ - DOXOR(p0, p1, 3); \ - DOXOR(p0, p1, 4); \ - DOXOR(p0, p1, 5); \ - DOXOR(p0, p1, 6); \ - DOXOR(p0, p1, 7); - - CRUNCH(L0, L1, R0, R1); - CRUNCH(R0, R1, L0, L1); - } while (--loop_count != 0); - kp = (C_block *) ((char *) kp - (ks_inc * KS_SIZE)); - - - /* swap L and R */ - L0 ^= R0; - L1 ^= R1; - R0 ^= L0; - R1 ^= L1; - L0 ^= R0; - L1 ^= R1; - } - - /* store the encrypted (or decrypted) result */ - L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L); - L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L); - STORE(L, L0, L1, B); - PERM6464(L, L0, L1, B.b, (C_block *) CF6464); -#if defined(MUST_ALIGN) - STORE(L, L0, L1, B); - out[0] = B.b[0]; - out[1] = B.b[1]; - out[2] = B.b[2]; - out[3] = B.b[3]; - out[4] = B.b[4]; - out[5] = B.b[5]; - out[6] = B.b[6]; - out[7] = B.b[7]; -#else - STORE(L, L0, L1, *(C_block *) out); -#endif - return (0); -} - - -/* - * Initialize various tables. This need only be done once. It could even be - * done at compile time, if the compiler were capable of that sort of thing. - */ -STATIC -init_des() -{ - int i, - j; - int32_t k; - int tableno; - static unsigned char perm[64], - tmp32[32]; /* "static" for speed */ - -/* static volatile long init_start = 0; not used */ - - /* - * table that converts chars "./0-9A-Za-z"to integers 0-63. - */ - for (i = 0; i < 64; i++) - a64toi[itoa64[i]] = i; - - /* - * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. - */ - for (i = 0; i < 64; i++) - perm[i] = 0; - for (i = 0; i < 64; i++) - { - if ((k = PC2[i]) == 0) - continue; - k += Rotates[0] - 1; - if ((k % 28) < Rotates[0]) - k -= 28; - k = PC1[k]; - if (k > 0) - { - k--; - k = (k | 07) - (k & 07); - k++; - } - perm[i] = k; - } -#ifdef DEBUG - prtab("pc1tab", perm, 8); -#endif - init_perm(PC1ROT, perm, 8, 8); - - /* - * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2. - */ - for (j = 0; j < 2; j++) - { - unsigned char pc2inv[64]; - - for (i = 0; i < 64; i++) - perm[i] = pc2inv[i] = 0; - for (i = 0; i < 64; i++) - { - if ((k = PC2[i]) == 0) - continue; - pc2inv[k - 1] = i + 1; - } - for (i = 0; i < 64; i++) - { - if ((k = PC2[i]) == 0) - continue; - k += j; - if ((k % 28) <= j) - k -= 28; - perm[i] = pc2inv[k]; - } -#ifdef DEBUG - prtab("pc2tab", perm, 8); -#endif - init_perm(PC2ROT[j], perm, 8, 8); - } - - /* - * Bit reverse, then initial permutation, then expansion. - */ - for (i = 0; i < 8; i++) - { - for (j = 0; j < 8; j++) - { - k = (j < 2) ? 0 : IP[ExpandTr[i * 6 + j - 2] - 1]; - if (k > 32) - k -= 32; - else if (k > 0) - k--; - if (k > 0) - { - k--; - k = (k | 07) - (k & 07); - k++; - } - perm[i * 8 + j] = k; - } - } -#ifdef DEBUG - prtab("ietab", perm, 8); -#endif - init_perm(IE3264, perm, 4, 8); - - /* - * Compression, then final permutation, then bit reverse. - */ - for (i = 0; i < 64; i++) - { - k = IP[CIFP[i] - 1]; - if (k > 0) - { - k--; - k = (k | 07) - (k & 07); - k++; - } - perm[k - 1] = i + 1; - } -#ifdef DEBUG - prtab("cftab", perm, 8); -#endif - init_perm(CF6464, perm, 8, 8); - - /* - * SPE table - */ - for (i = 0; i < 48; i++) - perm[i] = P32Tr[ExpandTr[i] - 1]; - for (tableno = 0; tableno < 8; tableno++) - { - for (j = 0; j < 64; j++) - { - k = (((j >> 0) & 01) << 5) | - (((j >> 1) & 01) << 3) | - (((j >> 2) & 01) << 2) | - (((j >> 3) & 01) << 1) | - (((j >> 4) & 01) << 0) | - (((j >> 5) & 01) << 4); - k = S[tableno][k]; - k = (((k >> 3) & 01) << 0) | - (((k >> 2) & 01) << 1) | - (((k >> 1) & 01) << 2) | - (((k >> 0) & 01) << 3); - for (i = 0; i < 32; i++) - tmp32[i] = 0; - for (i = 0; i < 4; i++) - tmp32[4 * tableno + i] = (k >> i) & 01; - k = 0; - for (i = 24; --i >= 0;) - k = (k << 1) | tmp32[perm[i] - 1]; - TO_SIX_BIT(SPE[0][tableno][j], k); - k = 0; - for (i = 24; --i >= 0;) - k = (k << 1) | tmp32[perm[i + 24] - 1]; - TO_SIX_BIT(SPE[1][tableno][j], k); - } - } - - des_ready = 1; -} - -/* - * Initialize "perm" to represent transformation "p", which rearranges - * (perhaps with expansion and/or contraction) one packed array of bits - * (of size "chars_in" characters) into another array (of size "chars_out" - * characters). - * - * "perm" must be all-zeroes on entry to this routine. - */ -STATIC -init_perm(perm, p, chars_in, chars_out) -C_block perm[64 / CHUNKBITS][1 << CHUNKBITS]; -unsigned char p[64]; -int chars_in, - chars_out; -{ - int i, - j, - k, - l; - - for (k = 0; k < chars_out * 8; k++) - { /* each output bit position */ - l = p[k] - 1; /* where this bit comes from */ - if (l < 0) - continue; /* output bit is always 0 */ - i = l >> LGCHUNKBITS; /* which chunk this bit comes from */ - l = 1 << (l & (CHUNKBITS - 1)); /* mask for this bit */ - for (j = 0; j < (1 << CHUNKBITS); j++) - { /* each chunk value */ - if ((j & l) != 0) - perm[i][j].b[k >> 3] |= 1 << (k & 07); - } - } -} - -/* - * "setkey" routine (for backwards compatibility) - */ -#ifdef NOT_USED -int -setkey(key) -const char *key; -{ - int i, - j, - k; - C_block keyblock; - - for (i = 0; i < 8; i++) - { - k = 0; - for (j = 0; j < 8; j++) - { - k <<= 1; - k |= (unsigned char) *key++; - } - keyblock.b[i] = k; - } - return (des_setkey((char *) keyblock.b)); -} - -/* - * "encrypt" routine (for backwards compatibility) - */ -static int -encrypt(block, flag) -char *block; -int flag; -{ - int i, - j, - k; - C_block cblock; - - for (i = 0; i < 8; i++) - { - k = 0; - for (j = 0; j < 8; j++) - { - k <<= 1; - k |= (unsigned char) *block++; - } - cblock.b[i] = k; - } - if (des_cipher((char *) &cblock, (char *) &cblock, 0L, (flag ? -1 : 1))) - return (1); - for (i = 7; i >= 0; i--) - { - k = cblock.b[i]; - for (j = 7; j >= 0; j--) - { - *--block = k & 01; - k >>= 1; - } - } - return (0); -} -#endif - -#ifdef DEBUG -STATIC -prtab(s, t, num_rows) -char *s; -unsigned char *t; -int num_rows; -{ - int i, - j; - - (void) printf("%s:\n", s); - for (i = 0; i < num_rows; i++) - { - for (j = 0; j < 8; j++) - (void) printf("%3d", t[i * 8 + j]); - (void) printf("\n"); - } - (void) printf("\n"); -} - -#endif diff --git a/libpq/win32/getaddrinfo.c b/libpq/win32/getaddrinfo.c deleted file mode 100644 index 90c1b87..0000000 --- a/libpq/win32/getaddrinfo.c +++ /dev/null @@ -1,412 +0,0 @@ -/*------------------------------------------------------------------------- - * - * getaddrinfo.c - * Support getaddrinfo() on platforms that don't have it. - * - * We also supply getnameinfo() here, assuming that the platform will have - * it if and only if it has getaddrinfo(). If this proves false on some - * platform, we'll need to split this file and provide a separate configure - * test for getnameinfo(). - * - * Windows may or may not have these routines, so we handle Windows specially - * by dynamically checking for their existence. If they already exist, we - * use the Windows native routines, but if not, we use our own. - * - * - * Copyright (c) 2003-2016, PostgreSQL Global Development Group - * - * IDENTIFICATION - * src/port/getaddrinfo.c - * - *------------------------------------------------------------------------- - */ - -/* This is intended to be used in both frontend and backend, so use c.h */ -#include "c.h" - -#include -#include -#include -#include - -#include "getaddrinfo.h" -#include "libpq/pqcomm.h" /* needed for struct sockaddr_storage */ - - -#ifdef WIN32 -/* - * The native routines may or may not exist on the Windows platform we are on, - * so we dynamically look up the routines, and call them via function pointers. - * Here we need to declare what the function pointers look like - */ -typedef int (__stdcall * getaddrinfo_ptr_t) (const char *nodename, - const char *servname, - const struct addrinfo * hints, - struct addrinfo ** res); - -typedef void (__stdcall * freeaddrinfo_ptr_t) (struct addrinfo * ai); - -typedef int (__stdcall * getnameinfo_ptr_t) (const struct sockaddr * sa, - int salen, - char *host, int hostlen, - char *serv, int servlen, - int flags); - -/* static pointers to the native routines, so we only do the lookup once. */ -static getaddrinfo_ptr_t getaddrinfo_ptr = NULL; -static freeaddrinfo_ptr_t freeaddrinfo_ptr = NULL; -static getnameinfo_ptr_t getnameinfo_ptr = NULL; - - -static bool -haveNativeWindowsIPv6routines(void) -{ - void *hLibrary = NULL; - static bool alreadyLookedForIpv6routines = false; - - if (alreadyLookedForIpv6routines) - return (getaddrinfo_ptr != NULL); - - /* - * For Windows XP and Windows 2003 (and longhorn/vista), the IPv6 routines - * are present in the WinSock 2 library (ws2_32.dll). Try that first - */ - - hLibrary = LoadLibraryA("ws2_32"); - - if (hLibrary == NULL || GetProcAddress(hLibrary, "getaddrinfo") == NULL) - { - /* - * Well, ws2_32 doesn't exist, or more likely doesn't have - * getaddrinfo. - */ - if (hLibrary != NULL) - FreeLibrary(hLibrary); - - /* - * In Windows 2000, there was only the IPv6 Technology Preview look in - * the IPv6 WinSock library (wship6.dll). - */ - - hLibrary = LoadLibraryA("wship6"); - } - - /* If hLibrary is null, we couldn't find a dll with functions */ - if (hLibrary != NULL) - { - /* We found a dll, so now get the addresses of the routines */ - - getaddrinfo_ptr = (getaddrinfo_ptr_t) GetProcAddress(hLibrary, - "getaddrinfo"); - freeaddrinfo_ptr = (freeaddrinfo_ptr_t) GetProcAddress(hLibrary, - "freeaddrinfo"); - getnameinfo_ptr = (getnameinfo_ptr_t) GetProcAddress(hLibrary, - "getnameinfo"); - - /* - * If any one of the routines is missing, let's play it safe and - * ignore them all - */ - if (getaddrinfo_ptr == NULL || - freeaddrinfo_ptr == NULL || - getnameinfo_ptr == NULL) - { - FreeLibrary(hLibrary); - hLibrary = NULL; - getaddrinfo_ptr = NULL; - freeaddrinfo_ptr = NULL; - getnameinfo_ptr = NULL; - } - } - - alreadyLookedForIpv6routines = true; - return (getaddrinfo_ptr != NULL); -} -#endif - - -/* - * get address info for ipv4 sockets. - * - * Bugs: - only one addrinfo is set even though hintp is NULL or - * ai_socktype is 0 - * - AI_CANONNAME is not supported. - * - servname can only be a number, not text. - */ -int -getaddrinfo(const char *node, const char *service, - const struct addrinfo * hintp, - struct addrinfo ** res) -{ - struct addrinfo *ai; - struct sockaddr_in sin, - *psin; - struct addrinfo hints; - -#ifdef WIN32 - - /* - * If Windows has native IPv6 support, use the native Windows routine. - * Otherwise, fall through and use our own code. - */ - if (haveNativeWindowsIPv6routines()) - return (*getaddrinfo_ptr) (node, service, hintp, res); -#endif - - if (hintp == NULL) - { - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - } - else - memcpy(&hints, hintp, sizeof(hints)); - - if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) - return EAI_FAMILY; - - if (hints.ai_socktype == 0) - hints.ai_socktype = SOCK_STREAM; - - if (!node && !service) - return EAI_NONAME; - - memset(&sin, 0, sizeof(sin)); - - sin.sin_family = AF_INET; - - if (node) - { - if (node[0] == '\0') - sin.sin_addr.s_addr = htonl(INADDR_ANY); - else if (hints.ai_flags & AI_NUMERICHOST) - { - if (!inet_aton(node, &sin.sin_addr)) - return EAI_NONAME; - } - else - { - struct hostent *hp; - -#ifdef FRONTEND - struct hostent hpstr; - char buf[BUFSIZ]; - int herrno = 0; - - pqGethostbyname(node, &hpstr, buf, sizeof(buf), - &hp, &herrno); -#else - hp = gethostbyname(node); -#endif - if (hp == NULL) - { - switch (h_errno) - { - case HOST_NOT_FOUND: - case NO_DATA: - return EAI_NONAME; - case TRY_AGAIN: - return EAI_AGAIN; - case NO_RECOVERY: - default: - return EAI_FAIL; - } - } - if (hp->h_addrtype != AF_INET) - return EAI_FAIL; - - memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length); - } - } - else - { - if (hints.ai_flags & AI_PASSIVE) - sin.sin_addr.s_addr = htonl(INADDR_ANY); - else - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - - if (service) - sin.sin_port = htons((unsigned short) atoi(service)); - -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN - sin.sin_len = sizeof(sin); -#endif - - ai = malloc(sizeof(*ai)); - if (!ai) - return EAI_MEMORY; - - psin = malloc(sizeof(*psin)); - if (!psin) - { - free(ai); - return EAI_MEMORY; - } - - memcpy(psin, &sin, sizeof(*psin)); - - ai->ai_flags = 0; - ai->ai_family = AF_INET; - ai->ai_socktype = hints.ai_socktype; - ai->ai_protocol = hints.ai_protocol; - ai->ai_addrlen = sizeof(*psin); - ai->ai_addr = (struct sockaddr *) psin; - ai->ai_canonname = NULL; - ai->ai_next = NULL; - - *res = ai; - - return 0; -} - - -void -freeaddrinfo(struct addrinfo * res) -{ - if (res) - { -#ifdef WIN32 - - /* - * If Windows has native IPv6 support, use the native Windows routine. - * Otherwise, fall through and use our own code. - */ - if (haveNativeWindowsIPv6routines()) - { - (*freeaddrinfo_ptr) (res); - return; - } -#endif - - if (res->ai_addr) - free(res->ai_addr); - free(res); - } -} - - -const char * -gai_strerror(int errcode) -{ -#ifdef HAVE_HSTRERROR - int hcode; - - switch (errcode) - { - case EAI_NONAME: - hcode = HOST_NOT_FOUND; - break; - case EAI_AGAIN: - hcode = TRY_AGAIN; - break; - case EAI_FAIL: - default: - hcode = NO_RECOVERY; - break; - } - - return hstrerror(hcode); -#else /* !HAVE_HSTRERROR */ - - switch (errcode) - { - case EAI_NONAME: - return "Unknown host"; - case EAI_AGAIN: - return "Host name lookup failure"; - /* Errors below are probably WIN32 only */ -#ifdef EAI_BADFLAGS - case EAI_BADFLAGS: - return "Invalid argument"; -#endif -#ifdef EAI_FAMILY - case EAI_FAMILY: - return "Address family not supported"; -#endif -#ifdef EAI_MEMORY - case EAI_MEMORY: - return "Not enough memory"; -#endif -#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME /* MSVC/WIN64 duplicate */ - case EAI_NODATA: - return "No host data of that type was found"; -#endif -#ifdef EAI_SERVICE - case EAI_SERVICE: - return "Class type not found"; -#endif -#ifdef EAI_SOCKTYPE - case EAI_SOCKTYPE: - return "Socket type not supported"; -#endif - default: - return "Unknown server error"; - } -#endif /* HAVE_HSTRERROR */ -} - -/* - * Convert an ipv4 address to a hostname. - * - * Bugs: - Only supports NI_NUMERICHOST and NI_NUMERICSERV behavior. - * It will never resolve a hostname. - * - No IPv6 support. - */ -int -getnameinfo(const struct sockaddr * sa, int salen, - char *node, int nodelen, - char *service, int servicelen, int flags) -{ -#ifdef WIN32 - - /* - * If Windows has native IPv6 support, use the native Windows routine. - * Otherwise, fall through and use our own code. - */ - if (haveNativeWindowsIPv6routines()) - return (*getnameinfo_ptr) (sa, salen, node, nodelen, - service, servicelen, flags); -#endif - - /* Invalid arguments. */ - if (sa == NULL || (node == NULL && service == NULL)) - return EAI_FAIL; - -#ifdef HAVE_IPV6 - if (sa->sa_family == AF_INET6) - return EAI_FAMILY; -#endif - - /* Unsupported flags. */ - if (flags & NI_NAMEREQD) - return EAI_AGAIN; - - if (node) - { - if (sa->sa_family == AF_INET) - { - if (inet_net_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr, - sa->sa_family == AF_INET ? 32 : 128, - node, nodelen) == NULL) - return EAI_MEMORY; - } - else - return EAI_MEMORY; - } - - if (service) - { - int ret = -1; - - if (sa->sa_family == AF_INET) - { - ret = snprintf(service, servicelen, "%d", - ntohs(((struct sockaddr_in *) sa)->sin_port)); - } - if (ret == -1 || ret >= servicelen) - return EAI_MEMORY; - } - - return 0; -} diff --git a/libpq/win32/inet_aton.c b/libpq/win32/inet_aton.c deleted file mode 100644 index 27e8aaa..0000000 --- a/libpq/win32/inet_aton.c +++ /dev/null @@ -1,147 +0,0 @@ -/* src/port/inet_aton.c - * - * This inet_aton() function was taken from the GNU C library and - * incorporated into Postgres for those systems which do not have this - * routine in their standard C libraries. - * - * The function was been extracted whole from the file inet_aton.c in - * Release 5.3.12 of the Linux C library, which is derived from the - * GNU C library, by Bryan Henderson in October 1996. The copyright - * notice from that file is below. - */ - -/* - * Copyright (c) 1983, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ - -#include "c.h" - -#include -#include - -/* - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - */ -int -inet_aton(const char *cp, struct in_addr * addr) -{ - unsigned int val; - int base, - n; - char c; - u_int parts[4]; - u_int *pp = parts; - - for (;;) - { - /* - * Collect number up to ``.''. Values are specified as for C: 0x=hex, - * 0=octal, other=decimal. - */ - val = 0; - base = 10; - if (*cp == '0') - { - if (*++cp == 'x' || *cp == 'X') - base = 16, cp++; - else - base = 8; - } - while ((c = *cp) != '\0') - { - if (isdigit((unsigned char) c)) - { - val = (val * base) + (c - '0'); - cp++; - continue; - } - if (base == 16 && isxdigit((unsigned char) c)) - { - val = (val << 4) + - (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); - cp++; - continue; - } - break; - } - if (*cp == '.') - { - /* - * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3 || val > 0xff) - return 0; - *pp++ = val, cp++; - } - else - break; - } - - /* - * Check for trailing junk. - */ - while (*cp) - if (!isspace((unsigned char) *cp++)) - return 0; - - /* - * Concoct the address according to the number of parts specified. - */ - n = pp - parts + 1; - switch (n) - { - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return 0; - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return 0; - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - if (addr) - addr->s_addr = htonl(val); - return 1; -} diff --git a/libpq/win32/libpq.rc.in b/libpq/win32/libpq.rc.in deleted file mode 100644 index da97574..0000000 --- a/libpq/win32/libpq.rc.in +++ /dev/null @@ -1,31 +0,0 @@ -#include - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 9,6,5,0 - PRODUCTVERSION 9,6,5,0 - FILEFLAGSMASK 0x3fL - FILEFLAGS 0 - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904B0" - BEGIN - VALUE "CompanyName", "\0" - VALUE "FileDescription", "PostgreSQL Access Library\0" - VALUE "FileVersion", "9.6.5\0" - VALUE "InternalName", "libpq\0" - VALUE "LegalCopyright", "Copyright (C) 2016\0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "libpq.dll\0" - VALUE "ProductName", "PostgreSQL\0" - VALUE "ProductVersion", "9.6.5\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/libpq/win32/libpqdll.def b/libpq/win32/libpqdll.def deleted file mode 100644 index 810d4be..0000000 --- a/libpq/win32/libpqdll.def +++ /dev/null @@ -1,174 +0,0 @@ -; DEF file for win32.mak release build and for Makefile.shlib (MinGW) -; LIBRARY LIBPQ.dll -EXPORTS - PQconnectdb @ 1 - PQsetdbLogin @ 2 - PQconndefaults @ 3 - PQfinish @ 4 - PQreset @ 5 - PQrequestCancel @ 6 - PQdb @ 7 - PQuser @ 8 - PQpass @ 9 - PQhost @ 10 - PQport @ 11 - PQtty @ 12 - PQoptions @ 13 - PQstatus @ 14 - PQerrorMessage @ 15 - PQsocket @ 16 - PQbackendPID @ 17 - PQtrace @ 18 - PQuntrace @ 19 - PQsetNoticeProcessor @ 20 - PQexec @ 21 - PQnotifies @ 22 - PQsendQuery @ 23 - PQgetResult @ 24 - PQisBusy @ 25 - PQconsumeInput @ 26 - PQgetline @ 27 - PQputline @ 28 - PQgetlineAsync @ 29 - PQputnbytes @ 30 - PQendcopy @ 31 - PQfn @ 32 - PQresultStatus @ 33 - PQntuples @ 34 - PQnfields @ 35 - PQbinaryTuples @ 36 - PQfname @ 37 - PQfnumber @ 38 - PQftype @ 39 - PQfsize @ 40 - PQfmod @ 41 - PQcmdStatus @ 42 - PQoidStatus @ 43 - PQcmdTuples @ 44 - PQgetvalue @ 45 - PQgetlength @ 46 - PQgetisnull @ 47 - PQclear @ 48 - PQmakeEmptyPGresult @ 49 - PQprint @ 50 - PQdisplayTuples @ 51 - PQprintTuples @ 52 - lo_open @ 53 - lo_close @ 54 - lo_read @ 55 - lo_write @ 56 - lo_lseek @ 57 - lo_creat @ 58 - lo_tell @ 59 - lo_unlink @ 60 - lo_import @ 61 - lo_export @ 62 - pgresStatus @ 63 - PQmblen @ 64 - PQresultErrorMessage @ 65 - PQresStatus @ 66 - termPQExpBuffer @ 67 - appendPQExpBufferChar @ 68 - initPQExpBuffer @ 69 - resetPQExpBuffer @ 70 - PQoidValue @ 71 - PQclientEncoding @ 72 - PQenv2encoding @ 73 - appendBinaryPQExpBuffer @ 74 - appendPQExpBufferStr @ 75 - destroyPQExpBuffer @ 76 - createPQExpBuffer @ 77 - PQconninfoFree @ 78 - PQconnectPoll @ 79 - PQconnectStart @ 80 - PQflush @ 81 - PQisnonblocking @ 82 - PQresetPoll @ 83 - PQresetStart @ 84 - PQsetClientEncoding @ 85 - PQsetnonblocking @ 86 - PQfreeNotify @ 87 - PQescapeString @ 88 - PQescapeBytea @ 89 - printfPQExpBuffer @ 90 - appendPQExpBuffer @ 91 - pg_encoding_to_char @ 92 - pg_utf_mblen @ 93 - PQunescapeBytea @ 94 - PQfreemem @ 95 - PQtransactionStatus @ 96 - PQparameterStatus @ 97 - PQprotocolVersion @ 98 - PQsetErrorVerbosity @ 99 - PQsetNoticeReceiver @ 100 - PQexecParams @ 101 - PQsendQueryParams @ 102 - PQputCopyData @ 103 - PQputCopyEnd @ 104 - PQgetCopyData @ 105 - PQresultErrorField @ 106 - PQftable @ 107 - PQftablecol @ 108 - PQfformat @ 109 - PQexecPrepared @ 110 - PQsendQueryPrepared @ 111 - PQdsplen @ 112 - PQserverVersion @ 113 - PQgetssl @ 114 - pg_char_to_encoding @ 115 - pg_valid_server_encoding @ 116 - pqsignal @ 117 - PQprepare @ 118 - PQsendPrepare @ 119 - PQgetCancel @ 120 - PQfreeCancel @ 121 - PQcancel @ 122 - lo_create @ 123 - PQinitSSL @ 124 - PQregisterThreadLock @ 125 - PQescapeStringConn @ 126 - PQescapeByteaConn @ 127 - PQencryptPassword @ 128 - PQisthreadsafe @ 129 - enlargePQExpBuffer @ 130 - PQnparams @ 131 - PQparamtype @ 132 - PQdescribePrepared @ 133 - PQdescribePortal @ 134 - PQsendDescribePrepared @ 135 - PQsendDescribePortal @ 136 - lo_truncate @ 137 - PQconnectionUsedPassword @ 138 - pg_valid_server_encoding_id @ 139 - PQconnectionNeedsPassword @ 140 - lo_import_with_oid @ 141 - PQcopyResult @ 142 - PQsetResultAttrs @ 143 - PQsetvalue @ 144 - PQresultAlloc @ 145 - PQregisterEventProc @ 146 - PQinstanceData @ 147 - PQsetInstanceData @ 148 - PQresultInstanceData @ 149 - PQresultSetInstanceData @ 150 - PQfireResultCreateEvents @ 151 - PQconninfoParse @ 152 - PQinitOpenSSL @ 153 - PQescapeLiteral @ 154 - PQescapeIdentifier @ 155 - PQconnectdbParams @ 156 - PQconnectStartParams @ 157 - PQping @ 158 - PQpingParams @ 159 - PQlibVersion @ 160 - PQsetSingleRowMode @ 161 - lo_lseek64 @ 162 - lo_tell64 @ 163 - lo_truncate64 @ 164 - PQconninfo @ 165 - PQsslInUse @ 166 - PQsslStruct @ 167 - PQsslAttributeNames @ 168 - PQsslAttribute @ 169 - PQsetErrorContextVisibility @ 170 - PQresultVerboseErrorMessage @ 171 diff --git a/libpq/win32/libpqdll.def.orig b/libpq/win32/libpqdll.def.orig deleted file mode 100644 index 0c9e8e4..0000000 --- a/libpq/win32/libpqdll.def.orig +++ /dev/null @@ -1,174 +0,0 @@ -; DEF file for win32.mak release build and for Makefile.shlib (MinGW) -LIBRARY LIBPQ.dll -EXPORTS - PQconnectdb @ 1 - PQsetdbLogin @ 2 - PQconndefaults @ 3 - PQfinish @ 4 - PQreset @ 5 - PQrequestCancel @ 6 - PQdb @ 7 - PQuser @ 8 - PQpass @ 9 - PQhost @ 10 - PQport @ 11 - PQtty @ 12 - PQoptions @ 13 - PQstatus @ 14 - PQerrorMessage @ 15 - PQsocket @ 16 - PQbackendPID @ 17 - PQtrace @ 18 - PQuntrace @ 19 - PQsetNoticeProcessor @ 20 - PQexec @ 21 - PQnotifies @ 22 - PQsendQuery @ 23 - PQgetResult @ 24 - PQisBusy @ 25 - PQconsumeInput @ 26 - PQgetline @ 27 - PQputline @ 28 - PQgetlineAsync @ 29 - PQputnbytes @ 30 - PQendcopy @ 31 - PQfn @ 32 - PQresultStatus @ 33 - PQntuples @ 34 - PQnfields @ 35 - PQbinaryTuples @ 36 - PQfname @ 37 - PQfnumber @ 38 - PQftype @ 39 - PQfsize @ 40 - PQfmod @ 41 - PQcmdStatus @ 42 - PQoidStatus @ 43 - PQcmdTuples @ 44 - PQgetvalue @ 45 - PQgetlength @ 46 - PQgetisnull @ 47 - PQclear @ 48 - PQmakeEmptyPGresult @ 49 - PQprint @ 50 - PQdisplayTuples @ 51 - PQprintTuples @ 52 - lo_open @ 53 - lo_close @ 54 - lo_read @ 55 - lo_write @ 56 - lo_lseek @ 57 - lo_creat @ 58 - lo_tell @ 59 - lo_unlink @ 60 - lo_import @ 61 - lo_export @ 62 - pgresStatus @ 63 - PQmblen @ 64 - PQresultErrorMessage @ 65 - PQresStatus @ 66 - termPQExpBuffer @ 67 - appendPQExpBufferChar @ 68 - initPQExpBuffer @ 69 - resetPQExpBuffer @ 70 - PQoidValue @ 71 - PQclientEncoding @ 72 - PQenv2encoding @ 73 - appendBinaryPQExpBuffer @ 74 - appendPQExpBufferStr @ 75 - destroyPQExpBuffer @ 76 - createPQExpBuffer @ 77 - PQconninfoFree @ 78 - PQconnectPoll @ 79 - PQconnectStart @ 80 - PQflush @ 81 - PQisnonblocking @ 82 - PQresetPoll @ 83 - PQresetStart @ 84 - PQsetClientEncoding @ 85 - PQsetnonblocking @ 86 - PQfreeNotify @ 87 - PQescapeString @ 88 - PQescapeBytea @ 89 - printfPQExpBuffer @ 90 - appendPQExpBuffer @ 91 - pg_encoding_to_char @ 92 - pg_utf_mblen @ 93 - PQunescapeBytea @ 94 - PQfreemem @ 95 - PQtransactionStatus @ 96 - PQparameterStatus @ 97 - PQprotocolVersion @ 98 - PQsetErrorVerbosity @ 99 - PQsetNoticeReceiver @ 100 - PQexecParams @ 101 - PQsendQueryParams @ 102 - PQputCopyData @ 103 - PQputCopyEnd @ 104 - PQgetCopyData @ 105 - PQresultErrorField @ 106 - PQftable @ 107 - PQftablecol @ 108 - PQfformat @ 109 - PQexecPrepared @ 110 - PQsendQueryPrepared @ 111 - PQdsplen @ 112 - PQserverVersion @ 113 - PQgetssl @ 114 - pg_char_to_encoding @ 115 - pg_valid_server_encoding @ 116 - pqsignal @ 117 - PQprepare @ 118 - PQsendPrepare @ 119 - PQgetCancel @ 120 - PQfreeCancel @ 121 - PQcancel @ 122 - lo_create @ 123 - PQinitSSL @ 124 - PQregisterThreadLock @ 125 - PQescapeStringConn @ 126 - PQescapeByteaConn @ 127 - PQencryptPassword @ 128 - PQisthreadsafe @ 129 - enlargePQExpBuffer @ 130 - PQnparams @ 131 - PQparamtype @ 132 - PQdescribePrepared @ 133 - PQdescribePortal @ 134 - PQsendDescribePrepared @ 135 - PQsendDescribePortal @ 136 - lo_truncate @ 137 - PQconnectionUsedPassword @ 138 - pg_valid_server_encoding_id @ 139 - PQconnectionNeedsPassword @ 140 - lo_import_with_oid @ 141 - PQcopyResult @ 142 - PQsetResultAttrs @ 143 - PQsetvalue @ 144 - PQresultAlloc @ 145 - PQregisterEventProc @ 146 - PQinstanceData @ 147 - PQsetInstanceData @ 148 - PQresultInstanceData @ 149 - PQresultSetInstanceData @ 150 - PQfireResultCreateEvents @ 151 - PQconninfoParse @ 152 - PQinitOpenSSL @ 153 - PQescapeLiteral @ 154 - PQescapeIdentifier @ 155 - PQconnectdbParams @ 156 - PQconnectStartParams @ 157 - PQping @ 158 - PQpingParams @ 159 - PQlibVersion @ 160 - PQsetSingleRowMode @ 161 - lo_lseek64 @ 162 - lo_tell64 @ 163 - lo_truncate64 @ 164 - PQconninfo @ 165 - PQsslInUse @ 166 - PQsslStruct @ 167 - PQsslAttributeNames @ 168 - PQsslAttribute @ 169 - PQsetErrorContextVisibility @ 170 - PQresultVerboseErrorMessage @ 171 diff --git a/libpq/win32/open.c b/libpq/win32/open.c deleted file mode 100644 index 717375d..0000000 --- a/libpq/win32/open.c +++ /dev/null @@ -1,167 +0,0 @@ -/*------------------------------------------------------------------------- - * - * open.c - * Win32 open() replacement - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * src/port/open.c - * - *------------------------------------------------------------------------- - */ - -#ifdef WIN32 - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#include -#include -#include - - -static int -openFlagsToCreateFileFlags(int openFlags) -{ - switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL)) - { - /* O_EXCL is meaningless without O_CREAT */ - case 0: - case O_EXCL: - return OPEN_EXISTING; - - case O_CREAT: - return OPEN_ALWAYS; - - /* O_EXCL is meaningless without O_CREAT */ - case O_TRUNC: - case O_TRUNC | O_EXCL: - return TRUNCATE_EXISTING; - - case O_CREAT | O_TRUNC: - return CREATE_ALWAYS; - - /* O_TRUNC is meaningless with O_CREAT */ - case O_CREAT | O_EXCL: - case O_CREAT | O_TRUNC | O_EXCL: - return CREATE_NEW; - } - - /* will never get here */ - return 0; -} - -/* - * - file attribute setting, based on fileMode? - */ -int -pgwin32_open(const char *fileName, int fileFlags,...) -{ - int fd; - HANDLE h = INVALID_HANDLE_VALUE; - SECURITY_ATTRIBUTES sa; - int loops = 0; - - /* Check that we can handle the request */ - assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND | - (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) | - _O_SHORT_LIVED | O_DSYNC | O_DIRECT | - (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags); - - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - while ((h = CreateFile(fileName, - /* cannot use O_RDONLY, as it == 0 */ - (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : - ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ), - /* These flags allow concurrent rename/unlink */ - (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), - &sa, - openFlagsToCreateFileFlags(fileFlags), - FILE_ATTRIBUTE_NORMAL | - ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) | - ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) | - ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) | - ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) | - ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) | - ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0), - NULL)) == INVALID_HANDLE_VALUE) - { - /* - * Sharing violation or locking error can indicate antivirus, backup - * or similar software that's locking the file. Try again for 30 - * seconds before giving up. - */ - DWORD err = GetLastError(); - - if (err == ERROR_SHARING_VIOLATION || - err == ERROR_LOCK_VIOLATION) - { - pg_usleep(100000); - loops++; - -#ifndef FRONTEND - if (loops == 50) - ereport(LOG, - (errmsg("could not open file \"%s\": %s", fileName, - (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")), - errdetail("Continuing to retry for 30 seconds."), - errhint("You might have antivirus, backup, or similar software interfering with the database system."))); -#endif - - if (loops < 300) - continue; - } - - _dosmaperr(err); - return -1; - } - - /* _open_osfhandle will, on error, set errno accordingly */ - if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0) - CloseHandle(h); /* will not affect errno */ - else if (fileFlags & (O_TEXT | O_BINARY) && - _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0) - { - _close(fd); - return -1; - } - - return fd; -} - -FILE * -pgwin32_fopen(const char *fileName, const char *mode) -{ - int openmode = 0; - int fd; - - if (strstr(mode, "r+")) - openmode |= O_RDWR; - else if (strchr(mode, 'r')) - openmode |= O_RDONLY; - if (strstr(mode, "w+")) - openmode |= O_RDWR | O_CREAT | O_TRUNC; - else if (strchr(mode, 'w')) - openmode |= O_WRONLY | O_CREAT | O_TRUNC; - if (strchr(mode, 'a')) - openmode |= O_WRONLY | O_CREAT | O_APPEND; - - if (strchr(mode, 'b')) - openmode |= O_BINARY; - if (strchr(mode, 't')) - openmode |= O_TEXT; - - fd = pgwin32_open(fileName, openmode); - if (fd == -1) - return NULL; - return _fdopen(fd, mode); -} - -#endif diff --git a/libpq/win32/pgsleep.c b/libpq/win32/pgsleep.c deleted file mode 100644 index ecefe04..0000000 --- a/libpq/win32/pgsleep.c +++ /dev/null @@ -1,63 +0,0 @@ -/*------------------------------------------------------------------------- - * - * pgsleep.c - * Portable delay handling. - * - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * src/port/pgsleep.c - * - *------------------------------------------------------------------------- - */ -#include "c.h" - -#include -#include -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -/* - * In a Windows backend, we don't use this implementation, but rather - * the signal-aware version in src/backend/port/win32/signal.c. - */ -#if defined(FRONTEND) || !defined(WIN32) - -/* - * pg_usleep --- delay the specified number of microseconds. - * - * NOTE: although the delay is specified in microseconds, the effective - * resolution is only 1/HZ, or 10 milliseconds, on most Unixen. Expect - * the requested delay to be rounded up to the next resolution boundary. - * - * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds. - * - * CAUTION: the behavior when a signal arrives during the sleep is platform - * dependent. On most Unix-ish platforms, a signal does not terminate the - * sleep; but on some, it will (the Windows implementation also allows signals - * to terminate pg_usleep). And there are platforms where not only does a - * signal not terminate the sleep, but it actually resets the timeout counter - * so that the sleep effectively starts over! It is therefore rather hazardous - * to use this for long sleeps; a continuing stream of signal events could - * prevent the sleep from ever terminating. Better practice for long sleeps - * is to use WaitLatch() with a timeout. - */ -void -pg_usleep(long microsec) -{ - if (microsec > 0) - { -#ifndef WIN32 - struct timeval delay; - - delay.tv_sec = microsec / 1000000L; - delay.tv_usec = microsec % 1000000L; - (void) select(0, NULL, NULL, NULL, &delay); -#else - SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); -#endif - } -} - -#endif /* defined(FRONTEND) || !defined(WIN32) */ diff --git a/libpq/win32/pthread-win32.c b/libpq/win32/pthread-win32.c deleted file mode 100644 index 68dfefc..0000000 --- a/libpq/win32/pthread-win32.c +++ /dev/null @@ -1,61 +0,0 @@ -/*------------------------------------------------------------------------- -* -* pthread-win32.c -* partial pthread implementation for win32 -* -* Copyright (c) 2004-2016, PostgreSQL Global Development Group -* IDENTIFICATION -* src/interfaces/libpq/pthread-win32.c -* -*------------------------------------------------------------------------- -*/ - -#include "postgres_fe.h" - -#include -#include "pthread-win32.h" - -DWORD -pthread_self(void) -{ - return GetCurrentThreadId(); -} - -void -pthread_setspecific(pthread_key_t key, void *val) -{ -} - -void * -pthread_getspecific(pthread_key_t key) -{ - return NULL; -} - -int -pthread_mutex_init(pthread_mutex_t *mp, void *attr) -{ - *mp = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION)); - if (!*mp) - return 1; - InitializeCriticalSection(*mp); - return 0; -} - -int -pthread_mutex_lock(pthread_mutex_t *mp) -{ - if (!*mp) - return 1; - EnterCriticalSection(*mp); - return 0; -} - -int -pthread_mutex_unlock(pthread_mutex_t *mp) -{ - if (!*mp) - return 1; - LeaveCriticalSection(*mp); - return 0; -} diff --git a/libpq/win32/pthread-win32.h b/libpq/win32/pthread-win32.h deleted file mode 100644 index 97ccc17..0000000 --- a/libpq/win32/pthread-win32.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * src/port/pthread-win32.h - */ -#ifndef __PTHREAD_H -#define __PTHREAD_H - -typedef ULONG pthread_key_t; -typedef CRITICAL_SECTION *pthread_mutex_t; -typedef int pthread_once_t; - -DWORD pthread_self(void); - -void pthread_setspecific(pthread_key_t, void *); -void *pthread_getspecific(pthread_key_t); - -int pthread_mutex_init(pthread_mutex_t *, void *attr); -int pthread_mutex_lock(pthread_mutex_t *); - -/* blocking */ -int pthread_mutex_unlock(pthread_mutex_t *); - -#endif diff --git a/libpq/win32/snprintf.c b/libpq/win32/snprintf.c deleted file mode 100644 index 62b23b0..0000000 --- a/libpq/win32/snprintf.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * src/port/snprintf.c - */ - -#include "c.h" - -#include -#ifdef _MSC_VER -#include /* for _isnan */ -#endif -#include -#include -#ifndef WIN32 -#include -#endif -#include - -#ifndef NL_ARGMAX -#define NL_ARGMAX 16 -#endif - - -/* - * SNPRINTF, VSNPRINTF and friends - * - * These versions have been grabbed off the net. They have been - * cleaned up to compile properly and support for most of the Single Unix - * Specification has been added. Remaining unimplemented features are: - * - * 1. No locale support: the radix character is always '.' and the ' - * (single quote) format flag is ignored. - * - * 2. No support for the "%n" format specification. - * - * 3. No support for wide characters ("lc" and "ls" formats). - * - * 4. No support for "long double" ("Lf" and related formats). - * - * 5. Space and '#' flags are not implemented. - * - * - * The result values of these functions are not the same across different - * platforms. This implementation is compatible with the Single Unix Spec: - * - * 1. -1 is returned only if processing is abandoned due to an invalid - * parameter, such as incorrect format string. (Although not required by - * the spec, this happens only when no characters have yet been transmitted - * to the destination.) - * - * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0; - * no data has been stored. - * - * 3. Otherwise, the number of bytes actually transmitted to the destination - * is returned (excluding the trailing '\0' for snprintf and sprintf). - * - * For snprintf with nonzero count, the result cannot be more than count-1 - * (a trailing '\0' is always stored); it is not possible to distinguish - * buffer overrun from exact fit. This is unlike some implementations that - * return the number of bytes that would have been needed for the complete - * result string. - */ - -/************************************************************** - * Original: - * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 - * A bombproof version of doprnt (dopr) included. - * Sigh. This sort of thing is always nasty do deal with. Note that - * the version here does not include floating point. (now it does ... tgl) - **************************************************************/ - -/* Prevent recursion */ -#undef vsnprintf -#undef snprintf -#undef sprintf -#undef vfprintf -#undef fprintf -#undef printf - -/* Info about where the formatted output is going */ -typedef struct -{ - char *bufptr; /* next buffer output position */ - char *bufstart; /* first buffer element */ - char *bufend; /* last buffer element, or NULL */ - /* bufend == NULL is for sprintf, where we assume buf is big enough */ - FILE *stream; /* eventual output destination, or NULL */ - int nchars; /* # chars already sent to stream */ - bool failed; /* call is a failure; errno is set */ -} PrintfTarget; - -/* - * Info about the type and value of a formatting parameter. Note that we - * don't currently support "long double", "wint_t", or "wchar_t *" data, - * nor the '%n' formatting code; else we'd need more types. Also, at this - * level we need not worry about signed vs unsigned values. - */ -typedef enum -{ - ATYPE_NONE = 0, - ATYPE_INT, - ATYPE_LONG, - ATYPE_LONGLONG, - ATYPE_DOUBLE, - ATYPE_CHARPTR -} PrintfArgType; - -typedef union -{ - int i; - long l; - int64 ll; - double d; - char *cptr; -} PrintfArgValue; - - -static void flushbuffer(PrintfTarget *target); -static void dopr(PrintfTarget *target, const char *format, va_list args); - - -int -pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) -{ - PrintfTarget target; - - if (str == NULL || count == 0) - return 0; - target.bufstart = target.bufptr = str; - target.bufend = str + count - 1; - target.stream = NULL; - /* target.nchars is unused in this case */ - target.failed = false; - dopr(&target, fmt, args); - *(target.bufptr) = '\0'; - return target.failed ? -1 : (target.bufptr - target.bufstart); -} - -int -pg_snprintf(char *str, size_t count, const char *fmt,...) -{ - int len; - va_list args; - - va_start(args, fmt); - len = pg_vsnprintf(str, count, fmt, args); - va_end(args); - return len; -} - -static int -pg_vsprintf(char *str, const char *fmt, va_list args) -{ - PrintfTarget target; - - if (str == NULL) - return 0; - target.bufstart = target.bufptr = str; - target.bufend = NULL; - target.stream = NULL; - /* target.nchars is unused in this case */ - target.failed = false; - dopr(&target, fmt, args); - *(target.bufptr) = '\0'; - return target.failed ? -1 : (target.bufptr - target.bufstart); -} - -int -pg_sprintf(char *str, const char *fmt,...) -{ - int len; - va_list args; - - va_start(args, fmt); - len = pg_vsprintf(str, fmt, args); - va_end(args); - return len; -} - -int -pg_vfprintf(FILE *stream, const char *fmt, va_list args) -{ - PrintfTarget target; - char buffer[1024]; /* size is arbitrary */ - - if (stream == NULL) - { - errno = EINVAL; - return -1; - } - target.bufstart = target.bufptr = buffer; - target.bufend = buffer + sizeof(buffer) - 1; - target.stream = stream; - target.nchars = 0; - target.failed = false; - dopr(&target, fmt, args); - /* dump any remaining buffer contents */ - flushbuffer(&target); - return target.failed ? -1 : target.nchars; -} - -int -pg_fprintf(FILE *stream, const char *fmt,...) -{ - int len; - va_list args; - - va_start(args, fmt); - len = pg_vfprintf(stream, fmt, args); - va_end(args); - return len; -} - -int -pg_printf(const char *fmt,...) -{ - int len; - va_list args; - - va_start(args, fmt); - len = pg_vfprintf(stdout, fmt, args); - va_end(args); - return len; -} - -/* - * Attempt to write the entire buffer to target->stream; discard the entire - * buffer in any case. Call this only when target->stream is defined. - */ -static void -flushbuffer(PrintfTarget *target) -{ - size_t nc = target->bufptr - target->bufstart; - - if (!target->failed && nc > 0) - { - size_t written; - - written = fwrite(target->bufstart, 1, nc, target->stream); - target->nchars += written; - if (written != nc) - target->failed = true; - } - target->bufptr = target->bufstart; -} - - -static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, - int pointflag, PrintfTarget *target); -static void fmtptr(void *value, PrintfTarget *target); -static void fmtint(int64 value, char type, int forcesign, - int leftjust, int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target); -static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target); -static void fmtfloat(double value, char type, int forcesign, - int leftjust, int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target); -static void dostr(const char *str, int slen, PrintfTarget *target); -static void dopr_outch(int c, PrintfTarget *target); -static int adjust_sign(int is_negative, int forcesign, int *signvalue); -static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); -static void leading_pad(int zpad, int *signvalue, int *padlen, - PrintfTarget *target); -static void trailing_pad(int *padlen, PrintfTarget *target); - - -/* - * dopr(): poor man's version of doprintf - */ -static void -dopr(PrintfTarget *target, const char *format, va_list args) -{ - const char *format_start = format; - int ch; - bool have_dollar; - bool have_non_dollar; - bool have_star; - bool afterstar; - int accum; - int longlongflag; - int longflag; - int pointflag; - int leftjust; - int fieldwidth; - int precision; - int zpad; - int forcesign; - int last_dollar; - int fmtpos; - int cvalue; - int64 numvalue; - double fvalue; - char *strvalue; - int i; - PrintfArgType argtypes[NL_ARGMAX + 1]; - PrintfArgValue argvalues[NL_ARGMAX + 1]; - - /* - * Parse the format string to determine whether there are %n$ format - * specs, and identify the types and order of the format parameters. - */ - have_dollar = have_non_dollar = false; - last_dollar = 0; - MemSet(argtypes, 0, sizeof(argtypes)); - - while ((ch = *format++) != '\0') - { - if (ch != '%') - continue; - longflag = longlongflag = pointflag = 0; - fmtpos = accum = 0; - afterstar = false; -nextch1: - ch = *format++; - if (ch == '\0') - break; /* illegal, but we don't complain */ - switch (ch) - { - case '-': - case '+': - goto nextch1; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - accum = accum * 10 + (ch - '0'); - goto nextch1; - case '.': - pointflag = 1; - accum = 0; - goto nextch1; - case '*': - if (afterstar) - have_non_dollar = true; /* multiple stars */ - afterstar = true; - accum = 0; - goto nextch1; - case '$': - have_dollar = true; - if (accum <= 0 || accum > NL_ARGMAX) - goto bad_format; - if (afterstar) - { - if (argtypes[accum] && - argtypes[accum] != ATYPE_INT) - goto bad_format; - argtypes[accum] = ATYPE_INT; - last_dollar = Max(last_dollar, accum); - afterstar = false; - } - else - fmtpos = accum; - accum = 0; - goto nextch1; - case 'l': - if (longflag) - longlongflag = 1; - else - longflag = 1; - goto nextch1; - case 'z': -#if SIZEOF_SIZE_T == 8 -#ifdef HAVE_LONG_INT_64 - longflag = 1; -#elif defined(HAVE_LONG_LONG_INT_64) - longlongflag = 1; -#else -#error "Don't know how to print 64bit integers" -#endif -#else - /* assume size_t is same size as int */ -#endif - goto nextch1; - case 'h': - case '\'': - /* ignore these */ - goto nextch1; - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - if (fmtpos) - { - PrintfArgType atype; - - if (longlongflag) - atype = ATYPE_LONGLONG; - else if (longflag) - atype = ATYPE_LONG; - else - atype = ATYPE_INT; - if (argtypes[fmtpos] && - argtypes[fmtpos] != atype) - goto bad_format; - argtypes[fmtpos] = atype; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 'c': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_INT) - goto bad_format; - argtypes[fmtpos] = ATYPE_INT; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 's': - case 'p': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_CHARPTR) - goto bad_format; - argtypes[fmtpos] = ATYPE_CHARPTR; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_DOUBLE) - goto bad_format; - argtypes[fmtpos] = ATYPE_DOUBLE; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case '%': - break; - } - - /* - * If we finish the spec with afterstar still set, there's a - * non-dollar star in there. - */ - if (afterstar) - have_non_dollar = true; - } - - /* Per spec, you use either all dollar or all not. */ - if (have_dollar && have_non_dollar) - goto bad_format; - - /* - * In dollar mode, collect the arguments in physical order. - */ - for (i = 1; i <= last_dollar; i++) - { - switch (argtypes[i]) - { - case ATYPE_NONE: - goto bad_format; - case ATYPE_INT: - argvalues[i].i = va_arg(args, int); - break; - case ATYPE_LONG: - argvalues[i].l = va_arg(args, long); - break; - case ATYPE_LONGLONG: - argvalues[i].ll = va_arg(args, int64); - break; - case ATYPE_DOUBLE: - argvalues[i].d = va_arg(args, double); - break; - case ATYPE_CHARPTR: - argvalues[i].cptr = va_arg(args, char *); - break; - } - } - - /* - * At last we can parse the format for real. - */ - format = format_start; - while ((ch = *format++) != '\0') - { - if (target->failed) - break; - - if (ch != '%') - { - dopr_outch(ch, target); - continue; - } - fieldwidth = precision = zpad = leftjust = forcesign = 0; - longflag = longlongflag = pointflag = 0; - fmtpos = accum = 0; - have_star = afterstar = false; -nextch2: - ch = *format++; - if (ch == '\0') - break; /* illegal, but we don't complain */ - switch (ch) - { - case '-': - leftjust = 1; - goto nextch2; - case '+': - forcesign = 1; - goto nextch2; - case '0': - /* set zero padding if no nonzero digits yet */ - if (accum == 0 && !pointflag) - zpad = '0'; - /* FALL THRU */ - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - accum = accum * 10 + (ch - '0'); - goto nextch2; - case '.': - if (have_star) - have_star = false; - else - fieldwidth = accum; - pointflag = 1; - accum = 0; - goto nextch2; - case '*': - if (have_dollar) - { - /* process value after reading n$ */ - afterstar = true; - } - else - { - /* fetch and process value now */ - int starval = va_arg(args, int); - - if (pointflag) - { - precision = starval; - if (precision < 0) - { - precision = 0; - pointflag = 0; - } - } - else - { - fieldwidth = starval; - if (fieldwidth < 0) - { - leftjust = 1; - fieldwidth = -fieldwidth; - } - } - } - have_star = true; - accum = 0; - goto nextch2; - case '$': - if (afterstar) - { - /* fetch and process star value */ - int starval = argvalues[accum].i; - - if (pointflag) - { - precision = starval; - if (precision < 0) - { - precision = 0; - pointflag = 0; - } - } - else - { - fieldwidth = starval; - if (fieldwidth < 0) - { - leftjust = 1; - fieldwidth = -fieldwidth; - } - } - afterstar = false; - } - else - fmtpos = accum; - accum = 0; - goto nextch2; - case 'l': - if (longflag) - longlongflag = 1; - else - longflag = 1; - goto nextch2; - case 'z': -#if SIZEOF_SIZE_T == 8 -#ifdef HAVE_LONG_INT_64 - longflag = 1; -#elif defined(HAVE_LONG_LONG_INT_64) - longlongflag = 1; -#else -#error "Don't know how to print 64bit integers" -#endif -#else - /* assume size_t is same size as int */ -#endif - goto nextch2; - case 'h': - case '\'': - /* ignore these */ - goto nextch2; - case 'd': - case 'i': - if (!have_star) - { - if (pointflag) - precision = accum; - else - fieldwidth = accum; - } - if (have_dollar) - { - if (longlongflag) - numvalue = argvalues[fmtpos].ll; - else if (longflag) - numvalue = argvalues[fmtpos].l; - else - numvalue = argvalues[fmtpos].i; - } - else - { - if (longlongflag) - numvalue = va_arg(args, int64); - else if (longflag) - numvalue = va_arg(args, long); - else - numvalue = va_arg(args, int); - } - fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad, - precision, pointflag, target); - break; - case 'o': - case 'u': - case 'x': - case 'X': - if (!have_star) - { - if (pointflag) - precision = accum; - else - fieldwidth = accum; - } - if (have_dollar) - { - if (longlongflag) - numvalue = (uint64) argvalues[fmtpos].ll; - else if (longflag) - numvalue = (unsigned long) argvalues[fmtpos].l; - else - numvalue = (unsigned int) argvalues[fmtpos].i; - } - else - { - if (longlongflag) - numvalue = (uint64) va_arg(args, int64); - else if (longflag) - numvalue = (unsigned long) va_arg(args, long); - else - numvalue = (unsigned int) va_arg(args, int); - } - fmtint(numvalue, ch, forcesign, leftjust, fieldwidth, zpad, - precision, pointflag, target); - break; - case 'c': - if (!have_star) - { - if (pointflag) - precision = accum; - else - fieldwidth = accum; - } - if (have_dollar) - cvalue = (unsigned char) argvalues[fmtpos].i; - else - cvalue = (unsigned char) va_arg(args, int); - fmtchar(cvalue, leftjust, fieldwidth, target); - break; - case 's': - if (!have_star) - { - if (pointflag) - precision = accum; - else - fieldwidth = accum; - } - if (have_dollar) - strvalue = argvalues[fmtpos].cptr; - else - strvalue = va_arg(args, char *); - fmtstr(strvalue, leftjust, fieldwidth, precision, pointflag, - target); - break; - case 'p': - /* fieldwidth/leftjust are ignored ... */ - if (have_dollar) - strvalue = argvalues[fmtpos].cptr; - else - strvalue = va_arg(args, char *); - fmtptr((void *) strvalue, target); - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (!have_star) - { - if (pointflag) - precision = accum; - else - fieldwidth = accum; - } - if (have_dollar) - fvalue = argvalues[fmtpos].d; - else - fvalue = va_arg(args, double); - fmtfloat(fvalue, ch, forcesign, leftjust, - fieldwidth, zpad, - precision, pointflag, - target); - break; - case '%': - dopr_outch('%', target); - break; - } - } - - return; - -bad_format: - errno = EINVAL; - target->failed = true; -} - -static size_t -pg_strnlen(const char *str, size_t maxlen) -{ - const char *p = str; - - while (maxlen-- > 0 && *p) - p++; - return p - str; -} - -static void -fmtstr(char *value, int leftjust, int minlen, int maxwidth, - int pointflag, PrintfTarget *target) -{ - int padlen, - vallen; /* amount to pad */ - - /* - * If a maxwidth (precision) is specified, we must not fetch more bytes - * than that. - */ - if (pointflag) - vallen = pg_strnlen(value, maxwidth); - else - vallen = strlen(value); - - adjust_padlen(minlen, vallen, leftjust, &padlen); - - while (padlen > 0) - { - dopr_outch(' ', target); - --padlen; - } - - dostr(value, vallen, target); - - trailing_pad(&padlen, target); -} - -static void -fmtptr(void *value, PrintfTarget *target) -{ - int vallen; - char convert[64]; - - /* we rely on regular C library's sprintf to do the basic conversion */ - vallen = sprintf(convert, "%p", value); - if (vallen < 0) - target->failed = true; - else - dostr(convert, vallen, target); -} - -static void -fmtint(int64 value, char type, int forcesign, int leftjust, - int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target) -{ - uint64 base; - int dosign; - const char *cvt = "0123456789abcdef"; - int signvalue = 0; - char convert[64]; - int vallen = 0; - int padlen = 0; /* amount to pad */ - int zeropad; /* extra leading zeroes */ - - switch (type) - { - case 'd': - case 'i': - base = 10; - dosign = 1; - break; - case 'o': - base = 8; - dosign = 0; - break; - case 'u': - base = 10; - dosign = 0; - break; - case 'x': - base = 16; - dosign = 0; - break; - case 'X': - cvt = "0123456789ABCDEF"; - base = 16; - dosign = 0; - break; - default: - return; /* keep compiler quiet */ - } - - /* Handle +/- */ - if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) - value = -value; - - /* - * SUS: the result of converting 0 with an explicit precision of 0 is no - * characters - */ - if (value == 0 && pointflag && precision == 0) - vallen = 0; - else - { - /* make integer string */ - uint64 uvalue = (uint64) value; - - do - { - convert[vallen++] = cvt[uvalue % base]; - uvalue = uvalue / base; - } while (uvalue); - } - - zeropad = Max(0, precision - vallen); - - adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen); - - leading_pad(zpad, &signvalue, &padlen, target); - - while (zeropad-- > 0) - dopr_outch('0', target); - - while (vallen > 0) - dopr_outch(convert[--vallen], target); - - trailing_pad(&padlen, target); -} - -static void -fmtchar(int value, int leftjust, int minlen, PrintfTarget *target) -{ - int padlen = 0; /* amount to pad */ - - adjust_padlen(minlen, 1, leftjust, &padlen); - - while (padlen > 0) - { - dopr_outch(' ', target); - --padlen; - } - - dopr_outch(value, target); - - trailing_pad(&padlen, target); -} - -static void -fmtfloat(double value, char type, int forcesign, int leftjust, - int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target) -{ - int signvalue = 0; - int prec; - int vallen; - char fmt[32]; - char convert[1024]; - int zeropadlen = 0; /* amount to pad with zeroes */ - int padlen = 0; /* amount to pad with spaces */ - - /* - * We rely on the regular C library's sprintf to do the basic conversion, - * then handle padding considerations here. - * - * The dynamic range of "double" is about 1E+-308 for IEEE math, and not - * too wildly more than that with other hardware. In "f" format, sprintf - * could therefore generate at most 308 characters to the left of the - * decimal point; while we need to allow the precision to get as high as - * 308+17 to ensure that we don't truncate significant digits from very - * small values. To handle both these extremes, we use a buffer of 1024 - * bytes and limit requested precision to 350 digits; this should prevent - * buffer overrun even with non-IEEE math. If the original precision - * request was more than 350, separately pad with zeroes. - */ - if (precision < 0) /* cover possible overflow of "accum" */ - precision = 0; - prec = Min(precision, 350); - - if (pointflag) - { - if (sprintf(fmt, "%%.%d%c", prec, type) < 0) - goto fail; - zeropadlen = precision - prec; - } - else if (sprintf(fmt, "%%%c", type) < 0) - goto fail; - - if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue)) - value = -value; - - vallen = sprintf(convert, fmt, value); - if (vallen < 0) - goto fail; - - /* If it's infinity or NaN, forget about doing any zero-padding */ - if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1])) - zeropadlen = 0; - - adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen); - - leading_pad(zpad, &signvalue, &padlen, target); - - if (zeropadlen > 0) - { - /* If 'e' or 'E' format, inject zeroes before the exponent */ - char *epos = strrchr(convert, 'e'); - - if (!epos) - epos = strrchr(convert, 'E'); - if (epos) - { - /* pad after exponent */ - dostr(convert, epos - convert, target); - while (zeropadlen-- > 0) - dopr_outch('0', target); - dostr(epos, vallen - (epos - convert), target); - } - else - { - /* no exponent, pad after the digits */ - dostr(convert, vallen, target); - while (zeropadlen-- > 0) - dopr_outch('0', target); - } - } - else - { - /* no zero padding, just emit the number as-is */ - dostr(convert, vallen, target); - } - - trailing_pad(&padlen, target); - return; - -fail: - target->failed = true; -} - -static void -dostr(const char *str, int slen, PrintfTarget *target) -{ - while (slen > 0) - { - int avail; - - if (target->bufend != NULL) - avail = target->bufend - target->bufptr; - else - avail = slen; - if (avail <= 0) - { - /* buffer full, can we dump to stream? */ - if (target->stream == NULL) - return; /* no, lose the data */ - flushbuffer(target); - continue; - } - avail = Min(avail, slen); - memmove(target->bufptr, str, avail); - target->bufptr += avail; - str += avail; - slen -= avail; - } -} - -static void -dopr_outch(int c, PrintfTarget *target) -{ - if (target->bufend != NULL && target->bufptr >= target->bufend) - { - /* buffer full, can we dump to stream? */ - if (target->stream == NULL) - return; /* no, lose the data */ - flushbuffer(target); - } - *(target->bufptr++) = c; -} - - -static int -adjust_sign(int is_negative, int forcesign, int *signvalue) -{ - if (is_negative) - { - *signvalue = '-'; - return true; - } - else if (forcesign) - *signvalue = '+'; - return false; -} - - -static void -adjust_padlen(int minlen, int vallen, int leftjust, int *padlen) -{ - *padlen = minlen - vallen; - if (*padlen < 0) - *padlen = 0; - if (leftjust) - *padlen = -(*padlen); -} - - -static void -leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target) -{ - if (*padlen > 0 && zpad) - { - if (*signvalue) - { - dopr_outch(*signvalue, target); - --(*padlen); - *signvalue = 0; - } - while (*padlen > 0) - { - dopr_outch(zpad, target); - --(*padlen); - } - } - while (*padlen > (*signvalue != 0)) - { - dopr_outch(' ', target); - --(*padlen); - } - if (*signvalue) - { - dopr_outch(*signvalue, target); - if (*padlen > 0) - --(*padlen); - else if (*padlen < 0) - ++(*padlen); - } -} - - -static void -trailing_pad(int *padlen, PrintfTarget *target) -{ - while (*padlen < 0) - { - dopr_outch(' ', target); - ++(*padlen); - } -} diff --git a/libpq/win32/system.c b/libpq/win32/system.c deleted file mode 100644 index 15b6e37..0000000 --- a/libpq/win32/system.c +++ /dev/null @@ -1,119 +0,0 @@ -/*------------------------------------------------------------------------- - * - * system.c - * Win32 system() and popen() replacements - * - * - * Win32 needs double quotes at the beginning and end of system() - * strings. If not, it gets confused with multiple quoted strings. - * It also requires double-quotes around the executable name and - * any files used for redirection. Filter other args through - * appendShellString() to quote them. - * - * Generated using Win32 "CMD /?": - * - * 1. If all of the following conditions are met, then quote characters - * on the command line are preserved: - * - * - no /S switch - * - exactly two quote characters - * - no special characters between the two quote characters, where special - * is one of: &<>()@^| - * - there are one or more whitespace characters between the two quote - * characters - * - the string between the two quote characters is the name of an - * executable file. - * - * 2. Otherwise, old behavior is to see if the first character is a quote - * character and if so, strip the leading character and remove the last - * quote character on the command line, preserving any text after the last - * quote character. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * src/port/system.c - * - *------------------------------------------------------------------------- - */ -int a; - -#if defined(WIN32) && !defined(__CYGWIN__) - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#include -#include - -#undef system -#undef popen - -int -pgwin32_system(const char *command) -{ - size_t cmdlen = strlen(command); - char *buf; - int save_errno; - int res; - - /* - * Create a malloc'd copy of the command string, enclosed with an extra - * pair of quotes - */ - buf = malloc(cmdlen + 2 + 1); - if (buf == NULL) - { - errno = ENOMEM; - return -1; - } - buf[0] = '"'; - memcpy(&buf[1], command, cmdlen); - buf[cmdlen + 1] = '"'; - buf[cmdlen + 2] = '\0'; - - res = system(buf); - - save_errno = errno; - free(buf); - errno = save_errno; - - return res; -} - - -FILE * -pgwin32_popen(const char *command, const char *type) -{ - size_t cmdlen = strlen(command); - char *buf; - int save_errno; - FILE *res; - - /* - * Create a malloc'd copy of the command string, enclosed with an extra - * pair of quotes - */ - buf = malloc(cmdlen + 2 + 1); - if (buf == NULL) - { - errno = ENOMEM; - return NULL; - } - buf[0] = '"'; - memcpy(&buf[1], command, cmdlen); - buf[cmdlen + 1] = '"'; - buf[cmdlen + 2] = '\0'; - - res = _popen(buf, type); - - save_errno = errno; - free(buf); - errno = save_errno; - - return res; -} - -#endif diff --git a/libpq/win32/win32.c b/libpq/win32/win32.c deleted file mode 100644 index 1b7ad37..0000000 --- a/libpq/win32/win32.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * src/interfaces/libpq/win32.c - * - * - * FILE - * win32.c - * - * DESCRIPTION - * Win32 support functions. - * - * Contains table and functions for looking up win32 socket error - * descriptions. But will/may contain other win32 helper functions - * for libpq. - * - * The error constants are taken from the Frambak Bakfram LGSOCKET - * library guys who in turn took them from the Winsock FAQ. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - */ - -/* Make stuff compile faster by excluding not used stuff */ - -#define VC_EXTRALEAN -#ifndef __MINGW32__ -#define NOGDI -#endif -#define NOCRYPT - -#include "postgres_fe.h" - -#include "win32.h" - -/* Declared here to avoid pulling in all includes, which causes name collisions */ -#ifdef ENABLE_NLS -extern char *libpq_gettext(const char *msgid) pg_attribute_format_arg(1); -#else -#define libpq_gettext(x) (x) -#endif - - -static struct WSErrorEntry -{ - DWORD error; - const char *description; -} WSErrors[] = - -{ - { - 0, "No error" - }, - { - WSAEINTR, "Interrupted system call" - }, - { - WSAEBADF, "Bad file number" - }, - { - WSAEACCES, "Permission denied" - }, - { - WSAEFAULT, "Bad address" - }, - { - WSAEINVAL, "Invalid argument" - }, - { - WSAEMFILE, "Too many open sockets" - }, - { - WSAEWOULDBLOCK, "Operation would block" - }, - { - WSAEINPROGRESS, "Operation now in progress" - }, - { - WSAEALREADY, "Operation already in progress" - }, - { - WSAENOTSOCK, "Socket operation on non-socket" - }, - { - WSAEDESTADDRREQ, "Destination address required" - }, - { - WSAEMSGSIZE, "Message too long" - }, - { - WSAEPROTOTYPE, "Protocol wrong type for socket" - }, - { - WSAENOPROTOOPT, "Bad protocol option" - }, - { - WSAEPROTONOSUPPORT, "Protocol not supported" - }, - { - WSAESOCKTNOSUPPORT, "Socket type not supported" - }, - { - WSAEOPNOTSUPP, "Operation not supported on socket" - }, - { - WSAEPFNOSUPPORT, "Protocol family not supported" - }, - { - WSAEAFNOSUPPORT, "Address family not supported" - }, - { - WSAEADDRINUSE, "Address already in use" - }, - { - WSAEADDRNOTAVAIL, "Cannot assign requested address" - }, - { - WSAENETDOWN, "Network is down" - }, - { - WSAENETUNREACH, "Network is unreachable" - }, - { - WSAENETRESET, "Net connection reset" - }, - { - WSAECONNABORTED, "Software caused connection abort" - }, - { - WSAECONNRESET, "Connection reset by peer" - }, - { - WSAENOBUFS, "No buffer space available" - }, - { - WSAEISCONN, "Socket is already connected" - }, - { - WSAENOTCONN, "Socket is not connected" - }, - { - WSAESHUTDOWN, "Cannot send after socket shutdown" - }, - { - WSAETOOMANYREFS, "Too many references, cannot splice" - }, - { - WSAETIMEDOUT, "Connection timed out" - }, - { - WSAECONNREFUSED, "Connection refused" - }, - { - WSAELOOP, "Too many levels of symbolic links" - }, - { - WSAENAMETOOLONG, "File name too long" - }, - { - WSAEHOSTDOWN, "Host is down" - }, - { - WSAEHOSTUNREACH, "No route to host" - }, - { - WSAENOTEMPTY, "Directory not empty" - }, - { - WSAEPROCLIM, "Too many processes" - }, - { - WSAEUSERS, "Too many users" - }, - { - WSAEDQUOT, "Disc quota exceeded" - }, - { - WSAESTALE, "Stale NFS file handle" - }, - { - WSAEREMOTE, "Too many levels of remote in path" - }, - { - WSASYSNOTREADY, "Network system is unavailable" - }, - { - WSAVERNOTSUPPORTED, "Winsock version out of range" - }, - { - WSANOTINITIALISED, "WSAStartup not yet called" - }, - { - WSAEDISCON, "Graceful shutdown in progress" - }, - { - WSAHOST_NOT_FOUND, "Host not found" - }, - { - WSATRY_AGAIN, "NA Host not found / SERVFAIL" - }, - { - WSANO_RECOVERY, "Non recoverable FORMERR||REFUSED||NOTIMP" - }, - { - WSANO_DATA, "No host data of that type was found" - }, - { - 0, 0 - } /* End of table */ -}; - - -/* - * Returns 0 if not found, linear but who cares, at this moment - * we're already in pain :) - */ - -static int -LookupWSErrorMessage(DWORD err, char *dest) -{ - struct WSErrorEntry *e; - - for (e = WSErrors; e->description; e++) - { - if (e->error == err) - { - strcpy(dest, e->description); - return 1; - } - } - return 0; -} - - -struct MessageDLL -{ - const char *dll_name; - void *handle; - int loaded; /* BOOL */ -} dlls[] = - -{ - { - "netmsg.dll", 0, 0 - }, - { - "winsock.dll", 0, 0 - }, - { - "ws2_32.dll", 0, 0 - }, - { - "wsock32n.dll", 0, 0 - }, - { - "mswsock.dll", 0, 0 - }, - { - "ws2help.dll", 0, 0 - }, - { - "ws2thk.dll", 0, 0 - }, - { - 0, 0, 1 - } /* Last one, no dll, always loaded */ -}; - -#define DLLS_SIZE (sizeof(dlls)/sizeof(struct MessageDLL)) - -/* - * Returns a description of the socket error by first trying - * to find it in the lookup table, and if that fails, tries - * to load any of the winsock dlls to find that message. - * The DLL thing works from Nt4 (spX ?) up, but some special - * versions of winsock might have this as well (seen on Win98 SE - * special install) / Magnus Naeslund (mag@fbab.net) - * - */ - -const char * -winsock_strerror(int err, char *strerrbuf, size_t buflen) -{ - unsigned long flags; - int offs, - i; - int success = LookupWSErrorMessage(err, strerrbuf); - - for (i = 0; !success && i < DLLS_SIZE; i++) - { - - if (!dlls[i].loaded) - { - dlls[i].loaded = 1; /* Only load once */ - dlls[i].handle = (void *) LoadLibraryEx( - dlls[i].dll_name, - 0, - LOAD_LIBRARY_AS_DATAFILE); - } - - if (dlls[i].dll_name && !dlls[i].handle) - continue; /* Didn't load */ - - flags = FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS - | (dlls[i].handle ? FORMAT_MESSAGE_FROM_HMODULE : 0); - - success = 0 != FormatMessage( - flags, - dlls[i].handle, err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - strerrbuf, buflen - 64, - 0 - ); - } - - if (!success) - sprintf(strerrbuf, libpq_gettext("unrecognized socket error: 0x%08X/%d"), err, err); - else - { - strerrbuf[buflen - 1] = '\0'; - offs = strlen(strerrbuf); - if (offs > (int) buflen - 64) - offs = buflen - 64; - sprintf(strerrbuf + offs, " (0x%08X/%d)", err, err); - } - return strerrbuf; -} diff --git a/libpq/win32/win32.h b/libpq/win32/win32.h deleted file mode 100644 index be00ea7..0000000 --- a/libpq/win32/win32.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * src/interfaces/libpq/win32.h - */ -#ifndef __win32_h_included -#define __win32_h_included - -/* - * Some compatibility functions - */ -#ifdef __BORLANDC__ -#define _timeb timeb -#define _ftime(a) ftime(a) -#define _errno errno -#define popen(a,b) _popen(a,b) -#else -/* open provided elsewhere */ -#define close(a) _close(a) -#define read(a,b,c) _read(a,b,c) -#define write(a,b,c) _write(a,b,c) -#endif - -#undef EAGAIN /* doesn't apply on sockets */ -#undef EINTR -#define EINTR WSAEINTR -#ifndef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif -#ifndef ECONNRESET -#define ECONNRESET WSAECONNRESET -#endif -#ifndef EINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif - -/* - * support for handling Windows Socket errors - */ -extern const char *winsock_strerror(int err, char *strerrbuf, size_t buflen); - -#endif diff --git a/libpq/win32/win32error.c b/libpq/win32/win32error.c deleted file mode 100644 index cf65225..0000000 --- a/libpq/win32/win32error.c +++ /dev/null @@ -1,206 +0,0 @@ -/*------------------------------------------------------------------------- - * - * win32error.c - * Map win32 error codes to errno values - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * - * IDENTIFICATION - * src/port/win32error.c - * - *------------------------------------------------------------------------- - */ - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -static const struct -{ - DWORD winerr; - int doserr; -} doserrors[] = - -{ - { - ERROR_INVALID_FUNCTION, EINVAL - }, - { - ERROR_FILE_NOT_FOUND, ENOENT - }, - { - ERROR_PATH_NOT_FOUND, ENOENT - }, - { - ERROR_TOO_MANY_OPEN_FILES, EMFILE - }, - { - ERROR_ACCESS_DENIED, EACCES - }, - { - ERROR_INVALID_HANDLE, EBADF - }, - { - ERROR_ARENA_TRASHED, ENOMEM - }, - { - ERROR_NOT_ENOUGH_MEMORY, ENOMEM - }, - { - ERROR_INVALID_BLOCK, ENOMEM - }, - { - ERROR_BAD_ENVIRONMENT, E2BIG - }, - { - ERROR_BAD_FORMAT, ENOEXEC - }, - { - ERROR_INVALID_ACCESS, EINVAL - }, - { - ERROR_INVALID_DATA, EINVAL - }, - { - ERROR_INVALID_DRIVE, ENOENT - }, - { - ERROR_CURRENT_DIRECTORY, EACCES - }, - { - ERROR_NOT_SAME_DEVICE, EXDEV - }, - { - ERROR_NO_MORE_FILES, ENOENT - }, - { - ERROR_LOCK_VIOLATION, EACCES - }, - { - ERROR_SHARING_VIOLATION, EACCES - }, - { - ERROR_BAD_NETPATH, ENOENT - }, - { - ERROR_NETWORK_ACCESS_DENIED, EACCES - }, - { - ERROR_BAD_NET_NAME, ENOENT - }, - { - ERROR_FILE_EXISTS, EEXIST - }, - { - ERROR_CANNOT_MAKE, EACCES - }, - { - ERROR_FAIL_I24, EACCES - }, - { - ERROR_INVALID_PARAMETER, EINVAL - }, - { - ERROR_NO_PROC_SLOTS, EAGAIN - }, - { - ERROR_DRIVE_LOCKED, EACCES - }, - { - ERROR_BROKEN_PIPE, EPIPE - }, - { - ERROR_DISK_FULL, ENOSPC - }, - { - ERROR_INVALID_TARGET_HANDLE, EBADF - }, - { - ERROR_INVALID_HANDLE, EINVAL - }, - { - ERROR_WAIT_NO_CHILDREN, ECHILD - }, - { - ERROR_CHILD_NOT_COMPLETE, ECHILD - }, - { - ERROR_DIRECT_ACCESS_HANDLE, EBADF - }, - { - ERROR_NEGATIVE_SEEK, EINVAL - }, - { - ERROR_SEEK_ON_DEVICE, EACCES - }, - { - ERROR_DIR_NOT_EMPTY, ENOTEMPTY - }, - { - ERROR_NOT_LOCKED, EACCES - }, - { - ERROR_BAD_PATHNAME, ENOENT - }, - { - ERROR_MAX_THRDS_REACHED, EAGAIN - }, - { - ERROR_LOCK_FAILED, EACCES - }, - { - ERROR_ALREADY_EXISTS, EEXIST - }, - { - ERROR_FILENAME_EXCED_RANGE, ENOENT - }, - { - ERROR_NESTING_NOT_ALLOWED, EAGAIN - }, - { - ERROR_NOT_ENOUGH_QUOTA, ENOMEM - } -}; - -void -_dosmaperr(unsigned long e) -{ - int i; - - if (e == 0) - { - errno = 0; - return; - } - - for (i = 0; i < lengthof(doserrors); i++) - { - if (doserrors[i].winerr == e) - { - int doserr = doserrors[i].doserr; - -#ifndef FRONTEND - ereport(DEBUG5, - (errmsg_internal("mapped win32 error code %lu to %d", - e, doserr))); -#elif FRONTEND_DEBUG - fprintf(stderr, "mapped win32 error code %lu to %d", e, doserr); -#endif - errno = doserr; - return; - } - } - -#ifndef FRONTEND - ereport(LOG, - (errmsg_internal("unrecognized win32 error code: %lu", - e))); -#else - fprintf(stderr, "unrecognized win32 error code: %lu", e); -#endif - - errno = EINVAL; - return; -} diff --git a/libpq/win32/win32setlocale.c b/libpq/win32/win32setlocale.c deleted file mode 100644 index 4abc7aa..0000000 --- a/libpq/win32/win32setlocale.c +++ /dev/null @@ -1,189 +0,0 @@ -/*------------------------------------------------------------------------- - * - * win32setlocale.c - * Wrapper to work around bugs in Windows setlocale() implementation - * - * Copyright (c) 2011-2016, PostgreSQL Global Development Group - * - * IDENTIFICATION - * src/port/win32setlocale.c - * - * - * The setlocale() function in Windows is broken in two ways. First, it - * has a problem with locale names that have a dot in the country name. For - * example: - * - * "Chinese (Traditional)_Hong Kong S.A.R..950" - * - * For some reason, setlocale() doesn't accept that as argument, even though - * setlocale(LC_ALL, NULL) returns exactly that. Fortunately, it accepts - * various alternative names for such countries, so to work around the broken - * setlocale() function, we map the troublemaking locale names to accepted - * aliases, before calling setlocale(). - * - * The second problem is that the locale name for "Norwegian (Bokmål)" - * contains a non-ASCII character. That's problematic, because it's not clear - * what encoding the locale name itself is supposed to be in, when you - * haven't yet set a locale. Also, it causes problems when the cluster - * contains databases with different encodings, as the locale name is stored - * in the pg_database system catalog. To work around that, when setlocale() - * returns that locale name, map it to a pure-ASCII alias for the same - * locale. - *------------------------------------------------------------------------- - */ - -#include "c.h" - -#undef setlocale - -struct locale_map -{ - /* - * String in locale name to replace. Can be a single string (end is NULL), - * or separate start and end strings. If two strings are given, the locale - * name must contain both of them, and everything between them is - * replaced. This is used for a poor-man's regexp search, allowing - * replacement of "start.*end". - */ - const char *locale_name_start; - const char *locale_name_end; - - const char *replacement; /* string to replace the match with */ -}; - -/* - * Mappings applied before calling setlocale(), to the argument. - */ -static const struct locale_map locale_map_argument[] = { - /* - * "HKG" is listed here: - * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx - * (Country/Region Strings). - * - * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the - * above list, but seems to work anyway. - */ - {"Hong Kong S.A.R.", NULL, "HKG"}, - {"U.A.E.", NULL, "ARE"}, - - /* - * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't - * seem to recognize that. And Macau isn't listed in the table of accepted - * abbreviations linked above. Fortunately, "ZHM" seems to be accepted as - * an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm not sure - * where "ZHM" comes from, must be some legacy naming scheme. But hey, it - * works. - * - * Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale - * name, not just the country part. - * - * Some versions of Windows spell it "Macau", others "Macao". - */ - {"Chinese (Traditional)_Macau S.A.R..950", NULL, "ZHM"}, - {"Chinese_Macau S.A.R..950", NULL, "ZHM"}, - {"Chinese (Traditional)_Macao S.A.R..950", NULL, "ZHM"}, - {"Chinese_Macao S.A.R..950", NULL, "ZHM"}, - {NULL, NULL, NULL} -}; - -/* - * Mappings applied after calling setlocale(), to its return value. - */ -static const struct locale_map locale_map_result[] = { - /* - * "Norwegian (Bokmål)" locale name contains the a-ring character. - * Map it to a pure-ASCII alias. - * - * It's not clear what encoding setlocale() uses when it returns the - * locale name, so to play it safe, we search for "Norwegian (Bok*l)". - */ - {"Norwegian (Bokm", "l)_Norway", "Norwegian_Norway"}, - {NULL, NULL, NULL} -}; - -#define MAX_LOCALE_NAME_LEN 100 - -static const char * -map_locale(const struct locale_map * map, const char *locale) -{ - static char aliasbuf[MAX_LOCALE_NAME_LEN]; - int i; - - /* Check if the locale name matches any of the problematic ones. */ - for (i = 0; map[i].locale_name_start != NULL; i++) - { - const char *needle_start = map[i].locale_name_start; - const char *needle_end = map[i].locale_name_end; - const char *replacement = map[i].replacement; - char *match; - char *match_start = NULL; - char *match_end = NULL; - - match = strstr(locale, needle_start); - if (match) - { - /* - * Found a match for the first part. If this was a two-part - * replacement, find the second part. - */ - match_start = match; - if (needle_end) - { - match = strstr(match_start + strlen(needle_start), needle_end); - if (match) - match_end = match + strlen(needle_end); - else - match_start = NULL; - } - else - match_end = match_start + strlen(needle_start); - } - - if (match_start) - { - /* Found a match. Replace the matched string. */ - int matchpos = match_start - locale; - int replacementlen = strlen(replacement); - char *rest = match_end; - int restlen = strlen(rest); - - /* check that the result fits in the static buffer */ - if (matchpos + replacementlen + restlen + 1 > MAX_LOCALE_NAME_LEN) - return NULL; - - memcpy(&aliasbuf[0], &locale[0], matchpos); - memcpy(&aliasbuf[matchpos], replacement, replacementlen); - /* includes null terminator */ - memcpy(&aliasbuf[matchpos + replacementlen], rest, restlen + 1); - - return aliasbuf; - } - } - - /* no match, just return the original string */ - return locale; -} - -char * -pgwin32_setlocale(int category, const char *locale) -{ - const char *argument; - char *result; - - if (locale == NULL) - argument = NULL; - else - argument = map_locale(locale_map_argument, locale); - - /* Call the real setlocale() function */ - result = setlocale(category, argument); - - /* - * setlocale() is specified to return a "char *" that the caller is - * forbidden to modify, so casting away the "const" is innocuous. - */ - if (result) - result = (char *) map_locale(locale_map_result, result); - - return result; -} -- cgit v1.1