diff options
author | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 11:26:33 +0300 |
---|---|---|
committer | galaxycrab <UgnineSirdis@ydb.tech> | 2023-11-23 12:01:57 +0300 |
commit | 44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300 (patch) | |
tree | cb4d75cd1c6dbc3da0ed927337fd8d1b6ed9da84 /contrib/libs/libpq | |
parent | 0e69bf615395fdd48ecee032faaec81bc468b0b8 (diff) | |
download | ydb-44354d0fc55926c1d4510d1d2c9c9f6a1a5e9300.tar.gz |
YQ Connector:test INNER JOIN
Diffstat (limited to 'contrib/libs/libpq')
222 files changed, 78349 insertions, 0 deletions
diff --git a/contrib/libs/libpq/CMakeLists.darwin-arm64.txt b/contrib/libs/libpq/CMakeLists.darwin-arm64.txt new file mode 100644 index 0000000000..68370e4e4a --- /dev/null +++ b/contrib/libs/libpq/CMakeLists.darwin-arm64.txt @@ -0,0 +1,112 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpq) +target_compile_options(contrib-libs-libpq PRIVATE + -DFRONTEND + -DUNSAFE_STAT_OK + -D_POSIX_PTHREAD_SEMANTICS + -D_REENTRANT + -D_THREAD_SAFE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpq PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/include +) +target_include_directories(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/backend + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port +) +target_link_libraries(contrib-libs-libpq PUBLIC + contrib-libs-libc_compat + contrib-libs-openssl + contrib-libs-zlib +) +target_sources(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/archive.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/base64.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/checksum_helper.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/compression.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/config_info.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/controldata_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/cryptohash_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/d2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/encnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/f2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/fe_memutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_perm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hashfn.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hmac_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/ip.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/jsonapi.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/keywords.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/kwlookup.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/link-canary.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/logging.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/md5_common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/percentrepl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_get_line.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_lzcompress.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_prng.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pgfnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/protocol_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/psprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/relpath.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/restricted_token.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/rmtree.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/saslprep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/scram-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/sprompt.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/string.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/stringinfo.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/unicode_norm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/username.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wait_error.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wchar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-print.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/bsearch_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/chklocale.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/getpeereid.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/inet_net_ntop.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/noblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/path.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_bitutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sb8.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_strong_random.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgcheckdir.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgmkdirp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgsleep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrcasecmp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pqsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/quotes.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/snprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/strerror.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/tar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/thread.c +) diff --git a/contrib/libs/libpq/CMakeLists.darwin-x86_64.txt b/contrib/libs/libpq/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..60eae0ae86 --- /dev/null +++ b/contrib/libs/libpq/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,114 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpq) +target_compile_options(contrib-libs-libpq PRIVATE + -DFRONTEND + -DUNSAFE_STAT_OK + -D_POSIX_PTHREAD_SEMANTICS + -D_REENTRANT + -D_THREAD_SAFE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpq PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/include +) +target_include_directories(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/backend + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port +) +target_link_libraries(contrib-libs-libpq PUBLIC + contrib-libs-libc_compat + contrib-libs-openssl + contrib-libs-zlib +) +target_sources(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/archive.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/base64.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/checksum_helper.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/compression.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/config_info.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/controldata_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/cryptohash_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/d2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/encnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/f2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/fe_memutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_perm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hashfn.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hmac_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/ip.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/jsonapi.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/keywords.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/kwlookup.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/link-canary.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/logging.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/md5_common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/percentrepl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_get_line.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_lzcompress.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_prng.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pgfnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/protocol_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/psprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/relpath.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/restricted_token.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/rmtree.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/saslprep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/scram-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/sprompt.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/string.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/stringinfo.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/unicode_norm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/username.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wait_error.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wchar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-print.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/bsearch_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/chklocale.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/getpeereid.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/inet_net_ntop.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/noblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/path.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_bitutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sb8.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_strong_random.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgcheckdir.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgmkdirp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgsleep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrcasecmp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pqsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/quotes.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/snprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/strerror.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/tar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/thread.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sse42.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sse42_choose.c +) diff --git a/contrib/libs/libpq/CMakeLists.linux-aarch64.txt b/contrib/libs/libpq/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..fc19677dc2 --- /dev/null +++ b/contrib/libs/libpq/CMakeLists.linux-aarch64.txt @@ -0,0 +1,113 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpq) +target_compile_options(contrib-libs-libpq PRIVATE + -DFRONTEND + -DUNSAFE_STAT_OK + -D_POSIX_PTHREAD_SEMANTICS + -D_REENTRANT + -D_THREAD_SAFE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpq PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/include +) +target_include_directories(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/backend + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port +) +target_link_libraries(contrib-libs-libpq PUBLIC + contrib-libs-linux-headers + contrib-libs-libc_compat + contrib-libs-openssl + contrib-libs-zlib +) +target_sources(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/archive.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/base64.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/checksum_helper.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/compression.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/config_info.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/controldata_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/cryptohash_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/d2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/encnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/f2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/fe_memutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_perm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hashfn.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hmac_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/ip.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/jsonapi.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/keywords.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/kwlookup.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/link-canary.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/logging.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/md5_common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/percentrepl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_get_line.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_lzcompress.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_prng.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pgfnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/protocol_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/psprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/relpath.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/restricted_token.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/rmtree.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/saslprep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/scram-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/sprompt.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/string.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/stringinfo.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/unicode_norm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/username.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wait_error.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wchar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-print.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/bsearch_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/chklocale.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/getpeereid.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/inet_net_ntop.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/noblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/path.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_bitutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sb8.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_strong_random.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgcheckdir.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgmkdirp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgsleep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrcasecmp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pqsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/quotes.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/snprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/strerror.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/tar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/thread.c +) diff --git a/contrib/libs/libpq/CMakeLists.linux-x86_64.txt b/contrib/libs/libpq/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..108f48a475 --- /dev/null +++ b/contrib/libs/libpq/CMakeLists.linux-x86_64.txt @@ -0,0 +1,115 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(contrib-libs-libpq) +target_compile_options(contrib-libs-libpq PRIVATE + -DFRONTEND + -DUNSAFE_STAT_OK + -D_POSIX_PTHREAD_SEMANTICS + -D_REENTRANT + -D_THREAD_SAFE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-libpq PUBLIC + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/include +) +target_include_directories(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/backend + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port +) +target_link_libraries(contrib-libs-libpq PUBLIC + contrib-libs-linux-headers + contrib-libs-libc_compat + contrib-libs-openssl + contrib-libs-zlib +) +target_sources(contrib-libs-libpq PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/archive.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/base64.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/checksum_helper.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/compression.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/config_info.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/controldata_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/cryptohash_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/d2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/encnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/f2s.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/fe_memutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_perm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/file_utils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hashfn.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/hmac_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/ip.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/jsonapi.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/keywords.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/kwlookup.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/link-canary.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/logging.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/md5_common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/percentrepl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_get_line.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_lzcompress.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pg_prng.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/pgfnames.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/protocol_openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/psprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/relpath.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/restricted_token.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/rmtree.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/saslprep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/scram-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/sprompt.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/string.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/stringinfo.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/unicode_norm.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/username.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wait_error.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/common/wchar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-print.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/bsearch_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/chklocale.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/getpeereid.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/inet_net_ntop.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/noblock.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/path.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_bitutils.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sb8.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_strong_random.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgcheckdir.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgmkdirp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgsleep.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrcasecmp.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pgstrsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pqsignal.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/qsort_arg.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/quotes.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/snprintf.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/strerror.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/tar.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/thread.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sse42.c + ${CMAKE_SOURCE_DIR}/contrib/libs/libpq/src/port/pg_crc32c_sse42_choose.c +) diff --git a/contrib/libs/libpq/CMakeLists.txt b/contrib/libs/libpq/CMakeLists.txt new file mode 100644 index 0000000000..1beba2829f --- /dev/null +++ b/contrib/libs/libpq/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + include(CMakeLists.darwin-arm64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/contrib/libs/libpq/COPYRIGHT b/contrib/libs/libpq/COPYRIGHT new file mode 100644 index 0000000000..d33e0f599d --- /dev/null +++ b/contrib/libs/libpq/COPYRIGHT @@ -0,0 +1,23 @@ +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/contrib/libs/libpq/README b/contrib/libs/libpq/README new file mode 100644 index 0000000000..6416a8cf3b --- /dev/null +++ b/contrib/libs/libpq/README @@ -0,0 +1,27 @@ +PostgreSQL Database Management System +===================================== + +This directory contains the source code distribution of the PostgreSQL +database management system. + +PostgreSQL is an advanced object-relational database management system +that supports an extended subset of the SQL standard, including +transactions, foreign keys, subqueries, triggers, user-defined types +and functions. This distribution also contains C language bindings. + +PostgreSQL has many language interfaces, many of which are listed here: + + https://www.postgresql.org/download/ + +See the file INSTALL for instructions on how to build and install +PostgreSQL. That file also lists supported operating systems and +hardware platforms and contains information regarding any other +software packages that are required to build or run the PostgreSQL +system. Copyright and license information can be found in the +file COPYRIGHT. A comprehensive documentation set is included in this +distribution; it can be read as described in the installation +instructions. + +The latest version of this software may be obtained at +https://www.postgresql.org/download/. For more information look at our +web site located at https://www.postgresql.org/. diff --git a/contrib/libs/libpq/README.git b/contrib/libs/libpq/README.git new file mode 100644 index 0000000000..4bf614eea4 --- /dev/null +++ b/contrib/libs/libpq/README.git @@ -0,0 +1,14 @@ +(This file does not appear in release tarballs.) + +In a release or snapshot tarball of PostgreSQL, a documentation file named +INSTALL will appear in this directory. However, this file is not stored in +git and so will not be present if you are using a git checkout. + +If you are using a git checkout, you can view the most recent installation +instructions at: + https://www.postgresql.org/docs/devel/installation.html + +Users compiling from git will also need compatible versions of Bison, Flex, +and Perl, as discussed in the install documentation. These programs are not +needed when using a tarball, since the files they are needed to build are +already present in the tarball. (On Windows, however, you need Perl anyway.) diff --git a/contrib/libs/libpq/src/backend/catalog/pg_tablespace_d.h b/contrib/libs/libpq/src/backend/catalog/pg_tablespace_d.h new file mode 100644 index 0000000000..064e58d758 --- /dev/null +++ b/contrib/libs/libpq/src/backend/catalog/pg_tablespace_d.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * pg_tablespace_d.h + * Macro definitions for pg_tablespace + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/backend/catalog/genbki.pl + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TABLESPACE_D_H +#define PG_TABLESPACE_D_H + +#define TableSpaceRelationId 1213 +#define PgTablespaceToastTable 4185 +#define PgTablespaceToastIndex 4186 +#define TablespaceOidIndexId 2697 +#define TablespaceNameIndexId 2698 + +#define Anum_pg_tablespace_oid 1 +#define Anum_pg_tablespace_spcname 2 +#define Anum_pg_tablespace_spcowner 3 +#define Anum_pg_tablespace_spcacl 4 +#define Anum_pg_tablespace_spcoptions 5 + +#define Natts_pg_tablespace 5 + +#define DEFAULTTABLESPACE_OID 1663 +#define GLOBALTABLESPACE_OID 1664 + +#endif /* PG_TABLESPACE_D_H */ diff --git a/contrib/libs/libpq/src/backend/utils/README.Gen_dummy_probes b/contrib/libs/libpq/src/backend/utils/README.Gen_dummy_probes new file mode 100644 index 0000000000..e17060ef24 --- /dev/null +++ b/contrib/libs/libpq/src/backend/utils/README.Gen_dummy_probes @@ -0,0 +1,27 @@ +# Generating dummy probes + +If Postgres isn't configured with dtrace enabled, we need to generate +dummy probes for the entries in probes.d, that do nothing. + +This is accomplished in Unix via the sed script `Gen_dummy_probes.sed`. We +used to use this in MSVC builds using the perl utility `psed`, which mimicked +sed. However, that utility disappeared from Windows perl distributions and so +we converted the sed script to a perl script to be used in MSVC builds. + +We still keep the sed script as the authoritative source for generating +these dummy probes because except on Windows perl is not a hard requirement +when building from a tarball. + +So, if you need to change the way dummy probes are generated, first change +the sed script, and when it's working generate the perl script. This can +be accomplished by using the perl utility s2p. + +s2p is no longer part of the perl core, so it might not be on your system, +but it is available on CPAN and also in many package systems. e.g. +on Fedora it can be installed using `cpan App::s2p` or +`dnf install perl-App-s2p`. + +The Makefile contains a recipe for regenerating Gen_dummy_probes.pl, so all +you need to do is once you have s2p installed is `make Gen_dummy_probes.pl` +Note that in a VPATH build this will generate the file in the vpath tree, +not the source tree. diff --git a/contrib/libs/libpq/src/backend/utils/errcodes.h b/contrib/libs/libpq/src/backend/utils/errcodes.h new file mode 100644 index 0000000000..a2f604c2fa --- /dev/null +++ b/contrib/libs/libpq/src/backend/utils/errcodes.h @@ -0,0 +1,354 @@ +/* autogenerated from src/backend/utils/errcodes.txt, do not edit */ +/* there is deliberately not an #ifndef ERRCODES_H here */ + +/* Class 00 - Successful Completion */ +#define ERRCODE_SUCCESSFUL_COMPLETION MAKE_SQLSTATE('0','0','0','0','0') + +/* Class 01 - Warning */ +#define ERRCODE_WARNING MAKE_SQLSTATE('0','1','0','0','0') +#define ERRCODE_WARNING_DYNAMIC_RESULT_SETS_RETURNED MAKE_SQLSTATE('0','1','0','0','C') +#define ERRCODE_WARNING_IMPLICIT_ZERO_BIT_PADDING MAKE_SQLSTATE('0','1','0','0','8') +#define ERRCODE_WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION MAKE_SQLSTATE('0','1','0','0','3') +#define ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED MAKE_SQLSTATE('0','1','0','0','7') +#define ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED MAKE_SQLSTATE('0','1','0','0','6') +#define ERRCODE_WARNING_STRING_DATA_RIGHT_TRUNCATION MAKE_SQLSTATE('0','1','0','0','4') +#define ERRCODE_WARNING_DEPRECATED_FEATURE MAKE_SQLSTATE('0','1','P','0','1') + +/* Class 02 - No Data (this is also a warning class per the SQL standard) */ +#define ERRCODE_NO_DATA MAKE_SQLSTATE('0','2','0','0','0') +#define ERRCODE_NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED MAKE_SQLSTATE('0','2','0','0','1') + +/* Class 03 - SQL Statement Not Yet Complete */ +#define ERRCODE_SQL_STATEMENT_NOT_YET_COMPLETE MAKE_SQLSTATE('0','3','0','0','0') + +/* Class 08 - Connection Exception */ +#define ERRCODE_CONNECTION_EXCEPTION MAKE_SQLSTATE('0','8','0','0','0') +#define ERRCODE_CONNECTION_DOES_NOT_EXIST MAKE_SQLSTATE('0','8','0','0','3') +#define ERRCODE_CONNECTION_FAILURE MAKE_SQLSTATE('0','8','0','0','6') +#define ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION MAKE_SQLSTATE('0','8','0','0','1') +#define ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION MAKE_SQLSTATE('0','8','0','0','4') +#define ERRCODE_TRANSACTION_RESOLUTION_UNKNOWN MAKE_SQLSTATE('0','8','0','0','7') +#define ERRCODE_PROTOCOL_VIOLATION MAKE_SQLSTATE('0','8','P','0','1') + +/* Class 09 - Triggered Action Exception */ +#define ERRCODE_TRIGGERED_ACTION_EXCEPTION MAKE_SQLSTATE('0','9','0','0','0') + +/* Class 0A - Feature Not Supported */ +#define ERRCODE_FEATURE_NOT_SUPPORTED MAKE_SQLSTATE('0','A','0','0','0') + +/* Class 0B - Invalid Transaction Initiation */ +#define ERRCODE_INVALID_TRANSACTION_INITIATION MAKE_SQLSTATE('0','B','0','0','0') + +/* Class 0F - Locator Exception */ +#define ERRCODE_LOCATOR_EXCEPTION MAKE_SQLSTATE('0','F','0','0','0') +#define ERRCODE_L_E_INVALID_SPECIFICATION MAKE_SQLSTATE('0','F','0','0','1') + +/* Class 0L - Invalid Grantor */ +#define ERRCODE_INVALID_GRANTOR MAKE_SQLSTATE('0','L','0','0','0') +#define ERRCODE_INVALID_GRANT_OPERATION MAKE_SQLSTATE('0','L','P','0','1') + +/* Class 0P - Invalid Role Specification */ +#define ERRCODE_INVALID_ROLE_SPECIFICATION MAKE_SQLSTATE('0','P','0','0','0') + +/* Class 0Z - Diagnostics Exception */ +#define ERRCODE_DIAGNOSTICS_EXCEPTION MAKE_SQLSTATE('0','Z','0','0','0') +#define ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER MAKE_SQLSTATE('0','Z','0','0','2') + +/* Class 20 - Case Not Found */ +#define ERRCODE_CASE_NOT_FOUND MAKE_SQLSTATE('2','0','0','0','0') + +/* Class 21 - Cardinality Violation */ +#define ERRCODE_CARDINALITY_VIOLATION MAKE_SQLSTATE('2','1','0','0','0') + +/* Class 22 - Data Exception */ +#define ERRCODE_DATA_EXCEPTION MAKE_SQLSTATE('2','2','0','0','0') +#define ERRCODE_ARRAY_ELEMENT_ERROR MAKE_SQLSTATE('2','2','0','2','E') +#define ERRCODE_ARRAY_SUBSCRIPT_ERROR MAKE_SQLSTATE('2','2','0','2','E') +#define ERRCODE_CHARACTER_NOT_IN_REPERTOIRE MAKE_SQLSTATE('2','2','0','2','1') +#define ERRCODE_DATETIME_FIELD_OVERFLOW MAKE_SQLSTATE('2','2','0','0','8') +#define ERRCODE_DATETIME_VALUE_OUT_OF_RANGE MAKE_SQLSTATE('2','2','0','0','8') +#define ERRCODE_DIVISION_BY_ZERO MAKE_SQLSTATE('2','2','0','1','2') +#define ERRCODE_ERROR_IN_ASSIGNMENT MAKE_SQLSTATE('2','2','0','0','5') +#define ERRCODE_ESCAPE_CHARACTER_CONFLICT MAKE_SQLSTATE('2','2','0','0','B') +#define ERRCODE_INDICATOR_OVERFLOW MAKE_SQLSTATE('2','2','0','2','2') +#define ERRCODE_INTERVAL_FIELD_OVERFLOW MAKE_SQLSTATE('2','2','0','1','5') +#define ERRCODE_INVALID_ARGUMENT_FOR_LOG MAKE_SQLSTATE('2','2','0','1','E') +#define ERRCODE_INVALID_ARGUMENT_FOR_NTILE MAKE_SQLSTATE('2','2','0','1','4') +#define ERRCODE_INVALID_ARGUMENT_FOR_NTH_VALUE MAKE_SQLSTATE('2','2','0','1','6') +#define ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION MAKE_SQLSTATE('2','2','0','1','F') +#define ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION MAKE_SQLSTATE('2','2','0','1','G') +#define ERRCODE_INVALID_CHARACTER_VALUE_FOR_CAST MAKE_SQLSTATE('2','2','0','1','8') +#define ERRCODE_INVALID_DATETIME_FORMAT MAKE_SQLSTATE('2','2','0','0','7') +#define ERRCODE_INVALID_ESCAPE_CHARACTER MAKE_SQLSTATE('2','2','0','1','9') +#define ERRCODE_INVALID_ESCAPE_OCTET MAKE_SQLSTATE('2','2','0','0','D') +#define ERRCODE_INVALID_ESCAPE_SEQUENCE MAKE_SQLSTATE('2','2','0','2','5') +#define ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER MAKE_SQLSTATE('2','2','P','0','6') +#define ERRCODE_INVALID_INDICATOR_PARAMETER_VALUE MAKE_SQLSTATE('2','2','0','1','0') +#define ERRCODE_INVALID_PARAMETER_VALUE MAKE_SQLSTATE('2','2','0','2','3') +#define ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE MAKE_SQLSTATE('2','2','0','1','3') +#define ERRCODE_INVALID_REGULAR_EXPRESSION MAKE_SQLSTATE('2','2','0','1','B') +#define ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE MAKE_SQLSTATE('2','2','0','1','W') +#define ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE MAKE_SQLSTATE('2','2','0','1','X') +#define ERRCODE_INVALID_TABLESAMPLE_ARGUMENT MAKE_SQLSTATE('2','2','0','2','H') +#define ERRCODE_INVALID_TABLESAMPLE_REPEAT MAKE_SQLSTATE('2','2','0','2','G') +#define ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE MAKE_SQLSTATE('2','2','0','0','9') +#define ERRCODE_INVALID_USE_OF_ESCAPE_CHARACTER MAKE_SQLSTATE('2','2','0','0','C') +#define ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH MAKE_SQLSTATE('2','2','0','0','G') +#define ERRCODE_NULL_VALUE_NOT_ALLOWED MAKE_SQLSTATE('2','2','0','0','4') +#define ERRCODE_NULL_VALUE_NO_INDICATOR_PARAMETER MAKE_SQLSTATE('2','2','0','0','2') +#define ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE MAKE_SQLSTATE('2','2','0','0','3') +#define ERRCODE_SEQUENCE_GENERATOR_LIMIT_EXCEEDED MAKE_SQLSTATE('2','2','0','0','H') +#define ERRCODE_STRING_DATA_LENGTH_MISMATCH MAKE_SQLSTATE('2','2','0','2','6') +#define ERRCODE_STRING_DATA_RIGHT_TRUNCATION MAKE_SQLSTATE('2','2','0','0','1') +#define ERRCODE_SUBSTRING_ERROR MAKE_SQLSTATE('2','2','0','1','1') +#define ERRCODE_TRIM_ERROR MAKE_SQLSTATE('2','2','0','2','7') +#define ERRCODE_UNTERMINATED_C_STRING MAKE_SQLSTATE('2','2','0','2','4') +#define ERRCODE_ZERO_LENGTH_CHARACTER_STRING MAKE_SQLSTATE('2','2','0','0','F') +#define ERRCODE_FLOATING_POINT_EXCEPTION MAKE_SQLSTATE('2','2','P','0','1') +#define ERRCODE_INVALID_TEXT_REPRESENTATION MAKE_SQLSTATE('2','2','P','0','2') +#define ERRCODE_INVALID_BINARY_REPRESENTATION MAKE_SQLSTATE('2','2','P','0','3') +#define ERRCODE_BAD_COPY_FILE_FORMAT MAKE_SQLSTATE('2','2','P','0','4') +#define ERRCODE_UNTRANSLATABLE_CHARACTER MAKE_SQLSTATE('2','2','P','0','5') +#define ERRCODE_NOT_AN_XML_DOCUMENT MAKE_SQLSTATE('2','2','0','0','L') +#define ERRCODE_INVALID_XML_DOCUMENT MAKE_SQLSTATE('2','2','0','0','M') +#define ERRCODE_INVALID_XML_CONTENT MAKE_SQLSTATE('2','2','0','0','N') +#define ERRCODE_INVALID_XML_COMMENT MAKE_SQLSTATE('2','2','0','0','S') +#define ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION MAKE_SQLSTATE('2','2','0','0','T') +#define ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE MAKE_SQLSTATE('2','2','0','3','0') +#define ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION MAKE_SQLSTATE('2','2','0','3','1') +#define ERRCODE_INVALID_JSON_TEXT MAKE_SQLSTATE('2','2','0','3','2') +#define ERRCODE_INVALID_SQL_JSON_SUBSCRIPT MAKE_SQLSTATE('2','2','0','3','3') +#define ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM MAKE_SQLSTATE('2','2','0','3','4') +#define ERRCODE_NO_SQL_JSON_ITEM MAKE_SQLSTATE('2','2','0','3','5') +#define ERRCODE_NON_NUMERIC_SQL_JSON_ITEM MAKE_SQLSTATE('2','2','0','3','6') +#define ERRCODE_NON_UNIQUE_KEYS_IN_A_JSON_OBJECT MAKE_SQLSTATE('2','2','0','3','7') +#define ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED MAKE_SQLSTATE('2','2','0','3','8') +#define ERRCODE_SQL_JSON_ARRAY_NOT_FOUND MAKE_SQLSTATE('2','2','0','3','9') +#define ERRCODE_SQL_JSON_MEMBER_NOT_FOUND MAKE_SQLSTATE('2','2','0','3','A') +#define ERRCODE_SQL_JSON_NUMBER_NOT_FOUND MAKE_SQLSTATE('2','2','0','3','B') +#define ERRCODE_SQL_JSON_OBJECT_NOT_FOUND MAKE_SQLSTATE('2','2','0','3','C') +#define ERRCODE_TOO_MANY_JSON_ARRAY_ELEMENTS MAKE_SQLSTATE('2','2','0','3','D') +#define ERRCODE_TOO_MANY_JSON_OBJECT_MEMBERS MAKE_SQLSTATE('2','2','0','3','E') +#define ERRCODE_SQL_JSON_SCALAR_REQUIRED MAKE_SQLSTATE('2','2','0','3','F') +#define ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE MAKE_SQLSTATE('2','2','0','3','G') + +/* Class 23 - Integrity Constraint Violation */ +#define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION MAKE_SQLSTATE('2','3','0','0','0') +#define ERRCODE_RESTRICT_VIOLATION MAKE_SQLSTATE('2','3','0','0','1') +#define ERRCODE_NOT_NULL_VIOLATION MAKE_SQLSTATE('2','3','5','0','2') +#define ERRCODE_FOREIGN_KEY_VIOLATION MAKE_SQLSTATE('2','3','5','0','3') +#define ERRCODE_UNIQUE_VIOLATION MAKE_SQLSTATE('2','3','5','0','5') +#define ERRCODE_CHECK_VIOLATION MAKE_SQLSTATE('2','3','5','1','4') +#define ERRCODE_EXCLUSION_VIOLATION MAKE_SQLSTATE('2','3','P','0','1') + +/* Class 24 - Invalid Cursor State */ +#define ERRCODE_INVALID_CURSOR_STATE MAKE_SQLSTATE('2','4','0','0','0') + +/* Class 25 - Invalid Transaction State */ +#define ERRCODE_INVALID_TRANSACTION_STATE MAKE_SQLSTATE('2','5','0','0','0') +#define ERRCODE_ACTIVE_SQL_TRANSACTION MAKE_SQLSTATE('2','5','0','0','1') +#define ERRCODE_BRANCH_TRANSACTION_ALREADY_ACTIVE MAKE_SQLSTATE('2','5','0','0','2') +#define ERRCODE_HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL MAKE_SQLSTATE('2','5','0','0','8') +#define ERRCODE_INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION MAKE_SQLSTATE('2','5','0','0','3') +#define ERRCODE_INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION MAKE_SQLSTATE('2','5','0','0','4') +#define ERRCODE_NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION MAKE_SQLSTATE('2','5','0','0','5') +#define ERRCODE_READ_ONLY_SQL_TRANSACTION MAKE_SQLSTATE('2','5','0','0','6') +#define ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED MAKE_SQLSTATE('2','5','0','0','7') +#define ERRCODE_NO_ACTIVE_SQL_TRANSACTION MAKE_SQLSTATE('2','5','P','0','1') +#define ERRCODE_IN_FAILED_SQL_TRANSACTION MAKE_SQLSTATE('2','5','P','0','2') +#define ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT MAKE_SQLSTATE('2','5','P','0','3') + +/* Class 26 - Invalid SQL Statement Name */ +#define ERRCODE_INVALID_SQL_STATEMENT_NAME MAKE_SQLSTATE('2','6','0','0','0') + +/* Class 27 - Triggered Data Change Violation */ +#define ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION MAKE_SQLSTATE('2','7','0','0','0') + +/* Class 28 - Invalid Authorization Specification */ +#define ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION MAKE_SQLSTATE('2','8','0','0','0') +#define ERRCODE_INVALID_PASSWORD MAKE_SQLSTATE('2','8','P','0','1') + +/* Class 2B - Dependent Privilege Descriptors Still Exist */ +#define ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST MAKE_SQLSTATE('2','B','0','0','0') +#define ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST MAKE_SQLSTATE('2','B','P','0','1') + +/* Class 2D - Invalid Transaction Termination */ +#define ERRCODE_INVALID_TRANSACTION_TERMINATION MAKE_SQLSTATE('2','D','0','0','0') + +/* Class 2F - SQL Routine Exception */ +#define ERRCODE_SQL_ROUTINE_EXCEPTION MAKE_SQLSTATE('2','F','0','0','0') +#define ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT MAKE_SQLSTATE('2','F','0','0','5') +#define ERRCODE_S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED MAKE_SQLSTATE('2','F','0','0','2') +#define ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED MAKE_SQLSTATE('2','F','0','0','3') +#define ERRCODE_S_R_E_READING_SQL_DATA_NOT_PERMITTED MAKE_SQLSTATE('2','F','0','0','4') + +/* Class 34 - Invalid Cursor Name */ +#define ERRCODE_INVALID_CURSOR_NAME MAKE_SQLSTATE('3','4','0','0','0') + +/* Class 38 - External Routine Exception */ +#define ERRCODE_EXTERNAL_ROUTINE_EXCEPTION MAKE_SQLSTATE('3','8','0','0','0') +#define ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED MAKE_SQLSTATE('3','8','0','0','1') +#define ERRCODE_E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED MAKE_SQLSTATE('3','8','0','0','2') +#define ERRCODE_E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED MAKE_SQLSTATE('3','8','0','0','3') +#define ERRCODE_E_R_E_READING_SQL_DATA_NOT_PERMITTED MAKE_SQLSTATE('3','8','0','0','4') + +/* Class 39 - External Routine Invocation Exception */ +#define ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION MAKE_SQLSTATE('3','9','0','0','0') +#define ERRCODE_E_R_I_E_INVALID_SQLSTATE_RETURNED MAKE_SQLSTATE('3','9','0','0','1') +#define ERRCODE_E_R_I_E_NULL_VALUE_NOT_ALLOWED MAKE_SQLSTATE('3','9','0','0','4') +#define ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED MAKE_SQLSTATE('3','9','P','0','1') +#define ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED MAKE_SQLSTATE('3','9','P','0','2') +#define ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED MAKE_SQLSTATE('3','9','P','0','3') + +/* Class 3B - Savepoint Exception */ +#define ERRCODE_SAVEPOINT_EXCEPTION MAKE_SQLSTATE('3','B','0','0','0') +#define ERRCODE_S_E_INVALID_SPECIFICATION MAKE_SQLSTATE('3','B','0','0','1') + +/* Class 3D - Invalid Catalog Name */ +#define ERRCODE_INVALID_CATALOG_NAME MAKE_SQLSTATE('3','D','0','0','0') + +/* Class 3F - Invalid Schema Name */ +#define ERRCODE_INVALID_SCHEMA_NAME MAKE_SQLSTATE('3','F','0','0','0') + +/* Class 40 - Transaction Rollback */ +#define ERRCODE_TRANSACTION_ROLLBACK MAKE_SQLSTATE('4','0','0','0','0') +#define ERRCODE_T_R_INTEGRITY_CONSTRAINT_VIOLATION MAKE_SQLSTATE('4','0','0','0','2') +#define ERRCODE_T_R_SERIALIZATION_FAILURE MAKE_SQLSTATE('4','0','0','0','1') +#define ERRCODE_T_R_STATEMENT_COMPLETION_UNKNOWN MAKE_SQLSTATE('4','0','0','0','3') +#define ERRCODE_T_R_DEADLOCK_DETECTED MAKE_SQLSTATE('4','0','P','0','1') + +/* Class 42 - Syntax Error or Access Rule Violation */ +#define ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION MAKE_SQLSTATE('4','2','0','0','0') +#define ERRCODE_SYNTAX_ERROR MAKE_SQLSTATE('4','2','6','0','1') +#define ERRCODE_INSUFFICIENT_PRIVILEGE MAKE_SQLSTATE('4','2','5','0','1') +#define ERRCODE_CANNOT_COERCE MAKE_SQLSTATE('4','2','8','4','6') +#define ERRCODE_GROUPING_ERROR MAKE_SQLSTATE('4','2','8','0','3') +#define ERRCODE_WINDOWING_ERROR MAKE_SQLSTATE('4','2','P','2','0') +#define ERRCODE_INVALID_RECURSION MAKE_SQLSTATE('4','2','P','1','9') +#define ERRCODE_INVALID_FOREIGN_KEY MAKE_SQLSTATE('4','2','8','3','0') +#define ERRCODE_INVALID_NAME MAKE_SQLSTATE('4','2','6','0','2') +#define ERRCODE_NAME_TOO_LONG MAKE_SQLSTATE('4','2','6','2','2') +#define ERRCODE_RESERVED_NAME MAKE_SQLSTATE('4','2','9','3','9') +#define ERRCODE_DATATYPE_MISMATCH MAKE_SQLSTATE('4','2','8','0','4') +#define ERRCODE_INDETERMINATE_DATATYPE MAKE_SQLSTATE('4','2','P','1','8') +#define ERRCODE_COLLATION_MISMATCH MAKE_SQLSTATE('4','2','P','2','1') +#define ERRCODE_INDETERMINATE_COLLATION MAKE_SQLSTATE('4','2','P','2','2') +#define ERRCODE_WRONG_OBJECT_TYPE MAKE_SQLSTATE('4','2','8','0','9') +#define ERRCODE_GENERATED_ALWAYS MAKE_SQLSTATE('4','2','8','C','9') +#define ERRCODE_UNDEFINED_COLUMN MAKE_SQLSTATE('4','2','7','0','3') +#define ERRCODE_UNDEFINED_CURSOR MAKE_SQLSTATE('3','4','0','0','0') +#define ERRCODE_UNDEFINED_DATABASE MAKE_SQLSTATE('3','D','0','0','0') +#define ERRCODE_UNDEFINED_FUNCTION MAKE_SQLSTATE('4','2','8','8','3') +#define ERRCODE_UNDEFINED_PSTATEMENT MAKE_SQLSTATE('2','6','0','0','0') +#define ERRCODE_UNDEFINED_SCHEMA MAKE_SQLSTATE('3','F','0','0','0') +#define ERRCODE_UNDEFINED_TABLE MAKE_SQLSTATE('4','2','P','0','1') +#define ERRCODE_UNDEFINED_PARAMETER MAKE_SQLSTATE('4','2','P','0','2') +#define ERRCODE_UNDEFINED_OBJECT MAKE_SQLSTATE('4','2','7','0','4') +#define ERRCODE_DUPLICATE_COLUMN MAKE_SQLSTATE('4','2','7','0','1') +#define ERRCODE_DUPLICATE_CURSOR MAKE_SQLSTATE('4','2','P','0','3') +#define ERRCODE_DUPLICATE_DATABASE MAKE_SQLSTATE('4','2','P','0','4') +#define ERRCODE_DUPLICATE_FUNCTION MAKE_SQLSTATE('4','2','7','2','3') +#define ERRCODE_DUPLICATE_PSTATEMENT MAKE_SQLSTATE('4','2','P','0','5') +#define ERRCODE_DUPLICATE_SCHEMA MAKE_SQLSTATE('4','2','P','0','6') +#define ERRCODE_DUPLICATE_TABLE MAKE_SQLSTATE('4','2','P','0','7') +#define ERRCODE_DUPLICATE_ALIAS MAKE_SQLSTATE('4','2','7','1','2') +#define ERRCODE_DUPLICATE_OBJECT MAKE_SQLSTATE('4','2','7','1','0') +#define ERRCODE_AMBIGUOUS_COLUMN MAKE_SQLSTATE('4','2','7','0','2') +#define ERRCODE_AMBIGUOUS_FUNCTION MAKE_SQLSTATE('4','2','7','2','5') +#define ERRCODE_AMBIGUOUS_PARAMETER MAKE_SQLSTATE('4','2','P','0','8') +#define ERRCODE_AMBIGUOUS_ALIAS MAKE_SQLSTATE('4','2','P','0','9') +#define ERRCODE_INVALID_COLUMN_REFERENCE MAKE_SQLSTATE('4','2','P','1','0') +#define ERRCODE_INVALID_COLUMN_DEFINITION MAKE_SQLSTATE('4','2','6','1','1') +#define ERRCODE_INVALID_CURSOR_DEFINITION MAKE_SQLSTATE('4','2','P','1','1') +#define ERRCODE_INVALID_DATABASE_DEFINITION MAKE_SQLSTATE('4','2','P','1','2') +#define ERRCODE_INVALID_FUNCTION_DEFINITION MAKE_SQLSTATE('4','2','P','1','3') +#define ERRCODE_INVALID_PSTATEMENT_DEFINITION MAKE_SQLSTATE('4','2','P','1','4') +#define ERRCODE_INVALID_SCHEMA_DEFINITION MAKE_SQLSTATE('4','2','P','1','5') +#define ERRCODE_INVALID_TABLE_DEFINITION MAKE_SQLSTATE('4','2','P','1','6') +#define ERRCODE_INVALID_OBJECT_DEFINITION MAKE_SQLSTATE('4','2','P','1','7') + +/* Class 44 - WITH CHECK OPTION Violation */ +#define ERRCODE_WITH_CHECK_OPTION_VIOLATION MAKE_SQLSTATE('4','4','0','0','0') + +/* Class 53 - Insufficient Resources */ +#define ERRCODE_INSUFFICIENT_RESOURCES MAKE_SQLSTATE('5','3','0','0','0') +#define ERRCODE_DISK_FULL MAKE_SQLSTATE('5','3','1','0','0') +#define ERRCODE_OUT_OF_MEMORY MAKE_SQLSTATE('5','3','2','0','0') +#define ERRCODE_TOO_MANY_CONNECTIONS MAKE_SQLSTATE('5','3','3','0','0') +#define ERRCODE_CONFIGURATION_LIMIT_EXCEEDED MAKE_SQLSTATE('5','3','4','0','0') + +/* Class 54 - Program Limit Exceeded */ +#define ERRCODE_PROGRAM_LIMIT_EXCEEDED MAKE_SQLSTATE('5','4','0','0','0') +#define ERRCODE_STATEMENT_TOO_COMPLEX MAKE_SQLSTATE('5','4','0','0','1') +#define ERRCODE_TOO_MANY_COLUMNS MAKE_SQLSTATE('5','4','0','1','1') +#define ERRCODE_TOO_MANY_ARGUMENTS MAKE_SQLSTATE('5','4','0','2','3') + +/* Class 55 - Object Not In Prerequisite State */ +#define ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE MAKE_SQLSTATE('5','5','0','0','0') +#define ERRCODE_OBJECT_IN_USE MAKE_SQLSTATE('5','5','0','0','6') +#define ERRCODE_CANT_CHANGE_RUNTIME_PARAM MAKE_SQLSTATE('5','5','P','0','2') +#define ERRCODE_LOCK_NOT_AVAILABLE MAKE_SQLSTATE('5','5','P','0','3') +#define ERRCODE_UNSAFE_NEW_ENUM_VALUE_USAGE MAKE_SQLSTATE('5','5','P','0','4') + +/* Class 57 - Operator Intervention */ +#define ERRCODE_OPERATOR_INTERVENTION MAKE_SQLSTATE('5','7','0','0','0') +#define ERRCODE_QUERY_CANCELED MAKE_SQLSTATE('5','7','0','1','4') +#define ERRCODE_ADMIN_SHUTDOWN MAKE_SQLSTATE('5','7','P','0','1') +#define ERRCODE_CRASH_SHUTDOWN MAKE_SQLSTATE('5','7','P','0','2') +#define ERRCODE_CANNOT_CONNECT_NOW MAKE_SQLSTATE('5','7','P','0','3') +#define ERRCODE_DATABASE_DROPPED MAKE_SQLSTATE('5','7','P','0','4') +#define ERRCODE_IDLE_SESSION_TIMEOUT MAKE_SQLSTATE('5','7','P','0','5') + +/* Class 58 - System Error (errors external to PostgreSQL itself) */ +#define ERRCODE_SYSTEM_ERROR MAKE_SQLSTATE('5','8','0','0','0') +#define ERRCODE_IO_ERROR MAKE_SQLSTATE('5','8','0','3','0') +#define ERRCODE_UNDEFINED_FILE MAKE_SQLSTATE('5','8','P','0','1') +#define ERRCODE_DUPLICATE_FILE MAKE_SQLSTATE('5','8','P','0','2') + +/* Class 72 - Snapshot Failure */ +#define ERRCODE_SNAPSHOT_TOO_OLD MAKE_SQLSTATE('7','2','0','0','0') + +/* Class F0 - Configuration File Error */ +#define ERRCODE_CONFIG_FILE_ERROR MAKE_SQLSTATE('F','0','0','0','0') +#define ERRCODE_LOCK_FILE_EXISTS MAKE_SQLSTATE('F','0','0','0','1') + +/* Class HV - Foreign Data Wrapper Error (SQL/MED) */ +#define ERRCODE_FDW_ERROR MAKE_SQLSTATE('H','V','0','0','0') +#define ERRCODE_FDW_COLUMN_NAME_NOT_FOUND MAKE_SQLSTATE('H','V','0','0','5') +#define ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED MAKE_SQLSTATE('H','V','0','0','2') +#define ERRCODE_FDW_FUNCTION_SEQUENCE_ERROR MAKE_SQLSTATE('H','V','0','1','0') +#define ERRCODE_FDW_INCONSISTENT_DESCRIPTOR_INFORMATION MAKE_SQLSTATE('H','V','0','2','1') +#define ERRCODE_FDW_INVALID_ATTRIBUTE_VALUE MAKE_SQLSTATE('H','V','0','2','4') +#define ERRCODE_FDW_INVALID_COLUMN_NAME MAKE_SQLSTATE('H','V','0','0','7') +#define ERRCODE_FDW_INVALID_COLUMN_NUMBER MAKE_SQLSTATE('H','V','0','0','8') +#define ERRCODE_FDW_INVALID_DATA_TYPE MAKE_SQLSTATE('H','V','0','0','4') +#define ERRCODE_FDW_INVALID_DATA_TYPE_DESCRIPTORS MAKE_SQLSTATE('H','V','0','0','6') +#define ERRCODE_FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER MAKE_SQLSTATE('H','V','0','9','1') +#define ERRCODE_FDW_INVALID_HANDLE MAKE_SQLSTATE('H','V','0','0','B') +#define ERRCODE_FDW_INVALID_OPTION_INDEX MAKE_SQLSTATE('H','V','0','0','C') +#define ERRCODE_FDW_INVALID_OPTION_NAME MAKE_SQLSTATE('H','V','0','0','D') +#define ERRCODE_FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH MAKE_SQLSTATE('H','V','0','9','0') +#define ERRCODE_FDW_INVALID_STRING_FORMAT MAKE_SQLSTATE('H','V','0','0','A') +#define ERRCODE_FDW_INVALID_USE_OF_NULL_POINTER MAKE_SQLSTATE('H','V','0','0','9') +#define ERRCODE_FDW_TOO_MANY_HANDLES MAKE_SQLSTATE('H','V','0','1','4') +#define ERRCODE_FDW_OUT_OF_MEMORY MAKE_SQLSTATE('H','V','0','0','1') +#define ERRCODE_FDW_NO_SCHEMAS MAKE_SQLSTATE('H','V','0','0','P') +#define ERRCODE_FDW_OPTION_NAME_NOT_FOUND MAKE_SQLSTATE('H','V','0','0','J') +#define ERRCODE_FDW_REPLY_HANDLE MAKE_SQLSTATE('H','V','0','0','K') +#define ERRCODE_FDW_SCHEMA_NOT_FOUND MAKE_SQLSTATE('H','V','0','0','Q') +#define ERRCODE_FDW_TABLE_NOT_FOUND MAKE_SQLSTATE('H','V','0','0','R') +#define ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION MAKE_SQLSTATE('H','V','0','0','L') +#define ERRCODE_FDW_UNABLE_TO_CREATE_REPLY MAKE_SQLSTATE('H','V','0','0','M') +#define ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION MAKE_SQLSTATE('H','V','0','0','N') + +/* Class P0 - PL/pgSQL Error */ +#define ERRCODE_PLPGSQL_ERROR MAKE_SQLSTATE('P','0','0','0','0') +#define ERRCODE_RAISE_EXCEPTION MAKE_SQLSTATE('P','0','0','0','1') +#define ERRCODE_NO_DATA_FOUND MAKE_SQLSTATE('P','0','0','0','2') +#define ERRCODE_TOO_MANY_ROWS MAKE_SQLSTATE('P','0','0','0','3') +#define ERRCODE_ASSERT_FAILURE MAKE_SQLSTATE('P','0','0','0','4') + +/* Class XX - Internal Error */ +#define ERRCODE_INTERNAL_ERROR MAKE_SQLSTATE('X','X','0','0','0') +#define ERRCODE_DATA_CORRUPTED MAKE_SQLSTATE('X','X','0','0','1') +#define ERRCODE_INDEX_CORRUPTED MAKE_SQLSTATE('X','X','0','0','2') diff --git a/contrib/libs/libpq/src/common/archive.c b/contrib/libs/libpq/src/common/archive.c new file mode 100644 index 0000000000..641a58ee88 --- /dev/null +++ b/contrib/libs/libpq/src/common/archive.c @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * archive.c + * Common WAL archive routines + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/archive.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/archive.h" +#include "common/percentrepl.h" + +/* + * BuildRestoreCommand + * + * Builds a restore command to retrieve a file from WAL archives, replacing + * the supported aliases with values supplied by the caller as defined by + * the GUC parameter restore_command: xlogpath for %p, xlogfname for %f and + * lastRestartPointFname for %r. + * + * The result is a palloc'd string for the restore command built. The + * caller is responsible for freeing it. If any of the required arguments + * is NULL and that the corresponding alias is found in the command given + * by the caller, then an error is thrown. + */ +char * +BuildRestoreCommand(const char *restoreCommand, + const char *xlogpath, + const char *xlogfname, + const char *lastRestartPointFname) +{ + char *nativePath = NULL; + char *result; + + if (xlogpath) + { + nativePath = pstrdup(xlogpath); + make_native_path(nativePath); + } + + result = replace_percent_placeholders(restoreCommand, "restore_command", "frp", + xlogfname, lastRestartPointFname, nativePath); + + if (nativePath) + pfree(nativePath); + + return result; +} diff --git a/contrib/libs/libpq/src/common/base64.c b/contrib/libs/libpq/src/common/base64.c new file mode 100644 index 0000000000..ec4eb49382 --- /dev/null +++ b/contrib/libs/libpq/src/common/base64.c @@ -0,0 +1,242 @@ +/*------------------------------------------------------------------------- + * + * base64.c + * Encoding and decoding routines for base64 without whitespace. + * + * Copyright (c) 2001-2023, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/common/base64.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/base64.h" + +/* + * BASE64 + */ + +static const char _base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const int8 b64lookup[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, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, +}; + +/* + * pg_b64_encode + * + * Encode into base64 the given string. Returns the length of the encoded + * string, and -1 in the event of an error with the result buffer zeroed + * for safety. + */ +int +pg_b64_encode(const char *src, int len, char *dst, int dstlen) +{ + char *p; + const char *s, + *end = src + len; + int pos = 2; + uint32 buf = 0; + + s = src; + p = dst; + + while (s < end) + { + buf |= (unsigned char) *s << (pos << 3); + pos--; + s++; + + /* write it out */ + if (pos < 0) + { + /* + * Leave if there is an overflow in the area allocated for the + * encoded string. + */ + if ((p - dst + 4) > dstlen) + goto error; + + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = _base64[(buf >> 6) & 0x3f]; + *p++ = _base64[buf & 0x3f]; + + pos = 2; + buf = 0; + } + } + if (pos != 2) + { + /* + * Leave if there is an overflow in the area allocated for the encoded + * string. + */ + if ((p - dst + 4) > dstlen) + goto error; + + *p++ = _base64[(buf >> 18) & 0x3f]; + *p++ = _base64[(buf >> 12) & 0x3f]; + *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '='; + *p++ = '='; + } + + Assert((p - dst) <= dstlen); + return p - dst; + +error: + memset(dst, 0, dstlen); + return -1; +} + +/* + * pg_b64_decode + * + * Decode the given base64 string. Returns the length of the decoded + * string on success, and -1 in the event of an error with the result + * buffer zeroed for safety. + */ +int +pg_b64_decode(const char *src, int len, char *dst, int dstlen) +{ + const char *srcend = src + len, + *s = src; + char *p = dst; + char c; + int b = 0; + uint32 buf = 0; + int pos = 0, + end = 0; + + while (s < srcend) + { + c = *s++; + + /* Leave if a whitespace is found */ + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + goto error; + + if (c == '=') + { + /* end sequence */ + if (!end) + { + if (pos == 2) + end = 1; + else if (pos == 3) + end = 2; + else + { + /* + * Unexpected "=" character found while decoding base64 + * sequence. + */ + goto error; + } + } + b = 0; + } + else + { + b = -1; + if (c > 0 && c < 127) + b = b64lookup[(unsigned char) c]; + if (b < 0) + { + /* invalid symbol found */ + goto error; + } + } + /* add it to buffer */ + buf = (buf << 6) + b; + pos++; + if (pos == 4) + { + /* + * Leave if there is an overflow in the area allocated for the + * decoded string. + */ + if ((p - dst + 1) > dstlen) + goto error; + *p++ = (buf >> 16) & 255; + + if (end == 0 || end > 1) + { + /* overflow check */ + if ((p - dst + 1) > dstlen) + goto error; + *p++ = (buf >> 8) & 255; + } + if (end == 0 || end > 2) + { + /* overflow check */ + if ((p - dst + 1) > dstlen) + goto error; + *p++ = buf & 255; + } + buf = 0; + pos = 0; + } + } + + if (pos != 0) + { + /* + * base64 end sequence is invalid. Input data is missing padding, is + * truncated or is otherwise corrupted. + */ + goto error; + } + + Assert((p - dst) <= dstlen); + return p - dst; + +error: + memset(dst, 0, dstlen); + return -1; +} + +/* + * pg_b64_enc_len + * + * Returns to caller the length of the string if it were encoded with + * base64 based on the length provided by caller. This is useful to + * estimate how large a buffer allocation needs to be done before doing + * the actual encoding. + */ +int +pg_b64_enc_len(int srclen) +{ + /* 3 bytes will be converted to 4 */ + return (srclen + 2) / 3 * 4; +} + +/* + * pg_b64_dec_len + * + * Returns to caller the length of the string if it were to be decoded + * with base64, based on the length given by caller. This is useful to + * estimate how large a buffer allocation needs to be done before doing + * the actual decoding. + */ +int +pg_b64_dec_len(int srclen) +{ + return (srclen * 3) >> 2; +} diff --git a/contrib/libs/libpq/src/common/checksum_helper.c b/contrib/libs/libpq/src/common/checksum_helper.c new file mode 100644 index 0000000000..21ff8954fd --- /dev/null +++ b/contrib/libs/libpq/src/common/checksum_helper.c @@ -0,0 +1,232 @@ +/*------------------------------------------------------------------------- + * + * checksum_helper.c + * Compute a checksum of any of various types using common routines + * + * Portions Copyright (c) 2016-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/checksum_helper.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/checksum_helper.h" + +/* + * If 'name' is a recognized checksum type, set *type to the corresponding + * constant and return true. Otherwise, set *type to CHECKSUM_TYPE_NONE and + * return false. + */ +bool +pg_checksum_parse_type(char *name, pg_checksum_type *type) +{ + pg_checksum_type result_type = CHECKSUM_TYPE_NONE; + bool result = true; + + if (pg_strcasecmp(name, "none") == 0) + result_type = CHECKSUM_TYPE_NONE; + else if (pg_strcasecmp(name, "crc32c") == 0) + result_type = CHECKSUM_TYPE_CRC32C; + else if (pg_strcasecmp(name, "sha224") == 0) + result_type = CHECKSUM_TYPE_SHA224; + else if (pg_strcasecmp(name, "sha256") == 0) + result_type = CHECKSUM_TYPE_SHA256; + else if (pg_strcasecmp(name, "sha384") == 0) + result_type = CHECKSUM_TYPE_SHA384; + else if (pg_strcasecmp(name, "sha512") == 0) + result_type = CHECKSUM_TYPE_SHA512; + else + result = false; + + *type = result_type; + return result; +} + +/* + * Get the canonical human-readable name corresponding to a checksum type. + */ +char * +pg_checksum_type_name(pg_checksum_type type) +{ + switch (type) + { + case CHECKSUM_TYPE_NONE: + return "NONE"; + case CHECKSUM_TYPE_CRC32C: + return "CRC32C"; + case CHECKSUM_TYPE_SHA224: + return "SHA224"; + case CHECKSUM_TYPE_SHA256: + return "SHA256"; + case CHECKSUM_TYPE_SHA384: + return "SHA384"; + case CHECKSUM_TYPE_SHA512: + return "SHA512"; + } + + Assert(false); + return "???"; +} + +/* + * Initialize a checksum context for checksums of the given type. + * Returns 0 for a success, -1 for a failure. + */ +int +pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) +{ + context->type = type; + + switch (type) + { + case CHECKSUM_TYPE_NONE: + /* do nothing */ + break; + case CHECKSUM_TYPE_CRC32C: + INIT_CRC32C(context->raw_context.c_crc32c); + break; + case CHECKSUM_TYPE_SHA224: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA256: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA384: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA512: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + } + + return 0; +} + +/* + * Update a checksum context with new data. + * Returns 0 for a success, -1 for a failure. + */ +int +pg_checksum_update(pg_checksum_context *context, const uint8 *input, + size_t len) +{ + switch (context->type) + { + case CHECKSUM_TYPE_NONE: + /* do nothing */ + break; + case CHECKSUM_TYPE_CRC32C: + COMP_CRC32C(context->raw_context.c_crc32c, input, len); + break; + case CHECKSUM_TYPE_SHA224: + case CHECKSUM_TYPE_SHA256: + case CHECKSUM_TYPE_SHA384: + case CHECKSUM_TYPE_SHA512: + if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0) + return -1; + break; + } + + return 0; +} + +/* + * Finalize a checksum computation and write the result to an output buffer. + * + * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH + * bytes in length. The return value is the number of bytes actually written, + * or -1 for a failure. + */ +int +pg_checksum_final(pg_checksum_context *context, uint8 *output) +{ + int retval = 0; + + StaticAssertDecl(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH, + "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertDecl(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertDecl(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertDecl(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertDecl(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH"); + + switch (context->type) + { + case CHECKSUM_TYPE_NONE: + break; + case CHECKSUM_TYPE_CRC32C: + FIN_CRC32C(context->raw_context.c_crc32c); + retval = sizeof(pg_crc32c); + memcpy(output, &context->raw_context.c_crc32c, retval); + break; + case CHECKSUM_TYPE_SHA224: + retval = PG_SHA224_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA256: + retval = PG_SHA256_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA384: + retval = PG_SHA384_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA512: + retval = PG_SHA512_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + } + + Assert(retval <= PG_CHECKSUM_MAX_LENGTH); + return retval; +} diff --git a/contrib/libs/libpq/src/common/compression.c b/contrib/libs/libpq/src/common/compression.c new file mode 100644 index 0000000000..47b18b8c60 --- /dev/null +++ b/contrib/libs/libpq/src/common/compression.c @@ -0,0 +1,476 @@ +/*------------------------------------------------------------------------- + * + * compression.c + * + * Shared code for compression methods and specifications. + * + * A compression specification specifies the parameters that should be used + * when performing compression with a specific algorithm. The simplest + * possible compression specification is an integer, which sets the + * compression level. + * + * Otherwise, a compression specification is a comma-separated list of items, + * each having the form keyword or keyword=value. + * + * Currently, the supported keywords are "level", "long", and "workers". + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/compression.c + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#ifdef USE_ZSTD +#error #include <zstd.h> +#endif +#ifdef HAVE_LIBZ +#include <zlib.h> +#endif + +#include "common/compression.h" + +static int expect_integer_value(char *keyword, char *value, + pg_compress_specification *result); +static bool expect_boolean_value(char *keyword, char *value, + pg_compress_specification *result); + +/* + * Look up a compression algorithm by name. Returns true and sets *algorithm + * if the name is recognized. Otherwise returns false. + */ +bool +parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm) +{ + if (strcmp(name, "none") == 0) + *algorithm = PG_COMPRESSION_NONE; + else if (strcmp(name, "gzip") == 0) + *algorithm = PG_COMPRESSION_GZIP; + else if (strcmp(name, "lz4") == 0) + *algorithm = PG_COMPRESSION_LZ4; + else if (strcmp(name, "zstd") == 0) + *algorithm = PG_COMPRESSION_ZSTD; + else + return false; + return true; +} + +/* + * Get the human-readable name corresponding to a particular compression + * algorithm. + */ +const char * +get_compress_algorithm_name(pg_compress_algorithm algorithm) +{ + switch (algorithm) + { + case PG_COMPRESSION_NONE: + return "none"; + case PG_COMPRESSION_GZIP: + return "gzip"; + case PG_COMPRESSION_LZ4: + return "lz4"; + case PG_COMPRESSION_ZSTD: + return "zstd"; + /* no default, to provoke compiler warnings if values are added */ + } + Assert(false); + return "???"; /* placate compiler */ +} + +/* + * Parse a compression specification for a specified algorithm. + * + * See the file header comments for a brief description of what a compression + * specification is expected to look like. + * + * On return, all fields of the result object will be initialized. + * In particular, result->parse_error will be NULL if no errors occurred + * during parsing, and will otherwise contain an appropriate error message. + * The caller may free this error message string using pfree, if desired. + * Note, however, even if there's no parse error, the string might not make + * sense: e.g. for gzip, level=12 is not sensible, but it does parse OK. + * + * The compression level is assigned by default if not directly specified + * by the specification. + * + * Use validate_compress_specification() to find out whether a compression + * specification is semantically sensible. + */ +void +parse_compress_specification(pg_compress_algorithm algorithm, char *specification, + pg_compress_specification *result) +{ + int bare_level; + char *bare_level_endp; + + /* Initial setup of result object. */ + result->algorithm = algorithm; + result->options = 0; + result->parse_error = NULL; + + /* + * Assign a default level depending on the compression method. This may + * be enforced later. + */ + switch (result->algorithm) + { + case PG_COMPRESSION_NONE: + result->level = 0; + break; + case PG_COMPRESSION_LZ4: +#ifdef USE_LZ4 + result->level = 0; /* fast compression mode */ +#else + result->parse_error = + psprintf(_("this build does not support compression with %s"), + "LZ4"); +#endif + break; + case PG_COMPRESSION_ZSTD: +#ifdef USE_ZSTD + result->level = ZSTD_CLEVEL_DEFAULT; +#else + result->parse_error = + psprintf(_("this build does not support compression with %s"), + "ZSTD"); +#endif + break; + case PG_COMPRESSION_GZIP: +#ifdef HAVE_LIBZ + result->level = Z_DEFAULT_COMPRESSION; +#else + result->parse_error = + psprintf(_("this build does not support compression with %s"), + "gzip"); +#endif + break; + } + + /* If there is no specification, we're done already. */ + if (specification == NULL) + return; + + /* As a special case, the specification can be a bare integer. */ + bare_level = strtol(specification, &bare_level_endp, 10); + if (specification != bare_level_endp && *bare_level_endp == '\0') + { + result->level = bare_level; + return; + } + + /* Look for comma-separated keyword or keyword=value entries. */ + while (1) + { + char *kwstart; + char *kwend; + char *vstart; + char *vend; + int kwlen; + int vlen; + bool has_value; + char *keyword; + char *value; + + /* Figure start, end, and length of next keyword and any value. */ + kwstart = kwend = specification; + while (*kwend != '\0' && *kwend != ',' && *kwend != '=') + ++kwend; + kwlen = kwend - kwstart; + if (*kwend != '=') + { + vstart = vend = NULL; + vlen = 0; + has_value = false; + } + else + { + vstart = vend = kwend + 1; + while (*vend != '\0' && *vend != ',') + ++vend; + vlen = vend - vstart; + has_value = true; + } + + /* Reject empty keyword. */ + if (kwlen == 0) + { + result->parse_error = + pstrdup(_("found empty string where a compression option was expected")); + break; + } + + /* Extract keyword and value as separate C strings. */ + keyword = palloc(kwlen + 1); + memcpy(keyword, kwstart, kwlen); + keyword[kwlen] = '\0'; + if (!has_value) + value = NULL; + else + { + value = palloc(vlen + 1); + memcpy(value, vstart, vlen); + value[vlen] = '\0'; + } + + /* Handle whatever keyword we found. */ + if (strcmp(keyword, "level") == 0) + { + result->level = expect_integer_value(keyword, value, result); + + /* + * No need to set a flag in "options", there is a default level + * set at least thanks to the logic above. + */ + } + else if (strcmp(keyword, "workers") == 0) + { + result->workers = expect_integer_value(keyword, value, result); + result->options |= PG_COMPRESSION_OPTION_WORKERS; + } + else if (strcmp(keyword, "long") == 0) + { + result->long_distance = expect_boolean_value(keyword, value, result); + result->options |= PG_COMPRESSION_OPTION_LONG_DISTANCE; + } + else + result->parse_error = + psprintf(_("unrecognized compression option: \"%s\""), keyword); + + /* Release memory, just to be tidy. */ + pfree(keyword); + if (value != NULL) + pfree(value); + + /* + * If we got an error or have reached the end of the string, stop. + * + * If there is no value, then the end of the keyword might have been + * the end of the string. If there is a value, then the end of the + * keyword cannot have been the end of the string, but the end of the + * value might have been. + */ + if (result->parse_error != NULL || + (vend == NULL ? *kwend == '\0' : *vend == '\0')) + break; + + /* Advance to next entry and loop around. */ + specification = vend == NULL ? kwend + 1 : vend + 1; + } +} + +/* + * Parse 'value' as an integer and return the result. + * + * If parsing fails, set result->parse_error to an appropriate message + * and return -1. + */ +static int +expect_integer_value(char *keyword, char *value, pg_compress_specification *result) +{ + int ivalue; + char *ivalue_endp; + + if (value == NULL) + { + result->parse_error = + psprintf(_("compression option \"%s\" requires a value"), + keyword); + return -1; + } + + ivalue = strtol(value, &ivalue_endp, 10); + if (ivalue_endp == value || *ivalue_endp != '\0') + { + result->parse_error = + psprintf(_("value for compression option \"%s\" must be an integer"), + keyword); + return -1; + } + return ivalue; +} + +/* + * Parse 'value' as a boolean and return the result. + * + * If parsing fails, set result->parse_error to an appropriate message + * and return -1. The caller must check result->parse_error to determine if + * the call was successful. + * + * Valid values are: yes, no, on, off, 1, 0. + * + * Inspired by ParseVariableBool(). + */ +static bool +expect_boolean_value(char *keyword, char *value, pg_compress_specification *result) +{ + if (value == NULL) + return true; + + if (pg_strcasecmp(value, "yes") == 0) + return true; + if (pg_strcasecmp(value, "on") == 0) + return true; + if (pg_strcasecmp(value, "1") == 0) + return true; + + if (pg_strcasecmp(value, "no") == 0) + return false; + if (pg_strcasecmp(value, "off") == 0) + return false; + if (pg_strcasecmp(value, "0") == 0) + return false; + + result->parse_error = + psprintf(_("value for compression option \"%s\" must be a Boolean value"), + keyword); + return false; +} + +/* + * Returns NULL if the compression specification string was syntactically + * valid and semantically sensible. Otherwise, returns an error message. + * + * Does not test whether this build of PostgreSQL supports the requested + * compression method. + */ +char * +validate_compress_specification(pg_compress_specification *spec) +{ + int min_level = 1; + int max_level = 1; + int default_level = 0; + + /* If it didn't even parse OK, it's definitely no good. */ + if (spec->parse_error != NULL) + return spec->parse_error; + + /* + * Check that the algorithm expects a compression level and it is within + * the legal range for the algorithm. + */ + switch (spec->algorithm) + { + case PG_COMPRESSION_GZIP: + max_level = 9; +#ifdef HAVE_LIBZ + default_level = Z_DEFAULT_COMPRESSION; +#endif + break; + case PG_COMPRESSION_LZ4: + max_level = 12; + default_level = 0; /* fast mode */ + break; + case PG_COMPRESSION_ZSTD: +#ifdef USE_ZSTD + max_level = ZSTD_maxCLevel(); + min_level = ZSTD_minCLevel(); + default_level = ZSTD_CLEVEL_DEFAULT; +#endif + break; + case PG_COMPRESSION_NONE: + if (spec->level != 0) + return psprintf(_("compression algorithm \"%s\" does not accept a compression level"), + get_compress_algorithm_name(spec->algorithm)); + break; + } + + if ((spec->level < min_level || spec->level > max_level) && + spec->level != default_level) + return psprintf(_("compression algorithm \"%s\" expects a compression level between %d and %d (default at %d)"), + get_compress_algorithm_name(spec->algorithm), + min_level, max_level, default_level); + + /* + * Of the compression algorithms that we currently support, only zstd + * allows parallel workers. + */ + if ((spec->options & PG_COMPRESSION_OPTION_WORKERS) != 0 && + (spec->algorithm != PG_COMPRESSION_ZSTD)) + { + return psprintf(_("compression algorithm \"%s\" does not accept a worker count"), + get_compress_algorithm_name(spec->algorithm)); + } + + /* + * Of the compression algorithms that we currently support, only zstd + * supports long-distance mode. + */ + if ((spec->options & PG_COMPRESSION_OPTION_LONG_DISTANCE) != 0 && + (spec->algorithm != PG_COMPRESSION_ZSTD)) + { + return psprintf(_("compression algorithm \"%s\" does not support long-distance mode"), + get_compress_algorithm_name(spec->algorithm)); + } + + return NULL; +} + +#ifdef FRONTEND + +/* + * Basic parsing of a value specified through a command-line option, commonly + * -Z/--compress. + * + * The parsing consists of a METHOD:DETAIL string fed later to + * parse_compress_specification(). This only extracts METHOD and DETAIL. + * If only an integer is found, the method is implied by the value specified. + */ +void +parse_compress_options(const char *option, char **algorithm, char **detail) +{ + char *sep; + char *endp; + long result; + + /* + * Check whether the compression specification consists of a bare integer. + * + * For backward-compatibility, assume "none" if the integer found is zero + * and "gzip" otherwise. + */ + result = strtol(option, &endp, 10); + if (*endp == '\0') + { + if (result == 0) + { + *algorithm = pstrdup("none"); + *detail = NULL; + } + else + { + *algorithm = pstrdup("gzip"); + *detail = pstrdup(option); + } + return; + } + + /* + * Check whether there is a compression detail following the algorithm + * name. + */ + sep = strchr(option, ':'); + if (sep == NULL) + { + *algorithm = pstrdup(option); + *detail = NULL; + } + else + { + char *alg; + + alg = palloc((sep - option) + 1); + memcpy(alg, option, sep - option); + alg[sep - option] = '\0'; + + *algorithm = alg; + *detail = pstrdup(sep + 1); + } +} +#endif /* FRONTEND */ diff --git a/contrib/libs/libpq/src/common/config_info.c b/contrib/libs/libpq/src/common/config_info.c new file mode 100644 index 0000000000..09e78a6efb --- /dev/null +++ b/contrib/libs/libpq/src/common/config_info.c @@ -0,0 +1,201 @@ +/*------------------------------------------------------------------------- + * + * config_info.c + * Common code for pg_config output + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/config_info.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/config_info.h" + + +/* + * get_configdata(const char *my_exec_path, size_t *configdata_len) + * + * Get configure-time constants. The caller is responsible + * for pfreeing the result. + */ +ConfigData * +get_configdata(const char *my_exec_path, size_t *configdata_len) +{ + ConfigData *configdata; + char path[MAXPGPATH]; + char *lastsep; + int i = 0; + + /* Adjust this to match the number of items filled below */ + *configdata_len = 23; + configdata = palloc_array(ConfigData, *configdata_len); + + configdata[i].name = pstrdup("BINDIR"); + strlcpy(path, my_exec_path, sizeof(path)); + lastsep = strrchr(path, '/'); + if (lastsep) + *lastsep = '\0'; + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("DOCDIR"); + get_doc_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("HTMLDIR"); + get_html_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("INCLUDEDIR"); + get_include_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("PKGINCLUDEDIR"); + get_pkginclude_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("INCLUDEDIR-SERVER"); + get_includeserver_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("LIBDIR"); + get_lib_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("PKGLIBDIR"); + get_pkglib_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("LOCALEDIR"); + get_locale_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("MANDIR"); + get_man_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("SHAREDIR"); + get_share_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("SYSCONFDIR"); + get_etc_path(my_exec_path, path); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("PGXS"); + get_pkglib_path(my_exec_path, path); + strlcat(path, "/pgxs/src/makefiles/pgxs.mk", sizeof(path)); + cleanup_path(path); + configdata[i].setting = pstrdup(path); + i++; + + configdata[i].name = pstrdup("CONFIGURE"); + configdata[i].setting = pstrdup(CONFIGURE_ARGS); + i++; + + configdata[i].name = pstrdup("CC"); +#ifdef VAL_CC + configdata[i].setting = pstrdup(VAL_CC); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("CPPFLAGS"); +#ifdef VAL_CPPFLAGS + configdata[i].setting = pstrdup(VAL_CPPFLAGS); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("CFLAGS"); +#ifdef VAL_CFLAGS + configdata[i].setting = pstrdup(VAL_CFLAGS); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("CFLAGS_SL"); +#ifdef VAL_CFLAGS_SL + configdata[i].setting = pstrdup(VAL_CFLAGS_SL); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("LDFLAGS"); +#ifdef VAL_LDFLAGS + configdata[i].setting = pstrdup(VAL_LDFLAGS); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("LDFLAGS_EX"); +#ifdef VAL_LDFLAGS_EX + configdata[i].setting = pstrdup(VAL_LDFLAGS_EX); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("LDFLAGS_SL"); +#ifdef VAL_LDFLAGS_SL + configdata[i].setting = pstrdup(VAL_LDFLAGS_SL); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("LIBS"); +#ifdef VAL_LIBS + configdata[i].setting = pstrdup(VAL_LIBS); +#else + configdata[i].setting = pstrdup(_("not recorded")); +#endif + i++; + + configdata[i].name = pstrdup("VERSION"); + configdata[i].setting = pstrdup("PostgreSQL " PG_VERSION); + i++; + + Assert(i == *configdata_len); + + return configdata; +} diff --git a/contrib/libs/libpq/src/common/controldata_utils.c b/contrib/libs/libpq/src/common/controldata_utils.c new file mode 100644 index 0000000000..19305fa07a --- /dev/null +++ b/contrib/libs/libpq/src/common/controldata_utils.c @@ -0,0 +1,269 @@ +/*------------------------------------------------------------------------- + * + * controldata_utils.c + * Common code for control data file output. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/controldata_utils.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> + +#include "access/xlog_internal.h" +#include "catalog/pg_control.h" +#include "common/controldata_utils.h" +#include "common/file_perm.h" +#ifdef FRONTEND +#include "common/logging.h" +#endif +#include "port/pg_crc32c.h" + +#ifndef FRONTEND +#error #include "pgstat.h" +#error #include "storage/fd.h" +#endif + +/* + * get_controlfile() + * + * Get controlfile values. The result is returned as a palloc'd copy of the + * control file data. + * + * crc_ok_p can be used by the caller to see whether the CRC of the control + * file data is correct. + */ +ControlFileData * +get_controlfile(const char *DataDir, bool *crc_ok_p) +{ + ControlFileData *ControlFile; + int fd; + char ControlFilePath[MAXPGPATH]; + pg_crc32c crc; + int r; +#ifdef FRONTEND + pg_crc32c last_crc; + int retries = 0; +#endif + + Assert(crc_ok_p); + + ControlFile = palloc_object(ControlFileData); + snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir); + +#ifdef FRONTEND + INIT_CRC32C(last_crc); + +retry: +#endif + +#ifndef FRONTEND + if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open file \"%s\" for reading: %m", + ControlFilePath))); +#else + if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1) + pg_fatal("could not open file \"%s\" for reading: %m", + ControlFilePath); +#endif + + r = read(fd, ControlFile, sizeof(ControlFileData)); + if (r != sizeof(ControlFileData)) + { + if (r < 0) +#ifndef FRONTEND + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not read file \"%s\": %m", ControlFilePath))); +#else + pg_fatal("could not read file \"%s\": %m", ControlFilePath); +#endif + else +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("could not read file \"%s\": read %d of %zu", + ControlFilePath, r, sizeof(ControlFileData)))); +#else + pg_fatal("could not read file \"%s\": read %d of %zu", + ControlFilePath, r, sizeof(ControlFileData)); +#endif + } + +#ifndef FRONTEND + if (CloseTransientFile(fd) != 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not close file \"%s\": %m", + ControlFilePath))); +#else + if (close(fd) != 0) + pg_fatal("could not close file \"%s\": %m", ControlFilePath); +#endif + + /* Check the CRC. */ + INIT_CRC32C(crc); + COMP_CRC32C(crc, + (char *) ControlFile, + offsetof(ControlFileData, crc)); + FIN_CRC32C(crc); + + *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc); + +#ifdef FRONTEND + + /* + * If the server was writing at the same time, it is possible that we read + * partially updated contents on some systems. If the CRC doesn't match, + * retry a limited number of times until we compute the same bad CRC twice + * in a row with a short sleep in between. Then the failure is unlikely + * to be due to a concurrent write. + */ + if (!*crc_ok_p && + (retries == 0 || !EQ_CRC32C(crc, last_crc)) && + retries < 10) + { + retries++; + last_crc = crc; + pg_usleep(10000); + goto retry; + } +#endif + + /* Make sure the control file is valid byte order. */ + if (ControlFile->pg_control_version % 65536 == 0 && + ControlFile->pg_control_version / 65536 != 0) +#ifndef FRONTEND + elog(ERROR, _("byte ordering mismatch")); +#else + pg_log_warning("possible byte ordering mismatch\n" + "The byte ordering used to store the pg_control file might not match the one\n" + "used by this program. In that case the results below would be incorrect, and\n" + "the PostgreSQL installation would be incompatible with this data directory."); +#endif + + return ControlFile; +} + +/* + * update_controlfile() + * + * Update controlfile values with the contents given by caller. The + * contents to write are included in "ControlFile". "do_sync" can be + * optionally used to flush the updated control file. Note that it is up + * to the caller to properly lock ControlFileLock when calling this + * routine in the backend. + */ +void +update_controlfile(const char *DataDir, + ControlFileData *ControlFile, bool do_sync) +{ + int fd; + char buffer[PG_CONTROL_FILE_SIZE]; + char ControlFilePath[MAXPGPATH]; + + /* Update timestamp */ + ControlFile->time = (pg_time_t) time(NULL); + + /* Recalculate CRC of control file */ + INIT_CRC32C(ControlFile->crc); + COMP_CRC32C(ControlFile->crc, + (char *) ControlFile, + offsetof(ControlFileData, crc)); + FIN_CRC32C(ControlFile->crc); + + /* + * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding + * the excess over sizeof(ControlFileData), to avoid premature EOF related + * errors when reading it. + */ + memset(buffer, 0, PG_CONTROL_FILE_SIZE); + memcpy(buffer, ControlFile, sizeof(ControlFileData)); + + snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE); + +#ifndef FRONTEND + + /* + * All errors issue a PANIC, so no need to use OpenTransientFile() and to + * worry about file descriptor leaks. + */ + if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0) + ereport(PANIC, + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", + ControlFilePath))); +#else + if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY, + pg_file_create_mode)) == -1) + pg_fatal("could not open file \"%s\": %m", ControlFilePath); +#endif + + errno = 0; +#ifndef FRONTEND + pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE); +#endif + if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE) + { + /* if write didn't set errno, assume problem is no disk space */ + if (errno == 0) + errno = ENOSPC; + +#ifndef FRONTEND + ereport(PANIC, + (errcode_for_file_access(), + errmsg("could not write file \"%s\": %m", + ControlFilePath))); +#else + pg_fatal("could not write file \"%s\": %m", ControlFilePath); +#endif + } +#ifndef FRONTEND + pgstat_report_wait_end(); +#endif + + if (do_sync) + { +#ifndef FRONTEND + pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE); + if (pg_fsync(fd) != 0) + ereport(PANIC, + (errcode_for_file_access(), + errmsg("could not fsync file \"%s\": %m", + ControlFilePath))); + pgstat_report_wait_end(); +#else + if (fsync(fd) != 0) + pg_fatal("could not fsync file \"%s\": %m", ControlFilePath); +#endif + } + + if (close(fd) != 0) + { +#ifndef FRONTEND + ereport(PANIC, + (errcode_for_file_access(), + errmsg("could not close file \"%s\": %m", + ControlFilePath))); +#else + pg_fatal("could not close file \"%s\": %m", ControlFilePath); +#endif + } +} diff --git a/contrib/libs/libpq/src/common/cryptohash_openssl.c b/contrib/libs/libpq/src/common/cryptohash_openssl.c new file mode 100644 index 0000000000..ac2cff0759 --- /dev/null +++ b/contrib/libs/libpq/src/common/cryptohash_openssl.c @@ -0,0 +1,353 @@ +/*------------------------------------------------------------------------- + * + * cryptohash_openssl.c + * Set of wrapper routines on top of OpenSSL to support cryptographic + * hash functions. + * + * This should only be used if code is compiled with OpenSSL support. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/cryptohash_openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <openssl/err.h> +#include <openssl/evp.h> + +#include "common/cryptohash.h" +#include "common/md5.h" +#include "common/sha1.h" +#include "common/sha2.h" +#ifndef FRONTEND +#error #include "utils/memutils.h" +#error #include "utils/resowner.h" +#error #include "utils/resowner_private.h" +#endif + +/* + * In the backend, use an allocation in TopMemoryContext to count for + * resowner cleanup handling. In the frontend, use malloc to be able + * to return a failure status back to the caller. + */ +#ifndef FRONTEND +#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size) +#define FREE(ptr) pfree(ptr) +#else +#define ALLOC(size) malloc(size) +#define FREE(ptr) free(ptr) +#endif + +/* Set of error states */ +typedef enum pg_cryptohash_errno +{ + PG_CRYPTOHASH_ERROR_NONE = 0, + PG_CRYPTOHASH_ERROR_DEST_LEN, + PG_CRYPTOHASH_ERROR_OPENSSL +} pg_cryptohash_errno; + +/* + * Internal pg_cryptohash_ctx structure. + * + * This tracks the resource owner associated to each EVP context data + * for the backend. + */ +struct pg_cryptohash_ctx +{ + pg_cryptohash_type type; + pg_cryptohash_errno error; + const char *errreason; + + EVP_MD_CTX *evpctx; + +#ifndef FRONTEND + ResourceOwner resowner; +#endif +}; + +static const char * +SSLerrmessage(unsigned long ecode) +{ + if (ecode == 0) + return NULL; + + /* + * This may return NULL, but we would fall back to a default error path if + * that were the case. + */ + return ERR_reason_error_string(ecode); +} + +/* + * pg_cryptohash_create + * + * Allocate a hash context. Returns NULL on failure for an OOM. The + * backend issues an error, without returning. + */ +pg_cryptohash_ctx * +pg_cryptohash_create(pg_cryptohash_type type) +{ + pg_cryptohash_ctx *ctx; + + /* + * Make sure that the resource owner has space to remember this reference. + * This can error out with "out of memory", so do this before any other + * allocation to avoid leaking. + */ +#ifndef FRONTEND + ResourceOwnerEnlargeCryptoHash(CurrentResourceOwner); +#endif + + ctx = ALLOC(sizeof(pg_cryptohash_ctx)); + if (ctx == NULL) + return NULL; + memset(ctx, 0, sizeof(pg_cryptohash_ctx)); + ctx->type = type; + ctx->error = PG_CRYPTOHASH_ERROR_NONE; + ctx->errreason = NULL; + + /* + * Initialization takes care of assigning the correct type for OpenSSL. + * Also ensure that there aren't any unconsumed errors in the queue from + * previous runs. + */ + ERR_clear_error(); + ctx->evpctx = EVP_MD_CTX_create(); + + if (ctx->evpctx == NULL) + { + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#else + return NULL; +#endif + } + +#ifndef FRONTEND + ctx->resowner = CurrentResourceOwner; + ResourceOwnerRememberCryptoHash(CurrentResourceOwner, + PointerGetDatum(ctx)); +#endif + + return ctx; +} + +/* + * pg_cryptohash_init + * + * Initialize a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_init(pg_cryptohash_ctx *ctx) +{ + int status = 0; + + if (ctx == NULL) + return -1; + + switch (ctx->type) + { + case PG_MD5: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_md5(), NULL); + break; + case PG_SHA1: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha1(), NULL); + break; + case PG_SHA224: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha224(), NULL); + break; + case PG_SHA256: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha256(), NULL); + break; + case PG_SHA384: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha384(), NULL); + break; + case PG_SHA512: + status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha512(), NULL); + break; + } + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; + + /* + * The OpenSSL error queue should normally be empty since we've + * consumed an error, but cipher initialization can in FIPS-enabled + * OpenSSL builds generate two errors so clear the queue here as well. + */ + ERR_clear_error(); + return -1; + } + return 0; +} + +/* + * pg_cryptohash_update + * + * Update a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) +{ + int status = 0; + + if (ctx == NULL) + return -1; + + status = EVP_DigestUpdate(ctx->evpctx, data, len); + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; + return -1; + } + return 0; +} + +/* + * pg_cryptohash_final + * + * Finalize a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len) +{ + int status = 0; + + if (ctx == NULL) + return -1; + + switch (ctx->type) + { + case PG_MD5: + if (len < MD5_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA1: + if (len < SHA1_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA224: + if (len < PG_SHA224_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA256: + if (len < PG_SHA256_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA384: + if (len < PG_SHA384_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA512: + if (len < PG_SHA512_DIGEST_LENGTH) + { + ctx->error = PG_CRYPTOHASH_ERROR_DEST_LEN; + return -1; + } + break; + } + + status = EVP_DigestFinal_ex(ctx->evpctx, dest, 0); + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_CRYPTOHASH_ERROR_OPENSSL; + return -1; + } + return 0; +} + +/* + * pg_cryptohash_free + * + * Free a hash context. + */ +void +pg_cryptohash_free(pg_cryptohash_ctx *ctx) +{ + if (ctx == NULL) + return; + + EVP_MD_CTX_destroy(ctx->evpctx); + +#ifndef FRONTEND + ResourceOwnerForgetCryptoHash(ctx->resowner, + PointerGetDatum(ctx)); +#endif + + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); +} + +/* + * pg_cryptohash_error + * + * Returns a static string providing details about an error that + * happened during a computation. + */ +const char * +pg_cryptohash_error(pg_cryptohash_ctx *ctx) +{ + /* + * This implementation would never fail because of an out-of-memory error, + * except when creating the context. + */ + if (ctx == NULL) + return _("out of memory"); + + /* + * If a reason is provided, rely on it, else fallback to any error code + * set. + */ + if (ctx->errreason) + return ctx->errreason; + + switch (ctx->error) + { + case PG_CRYPTOHASH_ERROR_NONE: + return _("success"); + case PG_CRYPTOHASH_ERROR_DEST_LEN: + return _("destination buffer too small"); + case PG_CRYPTOHASH_ERROR_OPENSSL: + return _("OpenSSL failure"); + } + + Assert(false); /* cannot be reached */ + return _("success"); +} diff --git a/contrib/libs/libpq/src/common/d2s.c b/contrib/libs/libpq/src/common/d2s.c new file mode 100644 index 0000000000..614e98192a --- /dev/null +++ b/contrib/libs/libpq/src/common/d2s.c @@ -0,0 +1,1076 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output for double precision. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/d2s.c + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ + +/* + * Runtime compiler options: + * + * -DRYU_ONLY_64_BIT_OPS Avoid using uint128 or 64-bit intrinsics. Slower, + * depending on your compiler. + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/shortest_dec.h" + +/* + * For consistency, we use 128-bit types if and only if the rest of PG also + * does, even though we could use them here without worrying about the + * alignment concerns that apply elsewhere. + */ +#if !defined(HAVE_INT128) && defined(_MSC_VER) \ + && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64) +#define HAS_64_BIT_INTRINSICS +#endif + +#include "ryu_common.h" +#include "digit_table.h" +#include "d2s_full_table.h" +#include "d2s_intrinsics.h" + +#define DOUBLE_MANTISSA_BITS 52 +#define DOUBLE_EXPONENT_BITS 11 +#define DOUBLE_BIAS 1023 + +#define DOUBLE_POW5_INV_BITCOUNT 122 +#define DOUBLE_POW5_BITCOUNT 121 + + +static inline uint32 +pow5Factor(uint64 value) +{ + uint32 count = 0; + + for (;;) + { + Assert(value != 0); + const uint64 q = div5(value); + const uint32 r = (uint32) (value - 5 * q); + + if (r != 0) + break; + + value = q; + ++count; + } + return count; +} + +/* Returns true if value is divisible by 5^p. */ +static inline bool +multipleOfPowerOf5(const uint64 value, const uint32 p) +{ + /* + * I tried a case distinction on p, but there was no performance + * difference. + */ + return pow5Factor(value) >= p; +} + +/* Returns true if value is divisible by 2^p. */ +static inline bool +multipleOfPowerOf2(const uint64 value, const uint32 p) +{ + /* return __builtin_ctzll(value) >= p; */ + return (value & ((UINT64CONST(1) << p) - 1)) == 0; +} + +/* + * We need a 64x128-bit multiplication and a subsequent 128-bit shift. + * + * Multiplication: + * + * The 64-bit factor is variable and passed in, the 128-bit factor comes + * from a lookup table. We know that the 64-bit factor only has 55 + * significant bits (i.e., the 9 topmost bits are zeros). The 128-bit + * factor only has 124 significant bits (i.e., the 4 topmost bits are + * zeros). + * + * Shift: + * + * In principle, the multiplication result requires 55 + 124 = 179 bits to + * represent. However, we then shift this value to the right by j, which is + * at least j >= 115, so the result is guaranteed to fit into 179 - 115 = + * 64 bits. This means that we only need the topmost 64 significant bits of + * the 64x128-bit multiplication. + * + * There are several ways to do this: + * + * 1. Best case: the compiler exposes a 128-bit type. + * We perform two 64x64-bit multiplications, add the higher 64 bits of the + * lower result to the higher result, and shift by j - 64 bits. + * + * We explicitly cast from 64-bit to 128-bit, so the compiler can tell + * that these are only 64-bit inputs, and can map these to the best + * possible sequence of assembly instructions. x86-64 machines happen to + * have matching assembly instructions for 64x64-bit multiplications and + * 128-bit shifts. + * + * 2. Second best case: the compiler exposes intrinsics for the x86-64 + * assembly instructions mentioned in 1. + * + * 3. We only have 64x64 bit instructions that return the lower 64 bits of + * the result, i.e., we have to use plain C. + * + * Our inputs are less than the full width, so we have three options: + * a. Ignore this fact and just implement the intrinsics manually. + * b. Split both into 31-bit pieces, which guarantees no internal + * overflow, but requires extra work upfront (unless we change the + * lookup table). + * c. Split only the first factor into 31-bit pieces, which also + * guarantees no internal overflow, but requires extra work since the + * intermediate results are not perfectly aligned. + */ +#if defined(HAVE_INT128) + +/* Best case: use 128-bit type. */ +static inline uint64 +mulShift(const uint64 m, const uint64 *const mul, const int32 j) +{ + const uint128 b0 = ((uint128) m) * mul[0]; + const uint128 b2 = ((uint128) m) * mul[1]; + + return (uint64) (((b0 >> 64) + b2) >> (j - 64)); +} + +static inline uint64 +mulShiftAll(const uint64 m, const uint64 *const mul, const int32 j, + uint64 *const vp, uint64 *const vm, const uint32 mmShift) +{ + *vp = mulShift(4 * m + 2, mul, j); + *vm = mulShift(4 * m - 1 - mmShift, mul, j); + return mulShift(4 * m, mul, j); +} + +#elif defined(HAS_64_BIT_INTRINSICS) + +static inline uint64 +mulShift(const uint64 m, const uint64 *const mul, const int32 j) +{ + /* m is maximum 55 bits */ + uint64 high1; + + /* 128 */ + const uint64 low1 = umul128(m, mul[1], &high1); + + /* 64 */ + uint64 high0; + uint64 sum; + + /* 64 */ + umul128(m, mul[0], &high0); + /* 0 */ + sum = high0 + low1; + + if (sum < high0) + { + ++high1; + /* overflow into high1 */ + } + return shiftright128(sum, high1, j - 64); +} + +static inline uint64 +mulShiftAll(const uint64 m, const uint64 *const mul, const int32 j, + uint64 *const vp, uint64 *const vm, const uint32 mmShift) +{ + *vp = mulShift(4 * m + 2, mul, j); + *vm = mulShift(4 * m - 1 - mmShift, mul, j); + return mulShift(4 * m, mul, j); +} + +#else /* // !defined(HAVE_INT128) && + * !defined(HAS_64_BIT_INTRINSICS) */ + +static inline uint64 +mulShiftAll(uint64 m, const uint64 *const mul, const int32 j, + uint64 *const vp, uint64 *const vm, const uint32 mmShift) +{ + m <<= 1; /* m is maximum 55 bits */ + + uint64 tmp; + const uint64 lo = umul128(m, mul[0], &tmp); + uint64 hi; + const uint64 mid = tmp + umul128(m, mul[1], &hi); + + hi += mid < tmp; /* overflow into hi */ + + const uint64 lo2 = lo + mul[0]; + const uint64 mid2 = mid + mul[1] + (lo2 < lo); + const uint64 hi2 = hi + (mid2 < mid); + + *vp = shiftright128(mid2, hi2, j - 64 - 1); + + if (mmShift == 1) + { + const uint64 lo3 = lo - mul[0]; + const uint64 mid3 = mid - mul[1] - (lo3 > lo); + const uint64 hi3 = hi - (mid3 > mid); + + *vm = shiftright128(mid3, hi3, j - 64 - 1); + } + else + { + const uint64 lo3 = lo + lo; + const uint64 mid3 = mid + mid + (lo3 < lo); + const uint64 hi3 = hi + hi + (mid3 < mid); + const uint64 lo4 = lo3 - mul[0]; + const uint64 mid4 = mid3 - mul[1] - (lo4 > lo3); + const uint64 hi4 = hi3 - (mid4 > mid3); + + *vm = shiftright128(mid4, hi4, j - 64); + } + + return shiftright128(mid, hi, j - 64 - 1); +} + +#endif /* // HAS_64_BIT_INTRINSICS */ + +static inline uint32 +decimalLength(const uint64 v) +{ + /* This is slightly faster than a loop. */ + /* The average output length is 16.38 digits, so we check high-to-low. */ + /* Function precondition: v is not an 18, 19, or 20-digit number. */ + /* (17 digits are sufficient for round-tripping.) */ + Assert(v < 100000000000000000L); + if (v >= 10000000000000000L) + { + return 17; + } + if (v >= 1000000000000000L) + { + return 16; + } + if (v >= 100000000000000L) + { + return 15; + } + if (v >= 10000000000000L) + { + return 14; + } + if (v >= 1000000000000L) + { + return 13; + } + if (v >= 100000000000L) + { + return 12; + } + if (v >= 10000000000L) + { + return 11; + } + if (v >= 1000000000L) + { + return 10; + } + if (v >= 100000000L) + { + return 9; + } + if (v >= 10000000L) + { + return 8; + } + if (v >= 1000000L) + { + return 7; + } + if (v >= 100000L) + { + return 6; + } + if (v >= 10000L) + { + return 5; + } + if (v >= 1000L) + { + return 4; + } + if (v >= 100L) + { + return 3; + } + if (v >= 10L) + { + return 2; + } + return 1; +} + +/* A floating decimal representing m * 10^e. */ +typedef struct floating_decimal_64 +{ + uint64 mantissa; + int32 exponent; +} floating_decimal_64; + +static inline floating_decimal_64 +d2d(const uint64 ieeeMantissa, const uint32 ieeeExponent) +{ + int32 e2; + uint64 m2; + + if (ieeeExponent == 0) + { + /* We subtract 2 so that the bounds computation has 2 additional bits. */ + e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2; + m2 = ieeeMantissa; + } + else + { + e2 = ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2; + m2 = (UINT64CONST(1) << DOUBLE_MANTISSA_BITS) | ieeeMantissa; + } + +#if STRICTLY_SHORTEST + const bool even = (m2 & 1) == 0; + const bool acceptBounds = even; +#else + const bool acceptBounds = false; +#endif + + /* Step 2: Determine the interval of legal decimal representations. */ + const uint64 mv = 4 * m2; + + /* Implicit bool -> int conversion. True is 1, false is 0. */ + const uint32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1; + + /* We would compute mp and mm like this: */ + /* uint64 mp = 4 * m2 + 2; */ + /* uint64 mm = mv - 1 - mmShift; */ + + /* Step 3: Convert to a decimal power base using 128-bit arithmetic. */ + uint64 vr, + vp, + vm; + int32 e10; + bool vmIsTrailingZeros = false; + bool vrIsTrailingZeros = false; + + if (e2 >= 0) + { + /* + * I tried special-casing q == 0, but there was no effect on + * performance. + * + * This expr is slightly faster than max(0, log10Pow2(e2) - 1). + */ + const uint32 q = log10Pow2(e2) - (e2 > 3); + const int32 k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q) - 1; + const int32 i = -e2 + q + k; + + e10 = q; + + vr = mulShiftAll(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift); + + if (q <= 21) + { + /* + * This should use q <= 22, but I think 21 is also safe. Smaller + * values may still be safe, but it's more difficult to reason + * about them. + * + * Only one of mp, mv, and mm can be a multiple of 5, if any. + */ + const uint32 mvMod5 = (uint32) (mv - 5 * div5(mv)); + + if (mvMod5 == 0) + { + vrIsTrailingZeros = multipleOfPowerOf5(mv, q); + } + else if (acceptBounds) + { + /*---- + * Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q + * <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q + * <=> true && pow5Factor(mm) >= q, since e2 >= q. + *---- + */ + vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q); + } + else + { + /* Same as min(e2 + 1, pow5Factor(mp)) >= q. */ + vp -= multipleOfPowerOf5(mv + 2, q); + } + } + } + else + { + /* + * This expression is slightly faster than max(0, log10Pow5(-e2) - 1). + */ + const uint32 q = log10Pow5(-e2) - (-e2 > 1); + const int32 i = -e2 - q; + const int32 k = pow5bits(i) - DOUBLE_POW5_BITCOUNT; + const int32 j = q - k; + + e10 = q + e2; + + vr = mulShiftAll(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift); + + if (q <= 1) + { + /* + * {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q + * trailing 0 bits. + */ + /* mv = 4 * m2, so it always has at least two trailing 0 bits. */ + vrIsTrailingZeros = true; + if (acceptBounds) + { + /* + * mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff + * mmShift == 1. + */ + vmIsTrailingZeros = mmShift == 1; + } + else + { + /* + * mp = mv + 2, so it always has at least one trailing 0 bit. + */ + --vp; + } + } + else if (q < 63) + { + /* TODO(ulfjack):Use a tighter bound here. */ + /* + * We need to compute min(ntz(mv), pow5Factor(mv) - e2) >= q - 1 + */ + /* <=> ntz(mv) >= q - 1 && pow5Factor(mv) - e2 >= q - 1 */ + /* <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q) */ + /* <=> (mv & ((1 << (q - 1)) - 1)) == 0 */ + + /* + * We also need to make sure that the left shift does not + * overflow. + */ + vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1); + } + } + + /* + * Step 4: Find the shortest decimal representation in the interval of + * legal representations. + */ + uint32 removed = 0; + uint8 lastRemovedDigit = 0; + uint64 output; + + /* On average, we remove ~2 digits. */ + if (vmIsTrailingZeros || vrIsTrailingZeros) + { + /* General case, which happens rarely (~0.7%). */ + for (;;) + { + const uint64 vpDiv10 = div10(vp); + const uint64 vmDiv10 = div10(vm); + + if (vpDiv10 <= vmDiv10) + break; + + const uint32 vmMod10 = (uint32) (vm - 10 * vmDiv10); + const uint64 vrDiv10 = div10(vr); + const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10); + + vmIsTrailingZeros &= vmMod10 == 0; + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8) vrMod10; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } + + if (vmIsTrailingZeros) + { + for (;;) + { + const uint64 vmDiv10 = div10(vm); + const uint32 vmMod10 = (uint32) (vm - 10 * vmDiv10); + + if (vmMod10 != 0) + break; + + const uint64 vpDiv10 = div10(vp); + const uint64 vrDiv10 = div10(vr); + const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10); + + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8) vrMod10; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } + } + + if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0) + { + /* Round even if the exact number is .....50..0. */ + lastRemovedDigit = 4; + } + + /* + * We need to take vr + 1 if vr is outside bounds or we need to round + * up. + */ + output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5); + } + else + { + /* + * Specialized for the common case (~99.3%). Percentages below are + * relative to this. + */ + bool roundUp = false; + const uint64 vpDiv100 = div100(vp); + const uint64 vmDiv100 = div100(vm); + + if (vpDiv100 > vmDiv100) + { + /* Optimization:remove two digits at a time(~86.2 %). */ + const uint64 vrDiv100 = div100(vr); + const uint32 vrMod100 = (uint32) (vr - 100 * vrDiv100); + + roundUp = vrMod100 >= 50; + vr = vrDiv100; + vp = vpDiv100; + vm = vmDiv100; + removed += 2; + } + + /*---- + * Loop iterations below (approximately), without optimization + * above: + * + * 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, + * 6+: 0.02% + * + * Loop iterations below (approximately), with optimization + * above: + * + * 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% + *---- + */ + for (;;) + { + const uint64 vpDiv10 = div10(vp); + const uint64 vmDiv10 = div10(vm); + + if (vpDiv10 <= vmDiv10) + break; + + const uint64 vrDiv10 = div10(vr); + const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10); + + roundUp = vrMod10 >= 5; + vr = vrDiv10; + vp = vpDiv10; + vm = vmDiv10; + ++removed; + } + + /* + * We need to take vr + 1 if vr is outside bounds or we need to round + * up. + */ + output = vr + (vr == vm || roundUp); + } + + const int32 exp = e10 + removed; + + floating_decimal_64 fd; + + fd.exponent = exp; + fd.mantissa = output; + return fd; +} + +static inline int +to_chars_df(const floating_decimal_64 v, const uint32 olength, char *const result) +{ + /* Step 5: Print the decimal representation. */ + int index = 0; + + uint64 output = v.mantissa; + int32 exp = v.exponent; + + /*---- + * On entry, mantissa * 10^exp is the result to be output. + * Caller has already done the - sign if needed. + * + * We want to insert the point somewhere depending on the output length + * and exponent, which might mean adding zeros: + * + * exp | format + * 1+ | ddddddddd000000 + * 0 | ddddddddd + * -1 .. -len+1 | dddddddd.d to d.ddddddddd + * -len ... | 0.ddddddddd to 0.000dddddd + */ + uint32 i = 0; + int32 nexp = exp + olength; + + if (nexp <= 0) + { + /* -nexp is number of 0s to add after '.' */ + Assert(nexp >= -3); + /* 0.000ddddd */ + index = 2 - nexp; + /* won't need more than this many 0s */ + memcpy(result, "0.000000", 8); + } + else if (exp < 0) + { + /* + * dddd.dddd; leave space at the start and move the '.' in after + */ + index = 1; + } + else + { + /* + * We can save some code later by pre-filling with zeros. We know that + * there can be no more than 16 output digits in this form, otherwise + * we would not choose fixed-point output. + */ + Assert(exp < 16 && exp + olength <= 16); + memset(result, '0', 16); + } + + /* + * We prefer 32-bit operations, even on 64-bit platforms. We have at most + * 17 digits, and uint32 can store 9 digits. If output doesn't fit into + * uint32, we cut off 8 digits, so the rest will fit into uint32. + */ + if ((output >> 32) != 0) + { + /* Expensive 64-bit division. */ + const uint64 q = div1e8(output); + uint32 output2 = (uint32) (output - 100000000 * q); + const uint32 c = output2 % 10000; + + output = q; + output2 /= 10000; + + const uint32 d = output2 % 10000; + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + const uint32 d0 = (d % 100) << 1; + const uint32 d1 = (d / 100) << 1; + + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2); + memcpy(result + index + olength - i - 6, DIGIT_TABLE + d0, 2); + memcpy(result + index + olength - i - 8, DIGIT_TABLE + d1, 2); + i += 8; + } + + uint32 output2 = (uint32) output; + + while (output2 >= 10000) + { + const uint32 c = output2 - 10000 * (output2 / 10000); + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + + output2 /= 10000; + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2); + i += 4; + } + if (output2 >= 100) + { + const uint32 c = (output2 % 100) << 1; + + output2 /= 100; + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2); + i += 2; + } + if (output2 >= 10) + { + const uint32 c = output2 << 1; + + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2); + } + else + { + result[index] = (char) ('0' + output2); + } + + if (index == 1) + { + /* + * nexp is 1..15 here, representing the number of digits before the + * point. A value of 16 is not possible because we switch to + * scientific notation when the display exponent reaches 15. + */ + Assert(nexp < 16); + /* gcc only seems to want to optimize memmove for small 2^n */ + if (nexp & 8) + { + memmove(result + index - 1, result + index, 8); + index += 8; + } + if (nexp & 4) + { + memmove(result + index - 1, result + index, 4); + index += 4; + } + if (nexp & 2) + { + memmove(result + index - 1, result + index, 2); + index += 2; + } + if (nexp & 1) + { + result[index - 1] = result[index]; + } + result[nexp] = '.'; + index = olength + 1; + } + else if (exp >= 0) + { + /* we supplied the trailing zeros earlier, now just set the length. */ + index = olength + exp; + } + else + { + index = olength + (2 - nexp); + } + + return index; +} + +static inline int +to_chars(floating_decimal_64 v, const bool sign, char *const result) +{ + /* Step 5: Print the decimal representation. */ + int index = 0; + + uint64 output = v.mantissa; + uint32 olength = decimalLength(output); + int32 exp = v.exponent + olength - 1; + + if (sign) + { + result[index++] = '-'; + } + + /* + * The thresholds for fixed-point output are chosen to match printf + * defaults. Beware that both the code of to_chars_df and the value of + * DOUBLE_SHORTEST_DECIMAL_LEN are sensitive to these thresholds. + */ + if (exp >= -4 && exp < 15) + return to_chars_df(v, olength, result + index) + sign; + + /* + * If v.exponent is exactly 0, we might have reached here via the small + * integer fast path, in which case v.mantissa might contain trailing + * (decimal) zeros. For scientific notation we need to move these zeros + * into the exponent. (For fixed point this doesn't matter, which is why + * we do this here rather than above.) + * + * Since we already calculated the display exponent (exp) above based on + * the old decimal length, that value does not change here. Instead, we + * just reduce the display length for each digit removed. + * + * If we didn't get here via the fast path, the raw exponent will not + * usually be 0, and there will be no trailing zeros, so we pay no more + * than one div10/multiply extra cost. We claw back half of that by + * checking for divisibility by 2 before dividing by 10. + */ + if (v.exponent == 0) + { + while ((output & 1) == 0) + { + const uint64 q = div10(output); + const uint32 r = (uint32) (output - 10 * q); + + if (r != 0) + break; + output = q; + --olength; + } + } + + /*---- + * Print the decimal digits. + * + * The following code is equivalent to: + * + * for (uint32 i = 0; i < olength - 1; ++i) { + * const uint32 c = output % 10; output /= 10; + * result[index + olength - i] = (char) ('0' + c); + * } + * result[index] = '0' + output % 10; + *---- + */ + + uint32 i = 0; + + /* + * We prefer 32-bit operations, even on 64-bit platforms. We have at most + * 17 digits, and uint32 can store 9 digits. If output doesn't fit into + * uint32, we cut off 8 digits, so the rest will fit into uint32. + */ + if ((output >> 32) != 0) + { + /* Expensive 64-bit division. */ + const uint64 q = div1e8(output); + uint32 output2 = (uint32) (output - 100000000 * q); + + output = q; + + const uint32 c = output2 % 10000; + + output2 /= 10000; + + const uint32 d = output2 % 10000; + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + const uint32 d0 = (d % 100) << 1; + const uint32 d1 = (d / 100) << 1; + + memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2); + memcpy(result + index + olength - i - 5, DIGIT_TABLE + d0, 2); + memcpy(result + index + olength - i - 7, DIGIT_TABLE + d1, 2); + i += 8; + } + + uint32 output2 = (uint32) output; + + while (output2 >= 10000) + { + const uint32 c = output2 - 10000 * (output2 / 10000); + + output2 /= 10000; + + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + + memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2); + i += 4; + } + if (output2 >= 100) + { + const uint32 c = (output2 % 100) << 1; + + output2 /= 100; + memcpy(result + index + olength - i - 1, DIGIT_TABLE + c, 2); + i += 2; + } + if (output2 >= 10) + { + const uint32 c = output2 << 1; + + /* + * We can't use memcpy here: the decimal dot goes between these two + * digits. + */ + result[index + olength - i] = DIGIT_TABLE[c + 1]; + result[index] = DIGIT_TABLE[c]; + } + else + { + result[index] = (char) ('0' + output2); + } + + /* Print decimal point if needed. */ + if (olength > 1) + { + result[index + 1] = '.'; + index += olength + 1; + } + else + { + ++index; + } + + /* Print the exponent. */ + result[index++] = 'e'; + if (exp < 0) + { + result[index++] = '-'; + exp = -exp; + } + else + result[index++] = '+'; + + if (exp >= 100) + { + const int32 c = exp % 10; + + memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2); + result[index + 2] = (char) ('0' + c); + index += 3; + } + else + { + memcpy(result + index, DIGIT_TABLE + 2 * exp, 2); + index += 2; + } + + return index; +} + +static inline bool +d2d_small_int(const uint64 ieeeMantissa, + const uint32 ieeeExponent, + floating_decimal_64 *v) +{ + const int32 e2 = (int32) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS; + + /* + * Avoid using multiple "return false;" here since it tends to provoke the + * compiler into inlining multiple copies of d2d, which is undesirable. + */ + + if (e2 >= -DOUBLE_MANTISSA_BITS && e2 <= 0) + { + /*---- + * Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52: + * 1 <= f = m2 / 2^-e2 < 2^53. + * + * Test if the lower -e2 bits of the significand are 0, i.e. whether + * the fraction is 0. We can use ieeeMantissa here, since the implied + * 1 bit can never be tested by this; the implied 1 can only be part + * of a fraction if e2 < -DOUBLE_MANTISSA_BITS which we already + * checked. (e.g. 0.5 gives ieeeMantissa == 0 and e2 == -53) + */ + const uint64 mask = (UINT64CONST(1) << -e2) - 1; + const uint64 fraction = ieeeMantissa & mask; + + if (fraction == 0) + { + /*---- + * f is an integer in the range [1, 2^53). + * Note: mantissa might contain trailing (decimal) 0's. + * Note: since 2^53 < 10^16, there is no need to adjust + * decimalLength(). + */ + const uint64 m2 = (UINT64CONST(1) << DOUBLE_MANTISSA_BITS) | ieeeMantissa; + + v->mantissa = m2 >> -e2; + v->exponent = 0; + return true; + } + } + + return false; +} + +/* + * Store the shortest decimal representation of the given double as an + * UNTERMINATED string in the caller's supplied buffer (which must be at least + * DOUBLE_SHORTEST_DECIMAL_LEN-1 bytes long). + * + * Returns the number of bytes stored. + */ +int +double_to_shortest_decimal_bufn(double f, char *result) +{ + /* + * Step 1: Decode the floating-point number, and unify normalized and + * subnormal cases. + */ + const uint64 bits = double_to_bits(f); + + /* Decode bits into sign, mantissa, and exponent. */ + const bool ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; + const uint64 ieeeMantissa = bits & ((UINT64CONST(1) << DOUBLE_MANTISSA_BITS) - 1); + const uint32 ieeeExponent = (uint32) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1)); + + /* Case distinction; exit early for the easy cases. */ + if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) + { + return copy_special_str(result, ieeeSign, (ieeeExponent != 0), (ieeeMantissa != 0)); + } + + floating_decimal_64 v; + const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v); + + if (!isSmallInt) + { + v = d2d(ieeeMantissa, ieeeExponent); + } + + return to_chars(v, ieeeSign, result); +} + +/* + * Store the shortest decimal representation of the given double as a + * null-terminated string in the caller's supplied buffer (which must be at + * least DOUBLE_SHORTEST_DECIMAL_LEN bytes long). + * + * Returns the string length. + */ +int +double_to_shortest_decimal_buf(double f, char *result) +{ + const int index = double_to_shortest_decimal_bufn(f, result); + + /* Terminate the string. */ + Assert(index < DOUBLE_SHORTEST_DECIMAL_LEN); + result[index] = '\0'; + return index; +} + +/* + * Return the shortest decimal representation as a null-terminated palloc'd + * string (outside the backend, uses malloc() instead). + * + * Caller is responsible for freeing the result. + */ +char * +double_to_shortest_decimal(double f) +{ + char *const result = (char *) palloc(DOUBLE_SHORTEST_DECIMAL_LEN); + + double_to_shortest_decimal_buf(f, result); + return result; +} diff --git a/contrib/libs/libpq/src/common/d2s_full_table.h b/contrib/libs/libpq/src/common/d2s_full_table.h new file mode 100644 index 0000000000..23f5e9a45e --- /dev/null +++ b/contrib/libs/libpq/src/common/d2s_full_table.h @@ -0,0 +1,358 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output for double precision. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/d2s_full_table.h + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ + +#ifndef RYU_D2S_FULL_TABLE_H +#define RYU_D2S_FULL_TABLE_H + +/* + * These tables are generated (by the upstream) using PrintDoubleLookupTable + * from the upstream sources at github.com/ulfjack/ryu, and then modified (by + * us) by adding UINT64CONST. + */ +static const uint64 DOUBLE_POW5_INV_SPLIT[292][2] = { + {UINT64CONST(1), UINT64CONST(288230376151711744)}, {UINT64CONST(3689348814741910324), UINT64CONST(230584300921369395)}, + {UINT64CONST(2951479051793528259), UINT64CONST(184467440737095516)}, {UINT64CONST(17118578500402463900), UINT64CONST(147573952589676412)}, + {UINT64CONST(12632330341676300947), UINT64CONST(236118324143482260)}, {UINT64CONST(10105864273341040758), UINT64CONST(188894659314785808)}, + {UINT64CONST(15463389048156653253), UINT64CONST(151115727451828646)}, {UINT64CONST(17362724847566824558), UINT64CONST(241785163922925834)}, + {UINT64CONST(17579528692795369969), UINT64CONST(193428131138340667)}, {UINT64CONST(6684925324752475329), UINT64CONST(154742504910672534)}, + {UINT64CONST(18074578149087781173), UINT64CONST(247588007857076054)}, {UINT64CONST(18149011334012135262), UINT64CONST(198070406285660843)}, + {UINT64CONST(3451162622983977240), UINT64CONST(158456325028528675)}, {UINT64CONST(5521860196774363583), UINT64CONST(253530120045645880)}, + {UINT64CONST(4417488157419490867), UINT64CONST(202824096036516704)}, {UINT64CONST(7223339340677503017), UINT64CONST(162259276829213363)}, + {UINT64CONST(7867994130342094503), UINT64CONST(259614842926741381)}, {UINT64CONST(2605046489531765280), UINT64CONST(207691874341393105)}, + {UINT64CONST(2084037191625412224), UINT64CONST(166153499473114484)}, {UINT64CONST(10713157136084480204), UINT64CONST(265845599156983174)}, + {UINT64CONST(12259874523609494487), UINT64CONST(212676479325586539)}, {UINT64CONST(13497248433629505913), UINT64CONST(170141183460469231)}, + {UINT64CONST(14216899864323388813), UINT64CONST(272225893536750770)}, {UINT64CONST(11373519891458711051), UINT64CONST(217780714829400616)}, + {UINT64CONST(5409467098425058518), UINT64CONST(174224571863520493)}, {UINT64CONST(4965798542738183305), UINT64CONST(278759314981632789)}, + {UINT64CONST(7661987648932456967), UINT64CONST(223007451985306231)}, {UINT64CONST(2440241304404055250), UINT64CONST(178405961588244985)}, + {UINT64CONST(3904386087046488400), UINT64CONST(285449538541191976)}, {UINT64CONST(17880904128604832013), UINT64CONST(228359630832953580)}, + {UINT64CONST(14304723302883865611), UINT64CONST(182687704666362864)}, {UINT64CONST(15133127457049002812), UINT64CONST(146150163733090291)}, + {UINT64CONST(16834306301794583852), UINT64CONST(233840261972944466)}, {UINT64CONST(9778096226693756759), UINT64CONST(187072209578355573)}, + {UINT64CONST(15201174610838826053), UINT64CONST(149657767662684458)}, {UINT64CONST(2185786488890659746), UINT64CONST(239452428260295134)}, + {UINT64CONST(5437978005854438120), UINT64CONST(191561942608236107)}, {UINT64CONST(15418428848909281466), UINT64CONST(153249554086588885)}, + {UINT64CONST(6222742084545298729), UINT64CONST(245199286538542217)}, {UINT64CONST(16046240111861969953), UINT64CONST(196159429230833773)}, + {UINT64CONST(1768945645263844993), UINT64CONST(156927543384667019)}, {UINT64CONST(10209010661905972635), UINT64CONST(251084069415467230)}, + {UINT64CONST(8167208529524778108), UINT64CONST(200867255532373784)}, {UINT64CONST(10223115638361732810), UINT64CONST(160693804425899027)}, + {UINT64CONST(1599589762411131202), UINT64CONST(257110087081438444)}, {UINT64CONST(4969020624670815285), UINT64CONST(205688069665150755)}, + {UINT64CONST(3975216499736652228), UINT64CONST(164550455732120604)}, {UINT64CONST(13739044029062464211), UINT64CONST(263280729171392966)}, + {UINT64CONST(7301886408508061046), UINT64CONST(210624583337114373)}, {UINT64CONST(13220206756290269483), UINT64CONST(168499666669691498)}, + {UINT64CONST(17462981995322520850), UINT64CONST(269599466671506397)}, {UINT64CONST(6591687966774196033), UINT64CONST(215679573337205118)}, + {UINT64CONST(12652048002903177473), UINT64CONST(172543658669764094)}, {UINT64CONST(9175230360419352987), UINT64CONST(276069853871622551)}, + {UINT64CONST(3650835473593572067), UINT64CONST(220855883097298041)}, {UINT64CONST(17678063637842498946), UINT64CONST(176684706477838432)}, + {UINT64CONST(13527506561580357021), UINT64CONST(282695530364541492)}, {UINT64CONST(3443307619780464970), UINT64CONST(226156424291633194)}, + {UINT64CONST(6443994910566282300), UINT64CONST(180925139433306555)}, {UINT64CONST(5155195928453025840), UINT64CONST(144740111546645244)}, + {UINT64CONST(15627011115008661990), UINT64CONST(231584178474632390)}, {UINT64CONST(12501608892006929592), UINT64CONST(185267342779705912)}, + {UINT64CONST(2622589484121723027), UINT64CONST(148213874223764730)}, {UINT64CONST(4196143174594756843), UINT64CONST(237142198758023568)}, + {UINT64CONST(10735612169159626121), UINT64CONST(189713759006418854)}, {UINT64CONST(12277838550069611220), UINT64CONST(151771007205135083)}, + {UINT64CONST(15955192865369467629), UINT64CONST(242833611528216133)}, {UINT64CONST(1696107848069843133), UINT64CONST(194266889222572907)}, + {UINT64CONST(12424932722681605476), UINT64CONST(155413511378058325)}, {UINT64CONST(1433148282581017146), UINT64CONST(248661618204893321)}, + {UINT64CONST(15903913885032455010), UINT64CONST(198929294563914656)}, {UINT64CONST(9033782293284053685), UINT64CONST(159143435651131725)}, + {UINT64CONST(14454051669254485895), UINT64CONST(254629497041810760)}, {UINT64CONST(11563241335403588716), UINT64CONST(203703597633448608)}, + {UINT64CONST(16629290697806691620), UINT64CONST(162962878106758886)}, {UINT64CONST(781423413297334329), UINT64CONST(260740604970814219)}, + {UINT64CONST(4314487545379777786), UINT64CONST(208592483976651375)}, {UINT64CONST(3451590036303822229), UINT64CONST(166873987181321100)}, + {UINT64CONST(5522544058086115566), UINT64CONST(266998379490113760)}, {UINT64CONST(4418035246468892453), UINT64CONST(213598703592091008)}, + {UINT64CONST(10913125826658934609), UINT64CONST(170878962873672806)}, {UINT64CONST(10082303693170474728), UINT64CONST(273406340597876490)}, + {UINT64CONST(8065842954536379782), UINT64CONST(218725072478301192)}, {UINT64CONST(17520720807854834795), UINT64CONST(174980057982640953)}, + {UINT64CONST(5897060404116273733), UINT64CONST(279968092772225526)}, {UINT64CONST(1028299508551108663), UINT64CONST(223974474217780421)}, + {UINT64CONST(15580034865808528224), UINT64CONST(179179579374224336)}, {UINT64CONST(17549358155809824511), UINT64CONST(286687326998758938)}, + {UINT64CONST(2971440080422128639), UINT64CONST(229349861599007151)}, {UINT64CONST(17134547323305344204), UINT64CONST(183479889279205720)}, + {UINT64CONST(13707637858644275364), UINT64CONST(146783911423364576)}, {UINT64CONST(14553522944347019935), UINT64CONST(234854258277383322)}, + {UINT64CONST(4264120725993795302), UINT64CONST(187883406621906658)}, {UINT64CONST(10789994210278856888), UINT64CONST(150306725297525326)}, + {UINT64CONST(9885293106962350374), UINT64CONST(240490760476040522)}, {UINT64CONST(529536856086059653), UINT64CONST(192392608380832418)}, + {UINT64CONST(7802327114352668369), UINT64CONST(153914086704665934)}, {UINT64CONST(1415676938738538420), UINT64CONST(246262538727465495)}, + {UINT64CONST(1132541550990830736), UINT64CONST(197010030981972396)}, {UINT64CONST(15663428499760305882), UINT64CONST(157608024785577916)}, + {UINT64CONST(17682787970132668764), UINT64CONST(252172839656924666)}, {UINT64CONST(10456881561364224688), UINT64CONST(201738271725539733)}, + {UINT64CONST(15744202878575200397), UINT64CONST(161390617380431786)}, {UINT64CONST(17812026976236499989), UINT64CONST(258224987808690858)}, + {UINT64CONST(3181575136763469022), UINT64CONST(206579990246952687)}, {UINT64CONST(13613306553636506187), UINT64CONST(165263992197562149)}, + {UINT64CONST(10713244041592678929), UINT64CONST(264422387516099439)}, {UINT64CONST(12259944048016053467), UINT64CONST(211537910012879551)}, + {UINT64CONST(6118606423670932450), UINT64CONST(169230328010303641)}, {UINT64CONST(2411072648389671274), UINT64CONST(270768524816485826)}, + {UINT64CONST(16686253377679378312), UINT64CONST(216614819853188660)}, {UINT64CONST(13349002702143502650), UINT64CONST(173291855882550928)}, + {UINT64CONST(17669055508687693916), UINT64CONST(277266969412081485)}, {UINT64CONST(14135244406950155133), UINT64CONST(221813575529665188)}, + {UINT64CONST(240149081334393137), UINT64CONST(177450860423732151)}, {UINT64CONST(11452284974360759988), UINT64CONST(283921376677971441)}, + {UINT64CONST(5472479164746697667), UINT64CONST(227137101342377153)}, {UINT64CONST(11756680961281178780), UINT64CONST(181709681073901722)}, + {UINT64CONST(2026647139541122378), UINT64CONST(145367744859121378)}, {UINT64CONST(18000030682233437097), UINT64CONST(232588391774594204)}, + {UINT64CONST(18089373360528660001), UINT64CONST(186070713419675363)}, {UINT64CONST(3403452244197197031), UINT64CONST(148856570735740291)}, + {UINT64CONST(16513570034941246220), UINT64CONST(238170513177184465)}, {UINT64CONST(13210856027952996976), UINT64CONST(190536410541747572)}, + {UINT64CONST(3189987192878576934), UINT64CONST(152429128433398058)}, {UINT64CONST(1414630693863812771), UINT64CONST(243886605493436893)}, + {UINT64CONST(8510402184574870864), UINT64CONST(195109284394749514)}, {UINT64CONST(10497670562401807014), UINT64CONST(156087427515799611)}, + {UINT64CONST(9417575270359070576), UINT64CONST(249739884025279378)}, {UINT64CONST(14912757845771077107), UINT64CONST(199791907220223502)}, + {UINT64CONST(4551508647133041040), UINT64CONST(159833525776178802)}, {UINT64CONST(10971762650154775986), UINT64CONST(255733641241886083)}, + {UINT64CONST(16156107749607641435), UINT64CONST(204586912993508866)}, {UINT64CONST(9235537384944202825), UINT64CONST(163669530394807093)}, + {UINT64CONST(11087511001168814197), UINT64CONST(261871248631691349)}, {UINT64CONST(12559357615676961681), UINT64CONST(209496998905353079)}, + {UINT64CONST(13736834907283479668), UINT64CONST(167597599124282463)}, {UINT64CONST(18289587036911657145), UINT64CONST(268156158598851941)}, + {UINT64CONST(10942320814787415393), UINT64CONST(214524926879081553)}, {UINT64CONST(16132554281313752961), UINT64CONST(171619941503265242)}, + {UINT64CONST(11054691591134363444), UINT64CONST(274591906405224388)}, {UINT64CONST(16222450902391311402), UINT64CONST(219673525124179510)}, + {UINT64CONST(12977960721913049122), UINT64CONST(175738820099343608)}, {UINT64CONST(17075388340318968271), UINT64CONST(281182112158949773)}, + {UINT64CONST(2592264228029443648), UINT64CONST(224945689727159819)}, {UINT64CONST(5763160197165465241), UINT64CONST(179956551781727855)}, + {UINT64CONST(9221056315464744386), UINT64CONST(287930482850764568)}, {UINT64CONST(14755542681855616155), UINT64CONST(230344386280611654)}, + {UINT64CONST(15493782960226403247), UINT64CONST(184275509024489323)}, {UINT64CONST(1326979923955391628), UINT64CONST(147420407219591459)}, + {UINT64CONST(9501865507812447252), UINT64CONST(235872651551346334)}, {UINT64CONST(11290841220991868125), UINT64CONST(188698121241077067)}, + {UINT64CONST(1653975347309673853), UINT64CONST(150958496992861654)}, {UINT64CONST(10025058185179298811), UINT64CONST(241533595188578646)}, + {UINT64CONST(4330697733401528726), UINT64CONST(193226876150862917)}, {UINT64CONST(14532604630946953951), UINT64CONST(154581500920690333)}, + {UINT64CONST(1116074521063664381), UINT64CONST(247330401473104534)}, {UINT64CONST(4582208431592841828), UINT64CONST(197864321178483627)}, + {UINT64CONST(14733813189500004432), UINT64CONST(158291456942786901)}, {UINT64CONST(16195403473716186445), UINT64CONST(253266331108459042)}, + {UINT64CONST(5577625149489128510), UINT64CONST(202613064886767234)}, {UINT64CONST(8151448934333213131), UINT64CONST(162090451909413787)}, + {UINT64CONST(16731667109675051333), UINT64CONST(259344723055062059)}, {UINT64CONST(17074682502481951390), UINT64CONST(207475778444049647)}, + {UINT64CONST(6281048372501740465), UINT64CONST(165980622755239718)}, {UINT64CONST(6360328581260874421), UINT64CONST(265568996408383549)}, + {UINT64CONST(8777611679750609860), UINT64CONST(212455197126706839)}, {UINT64CONST(10711438158542398211), UINT64CONST(169964157701365471)}, + {UINT64CONST(9759603424184016492), UINT64CONST(271942652322184754)}, {UINT64CONST(11497031554089123517), UINT64CONST(217554121857747803)}, + {UINT64CONST(16576322872755119460), UINT64CONST(174043297486198242)}, {UINT64CONST(11764721337440549842), UINT64CONST(278469275977917188)}, + {UINT64CONST(16790474699436260520), UINT64CONST(222775420782333750)}, {UINT64CONST(13432379759549008416), UINT64CONST(178220336625867000)}, + {UINT64CONST(3045063541568861850), UINT64CONST(285152538601387201)}, {UINT64CONST(17193446092222730773), UINT64CONST(228122030881109760)}, + {UINT64CONST(13754756873778184618), UINT64CONST(182497624704887808)}, {UINT64CONST(18382503128506368341), UINT64CONST(145998099763910246)}, + {UINT64CONST(3586563302416817083), UINT64CONST(233596959622256395)}, {UINT64CONST(2869250641933453667), UINT64CONST(186877567697805116)}, + {UINT64CONST(17052795772514404226), UINT64CONST(149502054158244092)}, {UINT64CONST(12527077977055405469), UINT64CONST(239203286653190548)}, + {UINT64CONST(17400360011128145022), UINT64CONST(191362629322552438)}, {UINT64CONST(2852241564676785048), UINT64CONST(153090103458041951)}, + {UINT64CONST(15631632947708587046), UINT64CONST(244944165532867121)}, {UINT64CONST(8815957543424959314), UINT64CONST(195955332426293697)}, + {UINT64CONST(18120812478965698421), UINT64CONST(156764265941034957)}, {UINT64CONST(14235904707377476180), UINT64CONST(250822825505655932)}, + {UINT64CONST(4010026136418160298), UINT64CONST(200658260404524746)}, {UINT64CONST(17965416168102169531), UINT64CONST(160526608323619796)}, + {UINT64CONST(2919224165770098987), UINT64CONST(256842573317791675)}, {UINT64CONST(2335379332616079190), UINT64CONST(205474058654233340)}, + {UINT64CONST(1868303466092863352), UINT64CONST(164379246923386672)}, {UINT64CONST(6678634360490491686), UINT64CONST(263006795077418675)}, + {UINT64CONST(5342907488392393349), UINT64CONST(210405436061934940)}, {UINT64CONST(4274325990713914679), UINT64CONST(168324348849547952)}, + {UINT64CONST(10528270399884173809), UINT64CONST(269318958159276723)}, {UINT64CONST(15801313949391159694), UINT64CONST(215455166527421378)}, + {UINT64CONST(1573004715287196786), UINT64CONST(172364133221937103)}, {UINT64CONST(17274202803427156150), UINT64CONST(275782613155099364)}, + {UINT64CONST(17508711057483635243), UINT64CONST(220626090524079491)}, {UINT64CONST(10317620031244997871), UINT64CONST(176500872419263593)}, + {UINT64CONST(12818843235250086271), UINT64CONST(282401395870821749)}, {UINT64CONST(13944423402941979340), UINT64CONST(225921116696657399)}, + {UINT64CONST(14844887537095493795), UINT64CONST(180736893357325919)}, {UINT64CONST(15565258844418305359), UINT64CONST(144589514685860735)}, + {UINT64CONST(6457670077359736959), UINT64CONST(231343223497377177)}, {UINT64CONST(16234182506113520537), UINT64CONST(185074578797901741)}, + {UINT64CONST(9297997190148906106), UINT64CONST(148059663038321393)}, {UINT64CONST(11187446689496339446), UINT64CONST(236895460861314229)}, + {UINT64CONST(12639306166338981880), UINT64CONST(189516368689051383)}, {UINT64CONST(17490142562555006151), UINT64CONST(151613094951241106)}, + {UINT64CONST(2158786396894637579), UINT64CONST(242580951921985771)}, {UINT64CONST(16484424376483351356), UINT64CONST(194064761537588616)}, + {UINT64CONST(9498190686444770762), UINT64CONST(155251809230070893)}, {UINT64CONST(11507756283569722895), UINT64CONST(248402894768113429)}, + {UINT64CONST(12895553841597688639), UINT64CONST(198722315814490743)}, {UINT64CONST(17695140702761971558), UINT64CONST(158977852651592594)}, + {UINT64CONST(17244178680193423523), UINT64CONST(254364564242548151)}, {UINT64CONST(10105994129412828495), UINT64CONST(203491651394038521)}, + {UINT64CONST(4395446488788352473), UINT64CONST(162793321115230817)}, {UINT64CONST(10722063196803274280), UINT64CONST(260469313784369307)}, + {UINT64CONST(1198952927958798777), UINT64CONST(208375451027495446)}, {UINT64CONST(15716557601334680315), UINT64CONST(166700360821996356)}, + {UINT64CONST(17767794532651667857), UINT64CONST(266720577315194170)}, {UINT64CONST(14214235626121334286), UINT64CONST(213376461852155336)}, + {UINT64CONST(7682039686155157106), UINT64CONST(170701169481724269)}, {UINT64CONST(1223217053622520399), UINT64CONST(273121871170758831)}, + {UINT64CONST(15735968901865657612), UINT64CONST(218497496936607064)}, {UINT64CONST(16278123936234436413), UINT64CONST(174797997549285651)}, + {UINT64CONST(219556594781725998), UINT64CONST(279676796078857043)}, {UINT64CONST(7554342905309201445), UINT64CONST(223741436863085634)}, + {UINT64CONST(9732823138989271479), UINT64CONST(178993149490468507)}, {UINT64CONST(815121763415193074), UINT64CONST(286389039184749612)}, + {UINT64CONST(11720143854957885429), UINT64CONST(229111231347799689)}, {UINT64CONST(13065463898708218666), UINT64CONST(183288985078239751)}, + {UINT64CONST(6763022304224664610), UINT64CONST(146631188062591801)}, {UINT64CONST(3442138057275642729), UINT64CONST(234609900900146882)}, + {UINT64CONST(13821756890046245153), UINT64CONST(187687920720117505)}, {UINT64CONST(11057405512036996122), UINT64CONST(150150336576094004)}, + {UINT64CONST(6623802375033462826), UINT64CONST(240240538521750407)}, {UINT64CONST(16367088344252501231), UINT64CONST(192192430817400325)}, + {UINT64CONST(13093670675402000985), UINT64CONST(153753944653920260)}, {UINT64CONST(2503129006933649959), UINT64CONST(246006311446272417)}, + {UINT64CONST(13070549649772650937), UINT64CONST(196805049157017933)}, {UINT64CONST(17835137349301941396), UINT64CONST(157444039325614346)}, + {UINT64CONST(2710778055689733971), UINT64CONST(251910462920982955)}, {UINT64CONST(2168622444551787177), UINT64CONST(201528370336786364)}, + {UINT64CONST(5424246770383340065), UINT64CONST(161222696269429091)}, {UINT64CONST(1300097203129523457), UINT64CONST(257956314031086546)}, + {UINT64CONST(15797473021471260058), UINT64CONST(206365051224869236)}, {UINT64CONST(8948629602435097724), UINT64CONST(165092040979895389)}, + {UINT64CONST(3249760919670425388), UINT64CONST(264147265567832623)}, {UINT64CONST(9978506365220160957), UINT64CONST(211317812454266098)}, + {UINT64CONST(15361502721659949412), UINT64CONST(169054249963412878)}, {UINT64CONST(2442311466204457120), UINT64CONST(270486799941460606)}, + {UINT64CONST(16711244431931206989), UINT64CONST(216389439953168484)}, {UINT64CONST(17058344360286875914), UINT64CONST(173111551962534787)}, + {UINT64CONST(12535955717491360170), UINT64CONST(276978483140055660)}, {UINT64CONST(10028764573993088136), UINT64CONST(221582786512044528)}, + {UINT64CONST(15401709288678291155), UINT64CONST(177266229209635622)}, {UINT64CONST(9885339602917624555), UINT64CONST(283625966735416996)}, + {UINT64CONST(4218922867592189321), UINT64CONST(226900773388333597)}, {UINT64CONST(14443184738299482427), UINT64CONST(181520618710666877)}, + {UINT64CONST(4175850161155765295), UINT64CONST(145216494968533502)}, {UINT64CONST(10370709072591134795), UINT64CONST(232346391949653603)}, + {UINT64CONST(15675264887556728482), UINT64CONST(185877113559722882)}, {UINT64CONST(5161514280561562140), UINT64CONST(148701690847778306)}, + {UINT64CONST(879725219414678777), UINT64CONST(237922705356445290)}, {UINT64CONST(703780175531743021), UINT64CONST(190338164285156232)}, + {UINT64CONST(11631070584651125387), UINT64CONST(152270531428124985)}, {UINT64CONST(162968861732249003), UINT64CONST(243632850284999977)}, + {UINT64CONST(11198421533611530172), UINT64CONST(194906280227999981)}, {UINT64CONST(5269388412147313814), UINT64CONST(155925024182399985)}, + {UINT64CONST(8431021459435702103), UINT64CONST(249480038691839976)}, {UINT64CONST(3055468352806651359), UINT64CONST(199584030953471981)}, + {UINT64CONST(17201769941212962380), UINT64CONST(159667224762777584)}, {UINT64CONST(16454785461715008838), UINT64CONST(255467559620444135)}, + {UINT64CONST(13163828369372007071), UINT64CONST(204374047696355308)}, {UINT64CONST(17909760324981426303), UINT64CONST(163499238157084246)}, + {UINT64CONST(2830174816776909822), UINT64CONST(261598781051334795)}, {UINT64CONST(2264139853421527858), UINT64CONST(209279024841067836)}, + {UINT64CONST(16568707141704863579), UINT64CONST(167423219872854268)}, {UINT64CONST(4373838538276319787), UINT64CONST(267877151796566830)}, + {UINT64CONST(3499070830621055830), UINT64CONST(214301721437253464)}, {UINT64CONST(6488605479238754987), UINT64CONST(171441377149802771)}, + {UINT64CONST(3003071137298187333), UINT64CONST(274306203439684434)}, {UINT64CONST(6091805724580460189), UINT64CONST(219444962751747547)}, + {UINT64CONST(15941491023890099121), UINT64CONST(175555970201398037)}, {UINT64CONST(10748990379256517301), UINT64CONST(280889552322236860)}, + {UINT64CONST(8599192303405213841), UINT64CONST(224711641857789488)}, {UINT64CONST(14258051472207991719), UINT64CONST(179769313486231590)} +}; + +static const uint64 DOUBLE_POW5_SPLIT[326][2] = { + {UINT64CONST(0), UINT64CONST(72057594037927936)}, {UINT64CONST(0), UINT64CONST(90071992547409920)}, + {UINT64CONST(0), UINT64CONST(112589990684262400)}, {UINT64CONST(0), UINT64CONST(140737488355328000)}, + {UINT64CONST(0), UINT64CONST(87960930222080000)}, {UINT64CONST(0), UINT64CONST(109951162777600000)}, + {UINT64CONST(0), UINT64CONST(137438953472000000)}, {UINT64CONST(0), UINT64CONST(85899345920000000)}, + {UINT64CONST(0), UINT64CONST(107374182400000000)}, {UINT64CONST(0), UINT64CONST(134217728000000000)}, + {UINT64CONST(0), UINT64CONST(83886080000000000)}, {UINT64CONST(0), UINT64CONST(104857600000000000)}, + {UINT64CONST(0), UINT64CONST(131072000000000000)}, {UINT64CONST(0), UINT64CONST(81920000000000000)}, + {UINT64CONST(0), UINT64CONST(102400000000000000)}, {UINT64CONST(0), UINT64CONST(128000000000000000)}, + {UINT64CONST(0), UINT64CONST(80000000000000000)}, {UINT64CONST(0), UINT64CONST(100000000000000000)}, + {UINT64CONST(0), UINT64CONST(125000000000000000)}, {UINT64CONST(0), UINT64CONST(78125000000000000)}, + {UINT64CONST(0), UINT64CONST(97656250000000000)}, {UINT64CONST(0), UINT64CONST(122070312500000000)}, + {UINT64CONST(0), UINT64CONST(76293945312500000)}, {UINT64CONST(0), UINT64CONST(95367431640625000)}, + {UINT64CONST(0), UINT64CONST(119209289550781250)}, {UINT64CONST(4611686018427387904), UINT64CONST(74505805969238281)}, + {UINT64CONST(10376293541461622784), UINT64CONST(93132257461547851)}, {UINT64CONST(8358680908399640576), UINT64CONST(116415321826934814)}, + {UINT64CONST(612489549322387456), UINT64CONST(72759576141834259)}, {UINT64CONST(14600669991935148032), UINT64CONST(90949470177292823)}, + {UINT64CONST(13639151471491547136), UINT64CONST(113686837721616029)}, {UINT64CONST(3213881284082270208), UINT64CONST(142108547152020037)}, + {UINT64CONST(4314518811765112832), UINT64CONST(88817841970012523)}, {UINT64CONST(781462496279003136), UINT64CONST(111022302462515654)}, + {UINT64CONST(10200200157203529728), UINT64CONST(138777878078144567)}, {UINT64CONST(13292654125893287936), UINT64CONST(86736173798840354)}, + {UINT64CONST(7392445620511834112), UINT64CONST(108420217248550443)}, {UINT64CONST(4628871007212404736), UINT64CONST(135525271560688054)}, + {UINT64CONST(16728102434789916672), UINT64CONST(84703294725430033)}, {UINT64CONST(7075069988205232128), UINT64CONST(105879118406787542)}, + {UINT64CONST(18067209522111315968), UINT64CONST(132348898008484427)}, {UINT64CONST(8986162942105878528), UINT64CONST(82718061255302767)}, + {UINT64CONST(6621017659204960256), UINT64CONST(103397576569128459)}, {UINT64CONST(3664586055578812416), UINT64CONST(129246970711410574)}, + {UINT64CONST(16125424340018921472), UINT64CONST(80779356694631608)}, {UINT64CONST(1710036351314100224), UINT64CONST(100974195868289511)}, + {UINT64CONST(15972603494424788992), UINT64CONST(126217744835361888)}, {UINT64CONST(9982877184015493120), UINT64CONST(78886090522101180)}, + {UINT64CONST(12478596480019366400), UINT64CONST(98607613152626475)}, {UINT64CONST(10986559581596820096), UINT64CONST(123259516440783094)}, + {UINT64CONST(2254913720070624656), UINT64CONST(77037197775489434)}, {UINT64CONST(12042014186943056628), UINT64CONST(96296497219361792)}, + {UINT64CONST(15052517733678820785), UINT64CONST(120370621524202240)}, {UINT64CONST(9407823583549262990), UINT64CONST(75231638452626400)}, + {UINT64CONST(11759779479436578738), UINT64CONST(94039548065783000)}, {UINT64CONST(14699724349295723422), UINT64CONST(117549435082228750)}, + {UINT64CONST(4575641699882439235), UINT64CONST(73468396926392969)}, {UINT64CONST(10331238143280436948), UINT64CONST(91835496157991211)}, + {UINT64CONST(8302361660673158281), UINT64CONST(114794370197489014)}, {UINT64CONST(1154580038986672043), UINT64CONST(143492962746861268)}, + {UINT64CONST(9944984561221445835), UINT64CONST(89683101716788292)}, {UINT64CONST(12431230701526807293), UINT64CONST(112103877145985365)}, + {UINT64CONST(1703980321626345405), UINT64CONST(140129846432481707)}, {UINT64CONST(17205888765512323542), UINT64CONST(87581154020301066)}, + {UINT64CONST(12283988920035628619), UINT64CONST(109476442525376333)}, {UINT64CONST(1519928094762372062), UINT64CONST(136845553156720417)}, + {UINT64CONST(12479170105294952299), UINT64CONST(85528470722950260)}, {UINT64CONST(15598962631618690374), UINT64CONST(106910588403687825)}, + {UINT64CONST(5663645234241199255), UINT64CONST(133638235504609782)}, {UINT64CONST(17374836326682913246), UINT64CONST(83523897190381113)}, + {UINT64CONST(7883487353071477846), UINT64CONST(104404871487976392)}, {UINT64CONST(9854359191339347308), UINT64CONST(130506089359970490)}, + {UINT64CONST(10770660513014479971), UINT64CONST(81566305849981556)}, {UINT64CONST(13463325641268099964), UINT64CONST(101957882312476945)}, + {UINT64CONST(2994098996302961243), UINT64CONST(127447352890596182)}, {UINT64CONST(15706369927971514489), UINT64CONST(79654595556622613)}, + {UINT64CONST(5797904354682229399), UINT64CONST(99568244445778267)}, {UINT64CONST(2635694424925398845), UINT64CONST(124460305557222834)}, + {UINT64CONST(6258995034005762182), UINT64CONST(77787690973264271)}, {UINT64CONST(3212057774079814824), UINT64CONST(97234613716580339)}, + {UINT64CONST(17850130272881932242), UINT64CONST(121543267145725423)}, {UINT64CONST(18073860448192289507), UINT64CONST(75964541966078389)}, + {UINT64CONST(8757267504958198172), UINT64CONST(94955677457597987)}, {UINT64CONST(6334898362770359811), UINT64CONST(118694596821997484)}, + {UINT64CONST(13182683513586250689), UINT64CONST(74184123013748427)}, {UINT64CONST(11866668373555425458), UINT64CONST(92730153767185534)}, + {UINT64CONST(5609963430089506015), UINT64CONST(115912692208981918)}, {UINT64CONST(17341285199088104971), UINT64CONST(72445432630613698)}, + {UINT64CONST(12453234462005355406), UINT64CONST(90556790788267123)}, {UINT64CONST(10954857059079306353), UINT64CONST(113195988485333904)}, + {UINT64CONST(13693571323849132942), UINT64CONST(141494985606667380)}, {UINT64CONST(17781854114260483896), UINT64CONST(88434366004167112)}, + {UINT64CONST(3780573569116053255), UINT64CONST(110542957505208891)}, {UINT64CONST(114030942967678664), UINT64CONST(138178696881511114)}, + {UINT64CONST(4682955357782187069), UINT64CONST(86361685550944446)}, {UINT64CONST(15077066234082509644), UINT64CONST(107952106938680557)}, + {UINT64CONST(5011274737320973344), UINT64CONST(134940133673350697)}, {UINT64CONST(14661261756894078100), UINT64CONST(84337583545844185)}, + {UINT64CONST(4491519140835433913), UINT64CONST(105421979432305232)}, {UINT64CONST(5614398926044292391), UINT64CONST(131777474290381540)}, + {UINT64CONST(12732371365632458552), UINT64CONST(82360921431488462)}, {UINT64CONST(6692092170185797382), UINT64CONST(102951151789360578)}, + {UINT64CONST(17588487249587022536), UINT64CONST(128688939736700722)}, {UINT64CONST(15604490549419276989), UINT64CONST(80430587335437951)}, + {UINT64CONST(14893927168346708332), UINT64CONST(100538234169297439)}, {UINT64CONST(14005722942005997511), UINT64CONST(125672792711621799)}, + {UINT64CONST(15671105866394830300), UINT64CONST(78545495444763624)}, {UINT64CONST(1142138259283986260), UINT64CONST(98181869305954531)}, + {UINT64CONST(15262730879387146537), UINT64CONST(122727336632443163)}, {UINT64CONST(7233363790403272633), UINT64CONST(76704585395276977)}, + {UINT64CONST(13653390756431478696), UINT64CONST(95880731744096221)}, {UINT64CONST(3231680390257184658), UINT64CONST(119850914680120277)}, + {UINT64CONST(4325643253124434363), UINT64CONST(74906821675075173)}, {UINT64CONST(10018740084832930858), UINT64CONST(93633527093843966)}, + {UINT64CONST(3300053069186387764), UINT64CONST(117041908867304958)}, {UINT64CONST(15897591223523656064), UINT64CONST(73151193042065598)}, + {UINT64CONST(10648616992549794273), UINT64CONST(91438991302581998)}, {UINT64CONST(4087399203832467033), UINT64CONST(114298739128227498)}, + {UINT64CONST(14332621041645359599), UINT64CONST(142873423910284372)}, {UINT64CONST(18181260187883125557), UINT64CONST(89295889943927732)}, + {UINT64CONST(4279831161144355331), UINT64CONST(111619862429909666)}, {UINT64CONST(14573160988285219972), UINT64CONST(139524828037387082)}, + {UINT64CONST(13719911636105650386), UINT64CONST(87203017523366926)}, {UINT64CONST(7926517508277287175), UINT64CONST(109003771904208658)}, + {UINT64CONST(684774848491833161), UINT64CONST(136254714880260823)}, {UINT64CONST(7345513307948477581), UINT64CONST(85159196800163014)}, + {UINT64CONST(18405263671790372785), UINT64CONST(106448996000203767)}, {UINT64CONST(18394893571310578077), UINT64CONST(133061245000254709)}, + {UINT64CONST(13802651491282805250), UINT64CONST(83163278125159193)}, {UINT64CONST(3418256308821342851), UINT64CONST(103954097656448992)}, + {UINT64CONST(4272820386026678563), UINT64CONST(129942622070561240)}, {UINT64CONST(2670512741266674102), UINT64CONST(81214138794100775)}, + {UINT64CONST(17173198981865506339), UINT64CONST(101517673492625968)}, {UINT64CONST(3019754653622331308), UINT64CONST(126897091865782461)}, + {UINT64CONST(4193189667727651020), UINT64CONST(79310682416114038)}, {UINT64CONST(14464859121514339583), UINT64CONST(99138353020142547)}, + {UINT64CONST(13469387883465536574), UINT64CONST(123922941275178184)}, {UINT64CONST(8418367427165960359), UINT64CONST(77451838296986365)}, + {UINT64CONST(15134645302384838353), UINT64CONST(96814797871232956)}, {UINT64CONST(471562554271496325), UINT64CONST(121018497339041196)}, + {UINT64CONST(9518098633274461011), UINT64CONST(75636560836900747)}, {UINT64CONST(7285937273165688360), UINT64CONST(94545701046125934)}, + {UINT64CONST(18330793628311886258), UINT64CONST(118182126307657417)}, {UINT64CONST(4539216990053847055), UINT64CONST(73863828942285886)}, + {UINT64CONST(14897393274422084627), UINT64CONST(92329786177857357)}, {UINT64CONST(4786683537745442072), UINT64CONST(115412232722321697)}, + {UINT64CONST(14520892257159371055), UINT64CONST(72132645451451060)}, {UINT64CONST(18151115321449213818), UINT64CONST(90165806814313825)}, + {UINT64CONST(8853836096529353561), UINT64CONST(112707258517892282)}, {UINT64CONST(1843923083806916143), UINT64CONST(140884073147365353)}, + {UINT64CONST(12681666973447792349), UINT64CONST(88052545717103345)}, {UINT64CONST(2017025661527576725), UINT64CONST(110065682146379182)}, + {UINT64CONST(11744654113764246714), UINT64CONST(137582102682973977)}, {UINT64CONST(422879793461572340), UINT64CONST(85988814176858736)}, + {UINT64CONST(528599741826965425), UINT64CONST(107486017721073420)}, {UINT64CONST(660749677283706782), UINT64CONST(134357522151341775)}, + {UINT64CONST(7330497575943398595), UINT64CONST(83973451344588609)}, {UINT64CONST(13774807988356636147), UINT64CONST(104966814180735761)}, + {UINT64CONST(3383451930163631472), UINT64CONST(131208517725919702)}, {UINT64CONST(15949715511634433382), UINT64CONST(82005323578699813)}, + {UINT64CONST(6102086334260878016), UINT64CONST(102506654473374767)}, {UINT64CONST(3015921899398709616), UINT64CONST(128133318091718459)}, + {UINT64CONST(18025852251620051174), UINT64CONST(80083323807324036)}, {UINT64CONST(4085571240815512351), UINT64CONST(100104154759155046)}, + {UINT64CONST(14330336087874166247), UINT64CONST(125130193448943807)}, {UINT64CONST(15873989082562435760), UINT64CONST(78206370905589879)}, + {UINT64CONST(15230800334775656796), UINT64CONST(97757963631987349)}, {UINT64CONST(5203442363187407284), UINT64CONST(122197454539984187)}, + {UINT64CONST(946308467778435600), UINT64CONST(76373409087490117)}, {UINT64CONST(5794571603150432404), UINT64CONST(95466761359362646)}, + {UINT64CONST(16466586540792816313), UINT64CONST(119333451699203307)}, {UINT64CONST(7985773578781816244), UINT64CONST(74583407312002067)}, + {UINT64CONST(5370530955049882401), UINT64CONST(93229259140002584)}, {UINT64CONST(6713163693812353001), UINT64CONST(116536573925003230)}, + {UINT64CONST(18030785363914884337), UINT64CONST(72835358703127018)}, {UINT64CONST(13315109668038829614), UINT64CONST(91044198378908773)}, + {UINT64CONST(2808829029766373305), UINT64CONST(113805247973635967)}, {UINT64CONST(17346094342490130344), UINT64CONST(142256559967044958)}, + {UINT64CONST(6229622945628943561), UINT64CONST(88910349979403099)}, {UINT64CONST(3175342663608791547), UINT64CONST(111137937474253874)}, + {UINT64CONST(13192550366365765242), UINT64CONST(138922421842817342)}, {UINT64CONST(3633657960551215372), UINT64CONST(86826513651760839)}, + {UINT64CONST(18377130505971182927), UINT64CONST(108533142064701048)}, {UINT64CONST(4524669058754427043), UINT64CONST(135666427580876311)}, + {UINT64CONST(9745447189362598758), UINT64CONST(84791517238047694)}, {UINT64CONST(2958436949848472639), UINT64CONST(105989396547559618)}, + {UINT64CONST(12921418224165366607), UINT64CONST(132486745684449522)}, {UINT64CONST(12687572408530742033), UINT64CONST(82804216052780951)}, + {UINT64CONST(11247779492236039638), UINT64CONST(103505270065976189)}, {UINT64CONST(224666310012885835), UINT64CONST(129381587582470237)}, + {UINT64CONST(2446259452971747599), UINT64CONST(80863492239043898)}, {UINT64CONST(12281196353069460307), UINT64CONST(101079365298804872)}, + {UINT64CONST(15351495441336825384), UINT64CONST(126349206623506090)}, {UINT64CONST(14206370669262903769), UINT64CONST(78968254139691306)}, + {UINT64CONST(8534591299723853903), UINT64CONST(98710317674614133)}, {UINT64CONST(15279925143082205283), UINT64CONST(123387897093267666)}, + {UINT64CONST(14161639232853766206), UINT64CONST(77117435683292291)}, {UINT64CONST(13090363022639819853), UINT64CONST(96396794604115364)}, + {UINT64CONST(16362953778299774816), UINT64CONST(120495993255144205)}, {UINT64CONST(12532689120651053212), UINT64CONST(75309995784465128)}, + {UINT64CONST(15665861400813816515), UINT64CONST(94137494730581410)}, {UINT64CONST(10358954714162494836), UINT64CONST(117671868413226763)}, + {UINT64CONST(4168503687137865320), UINT64CONST(73544917758266727)}, {UINT64CONST(598943590494943747), UINT64CONST(91931147197833409)}, + {UINT64CONST(5360365506546067587), UINT64CONST(114913933997291761)}, {UINT64CONST(11312142901609972388), UINT64CONST(143642417496614701)}, + {UINT64CONST(9375932322719926695), UINT64CONST(89776510935384188)}, {UINT64CONST(11719915403399908368), UINT64CONST(112220638669230235)}, + {UINT64CONST(10038208235822497557), UINT64CONST(140275798336537794)}, {UINT64CONST(10885566165816448877), UINT64CONST(87672373960336121)}, + {UINT64CONST(18218643725697949000), UINT64CONST(109590467450420151)}, {UINT64CONST(18161618638695048346), UINT64CONST(136988084313025189)}, + {UINT64CONST(13656854658398099168), UINT64CONST(85617552695640743)}, {UINT64CONST(12459382304570236056), UINT64CONST(107021940869550929)}, + {UINT64CONST(1739169825430631358), UINT64CONST(133777426086938662)}, {UINT64CONST(14922039196176308311), UINT64CONST(83610891304336663)}, + {UINT64CONST(14040862976792997485), UINT64CONST(104513614130420829)}, {UINT64CONST(3716020665709083144), UINT64CONST(130642017663026037)}, + {UINT64CONST(4628355925281870917), UINT64CONST(81651261039391273)}, {UINT64CONST(10397130925029726550), UINT64CONST(102064076299239091)}, + {UINT64CONST(8384727637859770284), UINT64CONST(127580095374048864)}, {UINT64CONST(5240454773662356427), UINT64CONST(79737559608780540)}, + {UINT64CONST(6550568467077945534), UINT64CONST(99671949510975675)}, {UINT64CONST(3576524565420044014), UINT64CONST(124589936888719594)}, + {UINT64CONST(6847013871814915412), UINT64CONST(77868710555449746)}, {UINT64CONST(17782139376623420074), UINT64CONST(97335888194312182)}, + {UINT64CONST(13004302183924499284), UINT64CONST(121669860242890228)}, {UINT64CONST(17351060901807587860), UINT64CONST(76043662651806392)}, + {UINT64CONST(3242082053549933210), UINT64CONST(95054578314757991)}, {UINT64CONST(17887660622219580224), UINT64CONST(118818222893447488)}, + {UINT64CONST(11179787888887237640), UINT64CONST(74261389308404680)}, {UINT64CONST(13974734861109047050), UINT64CONST(92826736635505850)}, + {UINT64CONST(8245046539531533005), UINT64CONST(116033420794382313)}, {UINT64CONST(16682369133275677888), UINT64CONST(72520887996488945)}, + {UINT64CONST(7017903361312433648), UINT64CONST(90651109995611182)}, {UINT64CONST(17995751238495317868), UINT64CONST(113313887494513977)}, + {UINT64CONST(8659630992836983623), UINT64CONST(141642359368142472)}, {UINT64CONST(5412269370523114764), UINT64CONST(88526474605089045)}, + {UINT64CONST(11377022731581281359), UINT64CONST(110658093256361306)}, {UINT64CONST(4997906377621825891), UINT64CONST(138322616570451633)}, + {UINT64CONST(14652906532082110942), UINT64CONST(86451635356532270)}, {UINT64CONST(9092761128247862869), UINT64CONST(108064544195665338)}, + {UINT64CONST(2142579373455052779), UINT64CONST(135080680244581673)}, {UINT64CONST(12868327154477877747), UINT64CONST(84425425152863545)}, + {UINT64CONST(2250350887815183471), UINT64CONST(105531781441079432)}, {UINT64CONST(2812938609768979339), UINT64CONST(131914726801349290)}, + {UINT64CONST(6369772649532999991), UINT64CONST(82446704250843306)}, {UINT64CONST(17185587848771025797), UINT64CONST(103058380313554132)}, + {UINT64CONST(3035240737254230630), UINT64CONST(128822975391942666)}, {UINT64CONST(6508711479211282048), UINT64CONST(80514359619964166)}, + {UINT64CONST(17359261385868878368), UINT64CONST(100642949524955207)}, {UINT64CONST(17087390713908710056), UINT64CONST(125803686906194009)}, + {UINT64CONST(3762090168551861929), UINT64CONST(78627304316371256)}, {UINT64CONST(4702612710689827411), UINT64CONST(98284130395464070)}, + {UINT64CONST(15101637925217060072), UINT64CONST(122855162994330087)}, {UINT64CONST(16356052730901744401), UINT64CONST(76784476871456304)}, + {UINT64CONST(1998321839917628885), UINT64CONST(95980596089320381)}, {UINT64CONST(7109588318324424010), UINT64CONST(119975745111650476)}, + {UINT64CONST(13666864735807540814), UINT64CONST(74984840694781547)}, {UINT64CONST(12471894901332038114), UINT64CONST(93731050868476934)}, + {UINT64CONST(6366496589810271835), UINT64CONST(117163813585596168)}, {UINT64CONST(3979060368631419896), UINT64CONST(73227383490997605)}, + {UINT64CONST(9585511479216662775), UINT64CONST(91534229363747006)}, {UINT64CONST(2758517312166052660), UINT64CONST(114417786704683758)}, + {UINT64CONST(12671518677062341634), UINT64CONST(143022233380854697)}, {UINT64CONST(1002170145522881665), UINT64CONST(89388895863034186)}, + {UINT64CONST(10476084718758377889), UINT64CONST(111736119828792732)}, {UINT64CONST(13095105898447972362), UINT64CONST(139670149785990915)}, + {UINT64CONST(5878598177316288774), UINT64CONST(87293843616244322)}, {UINT64CONST(16571619758500136775), UINT64CONST(109117304520305402)}, + {UINT64CONST(11491152661270395161), UINT64CONST(136396630650381753)}, {UINT64CONST(264441385652915120), UINT64CONST(85247894156488596)}, + {UINT64CONST(330551732066143900), UINT64CONST(106559867695610745)}, {UINT64CONST(5024875683510067779), UINT64CONST(133199834619513431)}, + {UINT64CONST(10058076329834874218), UINT64CONST(83249896637195894)}, {UINT64CONST(3349223375438816964), UINT64CONST(104062370796494868)}, + {UINT64CONST(4186529219298521205), UINT64CONST(130077963495618585)}, {UINT64CONST(14145795808130045513), UINT64CONST(81298727184761615)}, + {UINT64CONST(13070558741735168987), UINT64CONST(101623408980952019)}, {UINT64CONST(11726512408741573330), UINT64CONST(127029261226190024)}, + {UINT64CONST(7329070255463483331), UINT64CONST(79393288266368765)}, {UINT64CONST(13773023837756742068), UINT64CONST(99241610332960956)}, + {UINT64CONST(17216279797195927585), UINT64CONST(124052012916201195)}, {UINT64CONST(8454331864033760789), UINT64CONST(77532508072625747)}, + {UINT64CONST(5956228811614813082), UINT64CONST(96915635090782184)}, {UINT64CONST(7445286014518516353), UINT64CONST(121144543863477730)}, + {UINT64CONST(9264989777501460624), UINT64CONST(75715339914673581)}, {UINT64CONST(16192923240304213684), UINT64CONST(94644174893341976)}, + {UINT64CONST(1794409976670715490), UINT64CONST(118305218616677471)}, {UINT64CONST(8039035263060279037), UINT64CONST(73940761635423419)}, + {UINT64CONST(5437108060397960892), UINT64CONST(92425952044279274)}, {UINT64CONST(16019757112352226923), UINT64CONST(115532440055349092)}, + {UINT64CONST(788976158365366019), UINT64CONST(72207775034593183)}, {UINT64CONST(14821278253238871236), UINT64CONST(90259718793241478)}, + {UINT64CONST(9303225779693813237), UINT64CONST(112824648491551848)}, {UINT64CONST(11629032224617266546), UINT64CONST(141030810614439810)}, + {UINT64CONST(11879831158813179495), UINT64CONST(88144256634024881)}, {UINT64CONST(1014730893234310657), UINT64CONST(110180320792531102)}, + {UINT64CONST(10491785653397664129), UINT64CONST(137725400990663877)}, {UINT64CONST(8863209042587234033), UINT64CONST(86078375619164923)}, + {UINT64CONST(6467325284806654637), UINT64CONST(107597969523956154)}, {UINT64CONST(17307528642863094104), UINT64CONST(134497461904945192)}, + {UINT64CONST(10817205401789433815), UINT64CONST(84060913690590745)}, {UINT64CONST(18133192770664180173), UINT64CONST(105076142113238431)}, + {UINT64CONST(18054804944902837312), UINT64CONST(131345177641548039)}, {UINT64CONST(18201782118205355176), UINT64CONST(82090736025967524)}, + {UINT64CONST(4305483574047142354), UINT64CONST(102613420032459406)}, {UINT64CONST(14605226504413703751), UINT64CONST(128266775040574257)}, + {UINT64CONST(2210737537617482988), UINT64CONST(80166734400358911)}, {UINT64CONST(16598479977304017447), UINT64CONST(100208418000448638)}, + {UINT64CONST(11524727934775246001), UINT64CONST(125260522500560798)}, {UINT64CONST(2591268940807140847), UINT64CONST(78287826562850499)}, + {UINT64CONST(17074144231291089770), UINT64CONST(97859783203563123)}, {UINT64CONST(16730994270686474309), UINT64CONST(122324729004453904)}, + {UINT64CONST(10456871419179046443), UINT64CONST(76452955627783690)}, {UINT64CONST(3847717237119032246), UINT64CONST(95566194534729613)}, + {UINT64CONST(9421332564826178211), UINT64CONST(119457743168412016)}, {UINT64CONST(5888332853016361382), UINT64CONST(74661089480257510)}, + {UINT64CONST(16583788103125227536), UINT64CONST(93326361850321887)}, {UINT64CONST(16118049110479146516), UINT64CONST(116657952312902359)}, + {UINT64CONST(16991309721690548428), UINT64CONST(72911220195563974)}, {UINT64CONST(12015765115258409727), UINT64CONST(91139025244454968)}, + {UINT64CONST(15019706394073012159), UINT64CONST(113923781555568710)}, {UINT64CONST(9551260955736489391), UINT64CONST(142404726944460888)}, + {UINT64CONST(5969538097335305869), UINT64CONST(89002954340288055)}, {UINT64CONST(2850236603241744433), UINT64CONST(111253692925360069)} +}; + +#endif /* RYU_D2S_FULL_TABLE_H */ diff --git a/contrib/libs/libpq/src/common/d2s_intrinsics.h b/contrib/libs/libpq/src/common/d2s_intrinsics.h new file mode 100644 index 0000000000..ae0f28dbb2 --- /dev/null +++ b/contrib/libs/libpq/src/common/d2s_intrinsics.h @@ -0,0 +1,202 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output for double precision. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/d2s_intrinsics.h + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ +#ifndef RYU_D2S_INTRINSICS_H +#define RYU_D2S_INTRINSICS_H + +#if defined(HAS_64_BIT_INTRINSICS) + +#include <intrin.h> + +static inline uint64 +umul128(const uint64 a, const uint64 b, uint64 *const productHi) +{ + return _umul128(a, b, productHi); +} + +static inline uint64 +shiftright128(const uint64 lo, const uint64 hi, const uint32 dist) +{ + /* + * For the __shiftright128 intrinsic, the shift value is always modulo 64. + * In the current implementation of the double-precision version of Ryu, + * the shift value is always < 64. (In the case RYU_OPTIMIZE_SIZE == 0, + * the shift value is in the range [49, 58]. Otherwise in the range [2, + * 59].) Check this here in case a future change requires larger shift + * values. In this case this function needs to be adjusted. + */ + Assert(dist < 64); + return __shiftright128(lo, hi, (unsigned char) dist); +} + +#else /* defined(HAS_64_BIT_INTRINSICS) */ + +static inline uint64 +umul128(const uint64 a, const uint64 b, uint64 *const productHi) +{ + /* + * The casts here help MSVC to avoid calls to the __allmul library + * function. + */ + const uint32 aLo = (uint32) a; + const uint32 aHi = (uint32) (a >> 32); + const uint32 bLo = (uint32) b; + const uint32 bHi = (uint32) (b >> 32); + + const uint64 b00 = (uint64) aLo * bLo; + const uint64 b01 = (uint64) aLo * bHi; + const uint64 b10 = (uint64) aHi * bLo; + const uint64 b11 = (uint64) aHi * bHi; + + const uint32 b00Lo = (uint32) b00; + const uint32 b00Hi = (uint32) (b00 >> 32); + + const uint64 mid1 = b10 + b00Hi; + const uint32 mid1Lo = (uint32) (mid1); + const uint32 mid1Hi = (uint32) (mid1 >> 32); + + const uint64 mid2 = b01 + mid1Lo; + const uint32 mid2Lo = (uint32) (mid2); + const uint32 mid2Hi = (uint32) (mid2 >> 32); + + const uint64 pHi = b11 + mid1Hi + mid2Hi; + const uint64 pLo = ((uint64) mid2Lo << 32) + b00Lo; + + *productHi = pHi; + return pLo; +} + +static inline uint64 +shiftright128(const uint64 lo, const uint64 hi, const uint32 dist) +{ + /* We don't need to handle the case dist >= 64 here (see above). */ + Assert(dist < 64); +#if !defined(RYU_32_BIT_PLATFORM) + Assert(dist > 0); + return (hi << (64 - dist)) | (lo >> dist); +#else + /* Avoid a 64-bit shift by taking advantage of the range of shift values. */ + Assert(dist >= 32); + return (hi << (64 - dist)) | ((uint32) (lo >> 32) >> (dist - 32)); +#endif +} + +#endif /* // defined(HAS_64_BIT_INTRINSICS) */ + +#ifdef RYU_32_BIT_PLATFORM + +/* Returns the high 64 bits of the 128-bit product of a and b. */ +static inline uint64 +umulh(const uint64 a, const uint64 b) +{ + /* + * Reuse the umul128 implementation. Optimizers will likely eliminate the + * instructions used to compute the low part of the product. + */ + uint64 hi; + + umul128(a, b, &hi); + return hi; +} + +/*---- + * On 32-bit platforms, compilers typically generate calls to library + * functions for 64-bit divisions, even if the divisor is a constant. + * + * E.g.: + * https://bugs.llvm.org/show_bug.cgi?id=37932 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17958 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37443 + * + * The functions here perform division-by-constant using multiplications + * in the same way as 64-bit compilers would do. + * + * NB: + * The multipliers and shift values are the ones generated by clang x64 + * for expressions like x/5, x/10, etc. + *---- + */ + +static inline uint64 +div5(const uint64 x) +{ + return umulh(x, UINT64CONST(0xCCCCCCCCCCCCCCCD)) >> 2; +} + +static inline uint64 +div10(const uint64 x) +{ + return umulh(x, UINT64CONST(0xCCCCCCCCCCCCCCCD)) >> 3; +} + +static inline uint64 +div100(const uint64 x) +{ + return umulh(x >> 2, UINT64CONST(0x28F5C28F5C28F5C3)) >> 2; +} + +static inline uint64 +div1e8(const uint64 x) +{ + return umulh(x, UINT64CONST(0xABCC77118461CEFD)) >> 26; +} + +#else /* RYU_32_BIT_PLATFORM */ + +static inline uint64 +div5(const uint64 x) +{ + return x / 5; +} + +static inline uint64 +div10(const uint64 x) +{ + return x / 10; +} + +static inline uint64 +div100(const uint64 x) +{ + return x / 100; +} + +static inline uint64 +div1e8(const uint64 x) +{ + return x / 100000000; +} + +#endif /* RYU_32_BIT_PLATFORM */ + +#endif /* RYU_D2S_INTRINSICS_H */ diff --git a/contrib/libs/libpq/src/common/digit_table.h b/contrib/libs/libpq/src/common/digit_table.h new file mode 100644 index 0000000000..483aa17142 --- /dev/null +++ b/contrib/libs/libpq/src/common/digit_table.h @@ -0,0 +1,21 @@ +#ifndef RYU_DIGIT_TABLE_H +#define RYU_DIGIT_TABLE_H + +/* + * A table of all two-digit numbers. This is used to speed up decimal digit + * generation by copying pairs of digits into the final output. + */ +static const char DIGIT_TABLE[200] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', + '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', + '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', + '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', + '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', + '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', + '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', + '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' +}; + +#endif /* RYU_DIGIT_TABLE_H */ diff --git a/contrib/libs/libpq/src/common/encnames.c b/contrib/libs/libpq/src/common/encnames.c new file mode 100644 index 0000000000..0412a8220e --- /dev/null +++ b/contrib/libs/libpq/src/common/encnames.c @@ -0,0 +1,598 @@ +/*------------------------------------------------------------------------- + * + * encnames.c + * Encoding names and routines for working with them. + * + * Portions Copyright (c) 2001-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/encnames.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include <ctype.h> +#include <unistd.h> + +#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} +}; + + +/* + * Table of encoding names for ICU (currently covers backend encodings only) + * + * Reference: <https://ssl.icu-project.org/icu-bin/convexp> + * + * NULL entries are not supported by ICU, or their mapping is unclear. + */ +static const char *const pg_enc2icu_tbl[] = +{ + NULL, /* PG_SQL_ASCII */ + "EUC-JP", /* PG_EUC_JP */ + "EUC-CN", /* PG_EUC_CN */ + "EUC-KR", /* PG_EUC_KR */ + "EUC-TW", /* PG_EUC_TW */ + NULL, /* PG_EUC_JIS_2004 */ + "UTF-8", /* PG_UTF8 */ + NULL, /* PG_MULE_INTERNAL */ + "ISO-8859-1", /* PG_LATIN1 */ + "ISO-8859-2", /* PG_LATIN2 */ + "ISO-8859-3", /* PG_LATIN3 */ + "ISO-8859-4", /* PG_LATIN4 */ + "ISO-8859-9", /* PG_LATIN5 */ + "ISO-8859-10", /* PG_LATIN6 */ + "ISO-8859-13", /* PG_LATIN7 */ + "ISO-8859-14", /* PG_LATIN8 */ + "ISO-8859-15", /* PG_LATIN9 */ + NULL, /* PG_LATIN10 */ + "CP1256", /* PG_WIN1256 */ + "CP1258", /* PG_WIN1258 */ + "CP866", /* PG_WIN866 */ + NULL, /* PG_WIN874 */ + "KOI8-R", /* PG_KOI8R */ + "CP1251", /* PG_WIN1251 */ + "CP1252", /* PG_WIN1252 */ + "ISO-8859-5", /* PG_ISO_8859_5 */ + "ISO-8859-6", /* PG_ISO_8859_6 */ + "ISO-8859-7", /* PG_ISO_8859_7 */ + "ISO-8859-8", /* PG_ISO_8859_8 */ + "CP1250", /* PG_WIN1250 */ + "CP1253", /* PG_WIN1253 */ + "CP1254", /* PG_WIN1254 */ + "CP1255", /* PG_WIN1255 */ + "CP1257", /* PG_WIN1257 */ + "KOI8-U", /* PG_KOI8U */ +}; + +StaticAssertDecl(lengthof(pg_enc2icu_tbl) == PG_ENCODING_BE_LAST + 1, + "pg_enc2icu_tbl incomplete"); + + +/* + * Is this encoding supported by ICU? + */ +bool +is_encoding_supported_by_icu(int encoding) +{ + if (!PG_VALID_BE_ENCODING(encoding)) + return false; + return (pg_enc2icu_tbl[encoding] != NULL); +} + +/* + * Returns ICU's name for encoding, or NULL if not supported + */ +const char * +get_encoding_name_for_icu(int encoding) +{ + if (!PG_VALID_BE_ENCODING(encoding)) + return NULL; + return pg_enc2icu_tbl[encoding]; +} + + +/* ---------- + * 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, store at *newkey + * + * (Caller's responsibility to provide a large enough buffer) + */ +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 if not recognized + */ +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) + return -1; /* it's certainly not in the table */ + + 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; +} + +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 ""; +} diff --git a/contrib/libs/libpq/src/common/exec.c b/contrib/libs/libpq/src/common/exec.c new file mode 100644 index 0000000000..d3a967baa4 --- /dev/null +++ b/contrib/libs/libpq/src/common/exec.c @@ -0,0 +1,719 @@ +/*------------------------------------------------------------------------- + * + * exec.c + * Functions for finding and validating executable files + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/exec.c + * + *------------------------------------------------------------------------- + */ + +/* + * On macOS, "man realpath" avers: + * Defining _DARWIN_C_SOURCE or _DARWIN_BETTER_REALPATH before including + * stdlib.h will cause the provided implementation of realpath() to use + * F_GETPATH from fcntl(2) to discover the path. + * This should be harmless everywhere else. + */ +#define _DARWIN_BETTER_REALPATH + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <signal.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + +#ifdef EXEC_BACKEND +#if defined(HAVE_SYS_PERSONALITY_H) +#include <sys/personality.h> +#elif defined(HAVE_SYS_PROCCTL_H) +#error #include <sys/procctl.h> +#endif +#endif + +/* Inhibit mingw CRT's auto-globbing of command line arguments */ +#if defined(WIN32) && !defined(_MSC_VER) +extern int _CRT_glob = 0; /* 0 turns off globbing; 1 turns it on */ +#endif + +/* + * Hacky solution to allow expressing both frontend and backend error reports + * in one macro call. First argument of log_error is an errcode() call of + * some sort (ignored if FRONTEND); the rest are errmsg_internal() arguments, + * i.e. message string and any parameters for it. + * + * Caller must provide the gettext wrapper around the message string, if + * appropriate, so that it gets translated in the FRONTEND case; this + * motivates using errmsg_internal() not errmsg(). We handle appending a + * newline, if needed, inside the macro, so that there's only one translatable + * string per call not two. + */ +#ifndef FRONTEND +#define log_error(errcodefn, ...) \ + ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__))) +#else +#define log_error(errcodefn, ...) \ + (fprintf(stderr, __VA_ARGS__), fputc('\n', stderr)) +#endif + +static int normalize_exec_path(char *path); +static char *pg_realpath(const char *fname); + +#ifdef WIN32 +static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser); +#endif + +/* + * validate_exec -- validate "path" as an executable file + * + * returns 0 if the file is found and no error is encountered. + * -1 if the regular file "path" does not exist or cannot be executed. + * -2 if the file is otherwise valid but cannot be read. + * in the failure cases, errno is set appropriately + */ +int +validate_exec(const char *path) +{ + struct stat buf; + int is_r; + int is_x; + +#ifdef WIN32 + char path_exe[MAXPGPATH + sizeof(".exe") - 1]; + + /* Win32 requires a .exe suffix for stat() */ + if (strlen(path) < strlen(".exe") || + pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0) + { + strlcpy(path_exe, path, sizeof(path_exe) - 4); + strcat(path_exe, ".exe"); + path = path_exe; + } +#endif + + /* + * Ensure that the file exists and is a regular file. + * + * XXX if you have a broken system where stat() looks at the symlink + * instead of the underlying file, you lose. + */ + if (stat(path, &buf) < 0) + return -1; + + if (!S_ISREG(buf.st_mode)) + { + /* + * POSIX offers no errno code that's simply "not a regular file". If + * it's a directory we can use EISDIR. Otherwise, it's most likely a + * device special file, and EPERM (Operation not permitted) isn't too + * horribly off base. + */ + errno = S_ISDIR(buf.st_mode) ? EISDIR : EPERM; + return -1; + } + + /* + * Ensure that the file is both executable and readable (required for + * dynamic loading). + */ +#ifndef WIN32 + is_r = (access(path, R_OK) == 0); + is_x = (access(path, X_OK) == 0); + /* access() will set errno if it returns -1 */ +#else + is_r = buf.st_mode & S_IRUSR; + is_x = buf.st_mode & S_IXUSR; + errno = EACCES; /* appropriate thing if we return nonzero */ +#endif + return is_x ? (is_r ? 0 : -2) : -1; +} + + +/* + * find_my_exec -- find an absolute path to this program's executable + * + * argv0 is the name passed on the command line + * retpath is the output area (must be of size MAXPGPATH) + * Returns 0 if OK, -1 if error. + * + * The reason we have to work so hard to find an absolute path is that + * on some platforms we can't do dynamic loading unless we know the + * executable's location. Also, we need an absolute path not a relative + * path because we may later change working directory. Finally, we want + * a true path not a symlink location, so that we can locate other files + * that are part of our installation relative to the executable. + */ +int +find_my_exec(const char *argv0, char *retpath) +{ + char *path; + + /* + * If argv0 contains a separator, then PATH wasn't used. + */ + strlcpy(retpath, argv0, MAXPGPATH); + if (first_dir_separator(retpath) != NULL) + { + if (validate_exec(retpath) == 0) + return normalize_exec_path(retpath); + + log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE), + _("invalid binary \"%s\": %m"), retpath); + return -1; + } + +#ifdef WIN32 + /* Win32 checks the current directory first for names without slashes */ + if (validate_exec(retpath) == 0) + return normalize_exec_path(retpath); +#endif + + /* + * Since no explicit path was supplied, the user must have been relying on + * PATH. We'll search the same PATH. + */ + if ((path = getenv("PATH")) && *path) + { + char *startp = NULL, + *endp = NULL; + + do + { + if (!startp) + startp = path; + else + startp = endp + 1; + + endp = first_path_var_separator(startp); + if (!endp) + endp = startp + strlen(startp); /* point to end */ + + strlcpy(retpath, startp, Min(endp - startp + 1, MAXPGPATH)); + + join_path_components(retpath, retpath, argv0); + canonicalize_path(retpath); + + switch (validate_exec(retpath)) + { + case 0: /* found ok */ + return normalize_exec_path(retpath); + case -1: /* wasn't even a candidate, keep looking */ + break; + case -2: /* found but disqualified */ + log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE), + _("could not read binary \"%s\": %m"), + retpath); + break; + } + } while (*endp); + } + + log_error(errcode(ERRCODE_UNDEFINED_FILE), + _("could not find a \"%s\" to execute"), argv0); + return -1; +} + + +/* + * normalize_exec_path - resolve symlinks and convert to absolute path + * + * Given a path that refers to an executable, chase through any symlinks + * to find the real file location; then convert that to an absolute path. + * + * On success, replaces the contents of "path" with the absolute path. + * ("path" is assumed to be of size MAXPGPATH.) + * Returns 0 if OK, -1 if error. + */ +static int +normalize_exec_path(char *path) +{ + /* + * We used to do a lot of work ourselves here, but now we just let + * realpath(3) do all the heavy lifting. + */ + char *abspath = pg_realpath(path); + + if (abspath == NULL) + { + log_error(errcode_for_file_access(), + _("could not resolve path \"%s\" to absolute form: %m"), + path); + return -1; + } + strlcpy(path, abspath, MAXPGPATH); + free(abspath); + +#ifdef WIN32 + /* On Windows, be sure to convert '\' to '/' */ + canonicalize_path(path); +#endif + + return 0; +} + + +/* + * pg_realpath() - realpath(3) with POSIX.1-2008 semantics + * + * This is equivalent to realpath(fname, NULL), in that it returns a + * malloc'd buffer containing the absolute path equivalent to fname. + * On error, returns NULL with errno set. + * + * On Windows, what you get is spelled per platform conventions, + * so you probably want to apply canonicalize_path() to the result. + * + * For now, this is needed only here so mark it static. If you choose to + * move it into its own file, move the _DARWIN_BETTER_REALPATH #define too! + */ +static char * +pg_realpath(const char *fname) +{ + char *path; + +#ifndef WIN32 + path = realpath(fname, NULL); + if (path == NULL && errno == EINVAL) + { + /* + * Cope with old-POSIX systems that require a user-provided buffer. + * Assume MAXPGPATH is enough room on all such systems. + */ + char *buf = malloc(MAXPGPATH); + + if (buf == NULL) + return NULL; /* assume errno is set */ + path = realpath(fname, buf); + if (path == NULL) /* don't leak memory */ + { + int save_errno = errno; + + free(buf); + errno = save_errno; + } + } +#else /* WIN32 */ + + /* + * Microsoft is resolutely non-POSIX, but _fullpath() does the same thing. + * The documentation claims it reports errors by setting errno, which is a + * bit surprising for Microsoft, but we'll believe that until it's proven + * wrong. Clear errno first, though, so we can at least tell if a failure + * occurs and doesn't set it. + */ + errno = 0; + path = _fullpath(NULL, fname, 0); +#endif + + return path; +} + + +/* + * Find another program in our binary's directory, + * then make sure it is the proper version. + */ +int +find_other_exec(const char *argv0, const char *target, + const char *versionstr, char *retpath) +{ + char cmd[MAXPGPATH]; + char line[MAXPGPATH]; + + if (find_my_exec(argv0, retpath) < 0) + return -1; + + /* Trim off program name and keep just directory */ + *last_dir_separator(retpath) = '\0'; + canonicalize_path(retpath); + + /* Now append the other program's name */ + snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath), + "/%s%s", target, EXE); + + if (validate_exec(retpath) != 0) + return -1; + + snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath); + + if (!pipe_read_line(cmd, line, sizeof(line))) + return -1; + + if (strcmp(line, versionstr) != 0) + return -2; + + return 0; +} + + +/* + * Execute a command in a pipe and read the first line from it. + */ +char * +pipe_read_line(char *cmd, char *line, int maxsize) +{ + FILE *pgver; + + fflush(NULL); + + errno = 0; + if ((pgver = popen(cmd, "r")) == NULL) + { + perror("popen failure"); + return NULL; + } + + errno = 0; + if (fgets(line, maxsize, pgver) == NULL) + { + if (feof(pgver)) + fprintf(stderr, "no data was returned by command \"%s\"\n", cmd); + else + perror("fgets failure"); + pclose(pgver); /* no error checking */ + return NULL; + } + + if (pclose_check(pgver)) + return NULL; + + return line; +} + + +/* + * pclose() plus useful error reporting + */ +int +pclose_check(FILE *stream) +{ + int exitstatus; + char *reason; + + exitstatus = pclose(stream); + + if (exitstatus == 0) + return 0; /* all is well */ + + if (exitstatus == -1) + { + /* pclose() itself failed, and hopefully set errno */ + log_error(errcode(ERRCODE_SYSTEM_ERROR), + _("%s() failed: %m"), "pclose"); + } + else + { + reason = wait_result_to_str(exitstatus); + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "%s", reason); + pfree(reason); + } + return exitstatus; +} + +/* + * set_pglocale_pgservice + * + * Set application-specific locale and service directory + * + * This function takes the value of argv[0] rather than a full path. + * + * (You may be wondering why this is in exec.c. It requires this module's + * services and doesn't introduce any new dependencies, so this seems as + * good as anyplace.) + */ +void +set_pglocale_pgservice(const char *argv0, const char *app) +{ + char path[MAXPGPATH]; + char my_exec_path[MAXPGPATH]; + + /* don't set LC_ALL in the backend */ + if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0) + { + setlocale(LC_ALL, ""); + + /* + * One could make a case for reproducing here PostmasterMain()'s test + * for whether the process is multithreaded. Unlike the postmaster, + * no frontend program calls sigprocmask() or otherwise provides for + * mutual exclusion between signal handlers. While frontends using + * fork(), if multithreaded, are formally exposed to undefined + * behavior, we have not witnessed a concrete bug. Therefore, + * complaining about multithreading here may be mere pedantry. + */ + } + + if (find_my_exec(argv0, my_exec_path) < 0) + return; + +#ifdef ENABLE_NLS + get_locale_path(my_exec_path, path); + bindtextdomain(app, path); + textdomain(app); + /* set for libpq to use, but don't override existing setting */ + setenv("PGLOCALEDIR", path, 0); +#endif + + if (getenv("PGSYSCONFDIR") == NULL) + { + get_etc_path(my_exec_path, path); + /* set for libpq to use */ + setenv("PGSYSCONFDIR", path, 0); + } +} + +#ifdef EXEC_BACKEND +/* + * For the benefit of PostgreSQL developers testing EXEC_BACKEND on Unix + * systems (code paths normally exercised only on Windows), provide a way to + * disable address space layout randomization, if we know how on this platform. + * Otherwise, backends may fail to attach to shared memory at the fixed address + * chosen by the postmaster. (See also the macOS-specific hack in + * sysv_shmem.c.) + */ +int +pg_disable_aslr(void) +{ +#if defined(HAVE_SYS_PERSONALITY_H) + return personality(ADDR_NO_RANDOMIZE); +#elif defined(HAVE_SYS_PROCCTL_H) && defined(PROC_ASLR_FORCE_DISABLE) + int data = PROC_ASLR_FORCE_DISABLE; + + return procctl(P_PID, 0, PROC_ASLR_CTL, &data); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifdef WIN32 + +/* + * AddUserToTokenDacl(HANDLE hToken) + * + * This function adds the current user account to the restricted + * token used when we create a restricted process. + * + * This is required because of some security changes in Windows + * that appeared in patches to XP/2K3 and in Vista/2008. + * + * On these machines, the Administrator account is not included in + * the default DACL - you just get Administrators + System. For + * regular users you get User + System. Because we strip Administrators + * when we create the restricted token, we are left with only System + * in the DACL which leads to access denied errors for later CreatePipe() + * and CreateProcess() calls when running as Administrator. + * + * This function fixes this problem by modifying the DACL of the + * token the process will use, and explicitly re-adding the current + * user account. This is still secure because the Administrator account + * inherits its privileges from the Administrators group - it doesn't + * have any of its own. + */ +BOOL +AddUserToTokenDacl(HANDLE hToken) +{ + int i; + ACL_SIZE_INFORMATION asi; + ACCESS_ALLOWED_ACE *pace; + DWORD dwNewAclSize; + DWORD dwSize = 0; + DWORD dwTokenInfoLength = 0; + PACL pacl = NULL; + PTOKEN_USER pTokenUser = NULL; + TOKEN_DEFAULT_DACL tddNew; + TOKEN_DEFAULT_DACL *ptdd = NULL; + TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl; + BOOL ret = FALSE; + + /* Figure out the buffer size for the DACL info */ + if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize); + if (ptdd == NULL) + { + log_error(errcode(ERRCODE_OUT_OF_MEMORY), + _("out of memory")); + goto cleanup; + } + + if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get token information: error code %lu", + GetLastError()); + goto cleanup; + } + } + else + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get token information buffer size: error code %lu", + GetLastError()); + goto cleanup; + } + } + + /* Get the ACL info */ + if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) &asi, + (DWORD) sizeof(ACL_SIZE_INFORMATION), + AclSizeInformation)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get ACL information: error code %lu", + GetLastError()); + goto cleanup; + } + + /* Get the current user SID */ + if (!GetTokenUser(hToken, &pTokenUser)) + goto cleanup; /* callee printed a message */ + + /* Figure out the size of the new ACL */ + dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + + GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD); + + /* Allocate the ACL buffer & initialize it */ + pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize); + if (pacl == NULL) + { + log_error(errcode(ERRCODE_OUT_OF_MEMORY), + _("out of memory")); + goto cleanup; + } + + if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not initialize ACL: error code %lu", GetLastError()); + goto cleanup; + } + + /* Loop through the existing ACEs, and build the new ACL */ + for (i = 0; i < (int) asi.AceCount; i++) + { + if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) &pace)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get ACE: error code %lu", GetLastError()); + goto cleanup; + } + + if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not add ACE: error code %lu", GetLastError()); + goto cleanup; + } + } + + /* Add the new ACE for the current user */ + if (!AddAccessAllowedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE, GENERIC_ALL, pTokenUser->User.Sid)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not add access allowed ACE: error code %lu", + GetLastError()); + goto cleanup; + } + + /* Set the new DACL in the token */ + tddNew.DefaultDacl = pacl; + + if (!SetTokenInformation(hToken, tic, (LPVOID) &tddNew, dwNewAclSize)) + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not set token information: error code %lu", + GetLastError()); + goto cleanup; + } + + ret = TRUE; + +cleanup: + if (pTokenUser) + LocalFree((HLOCAL) pTokenUser); + + if (pacl) + LocalFree((HLOCAL) pacl); + + if (ptdd) + LocalFree((HLOCAL) ptdd); + + return ret; +} + +/* + * GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser) + * + * Get the users token information from a process token. + * + * The caller of this function is responsible for calling LocalFree() on the + * returned TOKEN_USER memory. + */ +static BOOL +GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser) +{ + DWORD dwLength; + + *ppTokenUser = NULL; + + if (!GetTokenInformation(hToken, + TokenUser, + NULL, + 0, + &dwLength)) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + *ppTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwLength); + + if (*ppTokenUser == NULL) + { + log_error(errcode(ERRCODE_OUT_OF_MEMORY), + _("out of memory")); + return FALSE; + } + } + else + { + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get token information buffer size: error code %lu", + GetLastError()); + return FALSE; + } + } + + if (!GetTokenInformation(hToken, + TokenUser, + *ppTokenUser, + dwLength, + &dwLength)) + { + LocalFree(*ppTokenUser); + *ppTokenUser = NULL; + + log_error(errcode(ERRCODE_SYSTEM_ERROR), + "could not get token information: error code %lu", + GetLastError()); + return FALSE; + } + + /* Memory in *ppTokenUser is LocalFree():d by the caller */ + return TRUE; +} + +#endif diff --git a/contrib/libs/libpq/src/common/f2s.c b/contrib/libs/libpq/src/common/f2s.c new file mode 100644 index 0000000000..ba08dcb6aa --- /dev/null +++ b/contrib/libs/libpq/src/common/f2s.c @@ -0,0 +1,803 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output for single precision. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/f2s.c + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/shortest_dec.h" +#include "digit_table.h" +#include "ryu_common.h" + +#define FLOAT_MANTISSA_BITS 23 +#define FLOAT_EXPONENT_BITS 8 +#define FLOAT_BIAS 127 + +/* + * This table is generated (by the upstream) by PrintFloatLookupTable, + * and modified (by us) to add UINT64CONST. + */ +#define FLOAT_POW5_INV_BITCOUNT 59 +static const uint64 FLOAT_POW5_INV_SPLIT[31] = { + UINT64CONST(576460752303423489), UINT64CONST(461168601842738791), UINT64CONST(368934881474191033), UINT64CONST(295147905179352826), + UINT64CONST(472236648286964522), UINT64CONST(377789318629571618), UINT64CONST(302231454903657294), UINT64CONST(483570327845851670), + UINT64CONST(386856262276681336), UINT64CONST(309485009821345069), UINT64CONST(495176015714152110), UINT64CONST(396140812571321688), + UINT64CONST(316912650057057351), UINT64CONST(507060240091291761), UINT64CONST(405648192073033409), UINT64CONST(324518553658426727), + UINT64CONST(519229685853482763), UINT64CONST(415383748682786211), UINT64CONST(332306998946228969), UINT64CONST(531691198313966350), + UINT64CONST(425352958651173080), UINT64CONST(340282366920938464), UINT64CONST(544451787073501542), UINT64CONST(435561429658801234), + UINT64CONST(348449143727040987), UINT64CONST(557518629963265579), UINT64CONST(446014903970612463), UINT64CONST(356811923176489971), + UINT64CONST(570899077082383953), UINT64CONST(456719261665907162), UINT64CONST(365375409332725730) +}; +#define FLOAT_POW5_BITCOUNT 61 +static const uint64 FLOAT_POW5_SPLIT[47] = { + UINT64CONST(1152921504606846976), UINT64CONST(1441151880758558720), UINT64CONST(1801439850948198400), UINT64CONST(2251799813685248000), + UINT64CONST(1407374883553280000), UINT64CONST(1759218604441600000), UINT64CONST(2199023255552000000), UINT64CONST(1374389534720000000), + UINT64CONST(1717986918400000000), UINT64CONST(2147483648000000000), UINT64CONST(1342177280000000000), UINT64CONST(1677721600000000000), + UINT64CONST(2097152000000000000), UINT64CONST(1310720000000000000), UINT64CONST(1638400000000000000), UINT64CONST(2048000000000000000), + UINT64CONST(1280000000000000000), UINT64CONST(1600000000000000000), UINT64CONST(2000000000000000000), UINT64CONST(1250000000000000000), + UINT64CONST(1562500000000000000), UINT64CONST(1953125000000000000), UINT64CONST(1220703125000000000), UINT64CONST(1525878906250000000), + UINT64CONST(1907348632812500000), UINT64CONST(1192092895507812500), UINT64CONST(1490116119384765625), UINT64CONST(1862645149230957031), + UINT64CONST(1164153218269348144), UINT64CONST(1455191522836685180), UINT64CONST(1818989403545856475), UINT64CONST(2273736754432320594), + UINT64CONST(1421085471520200371), UINT64CONST(1776356839400250464), UINT64CONST(2220446049250313080), UINT64CONST(1387778780781445675), + UINT64CONST(1734723475976807094), UINT64CONST(2168404344971008868), UINT64CONST(1355252715606880542), UINT64CONST(1694065894508600678), + UINT64CONST(2117582368135750847), UINT64CONST(1323488980084844279), UINT64CONST(1654361225106055349), UINT64CONST(2067951531382569187), + UINT64CONST(1292469707114105741), UINT64CONST(1615587133892632177), UINT64CONST(2019483917365790221) +}; + +static inline uint32 +pow5Factor(uint32 value) +{ + uint32 count = 0; + + for (;;) + { + Assert(value != 0); + const uint32 q = value / 5; + const uint32 r = value % 5; + + if (r != 0) + break; + + value = q; + ++count; + } + return count; +} + +/* Returns true if value is divisible by 5^p. */ +static inline bool +multipleOfPowerOf5(const uint32 value, const uint32 p) +{ + return pow5Factor(value) >= p; +} + +/* Returns true if value is divisible by 2^p. */ +static inline bool +multipleOfPowerOf2(const uint32 value, const uint32 p) +{ + /* return __builtin_ctz(value) >= p; */ + return (value & ((1u << p) - 1)) == 0; +} + +/* + * It seems to be slightly faster to avoid uint128_t here, although the + * generated code for uint128_t looks slightly nicer. + */ +static inline uint32 +mulShift(const uint32 m, const uint64 factor, const int32 shift) +{ + /* + * The casts here help MSVC to avoid calls to the __allmul library + * function. + */ + const uint32 factorLo = (uint32) (factor); + const uint32 factorHi = (uint32) (factor >> 32); + const uint64 bits0 = (uint64) m * factorLo; + const uint64 bits1 = (uint64) m * factorHi; + + Assert(shift > 32); + +#ifdef RYU_32_BIT_PLATFORM + + /* + * On 32-bit platforms we can avoid a 64-bit shift-right since we only + * need the upper 32 bits of the result and the shift value is > 32. + */ + const uint32 bits0Hi = (uint32) (bits0 >> 32); + uint32 bits1Lo = (uint32) (bits1); + uint32 bits1Hi = (uint32) (bits1 >> 32); + + bits1Lo += bits0Hi; + bits1Hi += (bits1Lo < bits0Hi); + + const int32 s = shift - 32; + + return (bits1Hi << (32 - s)) | (bits1Lo >> s); + +#else /* RYU_32_BIT_PLATFORM */ + + const uint64 sum = (bits0 >> 32) + bits1; + const uint64 shiftedSum = sum >> (shift - 32); + + Assert(shiftedSum <= PG_UINT32_MAX); + return (uint32) shiftedSum; + +#endif /* RYU_32_BIT_PLATFORM */ +} + +static inline uint32 +mulPow5InvDivPow2(const uint32 m, const uint32 q, const int32 j) +{ + return mulShift(m, FLOAT_POW5_INV_SPLIT[q], j); +} + +static inline uint32 +mulPow5divPow2(const uint32 m, const uint32 i, const int32 j) +{ + return mulShift(m, FLOAT_POW5_SPLIT[i], j); +} + +static inline uint32 +decimalLength(const uint32 v) +{ + /* Function precondition: v is not a 10-digit number. */ + /* (9 digits are sufficient for round-tripping.) */ + Assert(v < 1000000000); + if (v >= 100000000) + { + return 9; + } + if (v >= 10000000) + { + return 8; + } + if (v >= 1000000) + { + return 7; + } + if (v >= 100000) + { + return 6; + } + if (v >= 10000) + { + return 5; + } + if (v >= 1000) + { + return 4; + } + if (v >= 100) + { + return 3; + } + if (v >= 10) + { + return 2; + } + return 1; +} + +/* A floating decimal representing m * 10^e. */ +typedef struct floating_decimal_32 +{ + uint32 mantissa; + int32 exponent; +} floating_decimal_32; + +static inline floating_decimal_32 +f2d(const uint32 ieeeMantissa, const uint32 ieeeExponent) +{ + int32 e2; + uint32 m2; + + if (ieeeExponent == 0) + { + /* We subtract 2 so that the bounds computation has 2 additional bits. */ + e2 = 1 - FLOAT_BIAS - FLOAT_MANTISSA_BITS - 2; + m2 = ieeeMantissa; + } + else + { + e2 = ieeeExponent - FLOAT_BIAS - FLOAT_MANTISSA_BITS - 2; + m2 = (1u << FLOAT_MANTISSA_BITS) | ieeeMantissa; + } + +#if STRICTLY_SHORTEST + const bool even = (m2 & 1) == 0; + const bool acceptBounds = even; +#else + const bool acceptBounds = false; +#endif + + /* Step 2: Determine the interval of legal decimal representations. */ + const uint32 mv = 4 * m2; + const uint32 mp = 4 * m2 + 2; + + /* Implicit bool -> int conversion. True is 1, false is 0. */ + const uint32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1; + const uint32 mm = 4 * m2 - 1 - mmShift; + + /* Step 3: Convert to a decimal power base using 64-bit arithmetic. */ + uint32 vr, + vp, + vm; + int32 e10; + bool vmIsTrailingZeros = false; + bool vrIsTrailingZeros = false; + uint8 lastRemovedDigit = 0; + + if (e2 >= 0) + { + const uint32 q = log10Pow2(e2); + + e10 = q; + + const int32 k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q) - 1; + const int32 i = -e2 + q + k; + + vr = mulPow5InvDivPow2(mv, q, i); + vp = mulPow5InvDivPow2(mp, q, i); + vm = mulPow5InvDivPow2(mm, q, i); + + if (q != 0 && (vp - 1) / 10 <= vm / 10) + { + /* + * We need to know one removed digit even if we are not going to + * loop below. We could use q = X - 1 above, except that would + * require 33 bits for the result, and we've found that 32-bit + * arithmetic is faster even on 64-bit machines. + */ + const int32 l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q - 1) - 1; + + lastRemovedDigit = (uint8) (mulPow5InvDivPow2(mv, q - 1, -e2 + q - 1 + l) % 10); + } + if (q <= 9) + { + /* + * The largest power of 5 that fits in 24 bits is 5^10, but q <= 9 + * seems to be safe as well. + * + * Only one of mp, mv, and mm can be a multiple of 5, if any. + */ + if (mv % 5 == 0) + { + vrIsTrailingZeros = multipleOfPowerOf5(mv, q); + } + else if (acceptBounds) + { + vmIsTrailingZeros = multipleOfPowerOf5(mm, q); + } + else + { + vp -= multipleOfPowerOf5(mp, q); + } + } + } + else + { + const uint32 q = log10Pow5(-e2); + + e10 = q + e2; + + const int32 i = -e2 - q; + const int32 k = pow5bits(i) - FLOAT_POW5_BITCOUNT; + int32 j = q - k; + + vr = mulPow5divPow2(mv, i, j); + vp = mulPow5divPow2(mp, i, j); + vm = mulPow5divPow2(mm, i, j); + + if (q != 0 && (vp - 1) / 10 <= vm / 10) + { + j = q - 1 - (pow5bits(i + 1) - FLOAT_POW5_BITCOUNT); + lastRemovedDigit = (uint8) (mulPow5divPow2(mv, i + 1, j) % 10); + } + if (q <= 1) + { + /* + * {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q + * trailing 0 bits. + */ + /* mv = 4 * m2, so it always has at least two trailing 0 bits. */ + vrIsTrailingZeros = true; + if (acceptBounds) + { + /* + * mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff + * mmShift == 1. + */ + vmIsTrailingZeros = mmShift == 1; + } + else + { + /* + * mp = mv + 2, so it always has at least one trailing 0 bit. + */ + --vp; + } + } + else if (q < 31) + { + /* TODO(ulfjack):Use a tighter bound here. */ + vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1); + } + } + + /* + * Step 4: Find the shortest decimal representation in the interval of + * legal representations. + */ + uint32 removed = 0; + uint32 output; + + if (vmIsTrailingZeros || vrIsTrailingZeros) + { + /* General case, which happens rarely (~4.0%). */ + while (vp / 10 > vm / 10) + { + vmIsTrailingZeros &= vm - (vm / 10) * 10 == 0; + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8) (vr % 10); + vr /= 10; + vp /= 10; + vm /= 10; + ++removed; + } + if (vmIsTrailingZeros) + { + while (vm % 10 == 0) + { + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = (uint8) (vr % 10); + vr /= 10; + vp /= 10; + vm /= 10; + ++removed; + } + } + + if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0) + { + /* Round even if the exact number is .....50..0. */ + lastRemovedDigit = 4; + } + + /* + * We need to take vr + 1 if vr is outside bounds or we need to round + * up. + */ + output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5); + } + else + { + /* + * Specialized for the common case (~96.0%). Percentages below are + * relative to this. + * + * Loop iterations below (approximately): 0: 13.6%, 1: 70.7%, 2: + * 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01% + */ + while (vp / 10 > vm / 10) + { + lastRemovedDigit = (uint8) (vr % 10); + vr /= 10; + vp /= 10; + vm /= 10; + ++removed; + } + + /* + * We need to take vr + 1 if vr is outside bounds or we need to round + * up. + */ + output = vr + (vr == vm || lastRemovedDigit >= 5); + } + + const int32 exp = e10 + removed; + + floating_decimal_32 fd; + + fd.exponent = exp; + fd.mantissa = output; + return fd; +} + +static inline int +to_chars_f(const floating_decimal_32 v, const uint32 olength, char *const result) +{ + /* Step 5: Print the decimal representation. */ + int index = 0; + + uint32 output = v.mantissa; + int32 exp = v.exponent; + + /*---- + * On entry, mantissa * 10^exp is the result to be output. + * Caller has already done the - sign if needed. + * + * We want to insert the point somewhere depending on the output length + * and exponent, which might mean adding zeros: + * + * exp | format + * 1+ | ddddddddd000000 + * 0 | ddddddddd + * -1 .. -len+1 | dddddddd.d to d.ddddddddd + * -len ... | 0.ddddddddd to 0.000dddddd + */ + uint32 i = 0; + int32 nexp = exp + olength; + + if (nexp <= 0) + { + /* -nexp is number of 0s to add after '.' */ + Assert(nexp >= -3); + /* 0.000ddddd */ + index = 2 - nexp; + /* copy 8 bytes rather than 5 to let compiler optimize */ + memcpy(result, "0.000000", 8); + } + else if (exp < 0) + { + /* + * dddd.dddd; leave space at the start and move the '.' in after + */ + index = 1; + } + else + { + /* + * We can save some code later by pre-filling with zeros. We know that + * there can be no more than 6 output digits in this form, otherwise + * we would not choose fixed-point output. memset 8 rather than 6 + * bytes to let the compiler optimize it. + */ + Assert(exp < 6 && exp + olength <= 6); + memset(result, '0', 8); + } + + while (output >= 10000) + { + const uint32 c = output - 10000 * (output / 10000); + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + + output /= 10000; + + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2); + i += 4; + } + if (output >= 100) + { + const uint32 c = (output % 100) << 1; + + output /= 100; + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2); + i += 2; + } + if (output >= 10) + { + const uint32 c = output << 1; + + memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2); + } + else + { + result[index] = (char) ('0' + output); + } + + if (index == 1) + { + /* + * nexp is 1..6 here, representing the number of digits before the + * point. A value of 7+ is not possible because we switch to + * scientific notation when the display exponent reaches 6. + */ + Assert(nexp < 7); + /* gcc only seems to want to optimize memmove for small 2^n */ + if (nexp & 4) + { + memmove(result + index - 1, result + index, 4); + index += 4; + } + if (nexp & 2) + { + memmove(result + index - 1, result + index, 2); + index += 2; + } + if (nexp & 1) + { + result[index - 1] = result[index]; + } + result[nexp] = '.'; + index = olength + 1; + } + else if (exp >= 0) + { + /* we supplied the trailing zeros earlier, now just set the length. */ + index = olength + exp; + } + else + { + index = olength + (2 - nexp); + } + + return index; +} + +static inline int +to_chars(const floating_decimal_32 v, const bool sign, char *const result) +{ + /* Step 5: Print the decimal representation. */ + int index = 0; + + uint32 output = v.mantissa; + uint32 olength = decimalLength(output); + int32 exp = v.exponent + olength - 1; + + if (sign) + result[index++] = '-'; + + /* + * The thresholds for fixed-point output are chosen to match printf + * defaults. Beware that both the code of to_chars_f and the value of + * FLOAT_SHORTEST_DECIMAL_LEN are sensitive to these thresholds. + */ + if (exp >= -4 && exp < 6) + return to_chars_f(v, olength, result + index) + sign; + + /* + * If v.exponent is exactly 0, we might have reached here via the small + * integer fast path, in which case v.mantissa might contain trailing + * (decimal) zeros. For scientific notation we need to move these zeros + * into the exponent. (For fixed point this doesn't matter, which is why + * we do this here rather than above.) + * + * Since we already calculated the display exponent (exp) above based on + * the old decimal length, that value does not change here. Instead, we + * just reduce the display length for each digit removed. + * + * If we didn't get here via the fast path, the raw exponent will not + * usually be 0, and there will be no trailing zeros, so we pay no more + * than one div10/multiply extra cost. We claw back half of that by + * checking for divisibility by 2 before dividing by 10. + */ + if (v.exponent == 0) + { + while ((output & 1) == 0) + { + const uint32 q = output / 10; + const uint32 r = output - 10 * q; + + if (r != 0) + break; + output = q; + --olength; + } + } + + /*---- + * Print the decimal digits. + * The following code is equivalent to: + * + * for (uint32 i = 0; i < olength - 1; ++i) { + * const uint32 c = output % 10; output /= 10; + * result[index + olength - i] = (char) ('0' + c); + * } + * result[index] = '0' + output % 10; + */ + uint32 i = 0; + + while (output >= 10000) + { + const uint32 c = output - 10000 * (output / 10000); + const uint32 c0 = (c % 100) << 1; + const uint32 c1 = (c / 100) << 1; + + output /= 10000; + + memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2); + memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2); + i += 4; + } + if (output >= 100) + { + const uint32 c = (output % 100) << 1; + + output /= 100; + memcpy(result + index + olength - i - 1, DIGIT_TABLE + c, 2); + i += 2; + } + if (output >= 10) + { + const uint32 c = output << 1; + + /* + * We can't use memcpy here: the decimal dot goes between these two + * digits. + */ + result[index + olength - i] = DIGIT_TABLE[c + 1]; + result[index] = DIGIT_TABLE[c]; + } + else + { + result[index] = (char) ('0' + output); + } + + /* Print decimal point if needed. */ + if (olength > 1) + { + result[index + 1] = '.'; + index += olength + 1; + } + else + { + ++index; + } + + /* Print the exponent. */ + result[index++] = 'e'; + if (exp < 0) + { + result[index++] = '-'; + exp = -exp; + } + else + result[index++] = '+'; + + memcpy(result + index, DIGIT_TABLE + 2 * exp, 2); + index += 2; + + return index; +} + +static inline bool +f2d_small_int(const uint32 ieeeMantissa, + const uint32 ieeeExponent, + floating_decimal_32 *v) +{ + const int32 e2 = (int32) ieeeExponent - FLOAT_BIAS - FLOAT_MANTISSA_BITS; + + /* + * Avoid using multiple "return false;" here since it tends to provoke the + * compiler into inlining multiple copies of f2d, which is undesirable. + */ + + if (e2 >= -FLOAT_MANTISSA_BITS && e2 <= 0) + { + /*---- + * Since 2^23 <= m2 < 2^24 and 0 <= -e2 <= 23: + * 1 <= f = m2 / 2^-e2 < 2^24. + * + * Test if the lower -e2 bits of the significand are 0, i.e. whether + * the fraction is 0. We can use ieeeMantissa here, since the implied + * 1 bit can never be tested by this; the implied 1 can only be part + * of a fraction if e2 < -FLOAT_MANTISSA_BITS which we already + * checked. (e.g. 0.5 gives ieeeMantissa == 0 and e2 == -24) + */ + const uint32 mask = (1U << -e2) - 1; + const uint32 fraction = ieeeMantissa & mask; + + if (fraction == 0) + { + /*---- + * f is an integer in the range [1, 2^24). + * Note: mantissa might contain trailing (decimal) 0's. + * Note: since 2^24 < 10^9, there is no need to adjust + * decimalLength(). + */ + const uint32 m2 = (1U << FLOAT_MANTISSA_BITS) | ieeeMantissa; + + v->mantissa = m2 >> -e2; + v->exponent = 0; + return true; + } + } + + return false; +} + +/* + * Store the shortest decimal representation of the given float as an + * UNTERMINATED string in the caller's supplied buffer (which must be at least + * FLOAT_SHORTEST_DECIMAL_LEN-1 bytes long). + * + * Returns the number of bytes stored. + */ +int +float_to_shortest_decimal_bufn(float f, char *result) +{ + /* + * Step 1: Decode the floating-point number, and unify normalized and + * subnormal cases. + */ + const uint32 bits = float_to_bits(f); + + /* Decode bits into sign, mantissa, and exponent. */ + const bool ieeeSign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0; + const uint32 ieeeMantissa = bits & ((1u << FLOAT_MANTISSA_BITS) - 1); + const uint32 ieeeExponent = (bits >> FLOAT_MANTISSA_BITS) & ((1u << FLOAT_EXPONENT_BITS) - 1); + + /* Case distinction; exit early for the easy cases. */ + if (ieeeExponent == ((1u << FLOAT_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) + { + return copy_special_str(result, ieeeSign, (ieeeExponent != 0), (ieeeMantissa != 0)); + } + + floating_decimal_32 v; + const bool isSmallInt = f2d_small_int(ieeeMantissa, ieeeExponent, &v); + + if (!isSmallInt) + { + v = f2d(ieeeMantissa, ieeeExponent); + } + + return to_chars(v, ieeeSign, result); +} + +/* + * Store the shortest decimal representation of the given float as a + * null-terminated string in the caller's supplied buffer (which must be at + * least FLOAT_SHORTEST_DECIMAL_LEN bytes long). + * + * Returns the string length. + */ +int +float_to_shortest_decimal_buf(float f, char *result) +{ + const int index = float_to_shortest_decimal_bufn(f, result); + + /* Terminate the string. */ + Assert(index < FLOAT_SHORTEST_DECIMAL_LEN); + result[index] = '\0'; + return index; +} + +/* + * Return the shortest decimal representation as a null-terminated palloc'd + * string (outside the backend, uses malloc() instead). + * + * Caller is responsible for freeing the result. + */ +char * +float_to_shortest_decimal(float f) +{ + char *const result = (char *) palloc(FLOAT_SHORTEST_DECIMAL_LEN); + + float_to_shortest_decimal_buf(f, result); + return result; +} diff --git a/contrib/libs/libpq/src/common/fe_memutils.c b/contrib/libs/libpq/src/common/fe_memutils.c new file mode 100644 index 0000000000..3bad81eafc --- /dev/null +++ b/contrib/libs/libpq/src/common/fe_memutils.c @@ -0,0 +1,175 @@ +/*------------------------------------------------------------------------- + * + * fe_memutils.c + * memory management support for frontend code + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/fe_memutils.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#error "This file is not expected to be compiled for backend code" +#endif + +#include "postgres_fe.h" + +static inline void * +pg_malloc_internal(size_t size, int flags) +{ + void *tmp; + + /* Avoid unportable behavior of malloc(0) */ + if (size == 0) + size = 1; + tmp = malloc(size); + if (tmp == NULL) + { + if ((flags & MCXT_ALLOC_NO_OOM) == 0) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + return NULL; + } + + if ((flags & MCXT_ALLOC_ZERO) != 0) + MemSet(tmp, 0, size); + return tmp; +} + +void * +pg_malloc(size_t size) +{ + return pg_malloc_internal(size, 0); +} + +void * +pg_malloc0(size_t size) +{ + return pg_malloc_internal(size, MCXT_ALLOC_ZERO); +} + +void * +pg_malloc_extended(size_t size, int flags) +{ + return pg_malloc_internal(size, flags); +} + +void * +pg_realloc(void *ptr, size_t size) +{ + void *tmp; + + /* Avoid unportable behavior of realloc(NULL, 0) */ + if (ptr == NULL && size == 0) + size = 1; + tmp = realloc(ptr, size); + if (!tmp) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + return tmp; +} + +/* + * "Safe" wrapper around strdup(). + */ +char * +pg_strdup(const char *in) +{ + char *tmp; + + if (!in) + { + fprintf(stderr, + _("cannot duplicate null pointer (internal error)\n")); + exit(EXIT_FAILURE); + } + tmp = strdup(in); + if (!tmp) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + return tmp; +} + +void +pg_free(void *ptr) +{ + free(ptr); +} + +/* + * Frontend emulation of backend memory management functions. Useful for + * programs that compile backend files. + */ +void * +palloc(Size size) +{ + return pg_malloc_internal(size, 0); +} + +void * +palloc0(Size size) +{ + return pg_malloc_internal(size, MCXT_ALLOC_ZERO); +} + +void * +palloc_extended(Size size, int flags) +{ + return pg_malloc_internal(size, flags); +} + +void +pfree(void *pointer) +{ + pg_free(pointer); +} + +char * +pstrdup(const char *in) +{ + return pg_strdup(in); +} + +char * +pnstrdup(const char *in, Size size) +{ + char *tmp; + int len; + + if (!in) + { + fprintf(stderr, + _("cannot duplicate null pointer (internal error)\n")); + exit(EXIT_FAILURE); + } + + len = strnlen(in, size); + tmp = malloc(len + 1); + if (tmp == NULL) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + + memcpy(tmp, in, len); + tmp[len] = '\0'; + + return tmp; +} + +void * +repalloc(void *pointer, Size size) +{ + return pg_realloc(pointer, size); +} diff --git a/contrib/libs/libpq/src/common/file_perm.c b/contrib/libs/libpq/src/common/file_perm.c new file mode 100644 index 0000000000..60f88d2caf --- /dev/null +++ b/contrib/libs/libpq/src/common/file_perm.c @@ -0,0 +1,91 @@ +/*------------------------------------------------------------------------- + * + * File and directory permission routines + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/common/file_perm.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "common/file_perm.h" + +/* Modes for creating directories and files in the data directory */ +int pg_dir_create_mode = PG_DIR_MODE_OWNER; +int pg_file_create_mode = PG_FILE_MODE_OWNER; + +/* + * Mode mask to pass to umask(). This is more of a preventative measure since + * all file/directory creates should be performed using the create modes above. + */ +int pg_mode_mask = PG_MODE_MASK_OWNER; + +/* + * Set create modes and mask to use when writing to PGDATA based on the data + * directory mode passed. If group read/execute are present in the mode, then + * create modes and mask will be relaxed to allow group read/execute on all + * newly created files and directories. + */ +void +SetDataDirectoryCreatePerm(int dataDirMode) +{ + /* If the data directory mode has group access */ + if ((PG_DIR_MODE_GROUP & dataDirMode) == PG_DIR_MODE_GROUP) + { + pg_dir_create_mode = PG_DIR_MODE_GROUP; + pg_file_create_mode = PG_FILE_MODE_GROUP; + pg_mode_mask = PG_MODE_MASK_GROUP; + } + /* Else use default permissions */ + else + { + pg_dir_create_mode = PG_DIR_MODE_OWNER; + pg_file_create_mode = PG_FILE_MODE_OWNER; + pg_mode_mask = PG_MODE_MASK_OWNER; + } +} + +#ifdef FRONTEND + +/* + * Get the create modes and mask to use when writing to PGDATA by examining the + * mode of the PGDATA directory and calling SetDataDirectoryCreatePerm(). + * + * Errors are not handled here and should be reported by the application when + * false is returned. + * + * Suppress when on Windows, because there may not be proper support for Unix-y + * file permissions. + */ +bool +GetDataDirectoryCreatePerm(const char *dataDir) +{ +#if !defined(WIN32) && !defined(__CYGWIN__) + struct stat statBuf; + + /* + * If an error occurs getting the mode then return false. The caller is + * responsible for generating an error, if appropriate, indicating that we + * were unable to access the data directory. + */ + if (stat(dataDir, &statBuf) == -1) + return false; + + /* Set permissions */ + SetDataDirectoryCreatePerm(statBuf.st_mode); + return true; +#else /* !defined(WIN32) && !defined(__CYGWIN__) */ + /* + * On Windows, we don't have anything to do here since they don't have + * Unix-y permissions. + */ + return true; +#endif +} + + +#endif /* FRONTEND */ diff --git a/contrib/libs/libpq/src/common/file_utils.c b/contrib/libs/libpq/src/common/file_utils.c new file mode 100644 index 0000000000..74833c4acb --- /dev/null +++ b/contrib/libs/libpq/src/common/file_utils.c @@ -0,0 +1,582 @@ +/*------------------------------------------------------------------------- + * + * File-processing utility routines. + * + * Assorted utility functions to work on files. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/common/file_utils.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "common/file_utils.h" +#ifdef FRONTEND +#include "common/logging.h" +#endif +#include "port/pg_iovec.h" + +#ifdef FRONTEND + +/* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */ +#if defined(HAVE_SYNC_FILE_RANGE) +#define PG_FLUSH_DATA_WORKS 1 +#elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) +#define PG_FLUSH_DATA_WORKS 1 +#endif + +/* + * pg_xlog has been renamed to pg_wal in version 10. + */ +#define MINIMUM_VERSION_FOR_PG_WAL 100000 + +#ifdef PG_FLUSH_DATA_WORKS +static int pre_sync_fname(const char *fname, bool isdir); +#endif +static void walkdir(const char *path, + int (*action) (const char *fname, bool isdir), + bool process_symlinks); + +/* + * Issue fsync recursively on PGDATA and all its contents. + * + * We fsync regular files and directories wherever they are, but we follow + * symlinks only for pg_wal (or pg_xlog) and immediately under pg_tblspc. + * Other symlinks are presumed to point at files we're not responsible for + * fsyncing, and might not have privileges to write at all. + * + * serverVersion indicates the version of the server to be fsync'd. + */ +void +fsync_pgdata(const char *pg_data, + int serverVersion) +{ + bool xlog_is_symlink; + char pg_wal[MAXPGPATH]; + char pg_tblspc[MAXPGPATH]; + + /* handle renaming of pg_xlog to pg_wal in post-10 clusters */ + snprintf(pg_wal, MAXPGPATH, "%s/%s", pg_data, + serverVersion < MINIMUM_VERSION_FOR_PG_WAL ? "pg_xlog" : "pg_wal"); + snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data); + + /* + * If pg_wal is a symlink, we'll need to recurse into it separately, + * because the first walkdir below will ignore it. + */ + xlog_is_symlink = false; + + { + struct stat st; + + if (lstat(pg_wal, &st) < 0) + pg_log_error("could not stat file \"%s\": %m", pg_wal); + else if (S_ISLNK(st.st_mode)) + xlog_is_symlink = true; + } + + /* + * If possible, hint to the kernel that we're soon going to fsync the data + * directory and its contents. + */ +#ifdef PG_FLUSH_DATA_WORKS + walkdir(pg_data, pre_sync_fname, false); + if (xlog_is_symlink) + walkdir(pg_wal, pre_sync_fname, false); + walkdir(pg_tblspc, pre_sync_fname, true); +#endif + + /* + * Now we do the fsync()s in the same order. + * + * The main call ignores symlinks, so in addition to specially processing + * pg_wal if it's a symlink, pg_tblspc has to be visited separately with + * process_symlinks = true. Note that if there are any plain directories + * in pg_tblspc, they'll get fsync'd twice. That's not an expected case + * so we don't worry about optimizing it. + */ + walkdir(pg_data, fsync_fname, false); + if (xlog_is_symlink) + walkdir(pg_wal, fsync_fname, false); + walkdir(pg_tblspc, fsync_fname, true); +} + +/* + * Issue fsync recursively on the given directory and all its contents. + * + * This is a convenient wrapper on top of walkdir(). + */ +void +fsync_dir_recurse(const char *dir) +{ + /* + * If possible, hint to the kernel that we're soon going to fsync the data + * directory and its contents. + */ +#ifdef PG_FLUSH_DATA_WORKS + walkdir(dir, pre_sync_fname, false); +#endif + + walkdir(dir, fsync_fname, false); +} + +/* + * walkdir: recursively walk a directory, applying the action to each + * regular file and directory (including the named directory itself). + * + * If process_symlinks is true, the action and recursion are also applied + * to regular files and directories that are pointed to by symlinks in the + * given directory; otherwise symlinks are ignored. Symlinks are always + * ignored in subdirectories, ie we intentionally don't pass down the + * process_symlinks flag to recursive calls. + * + * Errors are reported but not considered fatal. + * + * See also walkdir in fd.c, which is a backend version of this logic. + */ +static void +walkdir(const char *path, + int (*action) (const char *fname, bool isdir), + bool process_symlinks) +{ + DIR *dir; + struct dirent *de; + + dir = opendir(path); + if (dir == NULL) + { + pg_log_error("could not open directory \"%s\": %m", path); + return; + } + + while (errno = 0, (de = readdir(dir)) != NULL) + { + char subpath[MAXPGPATH * 2]; + + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + snprintf(subpath, sizeof(subpath), "%s/%s", path, de->d_name); + + switch (get_dirent_type(subpath, de, process_symlinks, PG_LOG_ERROR)) + { + case PGFILETYPE_REG: + (*action) (subpath, false); + break; + case PGFILETYPE_DIR: + walkdir(subpath, action, false); + break; + default: + + /* + * Errors are already reported directly by get_dirent_type(), + * and any remaining symlinks and unknown file types are + * ignored. + */ + break; + } + } + + if (errno) + pg_log_error("could not read directory \"%s\": %m", path); + + (void) closedir(dir); + + /* + * It's important to fsync the destination directory itself as individual + * file fsyncs don't guarantee that the directory entry for the file is + * synced. Recent versions of ext4 have made the window much wider but + * it's been an issue for ext3 and other filesystems in the past. + */ + (*action) (path, true); +} + +/* + * Hint to the OS that it should get ready to fsync() this file. + * + * Ignores errors trying to open unreadable files, and reports other errors + * non-fatally. + */ +#ifdef PG_FLUSH_DATA_WORKS + +static int +pre_sync_fname(const char *fname, bool isdir) +{ + int fd; + + fd = open(fname, O_RDONLY | PG_BINARY, 0); + + if (fd < 0) + { + if (errno == EACCES || (isdir && errno == EISDIR)) + return 0; + pg_log_error("could not open file \"%s\": %m", fname); + return -1; + } + + /* + * We do what pg_flush_data() would do in the backend: prefer to use + * sync_file_range, but fall back to posix_fadvise. We ignore errors + * because this is only a hint. + */ +#if defined(HAVE_SYNC_FILE_RANGE) + (void) sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE); +#elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) + (void) posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); +#else +#error PG_FLUSH_DATA_WORKS should not have been defined +#endif + + (void) close(fd); + return 0; +} + +#endif /* PG_FLUSH_DATA_WORKS */ + +/* + * fsync_fname -- Try to fsync a file or directory + * + * Ignores errors trying to open unreadable files, or trying to fsync + * directories on systems where that isn't allowed/required. All other errors + * are fatal. + */ +int +fsync_fname(const char *fname, bool isdir) +{ + int fd; + int flags; + int returncode; + + /* + * Some OSs require directories to be opened read-only whereas other + * systems don't allow us to fsync files opened read-only; so we need both + * cases here. Using O_RDWR will cause us to fail to fsync files that are + * not writable by our userid, but we assume that's OK. + */ + flags = PG_BINARY; + if (!isdir) + flags |= O_RDWR; + else + flags |= O_RDONLY; + + /* + * Open the file, silently ignoring errors about unreadable files (or + * unsupported operations, e.g. opening a directory under Windows), and + * logging others. + */ + fd = open(fname, flags, 0); + if (fd < 0) + { + if (errno == EACCES || (isdir && errno == EISDIR)) + return 0; + pg_log_error("could not open file \"%s\": %m", fname); + return -1; + } + + returncode = fsync(fd); + + /* + * Some OSes don't allow us to fsync directories at all, so we can ignore + * those errors. Anything else needs to be reported. + */ + if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL))) + { + pg_log_error("could not fsync file \"%s\": %m", fname); + (void) close(fd); + exit(EXIT_FAILURE); + } + + (void) close(fd); + return 0; +} + +/* + * fsync_parent_path -- fsync the parent path of a file or directory + * + * This is aimed at making file operations persistent on disk in case of + * an OS crash or power failure. + */ +int +fsync_parent_path(const char *fname) +{ + char parentpath[MAXPGPATH]; + + strlcpy(parentpath, fname, MAXPGPATH); + get_parent_directory(parentpath); + + /* + * get_parent_directory() returns an empty string if the input argument is + * just a file name (see comments in path.c), so handle that as being the + * current directory. + */ + if (strlen(parentpath) == 0) + strlcpy(parentpath, ".", MAXPGPATH); + + if (fsync_fname(parentpath, true) != 0) + return -1; + + return 0; +} + +/* + * durable_rename -- rename(2) wrapper, issuing fsyncs required for durability + * + * Wrapper around rename, similar to the backend version. + */ +int +durable_rename(const char *oldfile, const char *newfile) +{ + int fd; + + /* + * First fsync the old and target path (if it exists), to ensure that they + * are properly persistent on disk. Syncing the target file is not + * strictly necessary, but it makes it easier to reason about crashes; + * because it's then guaranteed that either source or target file exists + * after a crash. + */ + if (fsync_fname(oldfile, false) != 0) + return -1; + + fd = open(newfile, PG_BINARY | O_RDWR, 0); + if (fd < 0) + { + if (errno != ENOENT) + { + pg_log_error("could not open file \"%s\": %m", newfile); + return -1; + } + } + else + { + if (fsync(fd) != 0) + { + pg_log_error("could not fsync file \"%s\": %m", newfile); + close(fd); + exit(EXIT_FAILURE); + } + close(fd); + } + + /* Time to do the real deal... */ + if (rename(oldfile, newfile) != 0) + { + pg_log_error("could not rename file \"%s\" to \"%s\": %m", + oldfile, newfile); + return -1; + } + + /* + * To guarantee renaming the file is persistent, fsync the file with its + * new name, and its containing directory. + */ + if (fsync_fname(newfile, false) != 0) + return -1; + + if (fsync_parent_path(newfile) != 0) + return -1; + + return 0; +} + +#endif /* FRONTEND */ + +/* + * Return the type of a directory entry. + * + * In frontend code, elevel should be a level from logging.h; in backend code + * it should be a level from elog.h. + */ +PGFileType +get_dirent_type(const char *path, + const struct dirent *de, + bool look_through_symlinks, + int elevel) +{ + PGFileType result; + + /* + * Some systems tell us the type directly in the dirent struct, but that's + * a BSD and Linux extension not required by POSIX. Even when the + * interface is present, sometimes the type is unknown, depending on the + * filesystem. + */ +#if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK) + if (de->d_type == DT_REG) + result = PGFILETYPE_REG; + else if (de->d_type == DT_DIR) + result = PGFILETYPE_DIR; + else if (de->d_type == DT_LNK && !look_through_symlinks) + result = PGFILETYPE_LNK; + else + result = PGFILETYPE_UNKNOWN; +#else + result = PGFILETYPE_UNKNOWN; +#endif + + if (result == PGFILETYPE_UNKNOWN) + { + struct stat fst; + int sret; + + + if (look_through_symlinks) + sret = stat(path, &fst); + else + sret = lstat(path, &fst); + + if (sret < 0) + { + result = PGFILETYPE_ERROR; +#ifdef FRONTEND + pg_log_generic(elevel, PG_LOG_PRIMARY, "could not stat file \"%s\": %m", path); +#else + ereport(elevel, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", path))); +#endif + } + else if (S_ISREG(fst.st_mode)) + result = PGFILETYPE_REG; + else if (S_ISDIR(fst.st_mode)) + result = PGFILETYPE_DIR; + else if (S_ISLNK(fst.st_mode)) + result = PGFILETYPE_LNK; + } + + return result; +} + +/* + * pg_pwritev_with_retry + * + * Convenience wrapper for pg_pwritev() that retries on partial write. If an + * error is returned, it is unspecified how much has been written. + */ +ssize_t +pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + struct iovec iov_copy[PG_IOV_MAX]; + ssize_t sum = 0; + ssize_t part; + + /* We'd better have space to make a copy, in case we need to retry. */ + if (iovcnt > PG_IOV_MAX) + { + errno = EINVAL; + return -1; + } + + for (;;) + { + /* Write as much as we can. */ + part = pg_pwritev(fd, iov, iovcnt, offset); + if (part < 0) + return -1; + +#ifdef SIMULATE_SHORT_WRITE + part = Min(part, 4096); +#endif + + /* Count our progress. */ + sum += part; + offset += part; + + /* Step over iovecs that are done. */ + while (iovcnt > 0 && iov->iov_len <= part) + { + part -= iov->iov_len; + ++iov; + --iovcnt; + } + + /* Are they all done? */ + if (iovcnt == 0) + { + /* We don't expect the kernel to write more than requested. */ + Assert(part == 0); + break; + } + + /* + * Move whatever's left to the front of our mutable copy and adjust + * the leading iovec. + */ + Assert(iovcnt > 0); + memmove(iov_copy, iov, sizeof(*iov) * iovcnt); + Assert(iov->iov_len > part); + iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part; + iov_copy[0].iov_len -= part; + iov = iov_copy; + } + + return sum; +} + +/* + * pg_pwrite_zeros + * + * Writes zeros to file worth "size" bytes at "offset" (from the start of the + * file), using vectored I/O. + * + * Returns the total amount of data written. On failure, a negative value + * is returned with errno set. + */ +ssize_t +pg_pwrite_zeros(int fd, size_t size, off_t offset) +{ + static const PGIOAlignedBlock zbuffer = {{0}}; /* worth BLCKSZ */ + void *zerobuf_addr = unconstify(PGIOAlignedBlock *, &zbuffer)->data; + struct iovec iov[PG_IOV_MAX]; + size_t remaining_size = size; + ssize_t total_written = 0; + + /* Loop, writing as many blocks as we can for each system call. */ + while (remaining_size > 0) + { + int iovcnt = 0; + ssize_t written; + + for (; iovcnt < PG_IOV_MAX && remaining_size > 0; iovcnt++) + { + size_t this_iov_size; + + iov[iovcnt].iov_base = zerobuf_addr; + + if (remaining_size < BLCKSZ) + this_iov_size = remaining_size; + else + this_iov_size = BLCKSZ; + + iov[iovcnt].iov_len = this_iov_size; + remaining_size -= this_iov_size; + } + + written = pg_pwritev_with_retry(fd, iov, iovcnt, offset); + + if (written < 0) + return written; + + offset += written; + total_written += written; + } + + Assert(total_written == size); + + return total_written; +} diff --git a/contrib/libs/libpq/src/common/hashfn.c b/contrib/libs/libpq/src/common/hashfn.c new file mode 100644 index 0000000000..2490607eea --- /dev/null +++ b/contrib/libs/libpq/src/common/hashfn.c @@ -0,0 +1,692 @@ +/*------------------------------------------------------------------------- + * + * hashfn.c + * Generic hashing functions, and hash functions for use in dynahash.c + * hashtables + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/hashfn.c + * + * NOTES + * It is expected that every bit of a hash function's 32-bit result is + * as random as every other; failure to ensure this is likely to lead + * to poor performance of hash tables. In most cases a hash + * function should use hash_bytes() or its variant hash_bytes_uint32(), + * or the wrappers hash_any() and hash_uint32 defined in hashfn.h. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "common/hashfn.h" +#include "port/pg_bitutils.h" + + +/* + * This hash function was written by Bob Jenkins + * (bob_jenkins@burtleburtle.net), and superficially adapted + * for PostgreSQL by Neil Conway. For more information on this + * hash function, see http://burtleburtle.net/bob/hash/doobs.html, + * or Bob's article in Dr. Dobb's Journal, Sept. 1997. + * + * In the current code, we have adopted Bob's 2006 update of his hash + * function to fetch the data a word at a time when it is suitably aligned. + * This makes for a useful speedup, at the cost of having to maintain + * four code paths (aligned vs unaligned, and little-endian vs big-endian). + * It also uses two separate mixing functions mix() and final(), instead + * of a slower multi-purpose function. + */ + +/* Get a bit mask of the bits set in non-uint32 aligned addresses */ +#define UINT32_ALIGN_MASK (sizeof(uint32) - 1) + +#define rot(x,k) pg_rotate_left32(x, k) + +/*---------- + * mix -- mix 3 32-bit values reversibly. + * + * This is reversible, so any information in (a,b,c) before mix() is + * still in (a,b,c) after mix(). + * + * If four pairs of (a,b,c) inputs are run through mix(), or through + * mix() in reverse, there are at least 32 bits of the output that + * are sometimes the same for one pair and different for another pair. + * This was tested for: + * * pairs that differed by one bit, by two bits, in any combination + * of top bits of (a,b,c), or in any combination of bottom bits of + * (a,b,c). + * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + * is commonly produced by subtraction) look like a single 1-bit + * difference. + * * the base values were pseudorandom, all zero but one bit set, or + * all zero plus a counter that starts at zero. + * + * This does not achieve avalanche. There are input bits of (a,b,c) + * that fail to affect some output bits of (a,b,c), especially of a. The + * most thoroughly mixed value is c, but it doesn't really even achieve + * avalanche in c. + * + * This allows some parallelism. Read-after-writes are good at doubling + * the number of bits affected, so the goal of mixing pulls in the opposite + * direction from the goal of parallelism. I did what I could. Rotates + * seem to cost as much as shifts on every machine I could lay my hands on, + * and rotates are much kinder to the top and bottom bits, so I used rotates. + *---------- + */ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/*---------- + * final -- final mixing of 3 32-bit values (a,b,c) into c + * + * Pairs of (a,b,c) values differing in only a few bits will usually + * produce values of c that look totally different. This was tested for + * * pairs that differed by one bit, by two bits, in any combination + * of top bits of (a,b,c), or in any combination of bottom bits of + * (a,b,c). + * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + * is commonly produced by subtraction) look like a single 1-bit + * difference. + * * the base values were pseudorandom, all zero but one bit set, or + * all zero plus a counter that starts at zero. + * + * The use of separate functions for mix() and final() allow for a + * substantial performance increase since final() does not need to + * do well in reverse, but is does need to affect all output bits. + * mix(), on the other hand, does not need to affect all output + * bits (affecting 32 bits is enough). The original hash function had + * a single mixing operation that had to satisfy both sets of requirements + * and was slower as a result. + *---------- + */ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c, 4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* + * hash_bytes() -- hash a variable-length key into a 32-bit value + * k : the key (the unaligned variable-length array of bytes) + * len : the length of the key, counting by bytes + * + * Returns a uint32 value. Every bit of the key affects every bit of + * the return value. Every 1-bit and 2-bit delta achieves avalanche. + * About 6*len+35 instructions. The best hash table sizes are powers + * of 2. There is no need to do mod a prime (mod is sooo slow!). + * If you need less than 32 bits, use a bitmask. + * + * This procedure must never throw elog(ERROR); the ResourceOwner code + * relies on this not to fail. + * + * Note: we could easily change this function to return a 64-bit hash value + * by using the final values of both b and c. b is perhaps a little less + * well mixed than c, however. + */ +uint32 +hash_bytes(const unsigned char *k, int keylen) +{ + uint32 a, + b, + c, + len; + + /* Set up the internal state */ + len = keylen; + a = b = c = 0x9e3779b9 + len + 3923095; + + /* If the source pointer is word-aligned, we use word-wide fetches */ + if (((uintptr_t) k & UINT32_ALIGN_MASK) == 0) + { + /* Code path for aligned source data */ + const uint32 *ka = (const uint32 *) k; + + /* handle most of the key */ + while (len >= 12) + { + a += ka[0]; + b += ka[1]; + c += ka[2]; + mix(a, b, c); + ka += 3; + len -= 12; + } + + /* handle the last 11 bytes */ + k = (const unsigned char *) ka; +#ifdef WORDS_BIGENDIAN + switch (len) + { + case 11: + c += ((uint32) k[10] << 8); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 24); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ka[1]; + a += ka[0]; + break; + case 7: + b += ((uint32) k[6] << 8); + /* fall through */ + case 6: + b += ((uint32) k[5] << 16); + /* fall through */ + case 5: + b += ((uint32) k[4] << 24); + /* fall through */ + case 4: + a += ka[0]; + break; + case 3: + a += ((uint32) k[2] << 8); + /* fall through */ + case 2: + a += ((uint32) k[1] << 16); + /* fall through */ + case 1: + a += ((uint32) k[0] << 24); + /* case 0: nothing left to add */ + } +#else /* !WORDS_BIGENDIAN */ + switch (len) + { + case 11: + c += ((uint32) k[10] << 24); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 8); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ka[1]; + a += ka[0]; + break; + case 7: + b += ((uint32) k[6] << 16); + /* fall through */ + case 6: + b += ((uint32) k[5] << 8); + /* fall through */ + case 5: + b += k[4]; + /* fall through */ + case 4: + a += ka[0]; + break; + case 3: + a += ((uint32) k[2] << 16); + /* fall through */ + case 2: + a += ((uint32) k[1] << 8); + /* fall through */ + case 1: + a += k[0]; + /* case 0: nothing left to add */ + } +#endif /* WORDS_BIGENDIAN */ + } + else + { + /* Code path for non-aligned source data */ + + /* handle most of the key */ + while (len >= 12) + { +#ifdef WORDS_BIGENDIAN + a += (k[3] + ((uint32) k[2] << 8) + ((uint32) k[1] << 16) + ((uint32) k[0] << 24)); + b += (k[7] + ((uint32) k[6] << 8) + ((uint32) k[5] << 16) + ((uint32) k[4] << 24)); + c += (k[11] + ((uint32) k[10] << 8) + ((uint32) k[9] << 16) + ((uint32) k[8] << 24)); +#else /* !WORDS_BIGENDIAN */ + a += (k[0] + ((uint32) k[1] << 8) + ((uint32) k[2] << 16) + ((uint32) k[3] << 24)); + b += (k[4] + ((uint32) k[5] << 8) + ((uint32) k[6] << 16) + ((uint32) k[7] << 24)); + c += (k[8] + ((uint32) k[9] << 8) + ((uint32) k[10] << 16) + ((uint32) k[11] << 24)); +#endif /* WORDS_BIGENDIAN */ + mix(a, b, c); + k += 12; + len -= 12; + } + + /* handle the last 11 bytes */ +#ifdef WORDS_BIGENDIAN + switch (len) + { + case 11: + c += ((uint32) k[10] << 8); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 24); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += k[7]; + /* fall through */ + case 7: + b += ((uint32) k[6] << 8); + /* fall through */ + case 6: + b += ((uint32) k[5] << 16); + /* fall through */ + case 5: + b += ((uint32) k[4] << 24); + /* fall through */ + case 4: + a += k[3]; + /* fall through */ + case 3: + a += ((uint32) k[2] << 8); + /* fall through */ + case 2: + a += ((uint32) k[1] << 16); + /* fall through */ + case 1: + a += ((uint32) k[0] << 24); + /* case 0: nothing left to add */ + } +#else /* !WORDS_BIGENDIAN */ + switch (len) + { + case 11: + c += ((uint32) k[10] << 24); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 8); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ((uint32) k[7] << 24); + /* fall through */ + case 7: + b += ((uint32) k[6] << 16); + /* fall through */ + case 6: + b += ((uint32) k[5] << 8); + /* fall through */ + case 5: + b += k[4]; + /* fall through */ + case 4: + a += ((uint32) k[3] << 24); + /* fall through */ + case 3: + a += ((uint32) k[2] << 16); + /* fall through */ + case 2: + a += ((uint32) k[1] << 8); + /* fall through */ + case 1: + a += k[0]; + /* case 0: nothing left to add */ + } +#endif /* WORDS_BIGENDIAN */ + } + + final(a, b, c); + + /* report the result */ + return c; +} + +/* + * hash_bytes_extended() -- hash into a 64-bit value, using an optional seed + * k : the key (the unaligned variable-length array of bytes) + * len : the length of the key, counting by bytes + * seed : a 64-bit seed (0 means no seed) + * + * Returns a uint64 value. Otherwise similar to hash_bytes. + */ +uint64 +hash_bytes_extended(const unsigned char *k, int keylen, uint64 seed) +{ + uint32 a, + b, + c, + len; + + /* Set up the internal state */ + len = keylen; + a = b = c = 0x9e3779b9 + len + 3923095; + + /* If the seed is non-zero, use it to perturb the internal state. */ + if (seed != 0) + { + /* + * In essence, the seed is treated as part of the data being hashed, + * but for simplicity, we pretend that it's padded with four bytes of + * zeroes so that the seed constitutes a 12-byte chunk. + */ + a += (uint32) (seed >> 32); + b += (uint32) seed; + mix(a, b, c); + } + + /* If the source pointer is word-aligned, we use word-wide fetches */ + if (((uintptr_t) k & UINT32_ALIGN_MASK) == 0) + { + /* Code path for aligned source data */ + const uint32 *ka = (const uint32 *) k; + + /* handle most of the key */ + while (len >= 12) + { + a += ka[0]; + b += ka[1]; + c += ka[2]; + mix(a, b, c); + ka += 3; + len -= 12; + } + + /* handle the last 11 bytes */ + k = (const unsigned char *) ka; +#ifdef WORDS_BIGENDIAN + switch (len) + { + case 11: + c += ((uint32) k[10] << 8); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 24); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ka[1]; + a += ka[0]; + break; + case 7: + b += ((uint32) k[6] << 8); + /* fall through */ + case 6: + b += ((uint32) k[5] << 16); + /* fall through */ + case 5: + b += ((uint32) k[4] << 24); + /* fall through */ + case 4: + a += ka[0]; + break; + case 3: + a += ((uint32) k[2] << 8); + /* fall through */ + case 2: + a += ((uint32) k[1] << 16); + /* fall through */ + case 1: + a += ((uint32) k[0] << 24); + /* case 0: nothing left to add */ + } +#else /* !WORDS_BIGENDIAN */ + switch (len) + { + case 11: + c += ((uint32) k[10] << 24); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 8); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ka[1]; + a += ka[0]; + break; + case 7: + b += ((uint32) k[6] << 16); + /* fall through */ + case 6: + b += ((uint32) k[5] << 8); + /* fall through */ + case 5: + b += k[4]; + /* fall through */ + case 4: + a += ka[0]; + break; + case 3: + a += ((uint32) k[2] << 16); + /* fall through */ + case 2: + a += ((uint32) k[1] << 8); + /* fall through */ + case 1: + a += k[0]; + /* case 0: nothing left to add */ + } +#endif /* WORDS_BIGENDIAN */ + } + else + { + /* Code path for non-aligned source data */ + + /* handle most of the key */ + while (len >= 12) + { +#ifdef WORDS_BIGENDIAN + a += (k[3] + ((uint32) k[2] << 8) + ((uint32) k[1] << 16) + ((uint32) k[0] << 24)); + b += (k[7] + ((uint32) k[6] << 8) + ((uint32) k[5] << 16) + ((uint32) k[4] << 24)); + c += (k[11] + ((uint32) k[10] << 8) + ((uint32) k[9] << 16) + ((uint32) k[8] << 24)); +#else /* !WORDS_BIGENDIAN */ + a += (k[0] + ((uint32) k[1] << 8) + ((uint32) k[2] << 16) + ((uint32) k[3] << 24)); + b += (k[4] + ((uint32) k[5] << 8) + ((uint32) k[6] << 16) + ((uint32) k[7] << 24)); + c += (k[8] + ((uint32) k[9] << 8) + ((uint32) k[10] << 16) + ((uint32) k[11] << 24)); +#endif /* WORDS_BIGENDIAN */ + mix(a, b, c); + k += 12; + len -= 12; + } + + /* handle the last 11 bytes */ +#ifdef WORDS_BIGENDIAN + switch (len) + { + case 11: + c += ((uint32) k[10] << 8); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 24); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += k[7]; + /* fall through */ + case 7: + b += ((uint32) k[6] << 8); + /* fall through */ + case 6: + b += ((uint32) k[5] << 16); + /* fall through */ + case 5: + b += ((uint32) k[4] << 24); + /* fall through */ + case 4: + a += k[3]; + /* fall through */ + case 3: + a += ((uint32) k[2] << 8); + /* fall through */ + case 2: + a += ((uint32) k[1] << 16); + /* fall through */ + case 1: + a += ((uint32) k[0] << 24); + /* case 0: nothing left to add */ + } +#else /* !WORDS_BIGENDIAN */ + switch (len) + { + case 11: + c += ((uint32) k[10] << 24); + /* fall through */ + case 10: + c += ((uint32) k[9] << 16); + /* fall through */ + case 9: + c += ((uint32) k[8] << 8); + /* fall through */ + case 8: + /* the lowest byte of c is reserved for the length */ + b += ((uint32) k[7] << 24); + /* fall through */ + case 7: + b += ((uint32) k[6] << 16); + /* fall through */ + case 6: + b += ((uint32) k[5] << 8); + /* fall through */ + case 5: + b += k[4]; + /* fall through */ + case 4: + a += ((uint32) k[3] << 24); + /* fall through */ + case 3: + a += ((uint32) k[2] << 16); + /* fall through */ + case 2: + a += ((uint32) k[1] << 8); + /* fall through */ + case 1: + a += k[0]; + /* case 0: nothing left to add */ + } +#endif /* WORDS_BIGENDIAN */ + } + + final(a, b, c); + + /* report the result */ + return ((uint64) b << 32) | c; +} + +/* + * hash_bytes_uint32() -- hash a 32-bit value to a 32-bit value + * + * This has the same result as + * hash_bytes(&k, sizeof(uint32)) + * but is faster and doesn't force the caller to store k into memory. + */ +uint32 +hash_bytes_uint32(uint32 k) +{ + uint32 a, + b, + c; + + a = b = c = 0x9e3779b9 + (uint32) sizeof(uint32) + 3923095; + a += k; + + final(a, b, c); + + /* report the result */ + return c; +} + +/* + * hash_bytes_uint32_extended() -- hash 32-bit value to 64-bit value, with seed + * + * Like hash_bytes_uint32, this is a convenience function. + */ +uint64 +hash_bytes_uint32_extended(uint32 k, uint64 seed) +{ + uint32 a, + b, + c; + + a = b = c = 0x9e3779b9 + (uint32) sizeof(uint32) + 3923095; + + if (seed != 0) + { + a += (uint32) (seed >> 32); + b += (uint32) seed; + mix(a, b, c); + } + + a += k; + + final(a, b, c); + + /* report the result */ + return ((uint64) b << 32) | c; +} + +/* + * string_hash: hash function for keys that are NUL-terminated strings. + * + * NOTE: this is the default hash function if none is specified. + */ +uint32 +string_hash(const void *key, Size keysize) +{ + /* + * If the string exceeds keysize-1 bytes, we want to hash only that many, + * because when it is copied into the hash table it will be truncated at + * that length. + */ + Size s_len = strlen((const char *) key); + + s_len = Min(s_len, keysize - 1); + return hash_bytes((const unsigned char *) key, (int) s_len); +} + +/* + * tag_hash: hash function for fixed-size tag values + */ +uint32 +tag_hash(const void *key, Size keysize) +{ + return hash_bytes((const unsigned char *) key, (int) keysize); +} + +/* + * uint32_hash: hash function for keys that are uint32 or int32 + * + * (tag_hash works for this case too, but is slower) + */ +uint32 +uint32_hash(const void *key, Size keysize) +{ + Assert(keysize == sizeof(uint32)); + return hash_bytes_uint32(*((const uint32 *) key)); +} diff --git a/contrib/libs/libpq/src/common/hmac_openssl.c b/contrib/libs/libpq/src/common/hmac_openssl.c new file mode 100644 index 0000000000..9aadbb886c --- /dev/null +++ b/contrib/libs/libpq/src/common/hmac_openssl.c @@ -0,0 +1,348 @@ +/*------------------------------------------------------------------------- + * + * hmac_openssl.c + * Implementation of HMAC with OpenSSL. + * + * This should only be used if code is compiled with OpenSSL support. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/hmac_openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + + +#include <openssl/err.h> +#include <openssl/hmac.h> + +#include "common/hmac.h" +#include "common/md5.h" +#include "common/sha1.h" +#include "common/sha2.h" +#ifndef FRONTEND +#error #include "utils/memutils.h" +#error #include "utils/resowner.h" +#error #include "utils/resowner_private.h" +#endif + +/* + * In backend, use an allocation in TopMemoryContext to count for resowner + * cleanup handling if necessary. For versions of OpenSSL where HMAC_CTX is + * known, just use palloc(). In frontend, use malloc to be able to return + * a failure status back to the caller. + */ +#ifndef FRONTEND +#ifdef HAVE_HMAC_CTX_NEW +#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size) +#else +#define ALLOC(size) palloc(size) +#endif +#define FREE(ptr) pfree(ptr) +#else /* FRONTEND */ +#define ALLOC(size) malloc(size) +#define FREE(ptr) free(ptr) +#endif /* FRONTEND */ + +/* Set of error states */ +typedef enum pg_hmac_errno +{ + PG_HMAC_ERROR_NONE = 0, + PG_HMAC_ERROR_DEST_LEN, + PG_HMAC_ERROR_OPENSSL +} pg_hmac_errno; + +/* Internal pg_hmac_ctx structure */ +struct pg_hmac_ctx +{ + HMAC_CTX *hmacctx; + pg_cryptohash_type type; + pg_hmac_errno error; + const char *errreason; + +#ifndef FRONTEND + ResourceOwner resowner; +#endif +}; + +static const char * +SSLerrmessage(unsigned long ecode) +{ + if (ecode == 0) + return NULL; + + /* + * This may return NULL, but we would fall back to a default error path if + * that were the case. + */ + return ERR_reason_error_string(ecode); +} + +/* + * pg_hmac_create + * + * Allocate a hash context. Returns NULL on failure for an OOM. The + * backend issues an error, without returning. + */ +pg_hmac_ctx * +pg_hmac_create(pg_cryptohash_type type) +{ + pg_hmac_ctx *ctx; + + ctx = ALLOC(sizeof(pg_hmac_ctx)); + if (ctx == NULL) + return NULL; + memset(ctx, 0, sizeof(pg_hmac_ctx)); + + ctx->type = type; + ctx->error = PG_HMAC_ERROR_NONE; + ctx->errreason = NULL; + + + /* + * Initialization takes care of assigning the correct type for OpenSSL. + * Also ensure that there aren't any unconsumed errors in the queue from + * previous runs. + */ + ERR_clear_error(); +#ifdef HAVE_HMAC_CTX_NEW +#ifndef FRONTEND + ResourceOwnerEnlargeHMAC(CurrentResourceOwner); +#endif + ctx->hmacctx = HMAC_CTX_new(); +#else + ctx->hmacctx = ALLOC(sizeof(HMAC_CTX)); +#endif + + if (ctx->hmacctx == NULL) + { + explicit_bzero(ctx, sizeof(pg_hmac_ctx)); + FREE(ctx); +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#endif + return NULL; + } + +#ifdef HAVE_HMAC_CTX_NEW +#ifndef FRONTEND + ctx->resowner = CurrentResourceOwner; + ResourceOwnerRememberHMAC(CurrentResourceOwner, PointerGetDatum(ctx)); +#endif +#else + memset(ctx->hmacctx, 0, sizeof(HMAC_CTX)); +#endif /* HAVE_HMAC_CTX_NEW */ + + return ctx; +} + +/* + * pg_hmac_init + * + * Initialize a HMAC context. Returns 0 on success, -1 on failure. + */ +int +pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len) +{ + int status = 0; + + if (ctx == NULL) + return -1; + + switch (ctx->type) + { + case PG_MD5: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_md5(), NULL); + break; + case PG_SHA1: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha1(), NULL); + break; + case PG_SHA224: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha224(), NULL); + break; + case PG_SHA256: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha256(), NULL); + break; + case PG_SHA384: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha384(), NULL); + break; + case PG_SHA512: + status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha512(), NULL); + break; + } + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_HMAC_ERROR_OPENSSL; + return -1; + } + + return 0; +} + +/* + * pg_hmac_update + * + * Update a HMAC context. Returns 0 on success, -1 on failure. + */ +int +pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len) +{ + int status = 0; + + if (ctx == NULL) + return -1; + + status = HMAC_Update(ctx->hmacctx, data, len); + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_HMAC_ERROR_OPENSSL; + return -1; + } + return 0; +} + +/* + * pg_hmac_final + * + * Finalize a HMAC context. Returns 0 on success, -1 on failure. + */ +int +pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len) +{ + int status = 0; + uint32 outlen; + + if (ctx == NULL) + return -1; + + switch (ctx->type) + { + case PG_MD5: + if (len < MD5_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA1: + if (len < SHA1_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA224: + if (len < PG_SHA224_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA256: + if (len < PG_SHA256_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA384: + if (len < PG_SHA384_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + case PG_SHA512: + if (len < PG_SHA512_DIGEST_LENGTH) + { + ctx->error = PG_HMAC_ERROR_DEST_LEN; + return -1; + } + break; + } + + status = HMAC_Final(ctx->hmacctx, dest, &outlen); + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + { + ctx->errreason = SSLerrmessage(ERR_get_error()); + ctx->error = PG_HMAC_ERROR_OPENSSL; + return -1; + } + return 0; +} + +/* + * pg_hmac_free + * + * Free a HMAC context. + */ +void +pg_hmac_free(pg_hmac_ctx *ctx) +{ + if (ctx == NULL) + return; + +#ifdef HAVE_HMAC_CTX_FREE + HMAC_CTX_free(ctx->hmacctx); +#ifndef FRONTEND + ResourceOwnerForgetHMAC(ctx->resowner, PointerGetDatum(ctx)); +#endif +#else + explicit_bzero(ctx->hmacctx, sizeof(HMAC_CTX)); + FREE(ctx->hmacctx); +#endif + + explicit_bzero(ctx, sizeof(pg_hmac_ctx)); + FREE(ctx); +} + +/* + * pg_hmac_error + * + * Returns a static string providing details about an error that happened + * during a HMAC computation. + */ +const char * +pg_hmac_error(pg_hmac_ctx *ctx) +{ + if (ctx == NULL) + return _("out of memory"); + + /* + * If a reason is provided, rely on it, else fallback to any error code + * set. + */ + if (ctx->errreason) + return ctx->errreason; + + switch (ctx->error) + { + case PG_HMAC_ERROR_NONE: + return _("success"); + case PG_HMAC_ERROR_DEST_LEN: + return _("destination buffer too small"); + case PG_HMAC_ERROR_OPENSSL: + return _("OpenSSL failure"); + } + + Assert(false); /* cannot be reached */ + return _("success"); +} diff --git a/contrib/libs/libpq/src/common/ip.c b/contrib/libs/libpq/src/common/ip.c new file mode 100644 index 0000000000..9baad3a337 --- /dev/null +++ b/contrib/libs/libpq/src/common/ip.c @@ -0,0 +1,262 @@ +/*------------------------------------------------------------------------- + * + * ip.c + * IPv6-aware network access. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/ip.c + * + * This file and the IPV6 implementation were initially provided by + * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design + * http://www.lbsd.net. + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <unistd.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <sys/file.h> + +#include "common/ip.h" + + + +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); + + +/* + * 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; + + if (hintp->ai_family == AF_UNIX) + return getaddrinfo_unix(servname, hintp, result); + + /* 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) +{ + 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 + { + /* 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; + + if (addr && addr->ss_family == AF_UNIX) + rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen, + node, nodelen, + service, servicelen, + flags); + else + 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; +} + + +/* ------- + * 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 = {0}; + struct addrinfo *aip; + struct sockaddr_un *unp; + + *result = NULL; + + 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); + + /* + * If the supplied path starts with @, replace that with a zero byte for + * the internal representation. In that mode, the entire sun_path is the + * address, including trailing zero bytes. But we set the address length + * to only include the length of the original string. That way the + * trailing zero bytes won't show up in any network or socket lists of the + * operating system. This is just a convention, also followed by other + * packages. + */ + if (path[0] == '@') + { + unp->sun_path[0] = '\0'; + aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path); + } + + 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; + + /* 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 < 0 || ret >= nodelen) + return EAI_MEMORY; + } + + if (service) + { + /* + * Check whether it looks like an abstract socket, but it could also + * just be an empty string. + */ + if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0') + ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1); + else + ret = snprintf(service, servicelen, "%s", sa->sun_path); + if (ret < 0 || ret >= servicelen) + return EAI_MEMORY; + } + + return 0; +} diff --git a/contrib/libs/libpq/src/common/jsonapi.c b/contrib/libs/libpq/src/common/jsonapi.c new file mode 100644 index 0000000000..bb8178e91d --- /dev/null +++ b/contrib/libs/libpq/src/common/jsonapi.c @@ -0,0 +1,1206 @@ +/*------------------------------------------------------------------------- + * + * jsonapi.c + * JSON parser and lexer interfaces + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/jsonapi.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/jsonapi.h" +#include "mb/pg_wchar.h" +#include "port/pg_lfind.h" + +#ifndef FRONTEND +#error #include "miscadmin.h" +#endif + +/* + * The context of the parser is maintained by the recursive descent + * mechanism, but is passed explicitly to the error reporting routine + * for better diagnostics. + */ +typedef enum /* contexts of JSON parser */ +{ + JSON_PARSE_VALUE, /* expecting a value */ + JSON_PARSE_STRING, /* expecting a string (for a field name) */ + JSON_PARSE_ARRAY_START, /* saw '[', expecting value or ']' */ + JSON_PARSE_ARRAY_NEXT, /* saw array element, expecting ',' or ']' */ + JSON_PARSE_OBJECT_START, /* saw '{', expecting label or '}' */ + JSON_PARSE_OBJECT_LABEL, /* saw object label, expecting ':' */ + JSON_PARSE_OBJECT_NEXT, /* saw object value, expecting ',' or '}' */ + JSON_PARSE_OBJECT_COMMA, /* saw object ',', expecting next label */ + JSON_PARSE_END /* saw the end of a document, expect nothing */ +} JsonParseContext; + +static inline JsonParseErrorType json_lex_string(JsonLexContext *lex); +static inline JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s, + bool *num_err, int *total_len); +static inline JsonParseErrorType parse_scalar(JsonLexContext *lex, JsonSemAction *sem); +static JsonParseErrorType parse_object_field(JsonLexContext *lex, JsonSemAction *sem); +static JsonParseErrorType parse_object(JsonLexContext *lex, JsonSemAction *sem); +static JsonParseErrorType parse_array_element(JsonLexContext *lex, JsonSemAction *sem); +static JsonParseErrorType parse_array(JsonLexContext *lex, JsonSemAction *sem); +static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex); + +/* the null action object used for pure validation */ +JsonSemAction nullSemAction = +{ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL +}; + +/* Recursive Descent parser support routines */ + +/* + * lex_peek + * + * what is the current look_ahead token? +*/ +static inline JsonTokenType +lex_peek(JsonLexContext *lex) +{ + return lex->token_type; +} + +/* + * lex_expect + * + * move the lexer to the next token if the current look_ahead token matches + * the parameter token. Otherwise, report an error. + */ +static inline JsonParseErrorType +lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token) +{ + if (lex_peek(lex) == token) + return json_lex(lex); + else + return report_parse_error(ctx, lex); +} + +/* chars to consider as part of an alphanumeric token */ +#define JSON_ALPHANUMERIC_CHAR(c) \ + (((c) >= 'a' && (c) <= 'z') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= '0' && (c) <= '9') || \ + (c) == '_' || \ + IS_HIGHBIT_SET(c)) + +/* + * Utility function to check if a string is a valid JSON number. + * + * str is of length len, and need not be null-terminated. + */ +bool +IsValidJsonNumber(const char *str, int len) +{ + bool numeric_error; + int total_len; + JsonLexContext dummy_lex; + + if (len <= 0) + return false; + + /* + * json_lex_number expects a leading '-' to have been eaten already. + * + * having to cast away the constness of str is ugly, but there's not much + * easy alternative. + */ + if (*str == '-') + { + dummy_lex.input = unconstify(char *, str) + 1; + dummy_lex.input_length = len - 1; + } + else + { + dummy_lex.input = unconstify(char *, str); + dummy_lex.input_length = len; + } + + json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len); + + return (!numeric_error) && (total_len == dummy_lex.input_length); +} + +/* + * makeJsonLexContextCstringLen + * + * lex constructor, with or without StringInfo object for de-escaped lexemes. + * + * Without is better as it makes the processing faster, so only make one + * if really required. + */ +JsonLexContext * +makeJsonLexContextCstringLen(char *json, int len, int encoding, bool need_escapes) +{ + JsonLexContext *lex = palloc0(sizeof(JsonLexContext)); + + lex->input = lex->token_terminator = lex->line_start = json; + lex->line_number = 1; + lex->input_length = len; + lex->input_encoding = encoding; + if (need_escapes) + lex->strval = makeStringInfo(); + return lex; +} + +/* + * pg_parse_json + * + * Publicly visible entry point for the JSON parser. + * + * lex is a lexing context, set up for the json to be processed by calling + * makeJsonLexContext(). sem is a structure of function pointers to semantic + * action routines to be called at appropriate spots during parsing, and a + * pointer to a state object to be passed to those routines. + */ +JsonParseErrorType +pg_parse_json(JsonLexContext *lex, JsonSemAction *sem) +{ + JsonTokenType tok; + JsonParseErrorType result; + + /* get the initial token */ + result = json_lex(lex); + if (result != JSON_SUCCESS) + return result; + + tok = lex_peek(lex); + + /* parse by recursive descent */ + switch (tok) + { + case JSON_TOKEN_OBJECT_START: + result = parse_object(lex, sem); + break; + case JSON_TOKEN_ARRAY_START: + result = parse_array(lex, sem); + break; + default: + result = parse_scalar(lex, sem); /* json can be a bare scalar */ + } + + if (result == JSON_SUCCESS) + result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END); + + return result; +} + +/* + * json_count_array_elements + * + * Returns number of array elements in lex context at start of array token + * until end of array token at same nesting level. + * + * Designed to be called from array_start routines. + */ +JsonParseErrorType +json_count_array_elements(JsonLexContext *lex, int *elements) +{ + JsonLexContext copylex; + int count; + JsonParseErrorType result; + + /* + * It's safe to do this with a shallow copy because the lexical routines + * don't scribble on the input. They do scribble on the other pointers + * etc, so doing this with a copy makes that safe. + */ + memcpy(©lex, lex, sizeof(JsonLexContext)); + copylex.strval = NULL; /* not interested in values here */ + copylex.lex_level++; + + count = 0; + result = lex_expect(JSON_PARSE_ARRAY_START, ©lex, + JSON_TOKEN_ARRAY_START); + if (result != JSON_SUCCESS) + return result; + if (lex_peek(©lex) != JSON_TOKEN_ARRAY_END) + { + while (1) + { + count++; + result = parse_array_element(©lex, &nullSemAction); + if (result != JSON_SUCCESS) + return result; + if (copylex.token_type != JSON_TOKEN_COMMA) + break; + result = json_lex(©lex); + if (result != JSON_SUCCESS) + return result; + } + } + result = lex_expect(JSON_PARSE_ARRAY_NEXT, ©lex, + JSON_TOKEN_ARRAY_END); + if (result != JSON_SUCCESS) + return result; + + *elements = count; + return JSON_SUCCESS; +} + +/* + * Recursive Descent parse routines. There is one for each structural + * element in a json document: + * - scalar (string, number, true, false, null) + * - array ( [ ] ) + * - array element + * - object ( { } ) + * - object field + */ +static inline JsonParseErrorType +parse_scalar(JsonLexContext *lex, JsonSemAction *sem) +{ + char *val = NULL; + json_scalar_action sfunc = sem->scalar; + JsonTokenType tok = lex_peek(lex); + JsonParseErrorType result; + + /* a scalar must be a string, a number, true, false, or null */ + if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER && + tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE && + tok != JSON_TOKEN_NULL) + return report_parse_error(JSON_PARSE_VALUE, lex); + + /* if no semantic function, just consume the token */ + if (sfunc == NULL) + return json_lex(lex); + + /* extract the de-escaped string value, or the raw lexeme */ + if (lex_peek(lex) == JSON_TOKEN_STRING) + { + if (lex->strval != NULL) + val = pstrdup(lex->strval->data); + } + else + { + int len = (lex->token_terminator - lex->token_start); + + val = palloc(len + 1); + memcpy(val, lex->token_start, len); + val[len] = '\0'; + } + + /* consume the token */ + result = json_lex(lex); + if (result != JSON_SUCCESS) + return result; + + /* invoke the callback */ + result = (*sfunc) (sem->semstate, val, tok); + + return result; +} + +static JsonParseErrorType +parse_object_field(JsonLexContext *lex, JsonSemAction *sem) +{ + /* + * An object field is "fieldname" : value where value can be a scalar, + * object or array. Note: in user-facing docs and error messages, we + * generally call a field name a "key". + */ + + char *fname = NULL; /* keep compiler quiet */ + json_ofield_action ostart = sem->object_field_start; + json_ofield_action oend = sem->object_field_end; + bool isnull; + JsonTokenType tok; + JsonParseErrorType result; + + if (lex_peek(lex) != JSON_TOKEN_STRING) + return report_parse_error(JSON_PARSE_STRING, lex); + if ((ostart != NULL || oend != NULL) && lex->strval != NULL) + fname = pstrdup(lex->strval->data); + result = json_lex(lex); + if (result != JSON_SUCCESS) + return result; + + result = lex_expect(JSON_PARSE_OBJECT_LABEL, lex, JSON_TOKEN_COLON); + if (result != JSON_SUCCESS) + return result; + + tok = lex_peek(lex); + isnull = tok == JSON_TOKEN_NULL; + + if (ostart != NULL) + { + result = (*ostart) (sem->semstate, fname, isnull); + if (result != JSON_SUCCESS) + return result; + } + + switch (tok) + { + case JSON_TOKEN_OBJECT_START: + result = parse_object(lex, sem); + break; + case JSON_TOKEN_ARRAY_START: + result = parse_array(lex, sem); + break; + default: + result = parse_scalar(lex, sem); + } + if (result != JSON_SUCCESS) + return result; + + if (oend != NULL) + { + result = (*oend) (sem->semstate, fname, isnull); + if (result != JSON_SUCCESS) + return result; + } + + return JSON_SUCCESS; +} + +static JsonParseErrorType +parse_object(JsonLexContext *lex, JsonSemAction *sem) +{ + /* + * an object is a possibly empty sequence of object fields, separated by + * commas and surrounded by curly braces. + */ + json_struct_action ostart = sem->object_start; + json_struct_action oend = sem->object_end; + JsonTokenType tok; + JsonParseErrorType result; + +#ifndef FRONTEND + check_stack_depth(); +#endif + + if (ostart != NULL) + { + result = (*ostart) (sem->semstate); + if (result != JSON_SUCCESS) + return result; + } + + /* + * Data inside an object is at a higher nesting level than the object + * itself. Note that we increment this after we call the semantic routine + * for the object start and restore it before we call the routine for the + * object end. + */ + lex->lex_level++; + + Assert(lex_peek(lex) == JSON_TOKEN_OBJECT_START); + result = json_lex(lex); + if (result != JSON_SUCCESS) + return result; + + tok = lex_peek(lex); + switch (tok) + { + case JSON_TOKEN_STRING: + result = parse_object_field(lex, sem); + while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA) + { + result = json_lex(lex); + if (result != JSON_SUCCESS) + break; + result = parse_object_field(lex, sem); + } + break; + case JSON_TOKEN_OBJECT_END: + break; + default: + /* case of an invalid initial token inside the object */ + result = report_parse_error(JSON_PARSE_OBJECT_START, lex); + } + if (result != JSON_SUCCESS) + return result; + + result = lex_expect(JSON_PARSE_OBJECT_NEXT, lex, JSON_TOKEN_OBJECT_END); + if (result != JSON_SUCCESS) + return result; + + lex->lex_level--; + + if (oend != NULL) + { + result = (*oend) (sem->semstate); + if (result != JSON_SUCCESS) + return result; + } + + return JSON_SUCCESS; +} + +static JsonParseErrorType +parse_array_element(JsonLexContext *lex, JsonSemAction *sem) +{ + json_aelem_action astart = sem->array_element_start; + json_aelem_action aend = sem->array_element_end; + JsonTokenType tok = lex_peek(lex); + JsonParseErrorType result; + bool isnull; + + isnull = tok == JSON_TOKEN_NULL; + + if (astart != NULL) + { + result = (*astart) (sem->semstate, isnull); + if (result != JSON_SUCCESS) + return result; + } + + /* an array element is any object, array or scalar */ + switch (tok) + { + case JSON_TOKEN_OBJECT_START: + result = parse_object(lex, sem); + break; + case JSON_TOKEN_ARRAY_START: + result = parse_array(lex, sem); + break; + default: + result = parse_scalar(lex, sem); + } + + if (result != JSON_SUCCESS) + return result; + + if (aend != NULL) + { + result = (*aend) (sem->semstate, isnull); + if (result != JSON_SUCCESS) + return result; + } + + return JSON_SUCCESS; +} + +static JsonParseErrorType +parse_array(JsonLexContext *lex, JsonSemAction *sem) +{ + /* + * an array is a possibly empty sequence of array elements, separated by + * commas and surrounded by square brackets. + */ + json_struct_action astart = sem->array_start; + json_struct_action aend = sem->array_end; + JsonParseErrorType result; + +#ifndef FRONTEND + check_stack_depth(); +#endif + + if (astart != NULL) + { + result = (*astart) (sem->semstate); + if (result != JSON_SUCCESS) + return result; + } + + /* + * Data inside an array is at a higher nesting level than the array + * itself. Note that we increment this after we call the semantic routine + * for the array start and restore it before we call the routine for the + * array end. + */ + lex->lex_level++; + + result = lex_expect(JSON_PARSE_ARRAY_START, lex, JSON_TOKEN_ARRAY_START); + if (result == JSON_SUCCESS && lex_peek(lex) != JSON_TOKEN_ARRAY_END) + { + result = parse_array_element(lex, sem); + + while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA) + { + result = json_lex(lex); + if (result != JSON_SUCCESS) + break; + result = parse_array_element(lex, sem); + } + } + if (result != JSON_SUCCESS) + return result; + + result = lex_expect(JSON_PARSE_ARRAY_NEXT, lex, JSON_TOKEN_ARRAY_END); + if (result != JSON_SUCCESS) + return result; + + lex->lex_level--; + + if (aend != NULL) + { + result = (*aend) (sem->semstate); + if (result != JSON_SUCCESS) + return result; + } + + return JSON_SUCCESS; +} + +/* + * Lex one token from the input stream. + */ +JsonParseErrorType +json_lex(JsonLexContext *lex) +{ + char *s; + char *const end = lex->input + lex->input_length; + JsonParseErrorType result; + + /* Skip leading whitespace. */ + s = lex->token_terminator; + while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')) + { + if (*s++ == '\n') + { + ++lex->line_number; + lex->line_start = s; + } + } + lex->token_start = s; + + /* Determine token type. */ + if (s >= end) + { + lex->token_start = NULL; + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s; + lex->token_type = JSON_TOKEN_END; + } + else + { + switch (*s) + { + /* Single-character token, some kind of punctuation mark. */ + case '{': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_OBJECT_START; + break; + case '}': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_OBJECT_END; + break; + case '[': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_ARRAY_START; + break; + case ']': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_ARRAY_END; + break; + case ',': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_COMMA; + break; + case ':': + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + lex->token_type = JSON_TOKEN_COLON; + break; + case '"': + /* string */ + result = json_lex_string(lex); + if (result != JSON_SUCCESS) + return result; + lex->token_type = JSON_TOKEN_STRING; + break; + case '-': + /* Negative number. */ + result = json_lex_number(lex, s + 1, NULL, NULL); + if (result != JSON_SUCCESS) + return result; + lex->token_type = JSON_TOKEN_NUMBER; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Positive number. */ + result = json_lex_number(lex, s, NULL, NULL); + if (result != JSON_SUCCESS) + return result; + lex->token_type = JSON_TOKEN_NUMBER; + break; + default: + { + char *p; + + /* + * We're not dealing with a string, number, legal + * punctuation mark, or end of string. The only legal + * tokens we might find here are true, false, and null, + * but for error reporting purposes we scan until we see a + * non-alphanumeric character. That way, we can report + * the whole word as an unexpected token, rather than just + * some unintuitive prefix thereof. + */ + for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++) + /* skip */ ; + + /* + * We got some sort of unexpected punctuation or an + * otherwise unexpected character, so just complain about + * that one character. + */ + if (p == s) + { + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + return JSON_INVALID_TOKEN; + } + + /* + * We've got a real alphanumeric token here. If it + * happens to be true, false, or null, all is well. If + * not, error out. + */ + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = p; + if (p - s == 4) + { + if (memcmp(s, "true", 4) == 0) + lex->token_type = JSON_TOKEN_TRUE; + else if (memcmp(s, "null", 4) == 0) + lex->token_type = JSON_TOKEN_NULL; + else + return JSON_INVALID_TOKEN; + } + else if (p - s == 5 && memcmp(s, "false", 5) == 0) + lex->token_type = JSON_TOKEN_FALSE; + else + return JSON_INVALID_TOKEN; + } + } /* end of switch */ + } + + return JSON_SUCCESS; +} + +/* + * The next token in the input stream is known to be a string; lex it. + * + * If lex->strval isn't NULL, fill it with the decoded string. + * Set lex->token_terminator to the end of the decoded input, and in + * success cases, transfer its previous value to lex->prev_token_terminator. + * Return JSON_SUCCESS or an error code. + * + * Note: be careful that all error exits advance lex->token_terminator + * to the point after the character we detected the error on. + */ +static inline JsonParseErrorType +json_lex_string(JsonLexContext *lex) +{ + char *s; + char *const end = lex->input + lex->input_length; + int hi_surrogate = -1; + + /* Convenience macros for error exits */ +#define FAIL_AT_CHAR_START(code) \ + do { \ + lex->token_terminator = s; \ + return code; \ + } while (0) +#define FAIL_AT_CHAR_END(code) \ + do { \ + lex->token_terminator = \ + s + pg_encoding_mblen_bounded(lex->input_encoding, s); \ + return code; \ + } while (0) + + if (lex->strval != NULL) + resetStringInfo(lex->strval); + + Assert(lex->input_length > 0); + s = lex->token_start; + for (;;) + { + s++; + /* Premature end of the string. */ + if (s >= end) + FAIL_AT_CHAR_START(JSON_INVALID_TOKEN); + else if (*s == '"') + break; + else if (*s == '\\') + { + /* OK, we have an escape character. */ + s++; + if (s >= end) + FAIL_AT_CHAR_START(JSON_INVALID_TOKEN); + else if (*s == 'u') + { + int i; + int ch = 0; + + for (i = 1; i <= 4; i++) + { + s++; + if (s >= end) + FAIL_AT_CHAR_START(JSON_INVALID_TOKEN); + else if (*s >= '0' && *s <= '9') + ch = (ch * 16) + (*s - '0'); + else if (*s >= 'a' && *s <= 'f') + ch = (ch * 16) + (*s - 'a') + 10; + else if (*s >= 'A' && *s <= 'F') + ch = (ch * 16) + (*s - 'A') + 10; + else + FAIL_AT_CHAR_END(JSON_UNICODE_ESCAPE_FORMAT); + } + if (lex->strval != NULL) + { + /* + * Combine surrogate pairs. + */ + if (is_utf16_surrogate_first(ch)) + { + if (hi_surrogate != -1) + FAIL_AT_CHAR_END(JSON_UNICODE_HIGH_SURROGATE); + hi_surrogate = ch; + continue; + } + else if (is_utf16_surrogate_second(ch)) + { + if (hi_surrogate == -1) + FAIL_AT_CHAR_END(JSON_UNICODE_LOW_SURROGATE); + ch = surrogate_pair_to_codepoint(hi_surrogate, ch); + hi_surrogate = -1; + } + + if (hi_surrogate != -1) + FAIL_AT_CHAR_END(JSON_UNICODE_LOW_SURROGATE); + + /* + * Reject invalid cases. We can't have a value above + * 0xFFFF here (since we only accepted 4 hex digits + * above), so no need to test for out-of-range chars. + */ + if (ch == 0) + { + /* We can't allow this, since our TEXT type doesn't */ + FAIL_AT_CHAR_END(JSON_UNICODE_CODE_POINT_ZERO); + } + + /* + * Add the represented character to lex->strval. In the + * backend, we can let pg_unicode_to_server_noerror() + * handle any required character set conversion; in + * frontend, we can only deal with trivial conversions. + */ +#ifndef FRONTEND + { + char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1]; + + if (!pg_unicode_to_server_noerror(ch, (unsigned char *) cbuf)) + FAIL_AT_CHAR_END(JSON_UNICODE_UNTRANSLATABLE); + appendStringInfoString(lex->strval, cbuf); + } +#else + if (lex->input_encoding == PG_UTF8) + { + /* OK, we can map the code point to UTF8 easily */ + char utf8str[5]; + int utf8len; + + unicode_to_utf8(ch, (unsigned char *) utf8str); + utf8len = pg_utf_mblen((unsigned char *) utf8str); + appendBinaryStringInfo(lex->strval, utf8str, utf8len); + } + else if (ch <= 0x007f) + { + /* The ASCII range is the same in all encodings */ + appendStringInfoChar(lex->strval, (char) ch); + } + else + FAIL_AT_CHAR_END(JSON_UNICODE_HIGH_ESCAPE); +#endif /* FRONTEND */ + } + } + else if (lex->strval != NULL) + { + if (hi_surrogate != -1) + FAIL_AT_CHAR_END(JSON_UNICODE_LOW_SURROGATE); + + switch (*s) + { + case '"': + case '\\': + case '/': + appendStringInfoChar(lex->strval, *s); + break; + case 'b': + appendStringInfoChar(lex->strval, '\b'); + break; + case 'f': + appendStringInfoChar(lex->strval, '\f'); + break; + case 'n': + appendStringInfoChar(lex->strval, '\n'); + break; + case 'r': + appendStringInfoChar(lex->strval, '\r'); + break; + case 't': + appendStringInfoChar(lex->strval, '\t'); + break; + default: + + /* + * Not a valid string escape, so signal error. We + * adjust token_start so that just the escape sequence + * is reported, not the whole string. + */ + lex->token_start = s; + FAIL_AT_CHAR_END(JSON_ESCAPING_INVALID); + } + } + else if (strchr("\"\\/bfnrt", *s) == NULL) + { + /* + * Simpler processing if we're not bothered about de-escaping + * + * It's very tempting to remove the strchr() call here and + * replace it with a switch statement, but testing so far has + * shown it's not a performance win. + */ + lex->token_start = s; + FAIL_AT_CHAR_END(JSON_ESCAPING_INVALID); + } + } + else + { + char *p = s; + + if (hi_surrogate != -1) + FAIL_AT_CHAR_END(JSON_UNICODE_LOW_SURROGATE); + + /* + * Skip to the first byte that requires special handling, so we + * can batch calls to appendBinaryStringInfo. + */ + while (p < end - sizeof(Vector8) && + !pg_lfind8('\\', (uint8 *) p, sizeof(Vector8)) && + !pg_lfind8('"', (uint8 *) p, sizeof(Vector8)) && + !pg_lfind8_le(31, (uint8 *) p, sizeof(Vector8))) + p += sizeof(Vector8); + + for (; p < end; p++) + { + if (*p == '\\' || *p == '"') + break; + else if ((unsigned char) *p <= 31) + { + /* Per RFC4627, these characters MUST be escaped. */ + /* + * Since *p isn't printable, exclude it from the context + * string + */ + lex->token_terminator = p; + return JSON_ESCAPING_REQUIRED; + } + } + + if (lex->strval != NULL) + appendBinaryStringInfo(lex->strval, s, p - s); + + /* + * s will be incremented at the top of the loop, so set it to just + * behind our lookahead position + */ + s = p - 1; + } + } + + if (hi_surrogate != -1) + { + lex->token_terminator = s + 1; + return JSON_UNICODE_LOW_SURROGATE; + } + + /* Hooray, we found the end of the string! */ + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s + 1; + return JSON_SUCCESS; + +#undef FAIL_AT_CHAR_START +#undef FAIL_AT_CHAR_END +} + +/* + * The next token in the input stream is known to be a number; lex it. + * + * In JSON, a number consists of four parts: + * + * (1) An optional minus sign ('-'). + * + * (2) Either a single '0', or a string of one or more digits that does not + * begin with a '0'. + * + * (3) An optional decimal part, consisting of a period ('.') followed by + * one or more digits. (Note: While this part can be omitted + * completely, it's not OK to have only the decimal point without + * any digits afterwards.) + * + * (4) An optional exponent part, consisting of 'e' or 'E', optionally + * followed by '+' or '-', followed by one or more digits. (Note: + * As with the decimal part, if 'e' or 'E' is present, it must be + * followed by at least one digit.) + * + * The 's' argument to this function points to the ostensible beginning + * of part 2 - i.e. the character after any optional minus sign, or the + * first character of the string if there is none. + * + * If num_err is not NULL, we return an error flag to *num_err rather than + * raising an error for a badly-formed number. Also, if total_len is not NULL + * the distance from lex->input to the token end+1 is returned to *total_len. + */ +static inline JsonParseErrorType +json_lex_number(JsonLexContext *lex, char *s, + bool *num_err, int *total_len) +{ + bool error = false; + int len = s - lex->input; + + /* Part (1): leading sign indicator. */ + /* Caller already did this for us; so do nothing. */ + + /* Part (2): parse main digit string. */ + if (len < lex->input_length && *s == '0') + { + s++; + len++; + } + else if (len < lex->input_length && *s >= '1' && *s <= '9') + { + do + { + s++; + len++; + } while (len < lex->input_length && *s >= '0' && *s <= '9'); + } + else + error = true; + + /* Part (3): parse optional decimal portion. */ + if (len < lex->input_length && *s == '.') + { + s++; + len++; + if (len == lex->input_length || *s < '0' || *s > '9') + error = true; + else + { + do + { + s++; + len++; + } while (len < lex->input_length && *s >= '0' && *s <= '9'); + } + } + + /* Part (4): parse optional exponent. */ + if (len < lex->input_length && (*s == 'e' || *s == 'E')) + { + s++; + len++; + if (len < lex->input_length && (*s == '+' || *s == '-')) + { + s++; + len++; + } + if (len == lex->input_length || *s < '0' || *s > '9') + error = true; + else + { + do + { + s++; + len++; + } while (len < lex->input_length && *s >= '0' && *s <= '9'); + } + } + + /* + * Check for trailing garbage. As in json_lex(), any alphanumeric stuff + * here should be considered part of the token for error-reporting + * purposes. + */ + for (; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*s); s++, len++) + error = true; + + if (total_len != NULL) + *total_len = len; + + if (num_err != NULL) + { + /* let the caller handle any error */ + *num_err = error; + } + else + { + /* return token endpoint */ + lex->prev_token_terminator = lex->token_terminator; + lex->token_terminator = s; + /* handle error if any */ + if (error) + return JSON_INVALID_TOKEN; + } + + return JSON_SUCCESS; +} + +/* + * Report a parse error. + * + * lex->token_start and lex->token_terminator must identify the current token. + */ +static JsonParseErrorType +report_parse_error(JsonParseContext ctx, JsonLexContext *lex) +{ + /* Handle case where the input ended prematurely. */ + if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END) + return JSON_EXPECTED_MORE; + + /* Otherwise choose the error type based on the parsing context. */ + switch (ctx) + { + case JSON_PARSE_END: + return JSON_EXPECTED_END; + case JSON_PARSE_VALUE: + return JSON_EXPECTED_JSON; + case JSON_PARSE_STRING: + return JSON_EXPECTED_STRING; + case JSON_PARSE_ARRAY_START: + return JSON_EXPECTED_ARRAY_FIRST; + case JSON_PARSE_ARRAY_NEXT: + return JSON_EXPECTED_ARRAY_NEXT; + case JSON_PARSE_OBJECT_START: + return JSON_EXPECTED_OBJECT_FIRST; + case JSON_PARSE_OBJECT_LABEL: + return JSON_EXPECTED_COLON; + case JSON_PARSE_OBJECT_NEXT: + return JSON_EXPECTED_OBJECT_NEXT; + case JSON_PARSE_OBJECT_COMMA: + return JSON_EXPECTED_STRING; + } + + /* + * We don't use a default: case, so that the compiler will warn about + * unhandled enum values. + */ + Assert(false); + return JSON_SUCCESS; /* silence stupider compilers */ +} + + +#ifndef FRONTEND +/* + * Extract the current token from a lexing context, for error reporting. + */ +static char * +extract_token(JsonLexContext *lex) +{ + int toklen = lex->token_terminator - lex->token_start; + char *token = palloc(toklen + 1); + + memcpy(token, lex->token_start, toklen); + token[toklen] = '\0'; + return token; +} + +/* + * Construct an (already translated) detail message for a JSON error. + * + * Note that the error message generated by this routine may not be + * palloc'd, making it unsafe for frontend code as there is no way to + * know if this can be safely pfree'd or not. + */ +char * +json_errdetail(JsonParseErrorType error, JsonLexContext *lex) +{ + switch (error) + { + case JSON_SUCCESS: + /* fall through to the error code after switch */ + break; + case JSON_ESCAPING_INVALID: + return psprintf(_("Escape sequence \"\\%s\" is invalid."), + extract_token(lex)); + case JSON_ESCAPING_REQUIRED: + return psprintf(_("Character with value 0x%02x must be escaped."), + (unsigned char) *(lex->token_terminator)); + case JSON_EXPECTED_END: + return psprintf(_("Expected end of input, but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_ARRAY_FIRST: + return psprintf(_("Expected array element or \"]\", but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_ARRAY_NEXT: + return psprintf(_("Expected \",\" or \"]\", but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_COLON: + return psprintf(_("Expected \":\", but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_JSON: + return psprintf(_("Expected JSON value, but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_MORE: + return _("The input string ended unexpectedly."); + case JSON_EXPECTED_OBJECT_FIRST: + return psprintf(_("Expected string or \"}\", but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_OBJECT_NEXT: + return psprintf(_("Expected \",\" or \"}\", but found \"%s\"."), + extract_token(lex)); + case JSON_EXPECTED_STRING: + return psprintf(_("Expected string, but found \"%s\"."), + extract_token(lex)); + case JSON_INVALID_TOKEN: + return psprintf(_("Token \"%s\" is invalid."), + extract_token(lex)); + case JSON_UNICODE_CODE_POINT_ZERO: + return _("\\u0000 cannot be converted to text."); + case JSON_UNICODE_ESCAPE_FORMAT: + return _("\"\\u\" must be followed by four hexadecimal digits."); + case JSON_UNICODE_HIGH_ESCAPE: + /* note: this case is only reachable in frontend not backend */ + return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8."); + case JSON_UNICODE_UNTRANSLATABLE: + /* note: this case is only reachable in backend not frontend */ + return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."), + GetDatabaseEncodingName()); + case JSON_UNICODE_HIGH_SURROGATE: + return _("Unicode high surrogate must not follow a high surrogate."); + case JSON_UNICODE_LOW_SURROGATE: + return _("Unicode low surrogate must follow a high surrogate."); + case JSON_SEM_ACTION_FAILED: + /* fall through to the error code after switch */ + break; + } + + /* + * We don't use a default: case, so that the compiler will warn about + * unhandled enum values. But this needs to be here anyway to cover the + * possibility of an incorrect input. + */ + elog(ERROR, "unexpected json parse error type: %d", (int) error); + return NULL; +} +#endif diff --git a/contrib/libs/libpq/src/common/keywords.c b/contrib/libs/libpq/src/common/keywords.c new file mode 100644 index 0000000000..b72f0d554f --- /dev/null +++ b/contrib/libs/libpq/src/common/keywords.c @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * keywords.c + * PostgreSQL's list of SQL keywords + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/keywords.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "common/keywords.h" + + +/* ScanKeywordList lookup data for SQL keywords */ + +#include "kwlist_d.h" + +/* Keyword categories for SQL keywords */ + +#define PG_KEYWORD(kwname, value, category, collabel) category, + +const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = { +#include "parser/kwlist.h" +}; + +#undef PG_KEYWORD + +/* Keyword can-be-bare-label flags for SQL keywords */ + +#define PG_KEYWORD(kwname, value, category, collabel) collabel, + +#define BARE_LABEL true +#define AS_LABEL false + +const bool ScanKeywordBareLabel[SCANKEYWORDS_NUM_KEYWORDS] = { +#include "parser/kwlist.h" +}; + +#undef PG_KEYWORD +#undef BARE_LABEL +#undef AS_LABEL diff --git a/contrib/libs/libpq/src/common/kwlist_d.h b/contrib/libs/libpq/src/common/kwlist_d.h new file mode 100644 index 0000000000..e8af260237 --- /dev/null +++ b/contrib/libs/libpq/src/common/kwlist_d.h @@ -0,0 +1,1119 @@ +/*------------------------------------------------------------------------- + * + * kwlist_d.h + * List of keywords represented as a ScanKeywordList. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/tools/gen_keywordlist.pl + * + *------------------------------------------------------------------------- + */ + +#ifndef KWLIST_D_H +#define KWLIST_D_H + +#include "common/kwlookup.h" + +static const char ScanKeywords_kw_string[] = + "abort\0" + "absent\0" + "absolute\0" + "access\0" + "action\0" + "add\0" + "admin\0" + "after\0" + "aggregate\0" + "all\0" + "also\0" + "alter\0" + "always\0" + "analyse\0" + "analyze\0" + "and\0" + "any\0" + "array\0" + "as\0" + "asc\0" + "asensitive\0" + "assertion\0" + "assignment\0" + "asymmetric\0" + "at\0" + "atomic\0" + "attach\0" + "attribute\0" + "authorization\0" + "backward\0" + "before\0" + "begin\0" + "between\0" + "bigint\0" + "binary\0" + "bit\0" + "boolean\0" + "both\0" + "breadth\0" + "by\0" + "cache\0" + "call\0" + "called\0" + "cascade\0" + "cascaded\0" + "case\0" + "cast\0" + "catalog\0" + "chain\0" + "char\0" + "character\0" + "characteristics\0" + "check\0" + "checkpoint\0" + "class\0" + "close\0" + "cluster\0" + "coalesce\0" + "collate\0" + "collation\0" + "column\0" + "columns\0" + "comment\0" + "comments\0" + "commit\0" + "committed\0" + "compression\0" + "concurrently\0" + "configuration\0" + "conflict\0" + "connection\0" + "constraint\0" + "constraints\0" + "content\0" + "continue\0" + "conversion\0" + "copy\0" + "cost\0" + "create\0" + "cross\0" + "csv\0" + "cube\0" + "current\0" + "current_catalog\0" + "current_date\0" + "current_role\0" + "current_schema\0" + "current_time\0" + "current_timestamp\0" + "current_user\0" + "cursor\0" + "cycle\0" + "data\0" + "database\0" + "day\0" + "deallocate\0" + "dec\0" + "decimal\0" + "declare\0" + "default\0" + "defaults\0" + "deferrable\0" + "deferred\0" + "definer\0" + "delete\0" + "delimiter\0" + "delimiters\0" + "depends\0" + "depth\0" + "desc\0" + "detach\0" + "dictionary\0" + "disable\0" + "discard\0" + "distinct\0" + "do\0" + "document\0" + "domain\0" + "double\0" + "drop\0" + "each\0" + "else\0" + "enable\0" + "encoding\0" + "encrypted\0" + "end\0" + "enum\0" + "escape\0" + "event\0" + "except\0" + "exclude\0" + "excluding\0" + "exclusive\0" + "execute\0" + "exists\0" + "explain\0" + "expression\0" + "extension\0" + "external\0" + "extract\0" + "false\0" + "family\0" + "fetch\0" + "filter\0" + "finalize\0" + "first\0" + "float\0" + "following\0" + "for\0" + "force\0" + "foreign\0" + "format\0" + "forward\0" + "freeze\0" + "from\0" + "full\0" + "function\0" + "functions\0" + "generated\0" + "global\0" + "grant\0" + "granted\0" + "greatest\0" + "group\0" + "grouping\0" + "groups\0" + "handler\0" + "having\0" + "header\0" + "hold\0" + "hour\0" + "identity\0" + "if\0" + "ilike\0" + "immediate\0" + "immutable\0" + "implicit\0" + "import\0" + "in\0" + "include\0" + "including\0" + "increment\0" + "indent\0" + "index\0" + "indexes\0" + "inherit\0" + "inherits\0" + "initially\0" + "inline\0" + "inner\0" + "inout\0" + "input\0" + "insensitive\0" + "insert\0" + "instead\0" + "int\0" + "integer\0" + "intersect\0" + "interval\0" + "into\0" + "invoker\0" + "is\0" + "isnull\0" + "isolation\0" + "join\0" + "json\0" + "json_array\0" + "json_arrayagg\0" + "json_object\0" + "json_objectagg\0" + "key\0" + "keys\0" + "label\0" + "language\0" + "large\0" + "last\0" + "lateral\0" + "leading\0" + "leakproof\0" + "least\0" + "left\0" + "level\0" + "like\0" + "limit\0" + "listen\0" + "load\0" + "local\0" + "localtime\0" + "localtimestamp\0" + "location\0" + "lock\0" + "locked\0" + "logged\0" + "mapping\0" + "match\0" + "matched\0" + "materialized\0" + "maxvalue\0" + "merge\0" + "method\0" + "minute\0" + "minvalue\0" + "mode\0" + "month\0" + "move\0" + "name\0" + "names\0" + "national\0" + "natural\0" + "nchar\0" + "new\0" + "next\0" + "nfc\0" + "nfd\0" + "nfkc\0" + "nfkd\0" + "no\0" + "none\0" + "normalize\0" + "normalized\0" + "not\0" + "nothing\0" + "notify\0" + "notnull\0" + "nowait\0" + "null\0" + "nullif\0" + "nulls\0" + "numeric\0" + "object\0" + "of\0" + "off\0" + "offset\0" + "oids\0" + "old\0" + "on\0" + "only\0" + "operator\0" + "option\0" + "options\0" + "or\0" + "order\0" + "ordinality\0" + "others\0" + "out\0" + "outer\0" + "over\0" + "overlaps\0" + "overlay\0" + "overriding\0" + "owned\0" + "owner\0" + "parallel\0" + "parameter\0" + "parser\0" + "partial\0" + "partition\0" + "passing\0" + "password\0" + "placing\0" + "plans\0" + "policy\0" + "position\0" + "preceding\0" + "precision\0" + "prepare\0" + "prepared\0" + "preserve\0" + "primary\0" + "prior\0" + "privileges\0" + "procedural\0" + "procedure\0" + "procedures\0" + "program\0" + "publication\0" + "quote\0" + "range\0" + "read\0" + "real\0" + "reassign\0" + "recheck\0" + "recursive\0" + "ref\0" + "references\0" + "referencing\0" + "refresh\0" + "reindex\0" + "relative\0" + "release\0" + "rename\0" + "repeatable\0" + "replace\0" + "replica\0" + "reset\0" + "restart\0" + "restrict\0" + "return\0" + "returning\0" + "returns\0" + "revoke\0" + "right\0" + "role\0" + "rollback\0" + "rollup\0" + "routine\0" + "routines\0" + "row\0" + "rows\0" + "rule\0" + "savepoint\0" + "scalar\0" + "schema\0" + "schemas\0" + "scroll\0" + "search\0" + "second\0" + "security\0" + "select\0" + "sequence\0" + "sequences\0" + "serializable\0" + "server\0" + "session\0" + "session_user\0" + "set\0" + "setof\0" + "sets\0" + "share\0" + "show\0" + "similar\0" + "simple\0" + "skip\0" + "smallint\0" + "snapshot\0" + "some\0" + "sql\0" + "stable\0" + "standalone\0" + "start\0" + "statement\0" + "statistics\0" + "stdin\0" + "stdout\0" + "storage\0" + "stored\0" + "strict\0" + "strip\0" + "subscription\0" + "substring\0" + "support\0" + "symmetric\0" + "sysid\0" + "system\0" + "system_user\0" + "table\0" + "tables\0" + "tablesample\0" + "tablespace\0" + "temp\0" + "template\0" + "temporary\0" + "text\0" + "then\0" + "ties\0" + "time\0" + "timestamp\0" + "to\0" + "trailing\0" + "transaction\0" + "transform\0" + "treat\0" + "trigger\0" + "trim\0" + "true\0" + "truncate\0" + "trusted\0" + "type\0" + "types\0" + "uescape\0" + "unbounded\0" + "uncommitted\0" + "unencrypted\0" + "union\0" + "unique\0" + "unknown\0" + "unlisten\0" + "unlogged\0" + "until\0" + "update\0" + "user\0" + "using\0" + "vacuum\0" + "valid\0" + "validate\0" + "validator\0" + "value\0" + "values\0" + "varchar\0" + "variadic\0" + "varying\0" + "verbose\0" + "version\0" + "view\0" + "views\0" + "volatile\0" + "when\0" + "where\0" + "whitespace\0" + "window\0" + "with\0" + "within\0" + "without\0" + "work\0" + "wrapper\0" + "write\0" + "xml\0" + "xmlattributes\0" + "xmlconcat\0" + "xmlelement\0" + "xmlexists\0" + "xmlforest\0" + "xmlnamespaces\0" + "xmlparse\0" + "xmlpi\0" + "xmlroot\0" + "xmlserialize\0" + "xmltable\0" + "year\0" + "yes\0" + "zone"; + +static const uint16 ScanKeywords_kw_offsets[] = { + 0, + 6, + 13, + 22, + 29, + 36, + 40, + 46, + 52, + 62, + 66, + 71, + 77, + 84, + 92, + 100, + 104, + 108, + 114, + 117, + 121, + 132, + 142, + 153, + 164, + 167, + 174, + 181, + 191, + 205, + 214, + 221, + 227, + 235, + 242, + 249, + 253, + 261, + 266, + 274, + 277, + 283, + 288, + 295, + 303, + 312, + 317, + 322, + 330, + 336, + 341, + 351, + 367, + 373, + 384, + 390, + 396, + 404, + 413, + 421, + 431, + 438, + 446, + 454, + 463, + 470, + 480, + 492, + 505, + 519, + 528, + 539, + 550, + 562, + 570, + 579, + 590, + 595, + 600, + 607, + 613, + 617, + 622, + 630, + 646, + 659, + 672, + 687, + 700, + 718, + 731, + 738, + 744, + 749, + 758, + 762, + 773, + 777, + 785, + 793, + 801, + 810, + 821, + 830, + 838, + 845, + 855, + 866, + 874, + 880, + 885, + 892, + 903, + 911, + 919, + 928, + 931, + 940, + 947, + 954, + 959, + 964, + 969, + 976, + 985, + 995, + 999, + 1004, + 1011, + 1017, + 1024, + 1032, + 1042, + 1052, + 1060, + 1067, + 1075, + 1086, + 1096, + 1105, + 1113, + 1119, + 1126, + 1132, + 1139, + 1148, + 1154, + 1160, + 1170, + 1174, + 1180, + 1188, + 1195, + 1203, + 1210, + 1215, + 1220, + 1229, + 1239, + 1249, + 1256, + 1262, + 1270, + 1279, + 1285, + 1294, + 1301, + 1309, + 1316, + 1323, + 1328, + 1333, + 1342, + 1345, + 1351, + 1361, + 1371, + 1380, + 1387, + 1390, + 1398, + 1408, + 1418, + 1425, + 1431, + 1439, + 1447, + 1456, + 1466, + 1473, + 1479, + 1485, + 1491, + 1503, + 1510, + 1518, + 1522, + 1530, + 1540, + 1549, + 1554, + 1562, + 1565, + 1572, + 1582, + 1587, + 1592, + 1603, + 1617, + 1629, + 1644, + 1648, + 1653, + 1659, + 1668, + 1674, + 1679, + 1687, + 1695, + 1705, + 1711, + 1716, + 1722, + 1727, + 1733, + 1740, + 1745, + 1751, + 1761, + 1776, + 1785, + 1790, + 1797, + 1804, + 1812, + 1818, + 1826, + 1839, + 1848, + 1854, + 1861, + 1868, + 1877, + 1882, + 1888, + 1893, + 1898, + 1904, + 1913, + 1921, + 1927, + 1931, + 1936, + 1940, + 1944, + 1949, + 1954, + 1957, + 1962, + 1972, + 1983, + 1987, + 1995, + 2002, + 2010, + 2017, + 2022, + 2029, + 2035, + 2043, + 2050, + 2053, + 2057, + 2064, + 2069, + 2073, + 2076, + 2081, + 2090, + 2097, + 2105, + 2108, + 2114, + 2125, + 2132, + 2136, + 2142, + 2147, + 2156, + 2164, + 2175, + 2181, + 2187, + 2196, + 2206, + 2213, + 2221, + 2231, + 2239, + 2248, + 2256, + 2262, + 2269, + 2278, + 2288, + 2298, + 2306, + 2315, + 2324, + 2332, + 2338, + 2349, + 2360, + 2370, + 2381, + 2389, + 2401, + 2407, + 2413, + 2418, + 2423, + 2432, + 2440, + 2450, + 2454, + 2465, + 2477, + 2485, + 2493, + 2502, + 2510, + 2517, + 2528, + 2536, + 2544, + 2550, + 2558, + 2567, + 2574, + 2584, + 2592, + 2599, + 2605, + 2610, + 2619, + 2626, + 2634, + 2643, + 2647, + 2652, + 2657, + 2667, + 2674, + 2681, + 2689, + 2696, + 2703, + 2710, + 2719, + 2726, + 2735, + 2745, + 2758, + 2765, + 2773, + 2786, + 2790, + 2796, + 2801, + 2807, + 2812, + 2820, + 2827, + 2832, + 2841, + 2850, + 2855, + 2859, + 2866, + 2877, + 2883, + 2893, + 2904, + 2910, + 2917, + 2925, + 2932, + 2939, + 2945, + 2958, + 2968, + 2976, + 2986, + 2992, + 2999, + 3011, + 3017, + 3024, + 3036, + 3047, + 3052, + 3061, + 3071, + 3076, + 3081, + 3086, + 3091, + 3101, + 3104, + 3113, + 3125, + 3135, + 3141, + 3149, + 3154, + 3159, + 3168, + 3176, + 3181, + 3187, + 3195, + 3205, + 3217, + 3229, + 3235, + 3242, + 3250, + 3259, + 3268, + 3274, + 3281, + 3286, + 3292, + 3299, + 3305, + 3314, + 3324, + 3330, + 3337, + 3345, + 3354, + 3362, + 3370, + 3378, + 3383, + 3389, + 3398, + 3403, + 3409, + 3420, + 3427, + 3432, + 3439, + 3447, + 3452, + 3460, + 3466, + 3470, + 3484, + 3494, + 3505, + 3515, + 3525, + 3539, + 3548, + 3554, + 3562, + 3575, + 3584, + 3589, + 3593, +}; + +#define SCANKEYWORDS_NUM_KEYWORDS 471 + +static int +ScanKeywords_hash_func(const void *key, size_t keylen) +{ + static const int16 h[943] = { + 543, -186, 201, 0, 32767, 32767, 32767, 32767, + 221, -207, 32767, 0, 135, 283, 32767, 454, + 14, 79, 32767, 32767, 77, 32767, 102, 160, + 0, 32767, 151, 32767, 30, 392, -322, 452, + 32767, 0, 32767, 0, 0, 32767, 32767, 32767, + 234, 32767, 0, 32767, 0, 631, 32767, 368, + 80, 0, 0, -115, 32767, 285, 32767, 423, + 0, 32767, 155, 229, 32767, 126, 291, 165, + -22, 400, 327, 32767, 32767, 32767, 32767, -399, + 0, 406, 32767, 210, 1102, -203, 32767, 32767, + 32767, -944, 0, -188, 32767, 32767, 0, 347, + 32767, 0, 559, 316, 133, 32767, 202, 32767, + 305, 0, 32767, -94, 32767, 0, 32767, -222, + 32767, 138, 32767, -52, 32767, 32767, 279, 69, + -136, 0, 32767, 32767, 189, 32767, 32767, 88, + 0, 32767, 32767, 274, 32767, 514, 769, 248, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 81, + 8, -29, 32767, 32767, 32767, -174, 258, 0, + 465, 211, 32767, 0, -229, 32767, -191, 32767, + 1263, 48, 32767, 343, 0, 58, 0, 32767, + 32767, 855, 0, 415, 0, -217, 32767, 1195, + 32767, 32767, 166, 32767, 42, 262, -736, 0, + 32767, 32767, 418, 178, 122, 32767, 46, 32767, + 32767, 32767, 229, 443, 32767, 32767, 250, 32767, + -300, 0, 32767, 1153, 32767, 108, 32767, -462, + 266, 32767, 478, -220, 235, 32767, 32767, -127, + 32767, 32767, 32767, 427, -231, 156, 32767, 0, + 0, 148, -218, 142, 73, 420, 32767, 32767, + 523, 32767, -36, 32767, 32767, 467, 844, -415, + 32767, 32767, -148, 179, 361, 32767, 151, 0, + 0, 32767, 145, 32767, 248, 110, 29, 125, + 282, 32767, -36, 43, 32767, 1125, 32767, 530, + 251, 519, 191, 0, 32767, -34, -502, 313, + 462, 845, 32767, 32767, -255, 412, 32767, 78, + 0, 32767, 444, 161, 0, 32767, 308, 32767, + -273, 400, 32767, 296, 32767, 32767, 72, 32767, + 32767, 34, 32767, 364, 151, -63, 4, 229, + 0, -276, 32767, 32767, 32767, 32767, -406, 32767, + 203, 32767, 140, 187, 160, 32767, 286, 0, + 32767, 32767, -88, 0, 100, -361, 32767, 9, + 0, -456, 32767, -37, -404, 32767, -969, 32767, + 371, 95, 0, 703, -31, 263, 373, -745, + 507, 14, 32767, -159, 0, 32767, 47, 299, + -126, 0, 32767, 83, 32767, 32767, 420, 236, + 32767, 32767, 0, 310, 89, 233, 32767, 93, + 32767, 0, 816, 60, 301, 211, 193, 0, + 452, -107, -403, -242, 353, 18, 32767, 32767, + 32767, 243, 104, 32767, 32767, 32767, -305, 32767, + -1048, 54, 0, 383, 32767, 32767, 32767, 226, + 319, 0, 32767, 32767, 32767, -130, 537, 32767, + 0, -206, 240, 696, 121, 32767, 180, 164, + 32767, 390, 185, 32767, 220, 545, 29, 32767, + 0, 32767, 32767, 1120, -163, 32767, 32767, 32767, + -368, 136, 445, 171, 233, 32767, 73, 32767, + 92, 32767, 0, 32767, 0, 208, 354, 32767, + 54, 32767, 32767, -246, -93, 389, 32767, 32767, + 32767, 32767, 50, 32767, 32767, 308, 32767, -278, + 0, 32767, 32767, -1172, 32767, 8, 32767, 0, + 32767, 341, 304, 242, -174, -92, 76, 419, + 32767, 87, 32767, -262, 32767, 32767, 32767, 109, + 200, 0, 32767, 0, 85, 530, 32767, -316, + 32767, 0, -286, 32767, 193, 268, 32767, 32767, + 278, 32767, 32767, 155, 445, 95, -310, 32767, + 207, -56, 32767, 32767, 0, -127, 232, -283, + 103, 32767, 1, 0, 32767, 32767, -485, 350, + 79, -56, -354, 32767, 121, 24, 81, 20, + 325, 40, 248, 32767, 32767, 32767, 358, 32767, + -56, 32767, 0, 174, -28, -301, -92, 32767, + 114, 295, 32767, 363, -355, 32767, 290, 0, + 32767, 32767, 32767, 122, 55, -142, 32767, 50, + 32767, 32767, 152, 571, 1397, 0, 472, -448, + 185, 140, 228, 435, 0, 32767, 32767, 414, + 32767, 379, 92, 185, 23, 299, 32767, 32767, + 0, 32767, 32767, 32767, 306, 439, -198, 219, + 340, 32767, 416, 0, -123, 377, 32767, 32767, + 0, 32767, 670, -670, 339, 32767, 32767, 32767, + 0, -256, 70, 514, 331, 0, 302, 469, + 0, 370, 32767, 32767, 42, 255, 212, 0, + 322, 277, 32767, -163, 32767, 216, 32767, 32767, + 0, 32767, 190, 32767, 32767, 0, 32767, 0, + -409, 1366, 32767, 32767, 32767, 193, 32767, 325, + 32767, 0, 142, 466, 32767, 32767, 32767, 113, + 32767, 32767, 62, 0, -62, 113, -90, 34, + -256, 32767, 32767, -936, 32767, 32767, 32767, 0, + -64, 0, -34, 451, 290, 108, 32767, 276, + 842, 0, 556, -153, 32767, 412, -168, 32767, + 32767, 1331, 407, 234, -60, 115, 457, -73, + 502, 772, 32767, 33, 404, -925, 32767, 32767, + 421, -123, 32767, 32767, 32767, 0, 0, 32767, + 32767, 32767, 429, 0, 3, 769, -81, 306, + 64, 32767, 192, 96, 0, 63, 44, 32767, + 32767, 32767, 32767, 0, 284, 32767, 575, 32767, + 32767, 12, 32767, 516, 116, 32767, 32767, 150, + 442, 134, 32767, 198, -45, 249, 40, 373, + 32767, 0, 32767, 32767, 0, 0, 352, 32767, + 117, 32767, 426, 0, 0, 32767, 32767, 32767, + 32767, -92, 32767, -442, 32767, 269, 32767, 32767, + 32767, 429, 32767, 0, 32767, 0, 143, 32767, + 508, -66, 32767, 280, 32767, 39, 162, 32767, + 32767, 0, 32767, 31, 32767, 32767, 32767, 0, + 32767, 257, -90, -249, 224, 272, 32767, 32767, + 313, -467, 214, 0, -85, 32767, 48, 0, + 32767, -336, 202, 0, 447, 90, 264, 32767, + 32767, 0, 101, 32767, 32767, 32767, 0, 32767, + 32767, 227, -1093, 32767, 0, 32767, 27, 174, + 32767, 7, 32767, -621, 146, 32767, 32767, 32767, + 854, 0, 32767, 161, 0, 137, 32767, 32767, + 32767, 32767, 0, 391, 219, 276, 32767, 168, + 32767, 32767, 0, 32767, 32767, 32767, 1, -4, + 32767, 0, 293, 0, 374, 256, 0, 0, + 32767, 355, 212, 404, 0, 186, 32767, 0, + 359, 32767, 32767, 172, 32767, 32767, -131, 0, + 402, 0, 56, 32767, 462, 389, 82, 0, + 32767, 0, 32767, 0, 32767, 32767, 32767, 32767, + 106, 425, -160, 31, 32767, 55, 0, 0, + 32767, 32767, 430, 1224, 179, -179, 0, 397, + 32767, 0, 0, 0, -60, 47, 32767, 396, + 32767, 326, 383, 369, 32767, 368, 32767 + }; + + const unsigned char *k = (const unsigned char *) key; + uint32 a = 0; + uint32 b = 0; + + while (keylen--) + { + unsigned char c = *k++ | 0x20; + + a = a * 257 + c; + b = b * 31 + c; + } + return h[a % 943] + h[b % 943]; +} + +const ScanKeywordList ScanKeywords = { + ScanKeywords_kw_string, + ScanKeywords_kw_offsets, + ScanKeywords_hash_func, + SCANKEYWORDS_NUM_KEYWORDS, + 17 +}; + +#endif /* KWLIST_D_H */ diff --git a/contrib/libs/libpq/src/common/kwlookup.c b/contrib/libs/libpq/src/common/kwlookup.c new file mode 100644 index 0000000000..7e49825c7b --- /dev/null +++ b/contrib/libs/libpq/src/common/kwlookup.c @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------- + * + * kwlookup.c + * Key word lookup for PostgreSQL + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/kwlookup.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "common/kwlookup.h" + + +/* + * ScanKeywordLookup - see if a given word is a keyword + * + * The list of keywords to be matched against is passed as a ScanKeywordList. + * + * Returns the keyword number (0..N-1) of the keyword, or -1 if no match. + * Callers typically use the keyword number to index into information + * arrays, but that is no concern of this code. + * + * The match is done case-insensitively. Note that we deliberately use a + * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z', + * even if we are in a locale where tolower() would produce more or different + * translations. This is to conform to the SQL99 spec, which says that + * keywords are to be matched in this way even though non-keyword identifiers + * receive a different case-normalization mapping. + */ +int +ScanKeywordLookup(const char *str, + const ScanKeywordList *keywords) +{ + size_t len; + int h; + const char *kw; + + /* + * Reject immediately if too long to be any keyword. This saves useless + * hashing and downcasing work on long strings. + */ + len = strlen(str); + if (len > keywords->max_kw_len) + return -1; + + /* + * Compute the hash function. We assume it was generated to produce + * case-insensitive results. Since it's a perfect hash, we need only + * match to the specific keyword it identifies. + */ + h = keywords->hash(str, len); + + /* An out-of-range result implies no match */ + if (h < 0 || h >= keywords->num_keywords) + return -1; + + /* + * Compare character-by-character to see if we have a match, applying an + * ASCII-only downcasing to the input characters. We must not use + * tolower() since it may produce the wrong translation in some locales + * (eg, Turkish). + */ + kw = GetScanKeyword(h, keywords); + while (*str != '\0') + { + char ch = *str++; + + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + if (ch != *kw++) + return -1; + } + if (*kw != '\0') + return -1; + + /* Success! */ + return h; +} diff --git a/contrib/libs/libpq/src/common/link-canary.c b/contrib/libs/libpq/src/common/link-canary.c new file mode 100644 index 0000000000..f84331a9a4 --- /dev/null +++ b/contrib/libs/libpq/src/common/link-canary.c @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------- + * link-canary.c + * Detect whether src/common functions came from frontend or backend. + * + * Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/link-canary.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "common/link-canary.h" + +/* + * This function just reports whether this file was compiled for frontend + * or backend environment. We need this because in some systems, mainly + * ELF-based platforms, it is possible for a shlib (such as libpq) loaded + * into the backend to call a backend function named XYZ in preference to + * the shlib's own function XYZ. That's bad if the two functions don't + * act identically. This exact situation comes up for many functions in + * src/common and src/port, where the same function names exist in both + * libpq and the backend but they don't act quite identically. To verify + * that appropriate measures have been taken to prevent incorrect symbol + * resolution, libpq should test that this function returns true. + */ +bool +pg_link_canary_is_frontend(void) +{ +#ifdef FRONTEND + return true; +#else + return false; +#endif +} diff --git a/contrib/libs/libpq/src/common/logging.c b/contrib/libs/libpq/src/common/logging.c new file mode 100644 index 0000000000..dab718b482 --- /dev/null +++ b/contrib/libs/libpq/src/common/logging.c @@ -0,0 +1,334 @@ +/*------------------------------------------------------------------------- + * Logging framework for frontend programs + * + * Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * src/common/logging.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#error "This file is not expected to be compiled for backend code" +#endif + +#include "postgres_fe.h" + +#include <unistd.h> + +#include "common/logging.h" + +enum pg_log_level __pg_log_level; + +static const char *progname; +static int log_flags; + +static void (*log_pre_callback) (void); +static void (*log_locus_callback) (const char **, uint64 *); + +static const char *sgr_error = NULL; +static const char *sgr_warning = NULL; +static const char *sgr_note = NULL; +static const char *sgr_locus = NULL; + +#define SGR_ERROR_DEFAULT "01;31" +#define SGR_WARNING_DEFAULT "01;35" +#define SGR_NOTE_DEFAULT "01;36" +#define SGR_LOCUS_DEFAULT "01" + +#define ANSI_ESCAPE_FMT "\x1b[%sm" +#define ANSI_ESCAPE_RESET "\x1b[0m" + +#ifdef WIN32 + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +/* + * Attempt to enable VT100 sequence processing for colorization on Windows. + * If current environment is not VT100-compatible or if this mode could not + * be enabled, return false. + */ +static bool +enable_vt_processing(void) +{ + /* Check stderr */ + HANDLE hOut = GetStdHandle(STD_ERROR_HANDLE); + DWORD dwMode = 0; + + if (hOut == INVALID_HANDLE_VALUE) + return false; + + /* + * Look for the current console settings and check if VT100 is already + * enabled. + */ + if (!GetConsoleMode(hOut, &dwMode)) + return false; + if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) + return true; + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(hOut, dwMode)) + return false; + return true; +} +#endif /* WIN32 */ + +/* + * This should be called before any output happens. + */ +void +pg_logging_init(const char *argv0) +{ + const char *pg_color_env = getenv("PG_COLOR"); + bool log_color = false; + bool color_terminal = isatty(fileno(stderr)); + +#ifdef WIN32 + + /* + * On Windows, check if environment is VT100-compatible if using a + * terminal. + */ + if (color_terminal) + color_terminal = enable_vt_processing(); +#endif + + /* usually the default, but not on Windows */ + setvbuf(stderr, NULL, _IONBF, 0); + + progname = get_progname(argv0); + __pg_log_level = PG_LOG_INFO; + + if (pg_color_env) + { + if (strcmp(pg_color_env, "always") == 0 || + (strcmp(pg_color_env, "auto") == 0 && color_terminal)) + log_color = true; + } + + if (log_color) + { + const char *pg_colors_env = getenv("PG_COLORS"); + + if (pg_colors_env) + { + char *colors = strdup(pg_colors_env); + + if (colors) + { + for (char *token = strtok(colors, ":"); token; token = strtok(NULL, ":")) + { + char *e = strchr(token, '='); + + if (e) + { + char *name; + char *value; + + *e = '\0'; + name = token; + value = e + 1; + + if (strcmp(name, "error") == 0) + sgr_error = strdup(value); + if (strcmp(name, "warning") == 0) + sgr_warning = strdup(value); + if (strcmp(name, "note") == 0) + sgr_note = strdup(value); + if (strcmp(name, "locus") == 0) + sgr_locus = strdup(value); + } + } + + free(colors); + } + } + else + { + sgr_error = SGR_ERROR_DEFAULT; + sgr_warning = SGR_WARNING_DEFAULT; + sgr_note = SGR_NOTE_DEFAULT; + sgr_locus = SGR_LOCUS_DEFAULT; + } + } +} + +/* + * Change the logging flags. + */ +void +pg_logging_config(int new_flags) +{ + log_flags = new_flags; +} + +/* + * pg_logging_init sets the default log level to INFO. Programs that prefer + * a different default should use this to set it, immediately afterward. + */ +void +pg_logging_set_level(enum pg_log_level new_level) +{ + __pg_log_level = new_level; +} + +/* + * Command line switches such as --verbose should invoke this. + */ +void +pg_logging_increase_verbosity(void) +{ + /* + * The enum values are chosen such that we have to decrease __pg_log_level + * in order to become more verbose. + */ + if (__pg_log_level > PG_LOG_NOTSET + 1) + __pg_log_level--; +} + +void +pg_logging_set_pre_callback(void (*cb) (void)) +{ + log_pre_callback = cb; +} + +void +pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno)) +{ + log_locus_callback = cb; +} + +void +pg_log_generic(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + pg_log_generic_v(level, part, fmt, ap); + va_end(ap); +} + +void +pg_log_generic_v(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt, va_list ap) +{ + int save_errno = errno; + const char *filename = NULL; + uint64 lineno = 0; + va_list ap2; + size_t required_len; + char *buf; + + Assert(progname); + Assert(level); + Assert(fmt); + Assert(fmt[strlen(fmt) - 1] != '\n'); + + /* Do nothing if log level is too low. */ + if (level < __pg_log_level) + return; + + /* + * Flush stdout before output to stderr, to ensure sync even when stdout + * is buffered. + */ + fflush(stdout); + + if (log_pre_callback) + log_pre_callback(); + + if (log_locus_callback) + log_locus_callback(&filename, &lineno); + + fmt = _(fmt); + + if (!(log_flags & PG_LOG_FLAG_TERSE) || filename) + { + if (sgr_locus) + fprintf(stderr, ANSI_ESCAPE_FMT, sgr_locus); + if (!(log_flags & PG_LOG_FLAG_TERSE)) + fprintf(stderr, "%s:", progname); + if (filename) + { + fprintf(stderr, "%s:", filename); + if (lineno > 0) + fprintf(stderr, UINT64_FORMAT ":", lineno); + } + fprintf(stderr, " "); + if (sgr_locus) + fprintf(stderr, ANSI_ESCAPE_RESET); + } + + if (!(log_flags & PG_LOG_FLAG_TERSE)) + { + switch (part) + { + case PG_LOG_PRIMARY: + switch (level) + { + case PG_LOG_ERROR: + if (sgr_error) + fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error); + fprintf(stderr, _("error: ")); + if (sgr_error) + fprintf(stderr, ANSI_ESCAPE_RESET); + break; + case PG_LOG_WARNING: + if (sgr_warning) + fprintf(stderr, ANSI_ESCAPE_FMT, sgr_warning); + fprintf(stderr, _("warning: ")); + if (sgr_warning) + fprintf(stderr, ANSI_ESCAPE_RESET); + break; + default: + break; + } + break; + case PG_LOG_DETAIL: + if (sgr_note) + fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note); + fprintf(stderr, _("detail: ")); + if (sgr_note) + fprintf(stderr, ANSI_ESCAPE_RESET); + break; + case PG_LOG_HINT: + if (sgr_note) + fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note); + fprintf(stderr, _("hint: ")); + if (sgr_note) + fprintf(stderr, ANSI_ESCAPE_RESET); + break; + } + } + + errno = save_errno; + + va_copy(ap2, ap); + required_len = vsnprintf(NULL, 0, fmt, ap2) + 1; + va_end(ap2); + + buf = pg_malloc_extended(required_len, MCXT_ALLOC_NO_OOM); + + errno = save_errno; /* malloc might change errno */ + + if (!buf) + { + /* memory trouble, just print what we can and get out of here */ + vfprintf(stderr, fmt, ap); + return; + } + + vsnprintf(buf, required_len, fmt, ap); + + /* strip one newline, for PQerrorMessage() */ + if (required_len >= 2 && buf[required_len - 2] == '\n') + buf[required_len - 2] = '\0'; + + fprintf(stderr, "%s\n", buf); + + free(buf); +} diff --git a/contrib/libs/libpq/src/common/md5_common.c b/contrib/libs/libpq/src/common/md5_common.c new file mode 100644 index 0000000000..82ce75dcf2 --- /dev/null +++ b/contrib/libs/libpq/src/common/md5_common.c @@ -0,0 +1,172 @@ +/*------------------------------------------------------------------------- + * + * md5_common.c + * Routines shared between all MD5 implementations used for encrypted + * passwords. + * + * Sverre H. Huseby <sverrehu@online.no> + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/md5_common.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/cryptohash.h" +#include "common/md5.h" + +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'; +} + +/* + * 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 hexadecimal + * characters. you thus need to provide an array + * of 33 characters, including the trailing '\0'. + * + * errstr filled with a constant-string error message + * on failure return; NULL on success. + * + * RETURNS false on failure (out of memory for internal buffers + * or MD5 computation failure) or true on success. + * + * STANDARDS MD5 is described in RFC 1321. + * + * AUTHOR Sverre H. Huseby <sverrehu@online.no> + * + */ + +bool +pg_md5_hash(const void *buff, size_t len, char *hexsum, const char **errstr) +{ + uint8 sum[MD5_DIGEST_LENGTH]; + pg_cryptohash_ctx *ctx; + + *errstr = NULL; + ctx = pg_cryptohash_create(PG_MD5); + if (ctx == NULL) + { + *errstr = pg_cryptohash_error(NULL); /* returns OOM */ + return false; + } + + if (pg_cryptohash_init(ctx) < 0 || + pg_cryptohash_update(ctx, buff, len) < 0 || + pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0) + { + *errstr = pg_cryptohash_error(ctx); + pg_cryptohash_free(ctx); + return false; + } + + bytesToHex(sum, hexsum); + pg_cryptohash_free(ctx); + return true; +} + +/* + * pg_md5_binary + * + * As above, except that the MD5 digest is returned as a binary string + * (of size MD5_DIGEST_LENGTH) rather than being converted to ASCII hex. + */ +bool +pg_md5_binary(const void *buff, size_t len, void *outbuf, const char **errstr) +{ + pg_cryptohash_ctx *ctx; + + *errstr = NULL; + ctx = pg_cryptohash_create(PG_MD5); + if (ctx == NULL) + { + *errstr = pg_cryptohash_error(NULL); /* returns OOM */ + return false; + } + + if (pg_cryptohash_init(ctx) < 0 || + pg_cryptohash_update(ctx, buff, len) < 0 || + pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0) + { + *errstr = pg_cryptohash_error(ctx); + pg_cryptohash_free(ctx); + return false; + } + + pg_cryptohash_free(ctx); + 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 with *errstr providing some + * error context. + */ +bool +pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, + char *buf, const char **errstr) +{ + 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) + { + *errstr = _("out of memory"); + 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, errstr); + + free(crypt_buf); + + return ret; +} diff --git a/contrib/libs/libpq/src/common/percentrepl.c b/contrib/libs/libpq/src/common/percentrepl.c new file mode 100644 index 0000000000..7aa85fdc94 --- /dev/null +++ b/contrib/libs/libpq/src/common/percentrepl.c @@ -0,0 +1,137 @@ +/*------------------------------------------------------------------------- + * + * percentrepl.c + * Common routines to replace percent placeholders in strings + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/percentrepl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#include "common/logging.h" +#endif + +#include "common/percentrepl.h" +#include "lib/stringinfo.h" + +/* + * replace_percent_placeholders + * + * Replace percent-letter placeholders in input string with the supplied + * values. For example, to replace %f with foo and %b with bar, call + * + * replace_percent_placeholders(instr, "param_name", "bf", bar, foo); + * + * The return value is palloc'd. + * + * "%%" is replaced by a single "%". + * + * This throws an error for an unsupported placeholder or a "%" at the end of + * the input string. + * + * A value may be NULL. If the corresponding placeholder is found in the + * input string, it will be treated as if an unsupported placeholder was used. + * This allows callers to share a "letters" specification but vary the + * actually supported placeholders at run time. + * + * This functions is meant for cases where all the values are readily + * available or cheap to compute and most invocations will use most values + * (for example for archive_command). Also, it requires that all values are + * strings. It won't be a good match for things like log prefixes or prompts + * that use a mix of data types and any invocation will only use a few of the + * possible values. + * + * param_name is the name of the underlying GUC parameter, for error + * reporting. At the moment, this function is only used for GUC parameters. + * If other kinds of uses were added, the error reporting would need to be + * revised. + */ +char * +replace_percent_placeholders(const char *instr, const char *param_name, const char *letters,...) +{ + StringInfoData result; + + initStringInfo(&result); + + for (const char *sp = instr; *sp; sp++) + { + if (*sp == '%') + { + if (sp[1] == '%') + { + /* Convert %% to a single % */ + sp++; + appendStringInfoChar(&result, *sp); + } + else if (sp[1] == '\0') + { + /* Incomplete escape sequence, expected a character afterward */ +#ifdef FRONTEND + pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name, instr); + pg_log_error_detail("String ends unexpectedly after escape character \"%%\"."); + exit(1); +#else + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", param_name, instr), + errdetail("String ends unexpectedly after escape character \"%%\".")); +#endif + } + else + { + /* Look up placeholder character */ + bool found = false; + va_list ap; + + sp++; + + va_start(ap, letters); + for (const char *lp = letters; *lp; lp++) + { + char *val = va_arg(ap, char *); + + if (*sp == *lp) + { + if (val) + { + appendStringInfoString(&result, val); + found = true; + } + /* If val is NULL, we will report an error. */ + break; + } + } + va_end(ap); + if (!found) + { + /* Unknown placeholder */ +#ifdef FRONTEND + pg_log_error("invalid value for parameter \"%s\": \"%s\"", param_name, instr); + pg_log_error_detail("String contains unexpected placeholder \"%%%c\".", *sp); + exit(1); +#else + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", param_name, instr), + errdetail("String contains unexpected placeholder \"%%%c\".", *sp)); +#endif + } + } + } + else + { + appendStringInfoChar(&result, *sp); + } + } + + return result.data; +} diff --git a/contrib/libs/libpq/src/common/pg_get_line.c b/contrib/libs/libpq/src/common/pg_get_line.c new file mode 100644 index 0000000000..3cdf0908d2 --- /dev/null +++ b/contrib/libs/libpq/src/common/pg_get_line.c @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- + * + * pg_get_line.c + * fgets() with an expansible result buffer + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/pg_get_line.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <setjmp.h> + +#include "common/string.h" +#include "lib/stringinfo.h" + + +/* + * pg_get_line() + * + * This is meant to be equivalent to fgets(), except that instead of + * reading into a caller-supplied, fixed-size buffer, it reads into + * a palloc'd (in frontend, really malloc'd) string, which is resized + * as needed to handle indefinitely long input lines. The caller is + * responsible for pfree'ing the result string when appropriate. + * + * As with fgets(), returns NULL if there is a read error or if no + * characters are available before EOF. The caller can distinguish + * these cases by checking ferror(stream). + * + * Since this is meant to be equivalent to fgets(), the trailing newline + * (if any) is not stripped. Callers may wish to apply pg_strip_crlf(). + * + * Note that while I/O errors are reflected back to the caller to be + * dealt with, an OOM condition for the palloc'd buffer will not be; + * there'll be an ereport(ERROR) or exit(1) inside stringinfo.c. + * + * Also note that the palloc'd buffer is usually a lot longer than + * strictly necessary, so it may be inadvisable to use this function + * to collect lots of long-lived data. A less memory-hungry option + * is to use pg_get_line_buf() or pg_get_line_append() in a loop, + * then pstrdup() each line. + * + * prompt_ctx can optionally be provided to allow this function to be + * canceled via an existing SIGINT signal handler that will longjmp to the + * specified place only when *(prompt_ctx->enabled) is true. If canceled, + * this function returns NULL, and prompt_ctx->canceled is set to true. + */ +char * +pg_get_line(FILE *stream, PromptInterruptContext *prompt_ctx) +{ + StringInfoData buf; + + initStringInfo(&buf); + + if (!pg_get_line_append(stream, &buf, prompt_ctx)) + { + /* ensure that free() doesn't mess up errno */ + int save_errno = errno; + + pfree(buf.data); + errno = save_errno; + return NULL; + } + + return buf.data; +} + +/* + * pg_get_line_buf() + * + * This has similar behavior to pg_get_line(), and thence to fgets(), + * except that the collected data is returned in a caller-supplied + * StringInfo buffer. This is a convenient API for code that just + * wants to read and process one line at a time, without any artificial + * limit on line length. + * + * Returns true if a line was successfully collected (including the + * case of a non-newline-terminated line at EOF). Returns false if + * there was an I/O error or no data was available before EOF. + * (Check ferror(stream) to distinguish these cases.) + * + * In the false-result case, buf is reset to empty. + */ +bool +pg_get_line_buf(FILE *stream, StringInfo buf) +{ + /* We just need to drop any data from the previous call */ + resetStringInfo(buf); + return pg_get_line_append(stream, buf, NULL); +} + +/* + * pg_get_line_append() + * + * This has similar behavior to pg_get_line(), and thence to fgets(), + * except that the collected data is appended to whatever is in *buf. + * This is useful in preference to pg_get_line_buf() if the caller wants + * to merge some lines together, e.g. to implement backslash continuation. + * + * Returns true if a line was successfully collected (including the + * case of a non-newline-terminated line at EOF). Returns false if + * there was an I/O error or no data was available before EOF. + * (Check ferror(stream) to distinguish these cases.) + * + * In the false-result case, the contents of *buf are logically unmodified, + * though it's possible that the buffer has been resized. + * + * prompt_ctx can optionally be provided to allow this function to be + * canceled via an existing SIGINT signal handler that will longjmp to the + * specified place only when *(prompt_ctx->enabled) is true. If canceled, + * this function returns false, and prompt_ctx->canceled is set to true. + */ +bool +pg_get_line_append(FILE *stream, StringInfo buf, + PromptInterruptContext *prompt_ctx) +{ + int orig_len = buf->len; + + if (prompt_ctx && sigsetjmp(*((sigjmp_buf *) prompt_ctx->jmpbuf), 1) != 0) + { + /* Got here with longjmp */ + prompt_ctx->canceled = true; + /* Discard any data we collected before detecting error */ + buf->len = orig_len; + buf->data[orig_len] = '\0'; + return false; + } + + /* Loop until newline or EOF/error */ + for (;;) + { + char *res; + + /* Enable longjmp while waiting for input */ + if (prompt_ctx) + *(prompt_ctx->enabled) = true; + + /* Read some data, appending it to whatever we already have */ + res = fgets(buf->data + buf->len, buf->maxlen - buf->len, stream); + + /* Disable longjmp again, then break if fgets failed */ + if (prompt_ctx) + *(prompt_ctx->enabled) = false; + + if (res == NULL) + break; + + /* Got data, so update buf->len */ + buf->len += strlen(buf->data + buf->len); + + /* Done if we have collected a newline */ + if (buf->len > orig_len && buf->data[buf->len - 1] == '\n') + return true; + + /* Make some more room in the buffer, and loop to read more data */ + enlargeStringInfo(buf, 128); + } + + /* Check for I/O errors and EOF */ + if (ferror(stream) || buf->len == orig_len) + { + /* Discard any data we collected before detecting error */ + buf->len = orig_len; + buf->data[orig_len] = '\0'; + return false; + } + + /* No newline at EOF, but we did collect some data */ + return true; +} diff --git a/contrib/libs/libpq/src/common/pg_lzcompress.c b/contrib/libs/libpq/src/common/pg_lzcompress.c new file mode 100644 index 0000000000..95ad3388ef --- /dev/null +++ b/contrib/libs/libpq/src/common/pg_lzcompress.c @@ -0,0 +1,876 @@ +/* ---------- + * pg_lzcompress.c - + * + * This is an implementation of LZ compression for PostgreSQL. + * It uses a simple history table and generates 2-3 byte tags + * capable of backward copy information for 3-273 bytes with + * a max offset of 4095. + * + * Entry routines: + * + * int32 + * pglz_compress(const char *source, int32 slen, char *dest, + * const PGLZ_Strategy *strategy); + * + * source is the input data to be compressed. + * + * slen is the length of the input data. + * + * dest is the output area for the compressed result. + * It must be at least as big as PGLZ_MAX_OUTPUT(slen). + * + * strategy is a pointer to some information controlling + * the compression algorithm. If NULL, the compiled + * in default strategy is used. + * + * The return value is the number of bytes written in the + * buffer dest, or -1 if compression fails; in the latter + * case the contents of dest are undefined. + * + * int32 + * pglz_decompress(const char *source, int32 slen, char *dest, + * int32 rawsize, bool check_complete) + * + * source is the compressed input. + * + * slen is the length of the compressed input. + * + * dest is the area where the uncompressed data will be + * written to. It is the callers responsibility to + * provide enough space. + * + * The data is written to buff exactly as it was handed + * to pglz_compress(). No terminating zero byte is added. + * + * rawsize is the length of the uncompressed data. + * + * check_complete is a flag to let us know if -1 should be + * returned in cases where we don't reach the end of the + * source or dest buffers, or not. This should be false + * if the caller is asking for only a partial result and + * true otherwise. + * + * The return value is the number of bytes written in the + * buffer dest, or -1 if decompression fails. + * + * The decompression algorithm and internal data format: + * + * It is made with the compressed data itself. + * + * The data representation is easiest explained by describing + * the process of decompression. + * + * If compressed_size == rawsize, then the data + * is stored uncompressed as plain bytes. Thus, the decompressor + * simply copies rawsize bytes to the destination. + * + * Otherwise the first byte tells what to do the next 8 times. + * We call this the control byte. + * + * An unset bit in the control byte means, that one uncompressed + * byte follows, which is copied from input to output. + * + * A set bit in the control byte means, that a tag of 2-3 bytes + * follows. A tag contains information to copy some bytes, that + * are already in the output buffer, to the current location in + * the output. Let's call the three tag bytes T1, T2 and T3. The + * position of the data to copy is coded as an offset from the + * actual output position. + * + * The offset is in the upper nibble of T1 and in T2. + * The length is in the lower nibble of T1. + * + * So the 16 bits of a 2 byte tag are coded as + * + * 7---T1--0 7---T2--0 + * OOOO LLLL OOOO OOOO + * + * This limits the offset to 1-4095 (12 bits) and the length + * to 3-18 (4 bits) because 3 is always added to it. To emit + * a tag of 2 bytes with a length of 2 only saves one control + * bit. But we lose one byte in the possible length of a tag. + * + * In the actual implementation, the 2 byte tag's length is + * limited to 3-17, because the value 0xF in the length nibble + * has special meaning. It means, that the next following + * byte (T3) has to be added to the length value of 18. That + * makes total limits of 1-4095 for offset and 3-273 for length. + * + * Now that we have successfully decoded a tag. We simply copy + * the output that occurred <offset> bytes back to the current + * output location in the specified <length>. Thus, a + * sequence of 200 spaces (think about bpchar fields) could be + * coded in 4 bytes. One literal space and a three byte tag to + * copy 199 bytes with a -1 offset. Whow - that's a compression + * rate of 98%! Well, the implementation needs to save the + * original data size too, so we need another 4 bytes for it + * and end up with a total compression rate of 96%, what's still + * worth a Whow. + * + * The compression algorithm + * + * The following uses numbers used in the default strategy. + * + * The compressor works best for attributes of a size between + * 1K and 1M. For smaller items there's not that much chance of + * redundancy in the character sequence (except for large areas + * of identical bytes like trailing spaces) and for bigger ones + * our 4K maximum look-back distance is too small. + * + * The compressor creates a table for lists of positions. + * For each input position (except the last 3), a hash key is + * built from the 4 next input bytes and the position remembered + * in the appropriate list. Thus, the table points to linked + * lists of likely to be at least in the first 4 characters + * matching strings. This is done on the fly while the input + * is compressed into the output area. Table entries are only + * kept for the last 4096 input positions, since we cannot use + * back-pointers larger than that anyway. The size of the hash + * table is chosen based on the size of the input - a larger table + * has a larger startup cost, as it needs to be initialized to + * zero, but reduces the number of hash collisions on long inputs. + * + * For each byte in the input, its hash key (built from this + * byte and the next 3) is used to find the appropriate list + * in the table. The lists remember the positions of all bytes + * that had the same hash key in the past in increasing backward + * offset order. Now for all entries in the used lists, the + * match length is computed by comparing the characters from the + * entries position with the characters from the actual input + * position. + * + * The compressor starts with a so called "good_match" of 128. + * It is a "prefer speed against compression ratio" optimizer. + * So if the first entry looked at already has 128 or more + * matching characters, the lookup stops and that position is + * used for the next tag in the output. + * + * For each subsequent entry in the history list, the "good_match" + * is lowered by 10%. So the compressor will be more happy with + * short matches the further it has to go back in the history. + * Another "speed against ratio" preference characteristic of + * the algorithm. + * + * Thus there are 3 stop conditions for the lookup of matches: + * + * - a match >= good_match is found + * - there are no more history entries to look at + * - the next history entry is already too far back + * to be coded into a tag. + * + * Finally the match algorithm checks that at least a match + * of 3 or more bytes has been found, because that is the smallest + * amount of copy information to code into a tag. If so, a tag + * is omitted and all the input bytes covered by that are just + * scanned for the history add's, otherwise a literal character + * is omitted and only his history entry added. + * + * Acknowledgments: + * + * Many thanks to Adisak Pochanayon, who's article about SLZ + * inspired me to write the PostgreSQL compression this way. + * + * Jan Wieck + * + * Copyright (c) 1999-2023, PostgreSQL Global Development Group + * + * src/common/pg_lzcompress.c + * ---------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <limits.h> + +#include "common/pg_lzcompress.h" + + +/* ---------- + * Local definitions + * ---------- + */ +#define PGLZ_MAX_HISTORY_LISTS 8192 /* must be power of 2 */ +#define PGLZ_HISTORY_SIZE 4096 +#define PGLZ_MAX_MATCH 273 + + +/* ---------- + * PGLZ_HistEntry - + * + * Linked list for the backward history lookup + * + * All the entries sharing a hash key are linked in a doubly linked list. + * This makes it easy to remove an entry when it's time to recycle it + * (because it's more than 4K positions old). + * ---------- + */ +typedef struct PGLZ_HistEntry +{ + struct PGLZ_HistEntry *next; /* links for my hash key's list */ + struct PGLZ_HistEntry *prev; + int hindex; /* my current hash key */ + const char *pos; /* my input position */ +} PGLZ_HistEntry; + + +/* ---------- + * The provided standard strategies + * ---------- + */ +static const PGLZ_Strategy strategy_default_data = { + 32, /* Data chunks less than 32 bytes are not + * compressed */ + INT_MAX, /* No upper limit on what we'll try to + * compress */ + 25, /* Require 25% compression rate, or not worth + * it */ + 1024, /* Give up if no compression in the first 1KB */ + 128, /* Stop history lookup if a match of 128 bytes + * is found */ + 10 /* Lower good match size by 10% at every loop + * iteration */ +}; +const PGLZ_Strategy *const PGLZ_strategy_default = &strategy_default_data; + + +static const PGLZ_Strategy strategy_always_data = { + 0, /* Chunks of any size are compressed */ + INT_MAX, + 0, /* It's enough to save one single byte */ + INT_MAX, /* Never give up early */ + 128, /* Stop history lookup if a match of 128 bytes + * is found */ + 6 /* Look harder for a good match */ +}; +const PGLZ_Strategy *const PGLZ_strategy_always = &strategy_always_data; + + +/* ---------- + * Statically allocated work arrays for history + * ---------- + */ +static int16 hist_start[PGLZ_MAX_HISTORY_LISTS]; +static PGLZ_HistEntry hist_entries[PGLZ_HISTORY_SIZE + 1]; + +/* + * Element 0 in hist_entries is unused, and means 'invalid'. Likewise, + * INVALID_ENTRY_PTR in next/prev pointers mean 'invalid'. + */ +#define INVALID_ENTRY 0 +#define INVALID_ENTRY_PTR (&hist_entries[INVALID_ENTRY]) + +/* ---------- + * pglz_hist_idx - + * + * Computes the history table slot for the lookup by the next 4 + * characters in the input. + * + * NB: because we use the next 4 characters, we are not guaranteed to + * find 3-character matches; they very possibly will be in the wrong + * hash list. This seems an acceptable tradeoff for spreading out the + * hash keys more. + * ---------- + */ +#define pglz_hist_idx(_s,_e, _mask) ( \ + ((((_e) - (_s)) < 4) ? (int) (_s)[0] : \ + (((_s)[0] << 6) ^ ((_s)[1] << 4) ^ \ + ((_s)[2] << 2) ^ (_s)[3])) & (_mask) \ + ) + + +/* ---------- + * pglz_hist_add - + * + * Adds a new entry to the history table. + * + * If _recycle is true, then we are recycling a previously used entry, + * and must first delink it from its old hashcode's linked list. + * + * NOTE: beware of multiple evaluations of macro's arguments, and note that + * _hn and _recycle are modified in the macro. + * ---------- + */ +#define pglz_hist_add(_hs,_he,_hn,_recycle,_s,_e, _mask) \ +do { \ + int __hindex = pglz_hist_idx((_s),(_e), (_mask)); \ + int16 *__myhsp = &(_hs)[__hindex]; \ + PGLZ_HistEntry *__myhe = &(_he)[_hn]; \ + if (_recycle) { \ + if (__myhe->prev == NULL) \ + (_hs)[__myhe->hindex] = __myhe->next - (_he); \ + else \ + __myhe->prev->next = __myhe->next; \ + if (__myhe->next != NULL) \ + __myhe->next->prev = __myhe->prev; \ + } \ + __myhe->next = &(_he)[*__myhsp]; \ + __myhe->prev = NULL; \ + __myhe->hindex = __hindex; \ + __myhe->pos = (_s); \ + /* If there was an existing entry in this hash slot, link */ \ + /* this new entry to it. However, the 0th entry in the */ \ + /* entries table is unused, so we can freely scribble on it. */ \ + /* So don't bother checking if the slot was used - we'll */ \ + /* scribble on the unused entry if it was not, but that's */ \ + /* harmless. Avoiding the branch in this critical path */ \ + /* speeds this up a little bit. */ \ + /* if (*__myhsp != INVALID_ENTRY) */ \ + (_he)[(*__myhsp)].prev = __myhe; \ + *__myhsp = _hn; \ + if (++(_hn) >= PGLZ_HISTORY_SIZE + 1) { \ + (_hn) = 1; \ + (_recycle) = true; \ + } \ +} while (0) + + +/* ---------- + * pglz_out_ctrl - + * + * Outputs the last and allocates a new control byte if needed. + * ---------- + */ +#define pglz_out_ctrl(__ctrlp,__ctrlb,__ctrl,__buf) \ +do { \ + if ((__ctrl & 0xff) == 0) \ + { \ + *(__ctrlp) = __ctrlb; \ + __ctrlp = (__buf)++; \ + __ctrlb = 0; \ + __ctrl = 1; \ + } \ +} while (0) + + +/* ---------- + * pglz_out_literal - + * + * Outputs a literal byte to the destination buffer including the + * appropriate control bit. + * ---------- + */ +#define pglz_out_literal(_ctrlp,_ctrlb,_ctrl,_buf,_byte) \ +do { \ + pglz_out_ctrl(_ctrlp,_ctrlb,_ctrl,_buf); \ + *(_buf)++ = (unsigned char)(_byte); \ + _ctrl <<= 1; \ +} while (0) + + +/* ---------- + * pglz_out_tag - + * + * Outputs a backward reference tag of 2-4 bytes (depending on + * offset and length) to the destination buffer including the + * appropriate control bit. + * ---------- + */ +#define pglz_out_tag(_ctrlp,_ctrlb,_ctrl,_buf,_len,_off) \ +do { \ + pglz_out_ctrl(_ctrlp,_ctrlb,_ctrl,_buf); \ + _ctrlb |= _ctrl; \ + _ctrl <<= 1; \ + if (_len > 17) \ + { \ + (_buf)[0] = (unsigned char)((((_off) & 0xf00) >> 4) | 0x0f); \ + (_buf)[1] = (unsigned char)(((_off) & 0xff)); \ + (_buf)[2] = (unsigned char)((_len) - 18); \ + (_buf) += 3; \ + } else { \ + (_buf)[0] = (unsigned char)((((_off) & 0xf00) >> 4) | ((_len) - 3)); \ + (_buf)[1] = (unsigned char)((_off) & 0xff); \ + (_buf) += 2; \ + } \ +} while (0) + + +/* ---------- + * pglz_find_match - + * + * Lookup the history table if the actual input stream matches + * another sequence of characters, starting somewhere earlier + * in the input buffer. + * ---------- + */ +static inline int +pglz_find_match(int16 *hstart, const char *input, const char *end, + int *lenp, int *offp, int good_match, int good_drop, int mask) +{ + PGLZ_HistEntry *hent; + int16 hentno; + int32 len = 0; + int32 off = 0; + + /* + * Traverse the linked history list until a good enough match is found. + */ + hentno = hstart[pglz_hist_idx(input, end, mask)]; + hent = &hist_entries[hentno]; + while (hent != INVALID_ENTRY_PTR) + { + const char *ip = input; + const char *hp = hent->pos; + int32 thisoff; + int32 thislen; + + /* + * Stop if the offset does not fit into our tag anymore. + */ + thisoff = ip - hp; + if (thisoff >= 0x0fff) + break; + + /* + * Determine length of match. A better match must be larger than the + * best so far. And if we already have a match of 16 or more bytes, + * it's worth the call overhead to use memcmp() to check if this match + * is equal for the same size. After that we must fallback to + * character by character comparison to know the exact position where + * the diff occurred. + */ + thislen = 0; + if (len >= 16) + { + if (memcmp(ip, hp, len) == 0) + { + thislen = len; + ip += len; + hp += len; + while (ip < end && *ip == *hp && thislen < PGLZ_MAX_MATCH) + { + thislen++; + ip++; + hp++; + } + } + } + else + { + while (ip < end && *ip == *hp && thislen < PGLZ_MAX_MATCH) + { + thislen++; + ip++; + hp++; + } + } + + /* + * Remember this match as the best (if it is) + */ + if (thislen > len) + { + len = thislen; + off = thisoff; + } + + /* + * Advance to the next history entry + */ + hent = hent->next; + + /* + * Be happy with lesser good matches the more entries we visited. But + * no point in doing calculation if we're at end of list. + */ + if (hent != INVALID_ENTRY_PTR) + { + if (len >= good_match) + break; + good_match -= (good_match * good_drop) / 100; + } + } + + /* + * Return match information only if it results at least in one byte + * reduction. + */ + if (len > 2) + { + *lenp = len; + *offp = off; + return 1; + } + + return 0; +} + + +/* ---------- + * pglz_compress - + * + * Compresses source into dest using strategy. Returns the number of + * bytes written in buffer dest, or -1 if compression fails. + * ---------- + */ +int32 +pglz_compress(const char *source, int32 slen, char *dest, + const PGLZ_Strategy *strategy) +{ + unsigned char *bp = (unsigned char *) dest; + unsigned char *bstart = bp; + int hist_next = 1; + bool hist_recycle = false; + const char *dp = source; + const char *dend = source + slen; + unsigned char ctrl_dummy = 0; + unsigned char *ctrlp = &ctrl_dummy; + unsigned char ctrlb = 0; + unsigned char ctrl = 0; + bool found_match = false; + int32 match_len; + int32 match_off; + int32 good_match; + int32 good_drop; + int32 result_size; + int32 result_max; + int32 need_rate; + int hashsz; + int mask; + + /* + * Our fallback strategy is the default. + */ + if (strategy == NULL) + strategy = PGLZ_strategy_default; + + /* + * If the strategy forbids compression (at all or if source chunk size out + * of range), fail. + */ + if (strategy->match_size_good <= 0 || + slen < strategy->min_input_size || + slen > strategy->max_input_size) + return -1; + + /* + * Limit the match parameters to the supported range. + */ + good_match = strategy->match_size_good; + if (good_match > PGLZ_MAX_MATCH) + good_match = PGLZ_MAX_MATCH; + else if (good_match < 17) + good_match = 17; + + good_drop = strategy->match_size_drop; + if (good_drop < 0) + good_drop = 0; + else if (good_drop > 100) + good_drop = 100; + + need_rate = strategy->min_comp_rate; + if (need_rate < 0) + need_rate = 0; + else if (need_rate > 99) + need_rate = 99; + + /* + * Compute the maximum result size allowed by the strategy, namely the + * input size minus the minimum wanted compression rate. This had better + * be <= slen, else we might overrun the provided output buffer. + */ + if (slen > (INT_MAX / 100)) + { + /* Approximate to avoid overflow */ + result_max = (slen / 100) * (100 - need_rate); + } + else + result_max = (slen * (100 - need_rate)) / 100; + + /* + * Experiments suggest that these hash sizes work pretty well. A large + * hash table minimizes collision, but has a higher startup cost. For a + * small input, the startup cost dominates. The table size must be a power + * of two. + */ + if (slen < 128) + hashsz = 512; + else if (slen < 256) + hashsz = 1024; + else if (slen < 512) + hashsz = 2048; + else if (slen < 1024) + hashsz = 4096; + else + hashsz = 8192; + mask = hashsz - 1; + + /* + * Initialize the history lists to empty. We do not need to zero the + * hist_entries[] array; its entries are initialized as they are used. + */ + memset(hist_start, 0, hashsz * sizeof(int16)); + + /* + * Compress the source directly into the output buffer. + */ + while (dp < dend) + { + /* + * If we already exceeded the maximum result size, fail. + * + * We check once per loop; since the loop body could emit as many as 4 + * bytes (a control byte and 3-byte tag), PGLZ_MAX_OUTPUT() had better + * allow 4 slop bytes. + */ + if (bp - bstart >= result_max) + return -1; + + /* + * If we've emitted more than first_success_by bytes without finding + * anything compressible at all, fail. This lets us fall out + * reasonably quickly when looking at incompressible input (such as + * pre-compressed data). + */ + if (!found_match && bp - bstart >= strategy->first_success_by) + return -1; + + /* + * Try to find a match in the history + */ + if (pglz_find_match(hist_start, dp, dend, &match_len, + &match_off, good_match, good_drop, mask)) + { + /* + * Create the tag and add history entries for all matched + * characters. + */ + pglz_out_tag(ctrlp, ctrlb, ctrl, bp, match_len, match_off); + while (match_len--) + { + pglz_hist_add(hist_start, hist_entries, + hist_next, hist_recycle, + dp, dend, mask); + dp++; /* Do not do this ++ in the line above! */ + /* The macro would do it four times - Jan. */ + } + found_match = true; + } + else + { + /* + * No match found. Copy one literal byte. + */ + pglz_out_literal(ctrlp, ctrlb, ctrl, bp, *dp); + pglz_hist_add(hist_start, hist_entries, + hist_next, hist_recycle, + dp, dend, mask); + dp++; /* Do not do this ++ in the line above! */ + /* The macro would do it four times - Jan. */ + } + } + + /* + * Write out the last control byte and check that we haven't overrun the + * output size allowed by the strategy. + */ + *ctrlp = ctrlb; + result_size = bp - bstart; + if (result_size >= result_max) + return -1; + + /* success */ + return result_size; +} + + +/* ---------- + * pglz_decompress - + * + * Decompresses source into dest. Returns the number of bytes + * decompressed into the destination buffer, or -1 if the + * compressed data is corrupted. + * + * If check_complete is true, the data is considered corrupted + * if we don't exactly fill the destination buffer. Callers that + * are extracting a slice typically can't apply this check. + * ---------- + */ +int32 +pglz_decompress(const char *source, int32 slen, char *dest, + int32 rawsize, bool check_complete) +{ + const unsigned char *sp; + const unsigned char *srcend; + unsigned char *dp; + unsigned char *destend; + + sp = (const unsigned char *) source; + srcend = ((const unsigned char *) source) + slen; + dp = (unsigned char *) dest; + destend = dp + rawsize; + + while (sp < srcend && dp < destend) + { + /* + * Read one control byte and process the next 8 items (or as many as + * remain in the compressed input). + */ + unsigned char ctrl = *sp++; + int ctrlc; + + for (ctrlc = 0; ctrlc < 8 && sp < srcend && dp < destend; ctrlc++) + { + if (ctrl & 1) + { + /* + * Set control bit means we must read a match tag. The match + * is coded with two bytes. First byte uses lower nibble to + * code length - 3. Higher nibble contains upper 4 bits of the + * offset. The next following byte contains the lower 8 bits + * of the offset. If the length is coded as 18, another + * extension tag byte tells how much longer the match really + * was (0-255). + */ + int32 len; + int32 off; + + len = (sp[0] & 0x0f) + 3; + off = ((sp[0] & 0xf0) << 4) | sp[1]; + sp += 2; + if (len == 18) + len += *sp++; + + /* + * Check for corrupt data: if we fell off the end of the + * source, or if we obtained off = 0, or if off is more than + * the distance back to the buffer start, we have problems. + * (We must check for off = 0, else we risk an infinite loop + * below in the face of corrupt data. Likewise, the upper + * limit on off prevents accessing outside the buffer + * boundaries.) + */ + if (unlikely(sp > srcend || off == 0 || + off > (dp - (unsigned char *) dest))) + return -1; + + /* + * Don't emit more data than requested. + */ + len = Min(len, destend - dp); + + /* + * Now we copy the bytes specified by the tag from OUTPUT to + * OUTPUT (copy len bytes from dp - off to dp). The copied + * areas could overlap, so to avoid undefined behavior in + * memcpy(), be careful to copy only non-overlapping regions. + * + * Note that we cannot use memmove() instead, since while its + * behavior is well-defined, it's also not what we want. + */ + while (off < len) + { + /* + * We can safely copy "off" bytes since that clearly + * results in non-overlapping source and destination. + */ + memcpy(dp, dp - off, off); + len -= off; + dp += off; + + /*---------- + * This bit is less obvious: we can double "off" after + * each such step. Consider this raw input: + * 112341234123412341234 + * This will be encoded as 5 literal bytes "11234" and + * then a match tag with length 16 and offset 4. After + * memcpy'ing the first 4 bytes, we will have emitted + * 112341234 + * so we can double "off" to 8, then after the next step + * we have emitted + * 11234123412341234 + * Then we can double "off" again, after which it is more + * than the remaining "len" so we fall out of this loop + * and finish with a non-overlapping copy of the + * remainder. In general, a match tag with off < len + * implies that the decoded data has a repeat length of + * "off". We can handle 1, 2, 4, etc repetitions of the + * repeated string per memcpy until we get to a situation + * where the final copy step is non-overlapping. + * + * (Another way to understand this is that we are keeping + * the copy source point dp - off the same throughout.) + *---------- + */ + off += off; + } + memcpy(dp, dp - off, len); + dp += len; + } + else + { + /* + * An unset control bit means LITERAL BYTE. So we just copy + * one from INPUT to OUTPUT. + */ + *dp++ = *sp++; + } + + /* + * Advance the control bit + */ + ctrl >>= 1; + } + } + + /* + * If requested, check we decompressed the right amount. + */ + if (check_complete && (dp != destend || sp != srcend)) + return -1; + + /* + * That's it. + */ + return (char *) dp - dest; +} + + +/* ---------- + * pglz_maximum_compressed_size - + * + * Calculate the maximum compressed size for a given amount of raw data. + * Return the maximum size, or total compressed size if maximum size is + * larger than total compressed size. + * + * We can't use PGLZ_MAX_OUTPUT for this purpose, because that's used to size + * the compression buffer (and abort the compression). It does not really say + * what's the maximum compressed size for an input of a given length, and it + * may happen that while the whole value is compressible (and thus fits into + * PGLZ_MAX_OUTPUT nicely), the prefix is not compressible at all. + * ---------- + */ +int32 +pglz_maximum_compressed_size(int32 rawsize, int32 total_compressed_size) +{ + int64 compressed_size; + + /* + * pglz uses one control bit per byte, so if the entire desired prefix is + * represented as literal bytes, we'll need (rawsize * 9) bits. We care + * about bytes though, so be sure to round up not down. + * + * Use int64 here to prevent overflow during calculation. + */ + compressed_size = ((int64) rawsize * 9 + 7) / 8; + + /* + * The above fails to account for a corner case: we could have compressed + * data that starts with N-1 or N-2 literal bytes and then has a match tag + * of 2 or 3 bytes. It's therefore possible that we need to fetch 1 or 2 + * more bytes in order to have the whole match tag. (Match tags earlier + * in the compressed data don't cause a problem, since they should + * represent more decompressed bytes than they occupy themselves.) + */ + compressed_size += 2; + + /* + * Maximum compressed size can't be larger than total compressed size. + * (This also ensures that our result fits in int32.) + */ + compressed_size = Min(compressed_size, total_compressed_size); + + return (int32) compressed_size; +} diff --git a/contrib/libs/libpq/src/common/pg_prng.c b/contrib/libs/libpq/src/common/pg_prng.c new file mode 100644 index 0000000000..c7bb92ede3 --- /dev/null +++ b/contrib/libs/libpq/src/common/pg_prng.c @@ -0,0 +1,282 @@ +/*------------------------------------------------------------------------- + * + * Pseudo-Random Number Generator + * + * We use Blackman and Vigna's xoroshiro128** 1.0 algorithm + * to have a small, fast PRNG suitable for generating reasonably + * good-quality 64-bit data. This should not be considered + * cryptographically strong, however. + * + * About these generators: https://prng.di.unimi.it/ + * See also https://en.wikipedia.org/wiki/List_of_random_number_generators + * + * Copyright (c) 2021-2023, PostgreSQL Global Development Group + * + * src/common/pg_prng.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <math.h> + +#include "common/pg_prng.h" +#include "port/pg_bitutils.h" + +/* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +/* process-wide state vector */ +pg_prng_state pg_global_prng_state; + + +/* + * 64-bit rotate left + */ +static inline uint64 +rotl(uint64 x, int bits) +{ + return (x << bits) | (x >> (64 - bits)); +} + +/* + * The basic xoroshiro128** algorithm. + * Generates and returns a 64-bit uniformly distributed number, + * updating the state vector for next time. + * + * Note: the state vector must not be all-zeroes, as that is a fixed point. + */ +static uint64 +xoroshiro128ss(pg_prng_state *state) +{ + uint64 s0 = state->s0, + sx = state->s1 ^ s0, + val = rotl(s0 * 5, 7) * 9; + + /* update state */ + state->s0 = rotl(s0, 24) ^ sx ^ (sx << 16); + state->s1 = rotl(sx, 37); + + return val; +} + +/* + * We use this generator just to fill the xoroshiro128** state vector + * from a 64-bit seed. + */ +static uint64 +splitmix64(uint64 *state) +{ + /* state update */ + uint64 val = (*state += UINT64CONST(0x9E3779B97f4A7C15)); + + /* value extraction */ + val = (val ^ (val >> 30)) * UINT64CONST(0xBF58476D1CE4E5B9); + val = (val ^ (val >> 27)) * UINT64CONST(0x94D049BB133111EB); + + return val ^ (val >> 31); +} + +/* + * Initialize the PRNG state from a 64-bit integer, + * taking care that we don't produce all-zeroes. + */ +void +pg_prng_seed(pg_prng_state *state, uint64 seed) +{ + state->s0 = splitmix64(&seed); + state->s1 = splitmix64(&seed); + /* Let's just make sure we didn't get all-zeroes */ + (void) pg_prng_seed_check(state); +} + +/* + * Initialize the PRNG state from a double in the range [-1.0, 1.0], + * taking care that we don't produce all-zeroes. + */ +void +pg_prng_fseed(pg_prng_state *state, double fseed) +{ + /* Assume there's about 52 mantissa bits; the sign contributes too. */ + int64 seed = ((double) ((UINT64CONST(1) << 52) - 1)) * fseed; + + pg_prng_seed(state, (uint64) seed); +} + +/* + * Validate a PRNG seed value. + */ +bool +pg_prng_seed_check(pg_prng_state *state) +{ + /* + * If the seeding mechanism chanced to produce all-zeroes, insert + * something nonzero. Anything would do; use Knuth's LCG parameters. + */ + if (unlikely(state->s0 == 0 && state->s1 == 0)) + { + state->s0 = UINT64CONST(0x5851F42D4C957F2D); + state->s1 = UINT64CONST(0x14057B7EF767814F); + } + + /* As a convenience for the pg_prng_strong_seed macro, return true */ + return true; +} + +/* + * Select a random uint64 uniformly from the range [0, PG_UINT64_MAX]. + */ +uint64 +pg_prng_uint64(pg_prng_state *state) +{ + return xoroshiro128ss(state); +} + +/* + * Select a random uint64 uniformly from the range [rmin, rmax]. + * If the range is empty, rmin is always produced. + */ +uint64 +pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax) +{ + uint64 val; + + if (likely(rmax > rmin)) + { + /* + * Use bitmask rejection method to generate an offset in 0..range. + * Each generated val is less than twice "range", so on average we + * should not have to iterate more than twice. + */ + uint64 range = rmax - rmin; + uint32 rshift = 63 - pg_leftmost_one_pos64(range); + + do + { + val = xoroshiro128ss(state) >> rshift; + } while (val > range); + } + else + val = 0; + + return rmin + val; +} + +/* + * Select a random int64 uniformly from the range [PG_INT64_MIN, PG_INT64_MAX]. + */ +int64 +pg_prng_int64(pg_prng_state *state) +{ + return (int64) xoroshiro128ss(state); +} + +/* + * Select a random int64 uniformly from the range [0, PG_INT64_MAX]. + */ +int64 +pg_prng_int64p(pg_prng_state *state) +{ + return (int64) (xoroshiro128ss(state) & UINT64CONST(0x7FFFFFFFFFFFFFFF)); +} + +/* + * Select a random uint32 uniformly from the range [0, PG_UINT32_MAX]. + */ +uint32 +pg_prng_uint32(pg_prng_state *state) +{ + /* + * Although xoroshiro128** is not known to have any weaknesses in + * randomness of low-order bits, we prefer to use the upper bits of its + * result here and below. + */ + uint64 v = xoroshiro128ss(state); + + return (uint32) (v >> 32); +} + +/* + * Select a random int32 uniformly from the range [PG_INT32_MIN, PG_INT32_MAX]. + */ +int32 +pg_prng_int32(pg_prng_state *state) +{ + uint64 v = xoroshiro128ss(state); + + return (int32) (v >> 32); +} + +/* + * Select a random int32 uniformly from the range [0, PG_INT32_MAX]. + */ +int32 +pg_prng_int32p(pg_prng_state *state) +{ + uint64 v = xoroshiro128ss(state); + + return (int32) (v >> 33); +} + +/* + * Select a random double uniformly from the range [0.0, 1.0). + * + * Note: if you want a result in the range (0.0, 1.0], the standard way + * to get that is "1.0 - pg_prng_double(state)". + */ +double +pg_prng_double(pg_prng_state *state) +{ + uint64 v = xoroshiro128ss(state); + + /* + * As above, assume there's 52 mantissa bits in a double. This result + * could round to 1.0 if double's precision is less than that; but we + * assume IEEE float arithmetic elsewhere in Postgres, so this seems OK. + */ + return ldexp((double) (v >> (64 - 52)), -52); +} + +/* + * Select a random double from the normal distribution with + * mean = 0.0 and stddev = 1.0. + * + * To get a result from a different normal distribution use + * STDDEV * pg_prng_double_normal() + MEAN + * + * Uses https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + */ +double +pg_prng_double_normal(pg_prng_state *state) +{ + double u1, + u2, + z0; + + /* + * pg_prng_double generates [0, 1), but for the basic version of the + * Box-Muller transform the two uniformly distributed random numbers are + * expected to be in (0, 1]; in particular we'd better not compute log(0). + */ + u1 = 1.0 - pg_prng_double(state); + u2 = 1.0 - pg_prng_double(state); + + /* Apply Box-Muller transform to get one normal-valued output */ + z0 = sqrt(-2.0 * log(u1)) * sin(2.0 * M_PI * u2); + return z0; +} + +/* + * Select a random boolean value. + */ +bool +pg_prng_bool(pg_prng_state *state) +{ + uint64 v = xoroshiro128ss(state); + + return (bool) (v >> 63); +} diff --git a/contrib/libs/libpq/src/common/pgfnames.c b/contrib/libs/libpq/src/common/pgfnames.c new file mode 100644 index 0000000000..9d2fe9d659 --- /dev/null +++ b/contrib/libs/libpq/src/common/pgfnames.c @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * pgfnames.c + * directory handling functions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/pgfnames.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <dirent.h> + +#ifndef FRONTEND +#define pg_log_warning(...) elog(WARNING, __VA_ARGS__) +#else +#include "common/logging.h" +#endif + +/* + * pgfnames + * + * return a list of the names of objects in the argument directory. Caller + * must call pgfnames_cleanup later to free the memory allocated by this + * function. + */ +char ** +pgfnames(const char *path) +{ + DIR *dir; + struct dirent *file; + char **filenames; + int numnames = 0; + int fnsize = 200; /* enough for many small dbs */ + + dir = opendir(path); + if (dir == NULL) + { + pg_log_warning("could not open directory \"%s\": %m", path); + return NULL; + } + + filenames = (char **) palloc(fnsize * sizeof(char *)); + + while (errno = 0, (file = readdir(dir)) != NULL) + { + if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0) + { + if (numnames + 1 >= fnsize) + { + fnsize *= 2; + filenames = (char **) repalloc(filenames, + fnsize * sizeof(char *)); + } + filenames[numnames++] = pstrdup(file->d_name); + } + } + + if (errno) + pg_log_warning("could not read directory \"%s\": %m", path); + + filenames[numnames] = NULL; + + if (closedir(dir)) + pg_log_warning("could not close directory \"%s\": %m", path); + + return filenames; +} + + +/* + * pgfnames_cleanup + * + * deallocate memory used for filenames + */ +void +pgfnames_cleanup(char **filenames) +{ + char **fn; + + for (fn = filenames; *fn; fn++) + pfree(*fn); + + pfree(filenames); +} diff --git a/contrib/libs/libpq/src/common/protocol_openssl.c b/contrib/libs/libpq/src/common/protocol_openssl.c new file mode 100644 index 0000000000..089cbd33cc --- /dev/null +++ b/contrib/libs/libpq/src/common/protocol_openssl.c @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------- + * + * protocol_openssl.c + * OpenSSL functionality shared between frontend and backend + * + * This should only be used if code is compiled with OpenSSL support. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/protocol_openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/openssl.h" + +/* + * Replacements for APIs introduced in OpenSSL 1.1.0. + */ +#ifndef SSL_CTX_set_min_proto_version + +/* + * OpenSSL versions that support TLS 1.3 shouldn't get here because they + * already have these functions. So we don't have to keep updating the below + * code for every new TLS version, and eventually it can go away. But let's + * just check this to make sure ... + */ +#ifdef TLS1_3_VERSION +#error OpenSSL version mismatch +#endif + +int +SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version) +{ + int ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + + if (version > TLS1_VERSION) + ssl_options |= SSL_OP_NO_TLSv1; + + /* + * Some OpenSSL versions define TLS*_VERSION macros but not the + * corresponding SSL_OP_NO_* macro, so in those cases we have to return + * unsuccessfully here. + */ +#ifdef TLS1_1_VERSION + if (version > TLS1_1_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_1 + ssl_options |= SSL_OP_NO_TLSv1_1; +#else + return 0; +#endif + } +#endif +#ifdef TLS1_2_VERSION + if (version > TLS1_2_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_2 + ssl_options |= SSL_OP_NO_TLSv1_2; +#else + return 0; +#endif + } +#endif + + SSL_CTX_set_options(ctx, ssl_options); + + return 1; /* success */ +} + +int +SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version) +{ + int ssl_options = 0; + + Assert(version != 0); + + /* + * Some OpenSSL versions define TLS*_VERSION macros but not the + * corresponding SSL_OP_NO_* macro, so in those cases we have to return + * unsuccessfully here. + */ +#ifdef TLS1_1_VERSION + if (version < TLS1_1_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_1 + ssl_options |= SSL_OP_NO_TLSv1_1; +#else + return 0; +#endif + } +#endif +#ifdef TLS1_2_VERSION + if (version < TLS1_2_VERSION) + { +#ifdef SSL_OP_NO_TLSv1_2 + ssl_options |= SSL_OP_NO_TLSv1_2; +#else + return 0; +#endif + } +#endif + + SSL_CTX_set_options(ctx, ssl_options); + + return 1; /* success */ +} + +#endif /* !SSL_CTX_set_min_proto_version */ diff --git a/contrib/libs/libpq/src/common/psprintf.c b/contrib/libs/libpq/src/common/psprintf.c new file mode 100644 index 0000000000..c8280c0880 --- /dev/null +++ b/contrib/libs/libpq/src/common/psprintf.c @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * psprintf.c + * sprintf into an allocated-on-demand buffer + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/psprintf.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND + +#include "postgres.h" + +#error #include "utils/memutils.h" + +#else + +#include "postgres_fe.h" + +/* It's possible we could use a different value for this in frontend code */ +#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ + +#endif + + +/* + * psprintf + * + * Format text data under the control of fmt (an sprintf-style format string) + * and return it in an allocated-on-demand buffer. The buffer is allocated + * with palloc in the backend, or malloc in frontend builds. Caller is + * responsible to free the buffer when no longer needed, if appropriate. + * + * Errors are not returned to the caller, but are reported via elog(ERROR) + * in the backend, or printf-to-stderr-and-exit() in frontend builds. + * One should therefore think twice about using this in libpq. + */ +char * +psprintf(const char *fmt,...) +{ + int save_errno = errno; + size_t len = 128; /* initial assumption about buffer size */ + + for (;;) + { + char *result; + va_list args; + size_t newlen; + + /* + * Allocate result buffer. Note that in frontend this maps to malloc + * with exit-on-error. + */ + result = (char *) palloc(len); + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + newlen = pvsnprintf(result, len, fmt, args); + va_end(args); + + if (newlen < len) + return result; /* success */ + + /* Release buffer and loop around to try again with larger len. */ + pfree(result); + len = newlen; + } +} + +/* + * pvsnprintf + * + * Attempt to format text data under the control of fmt (an sprintf-style + * format string) and insert it into buf (which has length len). + * + * If successful, return the number of bytes emitted, not counting the + * trailing zero byte. This will always be strictly less than len. + * + * If there's not enough space in buf, return an estimate of the buffer size + * needed to succeed (this *must* be more than the given len, else callers + * might loop infinitely). + * + * Other error cases do not return, but exit via elog(ERROR) or exit(). + * Hence, this shouldn't be used inside libpq. + * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + * + * Note that the semantics of the return value are not exactly C99's. + * First, we don't promise that the estimated buffer size is exactly right; + * callers must be prepared to loop multiple times to get the right size. + * (Given a C99-compliant vsnprintf, that won't happen, but it is rumored + * that some implementations don't always return the same value ...) + * Second, we return the recommended buffer size, not one less than that; + * this lets overflow concerns be handled here rather than in the callers. + */ +size_t +pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) +{ + int nprinted; + + nprinted = vsnprintf(buf, len, fmt, args); + + /* We assume failure means the fmt is bogus, hence hard failure is OK */ + if (unlikely(nprinted < 0)) + { +#ifndef FRONTEND + elog(ERROR, "vsnprintf failed: %m with format string \"%s\"", fmt); +#else + fprintf(stderr, "vsnprintf failed: %s with format string \"%s\"\n", + strerror(errno), fmt); + exit(EXIT_FAILURE); +#endif + } + + if ((size_t) nprinted < len) + { + /* Success. Note nprinted does not include trailing null. */ + return (size_t) nprinted; + } + + /* + * We assume a C99-compliant vsnprintf, so believe its estimate of the + * required space, and add one for the trailing null. (If it's wrong, the + * logic will still work, but we may loop multiple times.) + * + * Choke if the required space would exceed MaxAllocSize. Note we use + * this palloc-oriented overflow limit even when in frontend. + */ + if (unlikely((size_t) nprinted > MaxAllocSize - 1)) + { +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("out of memory"))); +#else + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); +#endif + } + + return nprinted + 1; +} diff --git a/contrib/libs/libpq/src/common/relpath.c b/contrib/libs/libpq/src/common/relpath.c new file mode 100644 index 0000000000..87de5f6c96 --- /dev/null +++ b/contrib/libs/libpq/src/common/relpath.c @@ -0,0 +1,210 @@ +/*------------------------------------------------------------------------- + * relpath.c + * Shared frontend/backend code to compute pathnames of relation files + * + * This module also contains some logic associated with fork names. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/relpath.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "catalog/pg_tablespace_d.h" +#include "common/relpath.h" +#include "storage/backendid.h" + + +/* + * Lookup table of fork name by fork number. + * + * If you add a new entry, remember to update the errhint in + * forkname_to_number() below, and update the SGML documentation for + * pg_relation_size(). + */ +const char *const forkNames[] = { + "main", /* MAIN_FORKNUM */ + "fsm", /* FSM_FORKNUM */ + "vm", /* VISIBILITYMAP_FORKNUM */ + "init" /* INIT_FORKNUM */ +}; + +StaticAssertDecl(lengthof(forkNames) == (MAX_FORKNUM + 1), + "array length mismatch"); + +/* + * forkname_to_number - look up fork number by name + * + * In backend, we throw an error for no match; in frontend, we just + * return InvalidForkNumber. + */ +ForkNumber +forkname_to_number(const char *forkName) +{ + ForkNumber forkNum; + + for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++) + if (strcmp(forkNames[forkNum], forkName) == 0) + return forkNum; + +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid fork name"), + errhint("Valid fork names are \"main\", \"fsm\", " + "\"vm\", and \"init\"."))); +#endif + + return InvalidForkNumber; +} + +/* + * forkname_chars + * We use this to figure out whether a filename could be a relation + * fork (as opposed to an oddly named stray file that somehow ended + * up in the database directory). If the passed string begins with + * a fork name (other than the main fork name), we return its length, + * and set *fork (if not NULL) to the fork number. If not, we return 0. + * + * Note that the present coding assumes that there are no fork names which + * are prefixes of other fork names. + */ +int +forkname_chars(const char *str, ForkNumber *fork) +{ + ForkNumber forkNum; + + for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++) + { + int len = strlen(forkNames[forkNum]); + + if (strncmp(forkNames[forkNum], str, len) == 0) + { + if (fork) + *fork = forkNum; + return len; + } + } + if (fork) + *fork = InvalidForkNumber; + return 0; +} + + +/* + * GetDatabasePath - construct path to a database directory + * + * Result is a palloc'd string. + * + * XXX this must agree with GetRelationPath()! + */ +char * +GetDatabasePath(Oid dbOid, Oid spcOid) +{ + if (spcOid == GLOBALTABLESPACE_OID) + { + /* Shared system relations live in {datadir}/global */ + Assert(dbOid == 0); + return pstrdup("global"); + } + else if (spcOid == DEFAULTTABLESPACE_OID) + { + /* The default tablespace is {datadir}/base */ + return psprintf("base/%u", dbOid); + } + else + { + /* All other tablespaces are accessed via symlinks */ + return psprintf("pg_tblspc/%u/%s/%u", + spcOid, TABLESPACE_VERSION_DIRECTORY, dbOid); + } +} + +/* + * GetRelationPath - construct path to a relation's file + * + * Result is a palloc'd string. + * + * Note: ideally, backendId would be declared as type BackendId, but relpath.h + * would have to include a backend-only header to do that; doesn't seem worth + * the trouble considering BackendId is just int anyway. + */ +char * +GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber, + int backendId, ForkNumber forkNumber) +{ + char *path; + + if (spcOid == GLOBALTABLESPACE_OID) + { + /* Shared system relations live in {datadir}/global */ + Assert(dbOid == 0); + Assert(backendId == InvalidBackendId); + if (forkNumber != MAIN_FORKNUM) + path = psprintf("global/%u_%s", + relNumber, forkNames[forkNumber]); + else + path = psprintf("global/%u", relNumber); + } + else if (spcOid == DEFAULTTABLESPACE_OID) + { + /* The default tablespace is {datadir}/base */ + if (backendId == InvalidBackendId) + { + if (forkNumber != MAIN_FORKNUM) + path = psprintf("base/%u/%u_%s", + dbOid, relNumber, + forkNames[forkNumber]); + else + path = psprintf("base/%u/%u", + dbOid, relNumber); + } + else + { + if (forkNumber != MAIN_FORKNUM) + path = psprintf("base/%u/t%d_%u_%s", + dbOid, backendId, relNumber, + forkNames[forkNumber]); + else + path = psprintf("base/%u/t%d_%u", + dbOid, backendId, relNumber); + } + } + else + { + /* All other tablespaces are accessed via symlinks */ + if (backendId == InvalidBackendId) + { + if (forkNumber != MAIN_FORKNUM) + path = psprintf("pg_tblspc/%u/%s/%u/%u_%s", + spcOid, TABLESPACE_VERSION_DIRECTORY, + dbOid, relNumber, + forkNames[forkNumber]); + else + path = psprintf("pg_tblspc/%u/%s/%u/%u", + spcOid, TABLESPACE_VERSION_DIRECTORY, + dbOid, relNumber); + } + else + { + if (forkNumber != MAIN_FORKNUM) + path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s", + spcOid, TABLESPACE_VERSION_DIRECTORY, + dbOid, backendId, relNumber, + forkNames[forkNumber]); + else + path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u", + spcOid, TABLESPACE_VERSION_DIRECTORY, + dbOid, backendId, relNumber); + } + } + return path; +} diff --git a/contrib/libs/libpq/src/common/restricted_token.c b/contrib/libs/libpq/src/common/restricted_token.c new file mode 100644 index 0000000000..4ae1ed1e8a --- /dev/null +++ b/contrib/libs/libpq/src/common/restricted_token.c @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------- + * + * restricted_token.c + * helper routine to ensure restricted token on Windows + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/restricted_token.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#error "This file is not expected to be compiled for backend code" +#endif + +#include "postgres_fe.h" + +#include "common/logging.h" +#include "common/restricted_token.h" + +#ifdef WIN32 + +/* internal vars */ +char *restrict_env; + +/* Windows API define missing from some versions of MingW headers */ +#ifndef DISABLE_MAX_PRIVILEGE +#define DISABLE_MAX_PRIVILEGE 0x1 +#endif + +/* + * Create a restricted token and execute the specified process with it. + * + * Returns restricted token on success and 0 on failure. + * + * On any system not containing the required functions, do nothing + * but still report an error. + */ +HANDLE +CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo) +{ + BOOL b; + STARTUPINFO si; + HANDLE origToken; + HANDLE restrictedToken; + SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; + SID_AND_ATTRIBUTES dropSids[2]; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + /* Open the current token to use as a base for the restricted one */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken)) + { + pg_log_error("could not open process token: error code %lu", + GetLastError()); + return 0; + } + + /* Allocate list of SIDs to remove */ + ZeroMemory(&dropSids, sizeof(dropSids)); + if (!AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, + 0, &dropSids[0].Sid) || + !AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, + 0, &dropSids[1].Sid)) + { + pg_log_error("could not allocate SIDs: error code %lu", + GetLastError()); + CloseHandle(origToken); + return 0; + } + + b = CreateRestrictedToken(origToken, + DISABLE_MAX_PRIVILEGE, + sizeof(dropSids) / sizeof(dropSids[0]), + dropSids, + 0, NULL, + 0, NULL, + &restrictedToken); + + FreeSid(dropSids[1].Sid); + FreeSid(dropSids[0].Sid); + CloseHandle(origToken); + + if (!b) + { + pg_log_error("could not create restricted token: error code %lu", GetLastError()); + return 0; + } + +#ifndef __CYGWIN__ + AddUserToTokenDacl(restrictedToken); +#endif + + if (!CreateProcessAsUser(restrictedToken, + NULL, + cmd, + NULL, + NULL, + TRUE, + CREATE_SUSPENDED, + NULL, + NULL, + &si, + processInfo)) + + { + pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError()); + return 0; + } + + ResumeThread(processInfo->hThread); + return restrictedToken; +} +#endif + +/* + * On Windows make sure that we are running with a restricted token, + * On other platforms do nothing. + */ +void +get_restricted_token(void) +{ +#ifdef WIN32 + HANDLE restrictedToken; + + /* + * Before we execute another program, make sure that we are running with a + * restricted token. If not, re-execute ourselves with one. + */ + + if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL + || strcmp(restrict_env, "1") != 0) + { + PROCESS_INFORMATION pi; + char *cmdline; + + ZeroMemory(&pi, sizeof(pi)); + + cmdline = pg_strdup(GetCommandLine()); + + setenv("PG_RESTRICT_EXEC", "1", 1); + + if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0) + { + pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError()); + } + else + { + /* + * Successfully re-executed. Now wait for child process to capture + * the exit code. + */ + DWORD x; + + CloseHandle(restrictedToken); + CloseHandle(pi.hThread); + WaitForSingleObject(pi.hProcess, INFINITE); + + if (!GetExitCodeProcess(pi.hProcess, &x)) + pg_fatal("could not get exit code from subprocess: error code %lu", GetLastError()); + exit(x); + } + pg_free(cmdline); + } +#endif +} diff --git a/contrib/libs/libpq/src/common/rmtree.c b/contrib/libs/libpq/src/common/rmtree.c new file mode 100644 index 0000000000..9d0c32955a --- /dev/null +++ b/contrib/libs/libpq/src/common/rmtree.c @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- + * + * rmtree.c + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/rmtree.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <unistd.h> +#include <sys/stat.h> + +#include "common/file_utils.h" + +#ifndef FRONTEND +#error #include "storage/fd.h" +#define pg_log_warning(...) elog(WARNING, __VA_ARGS__) +#define LOG_LEVEL WARNING +#define OPENDIR(x) AllocateDir(x) +#define CLOSEDIR(x) FreeDir(x) +#else +#include "common/logging.h" +#define LOG_LEVEL PG_LOG_WARNING +#define OPENDIR(x) opendir(x) +#define CLOSEDIR(x) closedir(x) +#endif + +/* + * rmtree + * + * Delete a directory tree recursively. + * Assumes path points to a valid directory. + * Deletes everything under path. + * If rmtopdir is true deletes the directory too. + * Returns true if successful, false if there was any problem. + * (The details of the problem are reported already, so caller + * doesn't really have to say anything more, but most do.) + */ +bool +rmtree(const char *path, bool rmtopdir) +{ + char pathbuf[MAXPGPATH]; + DIR *dir; + struct dirent *de; + bool result = true; + size_t dirnames_size = 0; + size_t dirnames_capacity = 8; + char **dirnames = palloc(sizeof(char *) * dirnames_capacity); + + dir = OPENDIR(path); + if (dir == NULL) + { + pg_log_warning("could not open directory \"%s\": %m", path); + return false; + } + + while (errno = 0, (de = readdir(dir))) + { + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name); + switch (get_dirent_type(pathbuf, de, false, LOG_LEVEL)) + { + case PGFILETYPE_ERROR: + /* already logged, press on */ + break; + case PGFILETYPE_DIR: + + /* + * Defer recursion until after we've closed this directory, to + * avoid using more than one file descriptor at a time. + */ + if (dirnames_size == dirnames_capacity) + { + dirnames = repalloc(dirnames, + sizeof(char *) * dirnames_capacity * 2); + dirnames_capacity *= 2; + } + dirnames[dirnames_size++] = pstrdup(pathbuf); + break; + default: + if (unlink(pathbuf) != 0 && errno != ENOENT) + { + pg_log_warning("could not remove file \"%s\": %m", pathbuf); + result = false; + } + break; + } + } + + if (errno != 0) + { + pg_log_warning("could not read directory \"%s\": %m", path); + result = false; + } + + CLOSEDIR(dir); + + /* Now recurse into the subdirectories we found. */ + for (size_t i = 0; i < dirnames_size; ++i) + { + if (!rmtree(dirnames[i], true)) + result = false; + pfree(dirnames[i]); + } + + if (rmtopdir) + { + if (rmdir(path) != 0) + { + pg_log_warning("could not remove directory \"%s\": %m", path); + result = false; + } + } + + pfree(dirnames); + + return result; +} diff --git a/contrib/libs/libpq/src/common/ryu_common.h b/contrib/libs/libpq/src/common/ryu_common.h new file mode 100644 index 0000000000..ad850acf62 --- /dev/null +++ b/contrib/libs/libpq/src/common/ryu_common.h @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------------------- + * + * Common routines for Ryu floating-point output. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/ryu_common.h + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ +#ifndef RYU_COMMON_H +#define RYU_COMMON_H + +/* + * Upstream Ryu's output is always the shortest possible. But we adjust that + * slightly to improve portability: we avoid outputting the exact midpoint + * value between two representable floats, since that relies on the reader + * getting the round-to-even rule correct, which seems to be the common + * failure mode. + * + * Defining this to 1 would restore the upstream behavior. + */ +#define STRICTLY_SHORTEST 0 + +#if SIZEOF_SIZE_T < 8 +#define RYU_32_BIT_PLATFORM +#endif + +/* Returns e == 0 ? 1 : ceil(log_2(5^e)). */ +static inline uint32 +pow5bits(const int32 e) +{ + /* + * This approximation works up to the point that the multiplication + * overflows at e = 3529. + * + * If the multiplication were done in 64 bits, it would fail at 5^4004 + * which is just greater than 2^9297. + */ + Assert(e >= 0); + Assert(e <= 3528); + return ((((uint32) e) * 1217359) >> 19) + 1; +} + +/* Returns floor(log_10(2^e)). */ +static inline int32 +log10Pow2(const int32 e) +{ + /* + * The first value this approximation fails for is 2^1651 which is just + * greater than 10^297. + */ + Assert(e >= 0); + Assert(e <= 1650); + return (int32) ((((uint32) e) * 78913) >> 18); +} + +/* Returns floor(log_10(5^e)). */ +static inline int32 +log10Pow5(const int32 e) +{ + /* + * The first value this approximation fails for is 5^2621 which is just + * greater than 10^1832. + */ + Assert(e >= 0); + Assert(e <= 2620); + return (int32) ((((uint32) e) * 732923) >> 20); +} + +static inline int +copy_special_str(char *const result, const bool sign, const bool exponent, const bool mantissa) +{ + if (mantissa) + { + memcpy(result, "NaN", 3); + return 3; + } + if (sign) + { + result[0] = '-'; + } + if (exponent) + { + memcpy(result + sign, "Infinity", 8); + return sign + 8; + } + result[sign] = '0'; + return sign + 1; +} + +static inline uint32 +float_to_bits(const float f) +{ + uint32 bits = 0; + + memcpy(&bits, &f, sizeof(float)); + return bits; +} + +static inline uint64 +double_to_bits(const double d) +{ + uint64 bits = 0; + + memcpy(&bits, &d, sizeof(double)); + return bits; +} + +#endif /* RYU_COMMON_H */ diff --git a/contrib/libs/libpq/src/common/saslprep.c b/contrib/libs/libpq/src/common/saslprep.c new file mode 100644 index 0000000000..3cf498866a --- /dev/null +++ b/contrib/libs/libpq/src/common/saslprep.c @@ -0,0 +1,1245 @@ +/*------------------------------------------------------------------------- + * saslprep.c + * SASLprep normalization, for SCRAM authentication + * + * The SASLprep algorithm is used to process a user-supplied password into + * canonical form. For more details, see: + * + * [RFC3454] Preparation of Internationalized Strings ("stringprep"), + * http://www.ietf.org/rfc/rfc3454.txt + * + * [RFC4013] SASLprep: Stringprep Profile for User Names and Passwords + * http://www.ietf.org/rfc/rfc4013.txt + * + * + * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/saslprep.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/saslprep.h" +#include "common/string.h" +#include "common/unicode_norm.h" +#include "mb/pg_wchar.h" + +/* + * In backend, we will use palloc/pfree. In frontend, use malloc, and + * return SASLPREP_OOM on out-of-memory. + */ +#ifndef FRONTEND +#define STRDUP(s) pstrdup(s) +#define ALLOC(size) palloc(size) +#define FREE(size) pfree(size) +#else +#define STRDUP(s) strdup(s) +#define ALLOC(size) malloc(size) +#define FREE(size) free(size) +#endif + +/* Prototypes for local functions */ +static int codepoint_range_cmp(const void *a, const void *b); +static bool is_code_in_table(pg_wchar code, const pg_wchar *map, int mapsize); +static int pg_utf8_string_len(const char *source); + +/* + * Stringprep Mapping Tables. + * + * The stringprep specification includes a number of tables of Unicode + * codepoints, used in different parts of the algorithm. They are below, + * as arrays of codepoint ranges. Each range is a pair of codepoints, + * for the first and last codepoint included the range (inclusive!). + */ + +/* + * C.1.2 Non-ASCII space characters + * + * These are all mapped to the ASCII space character (U+00A0). + */ +static const pg_wchar non_ascii_space_ranges[] = +{ + 0x00A0, 0x00A0, + 0x1680, 0x1680, + 0x2000, 0x200B, + 0x202F, 0x202F, + 0x205F, 0x205F, + 0x3000, 0x3000 +}; + +/* + * B.1 Commonly mapped to nothing + * + * If any of these appear in the input, they are removed. + */ +static const pg_wchar commonly_mapped_to_nothing_ranges[] = +{ + 0x00AD, 0x00AD, + 0x034F, 0x034F, + 0x1806, 0x1806, + 0x180B, 0x180D, + 0x200B, 0x200D, + 0x2060, 0x2060, + 0xFE00, 0xFE0F, + 0xFEFF, 0xFEFF +}; + +/* + * prohibited_output_ranges is a union of all the characters from + * the following tables: + * + * C.1.2 Non-ASCII space characters + * C.2.1 ASCII control characters + * C.2.2 Non-ASCII control characters + * C.3 Private Use characters + * C.4 Non-character code points + * C.5 Surrogate code points + * C.6 Inappropriate for plain text characters + * C.7 Inappropriate for canonical representation characters + * C.7 Change display properties or deprecated characters + * C.8 Tagging characters + * + * These are the tables that are listed as "prohibited output" + * characters in the SASLprep profile. + * + * The comment after each code range indicates which source table + * the code came from. Note that there is some overlap in the source + * tables, so one code might originate from multiple source tables. + * Adjacent ranges have also been merged together, to save space. + */ +static const pg_wchar prohibited_output_ranges[] = +{ + 0x0000, 0x001F, /* C.2.1 */ + 0x007F, 0x00A0, /* C.1.2, C.2.1, C.2.2 */ + 0x0340, 0x0341, /* C.8 */ + 0x06DD, 0x06DD, /* C.2.2 */ + 0x070F, 0x070F, /* C.2.2 */ + 0x1680, 0x1680, /* C.1.2 */ + 0x180E, 0x180E, /* C.2.2 */ + 0x2000, 0x200F, /* C.1.2, C.2.2, C.8 */ + 0x2028, 0x202F, /* C.1.2, C.2.2, C.8 */ + 0x205F, 0x2063, /* C.1.2, C.2.2 */ + 0x206A, 0x206F, /* C.2.2, C.8 */ + 0x2FF0, 0x2FFB, /* C.7 */ + 0x3000, 0x3000, /* C.1.2 */ + 0xD800, 0xF8FF, /* C.3, C.5 */ + 0xFDD0, 0xFDEF, /* C.4 */ + 0xFEFF, 0xFEFF, /* C.2.2 */ + 0xFFF9, 0xFFFF, /* C.2.2, C.4, C.6 */ + 0x1D173, 0x1D17A, /* C.2.2 */ + 0x1FFFE, 0x1FFFF, /* C.4 */ + 0x2FFFE, 0x2FFFF, /* C.4 */ + 0x3FFFE, 0x3FFFF, /* C.4 */ + 0x4FFFE, 0x4FFFF, /* C.4 */ + 0x5FFFE, 0x5FFFF, /* C.4 */ + 0x6FFFE, 0x6FFFF, /* C.4 */ + 0x7FFFE, 0x7FFFF, /* C.4 */ + 0x8FFFE, 0x8FFFF, /* C.4 */ + 0x9FFFE, 0x9FFFF, /* C.4 */ + 0xAFFFE, 0xAFFFF, /* C.4 */ + 0xBFFFE, 0xBFFFF, /* C.4 */ + 0xCFFFE, 0xCFFFF, /* C.4 */ + 0xDFFFE, 0xDFFFF, /* C.4 */ + 0xE0001, 0xE0001, /* C.9 */ + 0xE0020, 0xE007F, /* C.9 */ + 0xEFFFE, 0xEFFFF, /* C.4 */ + 0xF0000, 0xFFFFF, /* C.3, C.4 */ + 0x100000, 0x10FFFF /* C.3, C.4 */ +}; + +/* A.1 Unassigned code points in Unicode 3.2 */ +static const pg_wchar unassigned_codepoint_ranges[] = +{ + 0x0221, 0x0221, + 0x0234, 0x024F, + 0x02AE, 0x02AF, + 0x02EF, 0x02FF, + 0x0350, 0x035F, + 0x0370, 0x0373, + 0x0376, 0x0379, + 0x037B, 0x037D, + 0x037F, 0x0383, + 0x038B, 0x038B, + 0x038D, 0x038D, + 0x03A2, 0x03A2, + 0x03CF, 0x03CF, + 0x03F7, 0x03FF, + 0x0487, 0x0487, + 0x04CF, 0x04CF, + 0x04F6, 0x04F7, + 0x04FA, 0x04FF, + 0x0510, 0x0530, + 0x0557, 0x0558, + 0x0560, 0x0560, + 0x0588, 0x0588, + 0x058B, 0x0590, + 0x05A2, 0x05A2, + 0x05BA, 0x05BA, + 0x05C5, 0x05CF, + 0x05EB, 0x05EF, + 0x05F5, 0x060B, + 0x060D, 0x061A, + 0x061C, 0x061E, + 0x0620, 0x0620, + 0x063B, 0x063F, + 0x0656, 0x065F, + 0x06EE, 0x06EF, + 0x06FF, 0x06FF, + 0x070E, 0x070E, + 0x072D, 0x072F, + 0x074B, 0x077F, + 0x07B2, 0x0900, + 0x0904, 0x0904, + 0x093A, 0x093B, + 0x094E, 0x094F, + 0x0955, 0x0957, + 0x0971, 0x0980, + 0x0984, 0x0984, + 0x098D, 0x098E, + 0x0991, 0x0992, + 0x09A9, 0x09A9, + 0x09B1, 0x09B1, + 0x09B3, 0x09B5, + 0x09BA, 0x09BB, + 0x09BD, 0x09BD, + 0x09C5, 0x09C6, + 0x09C9, 0x09CA, + 0x09CE, 0x09D6, + 0x09D8, 0x09DB, + 0x09DE, 0x09DE, + 0x09E4, 0x09E5, + 0x09FB, 0x0A01, + 0x0A03, 0x0A04, + 0x0A0B, 0x0A0E, + 0x0A11, 0x0A12, + 0x0A29, 0x0A29, + 0x0A31, 0x0A31, + 0x0A34, 0x0A34, + 0x0A37, 0x0A37, + 0x0A3A, 0x0A3B, + 0x0A3D, 0x0A3D, + 0x0A43, 0x0A46, + 0x0A49, 0x0A4A, + 0x0A4E, 0x0A58, + 0x0A5D, 0x0A5D, + 0x0A5F, 0x0A65, + 0x0A75, 0x0A80, + 0x0A84, 0x0A84, + 0x0A8C, 0x0A8C, + 0x0A8E, 0x0A8E, + 0x0A92, 0x0A92, + 0x0AA9, 0x0AA9, + 0x0AB1, 0x0AB1, + 0x0AB4, 0x0AB4, + 0x0ABA, 0x0ABB, + 0x0AC6, 0x0AC6, + 0x0ACA, 0x0ACA, + 0x0ACE, 0x0ACF, + 0x0AD1, 0x0ADF, + 0x0AE1, 0x0AE5, + 0x0AF0, 0x0B00, + 0x0B04, 0x0B04, + 0x0B0D, 0x0B0E, + 0x0B11, 0x0B12, + 0x0B29, 0x0B29, + 0x0B31, 0x0B31, + 0x0B34, 0x0B35, + 0x0B3A, 0x0B3B, + 0x0B44, 0x0B46, + 0x0B49, 0x0B4A, + 0x0B4E, 0x0B55, + 0x0B58, 0x0B5B, + 0x0B5E, 0x0B5E, + 0x0B62, 0x0B65, + 0x0B71, 0x0B81, + 0x0B84, 0x0B84, + 0x0B8B, 0x0B8D, + 0x0B91, 0x0B91, + 0x0B96, 0x0B98, + 0x0B9B, 0x0B9B, + 0x0B9D, 0x0B9D, + 0x0BA0, 0x0BA2, + 0x0BA5, 0x0BA7, + 0x0BAB, 0x0BAD, + 0x0BB6, 0x0BB6, + 0x0BBA, 0x0BBD, + 0x0BC3, 0x0BC5, + 0x0BC9, 0x0BC9, + 0x0BCE, 0x0BD6, + 0x0BD8, 0x0BE6, + 0x0BF3, 0x0C00, + 0x0C04, 0x0C04, + 0x0C0D, 0x0C0D, + 0x0C11, 0x0C11, + 0x0C29, 0x0C29, + 0x0C34, 0x0C34, + 0x0C3A, 0x0C3D, + 0x0C45, 0x0C45, + 0x0C49, 0x0C49, + 0x0C4E, 0x0C54, + 0x0C57, 0x0C5F, + 0x0C62, 0x0C65, + 0x0C70, 0x0C81, + 0x0C84, 0x0C84, + 0x0C8D, 0x0C8D, + 0x0C91, 0x0C91, + 0x0CA9, 0x0CA9, + 0x0CB4, 0x0CB4, + 0x0CBA, 0x0CBD, + 0x0CC5, 0x0CC5, + 0x0CC9, 0x0CC9, + 0x0CCE, 0x0CD4, + 0x0CD7, 0x0CDD, + 0x0CDF, 0x0CDF, + 0x0CE2, 0x0CE5, + 0x0CF0, 0x0D01, + 0x0D04, 0x0D04, + 0x0D0D, 0x0D0D, + 0x0D11, 0x0D11, + 0x0D29, 0x0D29, + 0x0D3A, 0x0D3D, + 0x0D44, 0x0D45, + 0x0D49, 0x0D49, + 0x0D4E, 0x0D56, + 0x0D58, 0x0D5F, + 0x0D62, 0x0D65, + 0x0D70, 0x0D81, + 0x0D84, 0x0D84, + 0x0D97, 0x0D99, + 0x0DB2, 0x0DB2, + 0x0DBC, 0x0DBC, + 0x0DBE, 0x0DBF, + 0x0DC7, 0x0DC9, + 0x0DCB, 0x0DCE, + 0x0DD5, 0x0DD5, + 0x0DD7, 0x0DD7, + 0x0DE0, 0x0DF1, + 0x0DF5, 0x0E00, + 0x0E3B, 0x0E3E, + 0x0E5C, 0x0E80, + 0x0E83, 0x0E83, + 0x0E85, 0x0E86, + 0x0E89, 0x0E89, + 0x0E8B, 0x0E8C, + 0x0E8E, 0x0E93, + 0x0E98, 0x0E98, + 0x0EA0, 0x0EA0, + 0x0EA4, 0x0EA4, + 0x0EA6, 0x0EA6, + 0x0EA8, 0x0EA9, + 0x0EAC, 0x0EAC, + 0x0EBA, 0x0EBA, + 0x0EBE, 0x0EBF, + 0x0EC5, 0x0EC5, + 0x0EC7, 0x0EC7, + 0x0ECE, 0x0ECF, + 0x0EDA, 0x0EDB, + 0x0EDE, 0x0EFF, + 0x0F48, 0x0F48, + 0x0F6B, 0x0F70, + 0x0F8C, 0x0F8F, + 0x0F98, 0x0F98, + 0x0FBD, 0x0FBD, + 0x0FCD, 0x0FCE, + 0x0FD0, 0x0FFF, + 0x1022, 0x1022, + 0x1028, 0x1028, + 0x102B, 0x102B, + 0x1033, 0x1035, + 0x103A, 0x103F, + 0x105A, 0x109F, + 0x10C6, 0x10CF, + 0x10F9, 0x10FA, + 0x10FC, 0x10FF, + 0x115A, 0x115E, + 0x11A3, 0x11A7, + 0x11FA, 0x11FF, + 0x1207, 0x1207, + 0x1247, 0x1247, + 0x1249, 0x1249, + 0x124E, 0x124F, + 0x1257, 0x1257, + 0x1259, 0x1259, + 0x125E, 0x125F, + 0x1287, 0x1287, + 0x1289, 0x1289, + 0x128E, 0x128F, + 0x12AF, 0x12AF, + 0x12B1, 0x12B1, + 0x12B6, 0x12B7, + 0x12BF, 0x12BF, + 0x12C1, 0x12C1, + 0x12C6, 0x12C7, + 0x12CF, 0x12CF, + 0x12D7, 0x12D7, + 0x12EF, 0x12EF, + 0x130F, 0x130F, + 0x1311, 0x1311, + 0x1316, 0x1317, + 0x131F, 0x131F, + 0x1347, 0x1347, + 0x135B, 0x1360, + 0x137D, 0x139F, + 0x13F5, 0x1400, + 0x1677, 0x167F, + 0x169D, 0x169F, + 0x16F1, 0x16FF, + 0x170D, 0x170D, + 0x1715, 0x171F, + 0x1737, 0x173F, + 0x1754, 0x175F, + 0x176D, 0x176D, + 0x1771, 0x1771, + 0x1774, 0x177F, + 0x17DD, 0x17DF, + 0x17EA, 0x17FF, + 0x180F, 0x180F, + 0x181A, 0x181F, + 0x1878, 0x187F, + 0x18AA, 0x1DFF, + 0x1E9C, 0x1E9F, + 0x1EFA, 0x1EFF, + 0x1F16, 0x1F17, + 0x1F1E, 0x1F1F, + 0x1F46, 0x1F47, + 0x1F4E, 0x1F4F, + 0x1F58, 0x1F58, + 0x1F5A, 0x1F5A, + 0x1F5C, 0x1F5C, + 0x1F5E, 0x1F5E, + 0x1F7E, 0x1F7F, + 0x1FB5, 0x1FB5, + 0x1FC5, 0x1FC5, + 0x1FD4, 0x1FD5, + 0x1FDC, 0x1FDC, + 0x1FF0, 0x1FF1, + 0x1FF5, 0x1FF5, + 0x1FFF, 0x1FFF, + 0x2053, 0x2056, + 0x2058, 0x205E, + 0x2064, 0x2069, + 0x2072, 0x2073, + 0x208F, 0x209F, + 0x20B2, 0x20CF, + 0x20EB, 0x20FF, + 0x213B, 0x213C, + 0x214C, 0x2152, + 0x2184, 0x218F, + 0x23CF, 0x23FF, + 0x2427, 0x243F, + 0x244B, 0x245F, + 0x24FF, 0x24FF, + 0x2614, 0x2615, + 0x2618, 0x2618, + 0x267E, 0x267F, + 0x268A, 0x2700, + 0x2705, 0x2705, + 0x270A, 0x270B, + 0x2728, 0x2728, + 0x274C, 0x274C, + 0x274E, 0x274E, + 0x2753, 0x2755, + 0x2757, 0x2757, + 0x275F, 0x2760, + 0x2795, 0x2797, + 0x27B0, 0x27B0, + 0x27BF, 0x27CF, + 0x27EC, 0x27EF, + 0x2B00, 0x2E7F, + 0x2E9A, 0x2E9A, + 0x2EF4, 0x2EFF, + 0x2FD6, 0x2FEF, + 0x2FFC, 0x2FFF, + 0x3040, 0x3040, + 0x3097, 0x3098, + 0x3100, 0x3104, + 0x312D, 0x3130, + 0x318F, 0x318F, + 0x31B8, 0x31EF, + 0x321D, 0x321F, + 0x3244, 0x3250, + 0x327C, 0x327E, + 0x32CC, 0x32CF, + 0x32FF, 0x32FF, + 0x3377, 0x337A, + 0x33DE, 0x33DF, + 0x33FF, 0x33FF, + 0x4DB6, 0x4DFF, + 0x9FA6, 0x9FFF, + 0xA48D, 0xA48F, + 0xA4C7, 0xABFF, + 0xD7A4, 0xD7FF, + 0xFA2E, 0xFA2F, + 0xFA6B, 0xFAFF, + 0xFB07, 0xFB12, + 0xFB18, 0xFB1C, + 0xFB37, 0xFB37, + 0xFB3D, 0xFB3D, + 0xFB3F, 0xFB3F, + 0xFB42, 0xFB42, + 0xFB45, 0xFB45, + 0xFBB2, 0xFBD2, + 0xFD40, 0xFD4F, + 0xFD90, 0xFD91, + 0xFDC8, 0xFDCF, + 0xFDFD, 0xFDFF, + 0xFE10, 0xFE1F, + 0xFE24, 0xFE2F, + 0xFE47, 0xFE48, + 0xFE53, 0xFE53, + 0xFE67, 0xFE67, + 0xFE6C, 0xFE6F, + 0xFE75, 0xFE75, + 0xFEFD, 0xFEFE, + 0xFF00, 0xFF00, + 0xFFBF, 0xFFC1, + 0xFFC8, 0xFFC9, + 0xFFD0, 0xFFD1, + 0xFFD8, 0xFFD9, + 0xFFDD, 0xFFDF, + 0xFFE7, 0xFFE7, + 0xFFEF, 0xFFF8, + 0x10000, 0x102FF, + 0x1031F, 0x1031F, + 0x10324, 0x1032F, + 0x1034B, 0x103FF, + 0x10426, 0x10427, + 0x1044E, 0x1CFFF, + 0x1D0F6, 0x1D0FF, + 0x1D127, 0x1D129, + 0x1D1DE, 0x1D3FF, + 0x1D455, 0x1D455, + 0x1D49D, 0x1D49D, + 0x1D4A0, 0x1D4A1, + 0x1D4A3, 0x1D4A4, + 0x1D4A7, 0x1D4A8, + 0x1D4AD, 0x1D4AD, + 0x1D4BA, 0x1D4BA, + 0x1D4BC, 0x1D4BC, + 0x1D4C1, 0x1D4C1, + 0x1D4C4, 0x1D4C4, + 0x1D506, 0x1D506, + 0x1D50B, 0x1D50C, + 0x1D515, 0x1D515, + 0x1D51D, 0x1D51D, + 0x1D53A, 0x1D53A, + 0x1D53F, 0x1D53F, + 0x1D545, 0x1D545, + 0x1D547, 0x1D549, + 0x1D551, 0x1D551, + 0x1D6A4, 0x1D6A7, + 0x1D7CA, 0x1D7CD, + 0x1D800, 0x1FFFD, + 0x2A6D7, 0x2F7FF, + 0x2FA1E, 0x2FFFD, + 0x30000, 0x3FFFD, + 0x40000, 0x4FFFD, + 0x50000, 0x5FFFD, + 0x60000, 0x6FFFD, + 0x70000, 0x7FFFD, + 0x80000, 0x8FFFD, + 0x90000, 0x9FFFD, + 0xA0000, 0xAFFFD, + 0xB0000, 0xBFFFD, + 0xC0000, 0xCFFFD, + 0xD0000, 0xDFFFD, + 0xE0000, 0xE0000, + 0xE0002, 0xE001F, + 0xE0080, 0xEFFFD +}; + +/* D.1 Characters with bidirectional property "R" or "AL" */ +static const pg_wchar RandALCat_codepoint_ranges[] = +{ + 0x05BE, 0x05BE, + 0x05C0, 0x05C0, + 0x05C3, 0x05C3, + 0x05D0, 0x05EA, + 0x05F0, 0x05F4, + 0x061B, 0x061B, + 0x061F, 0x061F, + 0x0621, 0x063A, + 0x0640, 0x064A, + 0x066D, 0x066F, + 0x0671, 0x06D5, + 0x06DD, 0x06DD, + 0x06E5, 0x06E6, + 0x06FA, 0x06FE, + 0x0700, 0x070D, + 0x0710, 0x0710, + 0x0712, 0x072C, + 0x0780, 0x07A5, + 0x07B1, 0x07B1, + 0x200F, 0x200F, + 0xFB1D, 0xFB1D, + 0xFB1F, 0xFB28, + 0xFB2A, 0xFB36, + 0xFB38, 0xFB3C, + 0xFB3E, 0xFB3E, + 0xFB40, 0xFB41, + 0xFB43, 0xFB44, + 0xFB46, 0xFBB1, + 0xFBD3, 0xFD3D, + 0xFD50, 0xFD8F, + 0xFD92, 0xFDC7, + 0xFDF0, 0xFDFC, + 0xFE70, 0xFE74, + 0xFE76, 0xFEFC +}; + +/* D.2 Characters with bidirectional property "L" */ +static const pg_wchar LCat_codepoint_ranges[] = +{ + 0x0041, 0x005A, + 0x0061, 0x007A, + 0x00AA, 0x00AA, + 0x00B5, 0x00B5, + 0x00BA, 0x00BA, + 0x00C0, 0x00D6, + 0x00D8, 0x00F6, + 0x00F8, 0x0220, + 0x0222, 0x0233, + 0x0250, 0x02AD, + 0x02B0, 0x02B8, + 0x02BB, 0x02C1, + 0x02D0, 0x02D1, + 0x02E0, 0x02E4, + 0x02EE, 0x02EE, + 0x037A, 0x037A, + 0x0386, 0x0386, + 0x0388, 0x038A, + 0x038C, 0x038C, + 0x038E, 0x03A1, + 0x03A3, 0x03CE, + 0x03D0, 0x03F5, + 0x0400, 0x0482, + 0x048A, 0x04CE, + 0x04D0, 0x04F5, + 0x04F8, 0x04F9, + 0x0500, 0x050F, + 0x0531, 0x0556, + 0x0559, 0x055F, + 0x0561, 0x0587, + 0x0589, 0x0589, + 0x0903, 0x0903, + 0x0905, 0x0939, + 0x093D, 0x0940, + 0x0949, 0x094C, + 0x0950, 0x0950, + 0x0958, 0x0961, + 0x0964, 0x0970, + 0x0982, 0x0983, + 0x0985, 0x098C, + 0x098F, 0x0990, + 0x0993, 0x09A8, + 0x09AA, 0x09B0, + 0x09B2, 0x09B2, + 0x09B6, 0x09B9, + 0x09BE, 0x09C0, + 0x09C7, 0x09C8, + 0x09CB, 0x09CC, + 0x09D7, 0x09D7, + 0x09DC, 0x09DD, + 0x09DF, 0x09E1, + 0x09E6, 0x09F1, + 0x09F4, 0x09FA, + 0x0A05, 0x0A0A, + 0x0A0F, 0x0A10, + 0x0A13, 0x0A28, + 0x0A2A, 0x0A30, + 0x0A32, 0x0A33, + 0x0A35, 0x0A36, + 0x0A38, 0x0A39, + 0x0A3E, 0x0A40, + 0x0A59, 0x0A5C, + 0x0A5E, 0x0A5E, + 0x0A66, 0x0A6F, + 0x0A72, 0x0A74, + 0x0A83, 0x0A83, + 0x0A85, 0x0A8B, + 0x0A8D, 0x0A8D, + 0x0A8F, 0x0A91, + 0x0A93, 0x0AA8, + 0x0AAA, 0x0AB0, + 0x0AB2, 0x0AB3, + 0x0AB5, 0x0AB9, + 0x0ABD, 0x0AC0, + 0x0AC9, 0x0AC9, + 0x0ACB, 0x0ACC, + 0x0AD0, 0x0AD0, + 0x0AE0, 0x0AE0, + 0x0AE6, 0x0AEF, + 0x0B02, 0x0B03, + 0x0B05, 0x0B0C, + 0x0B0F, 0x0B10, + 0x0B13, 0x0B28, + 0x0B2A, 0x0B30, + 0x0B32, 0x0B33, + 0x0B36, 0x0B39, + 0x0B3D, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B48, + 0x0B4B, 0x0B4C, + 0x0B57, 0x0B57, + 0x0B5C, 0x0B5D, + 0x0B5F, 0x0B61, + 0x0B66, 0x0B70, + 0x0B83, 0x0B83, + 0x0B85, 0x0B8A, + 0x0B8E, 0x0B90, + 0x0B92, 0x0B95, + 0x0B99, 0x0B9A, + 0x0B9C, 0x0B9C, + 0x0B9E, 0x0B9F, + 0x0BA3, 0x0BA4, + 0x0BA8, 0x0BAA, + 0x0BAE, 0x0BB5, + 0x0BB7, 0x0BB9, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BC2, + 0x0BC6, 0x0BC8, + 0x0BCA, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0BE7, 0x0BF2, + 0x0C01, 0x0C03, + 0x0C05, 0x0C0C, + 0x0C0E, 0x0C10, + 0x0C12, 0x0C28, + 0x0C2A, 0x0C33, + 0x0C35, 0x0C39, + 0x0C41, 0x0C44, + 0x0C60, 0x0C61, + 0x0C66, 0x0C6F, + 0x0C82, 0x0C83, + 0x0C85, 0x0C8C, + 0x0C8E, 0x0C90, + 0x0C92, 0x0CA8, + 0x0CAA, 0x0CB3, + 0x0CB5, 0x0CB9, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CC8, + 0x0CCA, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0CDE, 0x0CDE, + 0x0CE0, 0x0CE1, + 0x0CE6, 0x0CEF, + 0x0D02, 0x0D03, + 0x0D05, 0x0D0C, + 0x0D0E, 0x0D10, + 0x0D12, 0x0D28, + 0x0D2A, 0x0D39, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D48, + 0x0D4A, 0x0D4C, + 0x0D57, 0x0D57, + 0x0D60, 0x0D61, + 0x0D66, 0x0D6F, + 0x0D82, 0x0D83, + 0x0D85, 0x0D96, + 0x0D9A, 0x0DB1, + 0x0DB3, 0x0DBB, + 0x0DBD, 0x0DBD, + 0x0DC0, 0x0DC6, + 0x0DCF, 0x0DD1, + 0x0DD8, 0x0DDF, + 0x0DF2, 0x0DF4, + 0x0E01, 0x0E30, + 0x0E32, 0x0E33, + 0x0E40, 0x0E46, + 0x0E4F, 0x0E5B, + 0x0E81, 0x0E82, + 0x0E84, 0x0E84, + 0x0E87, 0x0E88, + 0x0E8A, 0x0E8A, + 0x0E8D, 0x0E8D, + 0x0E94, 0x0E97, + 0x0E99, 0x0E9F, + 0x0EA1, 0x0EA3, + 0x0EA5, 0x0EA5, + 0x0EA7, 0x0EA7, + 0x0EAA, 0x0EAB, + 0x0EAD, 0x0EB0, + 0x0EB2, 0x0EB3, + 0x0EBD, 0x0EBD, + 0x0EC0, 0x0EC4, + 0x0EC6, 0x0EC6, + 0x0ED0, 0x0ED9, + 0x0EDC, 0x0EDD, + 0x0F00, 0x0F17, + 0x0F1A, 0x0F34, + 0x0F36, 0x0F36, + 0x0F38, 0x0F38, + 0x0F3E, 0x0F47, + 0x0F49, 0x0F6A, + 0x0F7F, 0x0F7F, + 0x0F85, 0x0F85, + 0x0F88, 0x0F8B, + 0x0FBE, 0x0FC5, + 0x0FC7, 0x0FCC, + 0x0FCF, 0x0FCF, + 0x1000, 0x1021, + 0x1023, 0x1027, + 0x1029, 0x102A, + 0x102C, 0x102C, + 0x1031, 0x1031, + 0x1038, 0x1038, + 0x1040, 0x1057, + 0x10A0, 0x10C5, + 0x10D0, 0x10F8, + 0x10FB, 0x10FB, + 0x1100, 0x1159, + 0x115F, 0x11A2, + 0x11A8, 0x11F9, + 0x1200, 0x1206, + 0x1208, 0x1246, + 0x1248, 0x1248, + 0x124A, 0x124D, + 0x1250, 0x1256, + 0x1258, 0x1258, + 0x125A, 0x125D, + 0x1260, 0x1286, + 0x1288, 0x1288, + 0x128A, 0x128D, + 0x1290, 0x12AE, + 0x12B0, 0x12B0, + 0x12B2, 0x12B5, + 0x12B8, 0x12BE, + 0x12C0, 0x12C0, + 0x12C2, 0x12C5, + 0x12C8, 0x12CE, + 0x12D0, 0x12D6, + 0x12D8, 0x12EE, + 0x12F0, 0x130E, + 0x1310, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x131E, + 0x1320, 0x1346, + 0x1348, 0x135A, + 0x1361, 0x137C, + 0x13A0, 0x13F4, + 0x1401, 0x1676, + 0x1681, 0x169A, + 0x16A0, 0x16F0, + 0x1700, 0x170C, + 0x170E, 0x1711, + 0x1720, 0x1731, + 0x1735, 0x1736, + 0x1740, 0x1751, + 0x1760, 0x176C, + 0x176E, 0x1770, + 0x1780, 0x17B6, + 0x17BE, 0x17C5, + 0x17C7, 0x17C8, + 0x17D4, 0x17DA, + 0x17DC, 0x17DC, + 0x17E0, 0x17E9, + 0x1810, 0x1819, + 0x1820, 0x1877, + 0x1880, 0x18A8, + 0x1E00, 0x1E9B, + 0x1EA0, 0x1EF9, + 0x1F00, 0x1F15, + 0x1F18, 0x1F1D, + 0x1F20, 0x1F45, + 0x1F48, 0x1F4D, + 0x1F50, 0x1F57, + 0x1F59, 0x1F59, + 0x1F5B, 0x1F5B, + 0x1F5D, 0x1F5D, + 0x1F5F, 0x1F7D, + 0x1F80, 0x1FB4, + 0x1FB6, 0x1FBC, + 0x1FBE, 0x1FBE, + 0x1FC2, 0x1FC4, + 0x1FC6, 0x1FCC, + 0x1FD0, 0x1FD3, + 0x1FD6, 0x1FDB, + 0x1FE0, 0x1FEC, + 0x1FF2, 0x1FF4, + 0x1FF6, 0x1FFC, + 0x200E, 0x200E, + 0x2071, 0x2071, + 0x207F, 0x207F, + 0x2102, 0x2102, + 0x2107, 0x2107, + 0x210A, 0x2113, + 0x2115, 0x2115, + 0x2119, 0x211D, + 0x2124, 0x2124, + 0x2126, 0x2126, + 0x2128, 0x2128, + 0x212A, 0x212D, + 0x212F, 0x2131, + 0x2133, 0x2139, + 0x213D, 0x213F, + 0x2145, 0x2149, + 0x2160, 0x2183, + 0x2336, 0x237A, + 0x2395, 0x2395, + 0x249C, 0x24E9, + 0x3005, 0x3007, + 0x3021, 0x3029, + 0x3031, 0x3035, + 0x3038, 0x303C, + 0x3041, 0x3096, + 0x309D, 0x309F, + 0x30A1, 0x30FA, + 0x30FC, 0x30FF, + 0x3105, 0x312C, + 0x3131, 0x318E, + 0x3190, 0x31B7, + 0x31F0, 0x321C, + 0x3220, 0x3243, + 0x3260, 0x327B, + 0x327F, 0x32B0, + 0x32C0, 0x32CB, + 0x32D0, 0x32FE, + 0x3300, 0x3376, + 0x337B, 0x33DD, + 0x33E0, 0x33FE, + 0x3400, 0x4DB5, + 0x4E00, 0x9FA5, + 0xA000, 0xA48C, + 0xAC00, 0xD7A3, + 0xD800, 0xFA2D, + 0xFA30, 0xFA6A, + 0xFB00, 0xFB06, + 0xFB13, 0xFB17, + 0xFF21, 0xFF3A, + 0xFF41, 0xFF5A, + 0xFF66, 0xFFBE, + 0xFFC2, 0xFFC7, + 0xFFCA, 0xFFCF, + 0xFFD2, 0xFFD7, + 0xFFDA, 0xFFDC, + 0x10300, 0x1031E, + 0x10320, 0x10323, + 0x10330, 0x1034A, + 0x10400, 0x10425, + 0x10428, 0x1044D, + 0x1D000, 0x1D0F5, + 0x1D100, 0x1D126, + 0x1D12A, 0x1D166, + 0x1D16A, 0x1D172, + 0x1D183, 0x1D184, + 0x1D18C, 0x1D1A9, + 0x1D1AE, 0x1D1DD, + 0x1D400, 0x1D454, + 0x1D456, 0x1D49C, + 0x1D49E, 0x1D49F, + 0x1D4A2, 0x1D4A2, + 0x1D4A5, 0x1D4A6, + 0x1D4A9, 0x1D4AC, + 0x1D4AE, 0x1D4B9, + 0x1D4BB, 0x1D4BB, + 0x1D4BD, 0x1D4C0, + 0x1D4C2, 0x1D4C3, + 0x1D4C5, 0x1D505, + 0x1D507, 0x1D50A, + 0x1D50D, 0x1D514, + 0x1D516, 0x1D51C, + 0x1D51E, 0x1D539, + 0x1D53B, 0x1D53E, + 0x1D540, 0x1D544, + 0x1D546, 0x1D546, + 0x1D54A, 0x1D550, + 0x1D552, 0x1D6A3, + 0x1D6A8, 0x1D7C9, + 0x20000, 0x2A6D6, + 0x2F800, 0x2FA1D, + 0xF0000, 0xFFFFD, + 0x100000, 0x10FFFD +}; + +/* End of stringprep tables */ + + +/* Is the given Unicode codepoint in the given table of ranges? */ +#define IS_CODE_IN_TABLE(code, map) is_code_in_table(code, map, lengthof(map)) + +static int +codepoint_range_cmp(const void *a, const void *b) +{ + const pg_wchar *key = (const pg_wchar *) a; + const pg_wchar *range = (const pg_wchar *) b; + + if (*key < range[0]) + return -1; /* less than lower bound */ + if (*key > range[1]) + return 1; /* greater than upper bound */ + + return 0; /* within range */ +} + +static bool +is_code_in_table(pg_wchar code, const pg_wchar *map, int mapsize) +{ + Assert(mapsize % 2 == 0); + + if (code < map[0] || code > map[mapsize - 1]) + return false; + + if (bsearch(&code, map, mapsize / 2, sizeof(pg_wchar) * 2, + codepoint_range_cmp)) + return true; + else + return false; +} + +/* + * Calculate the length in characters of a null-terminated UTF-8 string. + * + * Returns -1 if the input is not valid UTF-8. + */ +static int +pg_utf8_string_len(const char *source) +{ + const unsigned char *p = (const unsigned char *) source; + int l; + int num_chars = 0; + + while (*p) + { + l = pg_utf_mblen(p); + + if (!pg_utf8_islegal(p, l)) + return -1; + + p += l; + num_chars++; + } + + return num_chars; +} + + +/* + * pg_saslprep - Normalize a password with SASLprep. + * + * SASLprep requires the input to be in UTF-8 encoding, but PostgreSQL + * supports many encodings, so we don't blindly assume that. pg_saslprep + * will check if the input looks like valid UTF-8, and returns + * SASLPREP_INVALID_UTF8 if not. + * + * If the string contains prohibited characters (or more precisely, if the + * output string would contain prohibited characters after normalization), + * returns SASLPREP_PROHIBITED. + * + * On success, returns SASLPREP_SUCCESS, and the normalized string in + * *output. + * + * In frontend, the normalized string is malloc'd, and the caller is + * responsible for freeing it. If an allocation fails, returns + * SASLPREP_OOM. In backend, the normalized string is palloc'd instead, + * and a failed allocation leads to ereport(ERROR). + */ +pg_saslprep_rc +pg_saslprep(const char *input, char **output) +{ + pg_wchar *input_chars = NULL; + pg_wchar *output_chars = NULL; + int input_size; + char *result; + int result_size; + int count; + int i; + bool contains_RandALCat; + unsigned char *p; + pg_wchar *wp; + + /* Ensure we return *output as NULL on failure */ + *output = NULL; + + /* + * Quick check if the input is pure ASCII. An ASCII string requires no + * further processing. + */ + if (pg_is_ascii(input)) + { + *output = STRDUP(input); + if (!(*output)) + goto oom; + return SASLPREP_SUCCESS; + } + + /* + * Convert the input from UTF-8 to an array of Unicode codepoints. + * + * This also checks that the input is a legal UTF-8 string. + */ + input_size = pg_utf8_string_len(input); + if (input_size < 0) + return SASLPREP_INVALID_UTF8; + + input_chars = ALLOC((input_size + 1) * sizeof(pg_wchar)); + if (!input_chars) + goto oom; + + p = (unsigned char *) input; + for (i = 0; i < input_size; i++) + { + input_chars[i] = utf8_to_unicode(p); + p += pg_utf_mblen(p); + } + input_chars[i] = (pg_wchar) '\0'; + + /* + * The steps below correspond to the steps listed in [RFC3454], Section + * "2. Preparation Overview" + */ + + /* + * 1) Map -- For each character in the input, check if it has a mapping + * and, if so, replace it with its mapping. + */ + count = 0; + for (i = 0; i < input_size; i++) + { + pg_wchar code = input_chars[i]; + + if (IS_CODE_IN_TABLE(code, non_ascii_space_ranges)) + input_chars[count++] = 0x0020; + else if (IS_CODE_IN_TABLE(code, commonly_mapped_to_nothing_ranges)) + { + /* map to nothing */ + } + else + input_chars[count++] = code; + } + input_chars[count] = (pg_wchar) '\0'; + input_size = count; + + if (input_size == 0) + goto prohibited; /* don't allow empty password */ + + /* + * 2) Normalize -- Normalize the result of step 1 using Unicode + * normalization. + */ + output_chars = unicode_normalize(UNICODE_NFKC, input_chars); + if (!output_chars) + goto oom; + + /* + * 3) Prohibit -- Check for any characters that are not allowed in the + * output. If any are found, return an error. + */ + for (i = 0; i < input_size; i++) + { + pg_wchar code = input_chars[i]; + + if (IS_CODE_IN_TABLE(code, prohibited_output_ranges)) + goto prohibited; + if (IS_CODE_IN_TABLE(code, unassigned_codepoint_ranges)) + goto prohibited; + } + + /* + * 4) Check bidi -- Possibly check for right-to-left characters, and if + * any are found, make sure that the whole string satisfies the + * requirements for bidirectional strings. If the string does not satisfy + * the requirements for bidirectional strings, return an error. + * + * [RFC3454], Section "6. Bidirectional Characters" explains in more + * detail what that means: + * + * "In any profile that specifies bidirectional character handling, all + * three of the following requirements MUST be met: + * + * 1) The characters in section 5.8 MUST be prohibited. + * + * 2) If a string contains any RandALCat character, the string MUST NOT + * contain any LCat character. + * + * 3) If a string contains any RandALCat character, a RandALCat character + * MUST be the first character of the string, and a RandALCat character + * MUST be the last character of the string." + */ + contains_RandALCat = false; + for (i = 0; i < input_size; i++) + { + pg_wchar code = input_chars[i]; + + if (IS_CODE_IN_TABLE(code, RandALCat_codepoint_ranges)) + { + contains_RandALCat = true; + break; + } + } + + if (contains_RandALCat) + { + pg_wchar first = input_chars[0]; + pg_wchar last = input_chars[input_size - 1]; + + for (i = 0; i < input_size; i++) + { + pg_wchar code = input_chars[i]; + + if (IS_CODE_IN_TABLE(code, LCat_codepoint_ranges)) + goto prohibited; + } + + if (!IS_CODE_IN_TABLE(first, RandALCat_codepoint_ranges) || + !IS_CODE_IN_TABLE(last, RandALCat_codepoint_ranges)) + goto prohibited; + } + + /* + * Finally, convert the result back to UTF-8. + */ + result_size = 0; + for (wp = output_chars; *wp; wp++) + { + unsigned char buf[4]; + + unicode_to_utf8(*wp, buf); + result_size += pg_utf_mblen(buf); + } + + result = ALLOC(result_size + 1); + if (!result) + goto oom; + + /* + * There are no error exits below here, so the error exit paths don't need + * to worry about possibly freeing "result". + */ + p = (unsigned char *) result; + for (wp = output_chars; *wp; wp++) + { + unicode_to_utf8(*wp, p); + p += pg_utf_mblen(p); + } + Assert((char *) p == result + result_size); + *p = '\0'; + + FREE(input_chars); + FREE(output_chars); + + *output = result; + return SASLPREP_SUCCESS; + +prohibited: + if (input_chars) + FREE(input_chars); + if (output_chars) + FREE(output_chars); + + return SASLPREP_PROHIBITED; + +oom: + if (input_chars) + FREE(input_chars); + if (output_chars) + FREE(output_chars); + + return SASLPREP_OOM; +} diff --git a/contrib/libs/libpq/src/common/scram-common.c b/contrib/libs/libpq/src/common/scram-common.c new file mode 100644 index 0000000000..ef997ef684 --- /dev/null +++ b/contrib/libs/libpq/src/common/scram-common.c @@ -0,0 +1,319 @@ +/*------------------------------------------------------------------------- + * scram-common.c + * Shared frontend/backend code for SCRAM authentication + * + * This contains the common low-level functions needed in both frontend and + * backend, for implement the Salted Challenge Response Authentication + * Mechanism (SCRAM), per IETF's RFC 5802. + * + * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/scram-common.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/base64.h" +#include "common/hmac.h" +#include "common/scram-common.h" +#include "port/pg_bswap.h" + +/* + * Calculate SaltedPassword. + * + * The password should already be normalized by SASLprep. Returns 0 on + * success, -1 on failure with *errstr pointing to a message about the + * error details. + */ +int +scram_SaltedPassword(const char *password, + pg_cryptohash_type hash_type, int key_length, + const char *salt, int saltlen, int iterations, + uint8 *result, const char **errstr) +{ + int password_len = strlen(password); + uint32 one = pg_hton32(1); + int i, + j; + uint8 Ui[SCRAM_MAX_KEY_LEN]; + uint8 Ui_prev[SCRAM_MAX_KEY_LEN]; + pg_hmac_ctx *hmac_ctx = pg_hmac_create(hash_type); + + if (hmac_ctx == NULL) + { + *errstr = pg_hmac_error(NULL); /* returns OOM */ + return -1; + } + + /* + * Iterate hash calculation of HMAC entry using given salt. This is + * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom + * function. + */ + + /* First iteration */ + if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 || + pg_hmac_update(hmac_ctx, (uint8 *) salt, saltlen) < 0 || + pg_hmac_update(hmac_ctx, (uint8 *) &one, sizeof(uint32)) < 0 || + pg_hmac_final(hmac_ctx, Ui_prev, key_length) < 0) + { + *errstr = pg_hmac_error(hmac_ctx); + pg_hmac_free(hmac_ctx); + return -1; + } + + memcpy(result, Ui_prev, key_length); + + /* Subsequent iterations */ + for (i = 2; i <= iterations; i++) + { + if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 || + pg_hmac_update(hmac_ctx, (uint8 *) Ui_prev, key_length) < 0 || + pg_hmac_final(hmac_ctx, Ui, key_length) < 0) + { + *errstr = pg_hmac_error(hmac_ctx); + pg_hmac_free(hmac_ctx); + return -1; + } + + for (j = 0; j < key_length; j++) + result[j] ^= Ui[j]; + memcpy(Ui_prev, Ui, key_length); + } + + pg_hmac_free(hmac_ctx); + return 0; +} + + +/* + * Calculate hash for a NULL-terminated string. (The NULL terminator is + * not included in the hash). Returns 0 on success, -1 on failure with *errstr + * pointing to a message about the error details. + */ +int +scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, + uint8 *result, const char **errstr) +{ + pg_cryptohash_ctx *ctx; + + ctx = pg_cryptohash_create(hash_type); + if (ctx == NULL) + { + *errstr = pg_cryptohash_error(NULL); /* returns OOM */ + return -1; + } + + if (pg_cryptohash_init(ctx) < 0 || + pg_cryptohash_update(ctx, input, key_length) < 0 || + pg_cryptohash_final(ctx, result, key_length) < 0) + { + *errstr = pg_cryptohash_error(ctx); + pg_cryptohash_free(ctx); + return -1; + } + + pg_cryptohash_free(ctx); + return 0; +} + +/* + * Calculate ClientKey. Returns 0 on success, -1 on failure with *errstr + * pointing to a message about the error details. + */ +int +scram_ClientKey(const uint8 *salted_password, + pg_cryptohash_type hash_type, int key_length, + uint8 *result, const char **errstr) +{ + pg_hmac_ctx *ctx = pg_hmac_create(hash_type); + + if (ctx == NULL) + { + *errstr = pg_hmac_error(NULL); /* returns OOM */ + return -1; + } + + if (pg_hmac_init(ctx, salted_password, key_length) < 0 || + pg_hmac_update(ctx, (uint8 *) "Client Key", strlen("Client Key")) < 0 || + pg_hmac_final(ctx, result, key_length) < 0) + { + *errstr = pg_hmac_error(ctx); + pg_hmac_free(ctx); + return -1; + } + + pg_hmac_free(ctx); + return 0; +} + +/* + * Calculate ServerKey. Returns 0 on success, -1 on failure with *errstr + * pointing to a message about the error details. + */ +int +scram_ServerKey(const uint8 *salted_password, + pg_cryptohash_type hash_type, int key_length, + uint8 *result, const char **errstr) +{ + pg_hmac_ctx *ctx = pg_hmac_create(hash_type); + + if (ctx == NULL) + { + *errstr = pg_hmac_error(NULL); /* returns OOM */ + return -1; + } + + if (pg_hmac_init(ctx, salted_password, key_length) < 0 || + pg_hmac_update(ctx, (uint8 *) "Server Key", strlen("Server Key")) < 0 || + pg_hmac_final(ctx, result, key_length) < 0) + { + *errstr = pg_hmac_error(ctx); + pg_hmac_free(ctx); + return -1; + } + + pg_hmac_free(ctx); + return 0; +} + + +/* + * Construct a SCRAM secret, for storing in pg_authid.rolpassword. + * + * The password should already have been processed with SASLprep, if necessary! + * + * If iterations is 0, default number of iterations is used. The result is + * palloc'd or malloc'd, so caller is responsible for freeing it. + * + * On error, returns NULL and sets *errstr to point to a message about the + * error details. + */ +char * +scram_build_secret(pg_cryptohash_type hash_type, int key_length, + const char *salt, int saltlen, int iterations, + const char *password, const char **errstr) +{ + uint8 salted_password[SCRAM_MAX_KEY_LEN]; + uint8 stored_key[SCRAM_MAX_KEY_LEN]; + uint8 server_key[SCRAM_MAX_KEY_LEN]; + char *result; + char *p; + int maxlen; + int encoded_salt_len; + int encoded_stored_len; + int encoded_server_len; + int encoded_result; + + /* Only this hash method is supported currently */ + Assert(hash_type == PG_SHA256); + + Assert(iterations > 0); + + /* Calculate StoredKey and ServerKey */ + if (scram_SaltedPassword(password, hash_type, key_length, + salt, saltlen, iterations, + salted_password, errstr) < 0 || + scram_ClientKey(salted_password, hash_type, key_length, + stored_key, errstr) < 0 || + scram_H(stored_key, hash_type, key_length, + stored_key, errstr) < 0 || + scram_ServerKey(salted_password, hash_type, key_length, + server_key, errstr) < 0) + { + /* errstr is filled already here */ +#ifdef FRONTEND + return NULL; +#else + elog(ERROR, "could not calculate stored key and server key: %s", + *errstr); +#endif + } + + /*---------- + * The format is: + * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey> + *---------- + */ + encoded_salt_len = pg_b64_enc_len(saltlen); + encoded_stored_len = pg_b64_enc_len(key_length); + encoded_server_len = pg_b64_enc_len(key_length); + + maxlen = strlen("SCRAM-SHA-256") + 1 + + 10 + 1 /* iteration count */ + + encoded_salt_len + 1 /* Base64-encoded salt */ + + encoded_stored_len + 1 /* Base64-encoded StoredKey */ + + encoded_server_len + 1; /* Base64-encoded ServerKey */ + +#ifdef FRONTEND + result = malloc(maxlen); + if (!result) + { + *errstr = _("out of memory"); + return NULL; + } +#else + result = palloc(maxlen); +#endif + + p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations); + + /* salt */ + encoded_result = pg_b64_encode(salt, saltlen, p, encoded_salt_len); + if (encoded_result < 0) + { + *errstr = _("could not encode salt"); +#ifdef FRONTEND + free(result); + return NULL; +#else + elog(ERROR, "%s", *errstr); +#endif + } + p += encoded_result; + *(p++) = '$'; + + /* stored key */ + encoded_result = pg_b64_encode((char *) stored_key, key_length, p, + encoded_stored_len); + if (encoded_result < 0) + { + *errstr = _("could not encode stored key"); +#ifdef FRONTEND + free(result); + return NULL; +#else + elog(ERROR, "%s", *errstr); +#endif + } + + p += encoded_result; + *(p++) = ':'; + + /* server key */ + encoded_result = pg_b64_encode((char *) server_key, key_length, p, + encoded_server_len); + if (encoded_result < 0) + { + *errstr = _("could not encode server key"); +#ifdef FRONTEND + free(result); + return NULL; +#else + elog(ERROR, "%s", *errstr); +#endif + } + + p += encoded_result; + *(p++) = '\0'; + + Assert(p - result <= maxlen); + + return result; +} diff --git a/contrib/libs/libpq/src/common/sprompt.c b/contrib/libs/libpq/src/common/sprompt.c new file mode 100644 index 0000000000..201c831746 --- /dev/null +++ b/contrib/libs/libpq/src/common/sprompt.c @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + * + * sprompt.c + * simple_prompt() routine + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/sprompt.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "common/fe_memutils.h" +#include "common/string.h" + +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#endif + + +/* + * simple_prompt + * + * Generalized function especially intended for reading in usernames and + * passwords interactively. Reads from /dev/tty or stdin/stderr. + * + * prompt: The prompt to print, or NULL if none (automatically localized) + * echo: Set to false if you want to hide what is entered (for passwords) + * + * The input (without trailing newline) is returned as a malloc'd string. + * Caller is responsible for freeing it when done. + */ +char * +simple_prompt(const char *prompt, bool echo) +{ + return simple_prompt_extended(prompt, echo, NULL); +} + +/* + * simple_prompt_extended + * + * This is the same as simple_prompt(), except that prompt_ctx can + * optionally be provided to allow this function to be canceled via an + * existing SIGINT signal handler that will longjmp to the specified place + * only when *(prompt_ctx->enabled) is true. If canceled, this function + * returns an empty string, and prompt_ctx->canceled is set to true. + */ +char * +simple_prompt_extended(const char *prompt, bool echo, + PromptInterruptContext *prompt_ctx) +{ + char *result; + FILE *termin, + *termout; +#if defined(HAVE_TERMIOS_H) + struct termios t_orig, + t; +#elif defined(WIN32) + HANDLE t = NULL; + DWORD t_orig = 0; +#endif + +#ifdef WIN32 + + /* + * A Windows console has an "input code page" and an "output code page"; + * these usually match each other, but they rarely match the "Windows ANSI + * code page" defined at system boot and expected of "char *" arguments to + * Windows API functions. The Microsoft CRT write() implementation + * automatically converts text between these code pages when writing to a + * console. To identify such file descriptors, it calls GetConsoleMode() + * on the underlying HANDLE, which in turn requires GENERIC_READ access on + * the HANDLE. Opening termout in mode "w+" allows that detection to + * succeed. Otherwise, write() would not recognize the descriptor as a + * console, and non-ASCII characters would display incorrectly. + * + * XXX fgets() still receives text in the console's input code page. This + * makes non-ASCII credentials unportable. + * + * Unintuitively, we also open termin in mode "w+", even though we only + * read it; that's needed for SetConsoleMode() to succeed. + */ + termin = fopen("CONIN$", "w+"); + termout = fopen("CONOUT$", "w+"); +#else + + /* + * Do not try to collapse these into one "w+" mode file. Doesn't work on + * some platforms (eg, HPUX 10.20). + */ + termin = fopen("/dev/tty", "r"); + termout = fopen("/dev/tty", "w"); +#endif + if (!termin || !termout +#ifdef WIN32 + + /* + * Direct console I/O does not work from the MSYS 1.0.10 console. Writes + * reach nowhere user-visible; reads block indefinitely. XXX This affects + * most Windows terminal environments, including rxvt, mintty, Cygwin + * xterm, Cygwin sshd, and PowerShell ISE. Switch to a more-generic test. + */ + || (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0) +#endif + ) + { + if (termin) + fclose(termin); + if (termout) + fclose(termout); + termin = stdin; + termout = stderr; + } + + if (!echo) + { +#if defined(HAVE_TERMIOS_H) + /* disable echo via tcgetattr/tcsetattr */ + tcgetattr(fileno(termin), &t); + t_orig = t; + t.c_lflag &= ~ECHO; + tcsetattr(fileno(termin), TCSAFLUSH, &t); +#elif defined(WIN32) + /* need the file's HANDLE to turn echo off */ + t = (HANDLE) _get_osfhandle(_fileno(termin)); + + /* save the old configuration first */ + GetConsoleMode(t, &t_orig); + + /* set to the new mode */ + SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); +#endif + } + + if (prompt) + { + fputs(_(prompt), termout); + fflush(termout); + } + + result = pg_get_line(termin, prompt_ctx); + + /* If we failed to read anything, just return an empty string */ + if (result == NULL) + result = pg_strdup(""); + + /* strip trailing newline, including \r in case we're on Windows */ + (void) pg_strip_crlf(result); + + if (!echo) + { + /* restore previous echo behavior, then echo \n */ +#if defined(HAVE_TERMIOS_H) + tcsetattr(fileno(termin), TCSAFLUSH, &t_orig); + fputs("\n", termout); + fflush(termout); +#elif defined(WIN32) + SetConsoleMode(t, t_orig); + fputs("\n", termout); + fflush(termout); +#endif + } + else if (prompt_ctx && prompt_ctx->canceled) + { + /* also echo \n if prompt was canceled */ + fputs("\n", termout); + fflush(termout); + } + + if (termin != stdin) + { + fclose(termin); + fclose(termout); + } + + return result; +} diff --git a/contrib/libs/libpq/src/common/string.c b/contrib/libs/libpq/src/common/string.c new file mode 100644 index 0000000000..de97413635 --- /dev/null +++ b/contrib/libs/libpq/src/common/string.c @@ -0,0 +1,164 @@ +/*------------------------------------------------------------------------- + * + * string.c + * string handling helpers + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/string.c + * + *------------------------------------------------------------------------- + */ + + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/string.h" +#include "lib/stringinfo.h" + + +/* + * Returns whether the string `str' has the postfix `end'. + */ +bool +pg_str_endswith(const char *str, const char *end) +{ + size_t slen = strlen(str); + size_t elen = strlen(end); + + /* can't be a postfix if longer */ + if (elen > slen) + return false; + + /* compare the end of the strings */ + str += slen - elen; + return strcmp(str, end) == 0; +} + + +/* + * strtoint --- just like strtol, but returns int not long + */ +int +strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base) +{ + long val; + + val = strtol(str, endptr, base); + if (val != (int) val) + errno = ERANGE; + return (int) val; +} + + +/* + * pg_clean_ascii -- Replace any non-ASCII chars with a "\xXX" string + * + * Makes a newly allocated copy of the string passed in, which must be + * '\0'-terminated. In the backend, additional alloc_flags may be provided and + * will be passed as-is to palloc_extended(); in the frontend, alloc_flags is + * ignored and the copy is malloc'd. + * + * This function exists specifically to deal with filtering out + * non-ASCII characters in a few places where the client can provide an almost + * arbitrary string (and it isn't checked to ensure it's a valid username or + * database name or similar) and we don't want to have control characters or other + * things ending up in the log file where server admins might end up with a + * messed up terminal when looking at them. + * + * In general, this function should NOT be used- instead, consider how to handle + * the string without needing to filter out the non-ASCII characters. + * + * Ultimately, we'd like to improve the situation to not require replacing all + * non-ASCII but perform more intelligent filtering which would allow UTF or + * similar, but it's unclear exactly what we should allow, so stick to ASCII only + * for now. + */ +char * +pg_clean_ascii(const char *str, int alloc_flags) +{ + size_t dstlen; + char *dst; + const char *p; + size_t i = 0; + + /* Worst case, each byte can become four bytes, plus a null terminator. */ + dstlen = strlen(str) * 4 + 1; + +#ifdef FRONTEND + dst = malloc(dstlen); +#else + dst = palloc_extended(dstlen, alloc_flags); +#endif + + if (!dst) + return NULL; + + for (p = str; *p != '\0'; p++) + { + + /* Only allow clean ASCII chars in the string */ + if (*p < 32 || *p > 126) + { + Assert(i < (dstlen - 3)); + snprintf(&dst[i], dstlen - i, "\\x%02x", (unsigned char) *p); + i += 4; + } + else + { + Assert(i < dstlen); + dst[i] = *p; + i++; + } + } + + Assert(i < dstlen); + dst[i] = '\0'; + return dst; +} + + +/* + * pg_is_ascii -- Check if string is made only of ASCII characters + */ +bool +pg_is_ascii(const char *str) +{ + while (*str) + { + if (IS_HIGHBIT_SET(*str)) + return false; + str++; + } + return true; +} + + +/* + * pg_strip_crlf -- Remove any trailing newline and carriage return + * + * Removes any trailing newline and carriage return characters (\r on + * Windows) in the input string, zero-terminating it. + * + * The passed in string must be zero-terminated. This function returns + * the new length of the string. + */ +int +pg_strip_crlf(char *str) +{ + int len = strlen(str); + + while (len > 0 && (str[len - 1] == '\n' || + str[len - 1] == '\r')) + str[--len] = '\0'; + + return len; +} diff --git a/contrib/libs/libpq/src/common/stringinfo.c b/contrib/libs/libpq/src/common/stringinfo.c new file mode 100644 index 0000000000..230dafd6c8 --- /dev/null +++ b/contrib/libs/libpq/src/common/stringinfo.c @@ -0,0 +1,343 @@ +/*------------------------------------------------------------------------- + * + * stringinfo.c + * + * StringInfo provides an extensible string data type (currently limited to a + * length of 1GB). It can be used to buffer either ordinary C strings + * (null-terminated text) or arbitrary binary data. All storage is allocated + * with palloc() (falling back to malloc in frontend code). + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/common/stringinfo.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND + +#include "postgres.h" +#error #include "utils/memutils.h" + +#else + +#include "postgres_fe.h" + +/* It's possible we could use a different value for this in frontend code */ +#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ + +#endif + +#include "lib/stringinfo.h" + + +/* + * makeStringInfo + * + * Create an empty 'StringInfoData' & return a pointer to it. + */ +StringInfo +makeStringInfo(void) +{ + StringInfo res; + + res = (StringInfo) palloc(sizeof(StringInfoData)); + + initStringInfo(res); + + return res; +} + +/* + * initStringInfo + * + * Initialize a StringInfoData struct (with previously undefined contents) + * to describe an empty string. + */ +void +initStringInfo(StringInfo str) +{ + int size = 1024; /* initial default buffer size */ + + str->data = (char *) palloc(size); + str->maxlen = size; + resetStringInfo(str); +} + +/* + * resetStringInfo + * + * Reset the StringInfo: the data buffer remains valid, but its + * previous content, if any, is cleared. + */ +void +resetStringInfo(StringInfo str) +{ + str->data[0] = '\0'; + str->len = 0; + str->cursor = 0; +} + +/* + * appendStringInfo + * + * Format text data under the control of fmt (an sprintf-style 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 +appendStringInfo(StringInfo str, const char *fmt,...) +{ + int save_errno = errno; + + for (;;) + { + va_list args; + int needed; + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + needed = appendStringInfoVA(str, fmt, args); + va_end(args); + + if (needed == 0) + break; /* success */ + + /* Increase the buffer size and try again. */ + enlargeStringInfo(str, needed); + } +} + +/* + * appendStringInfoVA + * + * Attempt to format text data under the control of fmt (an sprintf-style + * format string) and append it to whatever is already in str. If successful + * return zero; if not (because there's not enough space), return an estimate + * of the space needed, without modifying str. Typically the caller should + * pass the return value to enlargeStringInfo() before trying again; see + * appendStringInfo for standard usage pattern. + * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + * + * XXX This API is ugly, but there seems no alternative given the C spec's + * restrictions on what can portably be done with va_list arguments: you have + * to redo va_start before you can rescan the argument list, and we can't do + * that from here. + */ +int +appendStringInfoVA(StringInfo str, const char *fmt, va_list args) +{ + int avail; + size_t nprinted; + + Assert(str != NULL); + + /* + * If there's hardly any space, don't bother trying, just fail to make the + * caller enlarge the buffer first. We have to guess at how much to + * enlarge, since we're skipping the formatting work. + */ + avail = str->maxlen - str->len; + if (avail < 16) + return 32; + + nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args); + + if (nprinted < (size_t) avail) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += (int) nprinted; + return 0; + } + + /* Restore the trailing null so that str is unmodified. */ + str->data[str->len] = '\0'; + + /* + * Return pvsnprintf's estimate of the space needed. (Although this is + * given as a size_t, we know it will fit in int because it's not more + * than MaxAllocSize.) + */ + return (int) nprinted; +} + +/* + * appendStringInfoString + * + * Append a null-terminated string to str. + * Like appendStringInfo(str, "%s", s) but faster. + */ +void +appendStringInfoString(StringInfo str, const char *s) +{ + appendBinaryStringInfo(str, s, strlen(s)); +} + +/* + * appendStringInfoChar + * + * Append a single byte to str. + * Like appendStringInfo(str, "%c", ch) but much faster. + */ +void +appendStringInfoChar(StringInfo str, char ch) +{ + /* Make more room if needed */ + if (str->len + 1 >= str->maxlen) + enlargeStringInfo(str, 1); + + /* OK, append the character */ + str->data[str->len] = ch; + str->len++; + str->data[str->len] = '\0'; +} + +/* + * appendStringInfoSpaces + * + * Append the specified number of spaces to a buffer. + */ +void +appendStringInfoSpaces(StringInfo str, int count) +{ + if (count > 0) + { + /* Make more room if needed */ + enlargeStringInfo(str, count); + + /* OK, append the spaces */ + memset(&str->data[str->len], ' ', count); + str->len += count; + str->data[str->len] = '\0'; + } +} + +/* + * appendBinaryStringInfo + * + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. Ensures that a trailing null byte is present. + */ +void +appendBinaryStringInfo(StringInfo str, const void *data, int datalen) +{ + Assert(str != NULL); + + /* Make more room if needed */ + enlargeStringInfo(str, datalen); + + /* 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. (Some callers are dealing with text but call this because + * their input isn't null-terminated.) + */ + str->data[str->len] = '\0'; +} + +/* + * appendBinaryStringInfoNT + * + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. Does not ensure a trailing null-byte exists. + */ +void +appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen) +{ + Assert(str != NULL); + + /* Make more room if needed */ + enlargeStringInfo(str, datalen); + + /* OK, append the data */ + memcpy(str->data + str->len, data, datalen); + str->len += datalen; +} + +/* + * enlargeStringInfo + * + * Make sure there is enough space for 'needed' more bytes + * ('needed' does not include the terminating null). + * + * External callers usually need not concern themselves with this, since + * all stringinfo.c routines do it automatically. However, if a caller + * knows that a StringInfo will eventually become X bytes large, it + * can save some palloc overhead by enlarging the buffer before starting + * to store data in it. + * + * NB: In the backend, because we use repalloc() to enlarge the buffer, the + * string buffer will remain allocated in the same memory context that was + * current when initStringInfo was called, even if another context is now + * current. This is the desired and indeed critical behavior! + */ +void +enlargeStringInfo(StringInfo str, int needed) +{ + int newlen; + + /* + * Guard against out-of-range "needed" values. Without this, we can get + * an overflow or infinite loop in the following. + */ + if (needed < 0) /* should not happen */ + { +#ifndef FRONTEND + elog(ERROR, "invalid string enlargement request size: %d", needed); +#else + fprintf(stderr, "invalid string enlargement request size: %d\n", needed); + exit(EXIT_FAILURE); +#endif + } + if (((Size) needed) >= (MaxAllocSize - (Size) str->len)) + { +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("out of memory"), + errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.", + str->len, needed))); +#else + fprintf(stderr, + _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"), + str->len, needed); + exit(EXIT_FAILURE); +#endif + } + + needed += str->len + 1; /* total space required now */ + + /* Because of the above test, we now have needed <= MaxAllocSize */ + + if (needed <= str->maxlen) + return; /* 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 = 2 * str->maxlen; + while (needed > newlen) + newlen = 2 * newlen; + + /* + * Clamp to MaxAllocSize in case we went past it. Note we are assuming + * here that MaxAllocSize <= INT_MAX/2, else the above loop could + * overflow. We will still have newlen >= needed. + */ + if (newlen > (int) MaxAllocSize) + newlen = (int) MaxAllocSize; + + str->data = (char *) repalloc(str->data, newlen); + + str->maxlen = newlen; +} diff --git a/contrib/libs/libpq/src/common/unicode_norm.c b/contrib/libs/libpq/src/common/unicode_norm.c new file mode 100644 index 0000000000..6b40bdfeb4 --- /dev/null +++ b/contrib/libs/libpq/src/common/unicode_norm.c @@ -0,0 +1,634 @@ +/*------------------------------------------------------------------------- + * unicode_norm.c + * Normalize a Unicode string + * + * This implements Unicode normalization, per the documentation at + * https://www.unicode.org/reports/tr15/. + * + * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/unicode_norm.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/unicode_norm.h" +#ifndef FRONTEND +#error #include "common/unicode_norm_hashfunc.h" +#error #include "common/unicode_normprops_table.h" +#include "port/pg_bswap.h" +#else +#include "common/unicode_norm_table.h" +#endif + +#ifndef FRONTEND +#define ALLOC(size) palloc(size) +#define FREE(size) pfree(size) +#else +#define ALLOC(size) malloc(size) +#define FREE(size) free(size) +#endif + +/* Constants for calculations with Hangul characters */ +#define SBASE 0xAC00 /* U+AC00 */ +#define LBASE 0x1100 /* U+1100 */ +#define VBASE 0x1161 /* U+1161 */ +#define TBASE 0x11A7 /* U+11A7 */ +#define LCOUNT 19 +#define VCOUNT 21 +#define TCOUNT 28 +#define NCOUNT VCOUNT * TCOUNT +#define SCOUNT LCOUNT * NCOUNT + +#ifdef FRONTEND +/* comparison routine for bsearch() of decomposition lookup table. */ +static int +conv_compare(const void *p1, const void *p2) +{ + uint32 v1, + v2; + + v1 = *(const uint32 *) p1; + v2 = ((const pg_unicode_decomposition *) p2)->codepoint; + return (v1 > v2) ? 1 : ((v1 == v2) ? 0 : -1); +} + +#endif + +/* + * get_code_entry + * + * Get the entry corresponding to code in the decomposition lookup table. + * The backend version of this code uses a perfect hash function for the + * lookup, while the frontend version uses a binary search. + */ +static const pg_unicode_decomposition * +get_code_entry(pg_wchar code) +{ +#ifndef FRONTEND + int h; + uint32 hashkey; + pg_unicode_decompinfo decompinfo = UnicodeDecompInfo; + + /* + * Compute the hash function. The hash key is the codepoint with the bytes + * in network order. + */ + hashkey = pg_hton32(code); + h = decompinfo.hash(&hashkey); + + /* An out-of-range result implies no match */ + if (h < 0 || h >= decompinfo.num_decomps) + return NULL; + + /* + * Since it's a perfect hash, we need only match to the specific codepoint + * it identifies. + */ + if (code != decompinfo.decomps[h].codepoint) + return NULL; + + /* Success! */ + return &decompinfo.decomps[h]; +#else + return bsearch(&(code), + UnicodeDecompMain, + lengthof(UnicodeDecompMain), + sizeof(pg_unicode_decomposition), + conv_compare); +#endif +} + +/* + * Get the combining class of the given codepoint. + */ +static uint8 +get_canonical_class(pg_wchar code) +{ + const pg_unicode_decomposition *entry = get_code_entry(code); + + /* + * If no entries are found, the character used is either an Hangul + * character or a character with a class of 0 and no decompositions. + */ + if (!entry) + return 0; + else + return entry->comb_class; +} + +/* + * Given a decomposition entry looked up earlier, get the decomposed + * characters. + * + * Note: the returned pointer can point to statically allocated buffer, and + * is only valid until next call to this function! + */ +static const pg_wchar * +get_code_decomposition(const pg_unicode_decomposition *entry, int *dec_size) +{ + static pg_wchar x; + + if (DECOMPOSITION_IS_INLINE(entry)) + { + Assert(DECOMPOSITION_SIZE(entry) == 1); + x = (pg_wchar) entry->dec_index; + *dec_size = 1; + return &x; + } + else + { + *dec_size = DECOMPOSITION_SIZE(entry); + return &UnicodeDecomp_codepoints[entry->dec_index]; + } +} + +/* + * Calculate how many characters a given character will decompose to. + * + * This needs to recurse, if the character decomposes into characters that + * are, in turn, decomposable. + */ +static int +get_decomposed_size(pg_wchar code, bool compat) +{ + const pg_unicode_decomposition *entry; + int size = 0; + int i; + const uint32 *decomp; + int dec_size; + + /* + * Fast path for Hangul characters not stored in tables to save memory as + * decomposition is algorithmic. See + * https://www.unicode.org/reports/tr15/tr15-18.html, annex 10 for details + * on the matter. + */ + if (code >= SBASE && code < SBASE + SCOUNT) + { + uint32 tindex, + sindex; + + sindex = code - SBASE; + tindex = sindex % TCOUNT; + + if (tindex != 0) + return 3; + return 2; + } + + entry = get_code_entry(code); + + /* + * Just count current code if no other decompositions. A NULL entry is + * equivalent to a character with class 0 and no decompositions. + */ + if (entry == NULL || DECOMPOSITION_SIZE(entry) == 0 || + (!compat && DECOMPOSITION_IS_COMPAT(entry))) + return 1; + + /* + * If this entry has other decomposition codes look at them as well. First + * get its decomposition in the list of tables available. + */ + decomp = get_code_decomposition(entry, &dec_size); + for (i = 0; i < dec_size; i++) + { + uint32 lcode = decomp[i]; + + size += get_decomposed_size(lcode, compat); + } + + return size; +} + +/* + * Recompose a set of characters. For hangul characters, the calculation + * is algorithmic. For others, an inverse lookup at the decomposition + * table is necessary. Returns true if a recomposition can be done, and + * false otherwise. + */ +static bool +recompose_code(uint32 start, uint32 code, uint32 *result) +{ + /* + * Handle Hangul characters algorithmically, per the Unicode spec. + * + * Check if two current characters are L and V. + */ + if (start >= LBASE && start < LBASE + LCOUNT && + code >= VBASE && code < VBASE + VCOUNT) + { + /* make syllable of form LV */ + uint32 lindex = start - LBASE; + uint32 vindex = code - VBASE; + + *result = SBASE + (lindex * VCOUNT + vindex) * TCOUNT; + return true; + } + /* Check if two current characters are LV and T */ + else if (start >= SBASE && start < (SBASE + SCOUNT) && + ((start - SBASE) % TCOUNT) == 0 && + code >= TBASE && code < (TBASE + TCOUNT)) + { + /* make syllable of form LVT */ + uint32 tindex = code - TBASE; + + *result = start + tindex; + return true; + } + else + { + const pg_unicode_decomposition *entry; + + /* + * Do an inverse lookup of the decomposition tables to see if anything + * matches. The comparison just needs to be a perfect match on the + * sub-table of size two, because the start character has already been + * recomposed partially. This lookup uses a perfect hash function for + * the backend code. + */ +#ifndef FRONTEND + + int h, + inv_lookup_index; + uint64 hashkey; + pg_unicode_recompinfo recompinfo = UnicodeRecompInfo; + + /* + * Compute the hash function. The hash key is formed by concatenating + * bytes of the two codepoints in network order. See also + * src/common/unicode/generate-unicode_norm_table.pl. + */ + hashkey = pg_hton64(((uint64) start << 32) | (uint64) code); + h = recompinfo.hash(&hashkey); + + /* An out-of-range result implies no match */ + if (h < 0 || h >= recompinfo.num_recomps) + return false; + + inv_lookup_index = recompinfo.inverse_lookup[h]; + entry = &UnicodeDecompMain[inv_lookup_index]; + + if (start == UnicodeDecomp_codepoints[entry->dec_index] && + code == UnicodeDecomp_codepoints[entry->dec_index + 1]) + { + *result = entry->codepoint; + return true; + } + +#else + + int i; + + for (i = 0; i < lengthof(UnicodeDecompMain); i++) + { + entry = &UnicodeDecompMain[i]; + + if (DECOMPOSITION_SIZE(entry) != 2) + continue; + + if (DECOMPOSITION_NO_COMPOSE(entry)) + continue; + + if (start == UnicodeDecomp_codepoints[entry->dec_index] && + code == UnicodeDecomp_codepoints[entry->dec_index + 1]) + { + *result = entry->codepoint; + return true; + } + } +#endif /* !FRONTEND */ + } + + return false; +} + +/* + * Decompose the given code into the array given by caller. The + * decomposition begins at the position given by caller, saving one + * lookup on the decomposition table. The current position needs to be + * updated here to let the caller know from where to continue filling + * in the array result. + */ +static void +decompose_code(pg_wchar code, bool compat, pg_wchar **result, int *current) +{ + const pg_unicode_decomposition *entry; + int i; + const uint32 *decomp; + int dec_size; + + /* + * Fast path for Hangul characters not stored in tables to save memory as + * decomposition is algorithmic. See + * https://www.unicode.org/reports/tr15/tr15-18.html, annex 10 for details + * on the matter. + */ + if (code >= SBASE && code < SBASE + SCOUNT) + { + uint32 l, + v, + tindex, + sindex; + pg_wchar *res = *result; + + sindex = code - SBASE; + l = LBASE + sindex / (VCOUNT * TCOUNT); + v = VBASE + (sindex % (VCOUNT * TCOUNT)) / TCOUNT; + tindex = sindex % TCOUNT; + + res[*current] = l; + (*current)++; + res[*current] = v; + (*current)++; + + if (tindex != 0) + { + res[*current] = TBASE + tindex; + (*current)++; + } + + return; + } + + entry = get_code_entry(code); + + /* + * Just fill in with the current decomposition if there are no + * decomposition codes to recurse to. A NULL entry is equivalent to a + * character with class 0 and no decompositions, so just leave also in + * this case. + */ + if (entry == NULL || DECOMPOSITION_SIZE(entry) == 0 || + (!compat && DECOMPOSITION_IS_COMPAT(entry))) + { + pg_wchar *res = *result; + + res[*current] = code; + (*current)++; + return; + } + + /* + * If this entry has other decomposition codes look at them as well. + */ + decomp = get_code_decomposition(entry, &dec_size); + for (i = 0; i < dec_size; i++) + { + pg_wchar lcode = (pg_wchar) decomp[i]; + + /* Leave if no more decompositions */ + decompose_code(lcode, compat, result, current); + } +} + +/* + * unicode_normalize - Normalize a Unicode string to the specified form. + * + * The input is a 0-terminated array of codepoints. + * + * In frontend, returns a 0-terminated array of codepoints, allocated with + * malloc. Or NULL if we run out of memory. In backend, the returned + * string is palloc'd instead, and OOM is reported with ereport(). + */ +pg_wchar * +unicode_normalize(UnicodeNormalizationForm form, const pg_wchar *input) +{ + bool compat = (form == UNICODE_NFKC || form == UNICODE_NFKD); + bool recompose = (form == UNICODE_NFC || form == UNICODE_NFKC); + pg_wchar *decomp_chars; + pg_wchar *recomp_chars; + int decomp_size, + current_size; + int count; + const pg_wchar *p; + + /* variables for recomposition */ + int last_class; + int starter_pos; + int target_pos; + uint32 starter_ch; + + /* First, do character decomposition */ + + /* + * Calculate how many characters long the decomposed version will be. + */ + decomp_size = 0; + for (p = input; *p; p++) + decomp_size += get_decomposed_size(*p, compat); + + decomp_chars = (pg_wchar *) ALLOC((decomp_size + 1) * sizeof(pg_wchar)); + if (decomp_chars == NULL) + return NULL; + + /* + * Now fill in each entry recursively. This needs a second pass on the + * decomposition table. + */ + current_size = 0; + for (p = input; *p; p++) + decompose_code(*p, compat, &decomp_chars, ¤t_size); + decomp_chars[decomp_size] = '\0'; + Assert(decomp_size == current_size); + + /* Leave if there is nothing to decompose */ + if (decomp_size == 0) + return decomp_chars; + + /* + * Now apply canonical ordering. + */ + for (count = 1; count < decomp_size; count++) + { + pg_wchar prev = decomp_chars[count - 1]; + pg_wchar next = decomp_chars[count]; + pg_wchar tmp; + const uint8 prevClass = get_canonical_class(prev); + const uint8 nextClass = get_canonical_class(next); + + /* + * Per Unicode (https://www.unicode.org/reports/tr15/tr15-18.html) + * annex 4, a sequence of two adjacent characters in a string is an + * exchangeable pair if the combining class (from the Unicode + * Character Database) for the first character is greater than the + * combining class for the second, and the second is not a starter. A + * character is a starter if its combining class is 0. + */ + if (prevClass == 0 || nextClass == 0) + continue; + + if (prevClass <= nextClass) + continue; + + /* exchange can happen */ + tmp = decomp_chars[count - 1]; + decomp_chars[count - 1] = decomp_chars[count]; + decomp_chars[count] = tmp; + + /* backtrack to check again */ + if (count > 1) + count -= 2; + } + + if (!recompose) + return decomp_chars; + + /* + * The last phase of NFC and NFKC is the recomposition of the reordered + * Unicode string using combining classes. The recomposed string cannot be + * longer than the decomposed one, so make the allocation of the output + * string based on that assumption. + */ + recomp_chars = (pg_wchar *) ALLOC((decomp_size + 1) * sizeof(pg_wchar)); + if (!recomp_chars) + { + FREE(decomp_chars); + return NULL; + } + + last_class = -1; /* this eliminates a special check */ + starter_pos = 0; + target_pos = 1; + starter_ch = recomp_chars[0] = decomp_chars[0]; + + for (count = 1; count < decomp_size; count++) + { + pg_wchar ch = decomp_chars[count]; + int ch_class = get_canonical_class(ch); + pg_wchar composite; + + if (last_class < ch_class && + recompose_code(starter_ch, ch, &composite)) + { + recomp_chars[starter_pos] = composite; + starter_ch = composite; + } + else if (ch_class == 0) + { + starter_pos = target_pos; + starter_ch = ch; + last_class = -1; + recomp_chars[target_pos++] = ch; + } + else + { + last_class = ch_class; + recomp_chars[target_pos++] = ch; + } + } + recomp_chars[target_pos] = (pg_wchar) '\0'; + + FREE(decomp_chars); + + return recomp_chars; +} + +/* + * Normalization "quick check" algorithm; see + * <http://www.unicode.org/reports/tr15/#Detecting_Normalization_Forms> + */ + +/* We only need this in the backend. */ +#ifndef FRONTEND + +static const pg_unicode_normprops * +qc_hash_lookup(pg_wchar ch, const pg_unicode_norminfo *norminfo) +{ + int h; + uint32 hashkey; + + /* + * Compute the hash function. The hash key is the codepoint with the bytes + * in network order. + */ + hashkey = pg_hton32(ch); + h = norminfo->hash(&hashkey); + + /* An out-of-range result implies no match */ + if (h < 0 || h >= norminfo->num_normprops) + return NULL; + + /* + * Since it's a perfect hash, we need only match to the specific codepoint + * it identifies. + */ + if (ch != norminfo->normprops[h].codepoint) + return NULL; + + /* Success! */ + return &norminfo->normprops[h]; +} + +/* + * Look up the normalization quick check character property + */ +static UnicodeNormalizationQC +qc_is_allowed(UnicodeNormalizationForm form, pg_wchar ch) +{ + const pg_unicode_normprops *found = NULL; + + switch (form) + { + case UNICODE_NFC: + found = qc_hash_lookup(ch, &UnicodeNormInfo_NFC_QC); + break; + case UNICODE_NFKC: + found = qc_hash_lookup(ch, &UnicodeNormInfo_NFKC_QC); + break; + default: + Assert(false); + break; + } + + if (found) + return found->quickcheck; + else + return UNICODE_NORM_QC_YES; +} + +UnicodeNormalizationQC +unicode_is_normalized_quickcheck(UnicodeNormalizationForm form, const pg_wchar *input) +{ + uint8 lastCanonicalClass = 0; + UnicodeNormalizationQC result = UNICODE_NORM_QC_YES; + + /* + * For the "D" forms, we don't run the quickcheck. We don't include the + * lookup tables for those because they are huge, checking for these + * particular forms is less common, and running the slow path is faster + * for the "D" forms than the "C" forms because you don't need to + * recompose, which is slow. + */ + if (form == UNICODE_NFD || form == UNICODE_NFKD) + return UNICODE_NORM_QC_MAYBE; + + for (const pg_wchar *p = input; *p; p++) + { + pg_wchar ch = *p; + uint8 canonicalClass; + UnicodeNormalizationQC check; + + canonicalClass = get_canonical_class(ch); + if (lastCanonicalClass > canonicalClass && canonicalClass != 0) + return UNICODE_NORM_QC_NO; + + check = qc_is_allowed(form, ch); + if (check == UNICODE_NORM_QC_NO) + return UNICODE_NORM_QC_NO; + else if (check == UNICODE_NORM_QC_MAYBE) + result = UNICODE_NORM_QC_MAYBE; + + lastCanonicalClass = canonicalClass; + } + return result; +} + +#endif /* !FRONTEND */ diff --git a/contrib/libs/libpq/src/common/username.c b/contrib/libs/libpq/src/common/username.c new file mode 100644 index 0000000000..e8ac4c4977 --- /dev/null +++ b/contrib/libs/libpq/src/common/username.c @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------- + * + * username.c + * get user name + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/username.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <pwd.h> +#include <unistd.h> + +#include "common/username.h" + +/* + * Returns the current user name in a static buffer + * On error, returns NULL and sets *errstr to point to a palloc'd message + */ +const char * +get_user_name(char **errstr) +{ +#ifndef WIN32 + struct passwd *pw; + uid_t user_id = geteuid(); + + *errstr = NULL; + + errno = 0; /* clear errno before call */ + pw = getpwuid(user_id); + if (!pw) + { + *errstr = psprintf(_("could not look up effective user ID %ld: %s"), + (long) user_id, + errno ? strerror(errno) : _("user does not exist")); + return NULL; + } + + return pw->pw_name; +#else + /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */ + /* "static" variable remains after function exit */ + static char username[256 + 1]; + DWORD len = sizeof(username); + + *errstr = NULL; + + if (!GetUserName(username, &len)) + { + *errstr = psprintf(_("user name lookup failure: error code %lu"), + GetLastError()); + return NULL; + } + + return username; +#endif +} + + +/* + * Returns the current user name in a static buffer or exits + */ +const char * +get_user_name_or_exit(const char *progname) +{ + const char *user_name; + char *errstr; + + user_name = get_user_name(&errstr); + + if (!user_name) + { + fprintf(stderr, "%s: %s\n", progname, errstr); + exit(1); + } + return user_name; +} diff --git a/contrib/libs/libpq/src/common/wait_error.c b/contrib/libs/libpq/src/common/wait_error.c new file mode 100644 index 0000000000..a90b745f07 --- /dev/null +++ b/contrib/libs/libpq/src/common/wait_error.c @@ -0,0 +1,148 @@ +/*------------------------------------------------------------------------- + * + * wait_error.c + * Convert a wait/waitpid(2) result code to a human-readable string + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/wait_error.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <signal.h> +#include <sys/wait.h> + +/* + * Return a human-readable string explaining the reason a child process + * terminated. The argument is a return code returned by wait(2) or + * waitpid(2), which also applies to pclose(3) and system(3). The result is a + * translated, palloc'd or malloc'd string. + */ +char * +wait_result_to_str(int exitstatus) +{ + char str[512]; + + /* + * To simplify using this after pclose() and system(), handle status -1 + * first. In that case, there is no wait result but some error indicated + * by errno. + */ + if (exitstatus == -1) + { + snprintf(str, sizeof(str), "%m"); + } + else if (WIFEXITED(exitstatus)) + { + /* + * Give more specific error message for some common exit codes that + * have a special meaning in shells. + */ + switch (WEXITSTATUS(exitstatus)) + { + case 126: + snprintf(str, sizeof(str), _("command not executable")); + break; + + case 127: + snprintf(str, sizeof(str), _("command not found")); + break; + + default: + snprintf(str, sizeof(str), + _("child process exited with exit code %d"), + WEXITSTATUS(exitstatus)); + } + } + else if (WIFSIGNALED(exitstatus)) + { +#if defined(WIN32) + snprintf(str, sizeof(str), + _("child process was terminated by exception 0x%X"), + WTERMSIG(exitstatus)); +#else + snprintf(str, sizeof(str), + _("child process was terminated by signal %d: %s"), + WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus))); +#endif + } + else + snprintf(str, sizeof(str), + _("child process exited with unrecognized status %d"), + exitstatus); + + return pstrdup(str); +} + +/* + * Return true if a wait(2) result indicates that the child process + * died due to the specified signal. + * + * The reason this is worth having a wrapper function for is that + * there are two cases: the signal might have been received by our + * immediate child process, or there might've been a shell process + * between us and the child that died. The shell will, per POSIX, + * report the child death using exit code 128 + signal number. + * + * If there is no possibility of an intermediate shell, this function + * need not (and probably should not) be used. + */ +bool +wait_result_is_signal(int exit_status, int signum) +{ + if (WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum) + return true; + if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 128 + signum) + return true; + return false; +} + +/* + * Return true if a wait(2) result indicates that the child process + * died due to any signal. We consider either direct child death + * or a shell report of child process death as matching the condition. + * + * If include_command_not_found is true, also return true for shell + * exit codes indicating "command not found" and the like + * (specifically, exit codes 126 and 127; see above). + */ +bool +wait_result_is_any_signal(int exit_status, bool include_command_not_found) +{ + if (WIFSIGNALED(exit_status)) + return true; + if (WIFEXITED(exit_status) && + WEXITSTATUS(exit_status) > (include_command_not_found ? 125 : 128)) + return true; + return false; +} + +/* + * Return the shell exit code (normally 0 to 255) that corresponds to the + * given wait status. The argument is a wait status as returned by wait(2) + * or waitpid(2), which also applies to pclose(3) and system(3). To support + * the latter two cases, we pass through "-1" unchanged. + */ +int +wait_result_to_exit_code(int exit_status) +{ + if (exit_status == -1) + return -1; /* failure of pclose() or system() */ + if (WIFEXITED(exit_status)) + return WEXITSTATUS(exit_status); + if (WIFSIGNALED(exit_status)) + return 128 + WTERMSIG(exit_status); + /* On many systems, this is unreachable */ + return -1; +} diff --git a/contrib/libs/libpq/src/common/wchar.c b/contrib/libs/libpq/src/common/wchar.c new file mode 100644 index 0000000000..fb9d9f5c85 --- /dev/null +++ b/contrib/libs/libpq/src/common/wchar.c @@ -0,0 +1,2193 @@ +/*------------------------------------------------------------------------- + * + * wchar.c + * Functions for working with multibyte characters in various encodings. + * + * Portions Copyright (c) 1998-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/wchar.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include "mb/pg_wchar.h" + + +/* + * Operations on multi-byte encodings are driven by a table of helper + * functions. + * + * To add an encoding support, define mblen(), dsplen(), verifychar() and + * verifystr() for the encoding. For server-encodings, also define mb2wchar() + * and wchar2mb() conversion functions. + * + * 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. GB18030 is an exception + * to that rule, though, as it also looks at second byte. But even that + * behaves in a predictable way, if you only pass the first byte: it will + * treat 4-byte encoded characters as two 2-byte encoded characters, which is + * good enough for all current uses. + * + * 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" + * <http://www.unix.org/online.html> + * + * 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 int first; + unsigned int 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, Me or Cf in the Unicode database) 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) +{ +#include "common/unicode_nonspacing_table.h" +#include "common/unicode_east_asian_fw_table.h" + + /* 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 + * + * XXX: In the official Unicode sources, it is possible for a character to + * be described as both non-spacing and wide at the same time. As of + * Unicode 13.0, treating the non-spacing property as the determining + * factor for display width leads to the correct behavior, so do that + * search first. + */ + if (mbbisearch(ucs, nonspacing, + sizeof(nonspacing) / sizeof(struct mbinterval) - 1)) + return 0; + + /* binary search in table of wide characters */ + if (mbbisearch(ucs, east_asian_fw, + sizeof(east_asian_fw) / sizeof(struct mbinterval) - 1)) + return 2; + + return 1; +} + +/* + * 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; +} + +/* exported for direct use by conv.c */ +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 <bhuang@redhat.com>,<bill_huanghb@ybb.ne.jp> + */ + +/* + * Unlike all other mblen() functions, this also looks at the second byte of + * the input. However, if you only pass the first byte of a multi-byte + * string, and \0 as the second byte, this still works in a predictable way: + * a 4-byte character will be reported as two 2-byte characters. That's + * enough for all current uses, as a client-only encoding. It works that + * way, because in any valid 4-byte GB18030-encoded character, the third and + * fourth byte look like a 2-byte encoded character, when looked at + * separately. + */ +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 + * + * The verifychar 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 verifystr functions also accept "s", a pointer to a string and "len", + * the length of the string. They verify the whole string, and return the + * number of input bytes (<= len) that are valid. In other words, if the + * whole string is valid, verifystr returns "len", otherwise it returns the + * byte offset of the first invalid character. The verifystr functions must + * test for and reject zeroes in the input. + * + * The verifychar 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_verifychar(const unsigned char *s, int len) +{ + return 1; +} + +static int +pg_ascii_verifystr(const unsigned char *s, int len) +{ + const unsigned char *nullpos = memchr(s, 0, len); + + if (nullpos == NULL) + return len; + else + return nullpos - s; +} + +#define IS_EUC_RANGE_VALID(c) ((c) >= 0xa1 && (c) <= 0xfe) + +static int +pg_eucjp_verifychar(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_eucjp_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_eucjp_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_euckr_verifychar(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; +} + +static int +pg_euckr_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_euckr_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +/* EUC-CN byte sequences are exactly same as EUC-KR */ +#define pg_euccn_verifychar pg_euckr_verifychar +#define pg_euccn_verifystr pg_euckr_verifystr + +static int +pg_euctw_verifychar(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_euctw_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_euctw_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_johab_verifychar(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_johab_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_johab_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_mule_verifychar(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_mule_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_mule_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_latin1_verifychar(const unsigned char *s, int len) +{ + return 1; +} + +static int +pg_latin1_verifystr(const unsigned char *s, int len) +{ + const unsigned char *nullpos = memchr(s, 0, len); + + if (nullpos == NULL) + return len; + else + return nullpos - s; +} + +static int +pg_sjis_verifychar(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_sjis_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_sjis_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_big5_verifychar(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_big5_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_big5_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_gbk_verifychar(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_gbk_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_gbk_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_uhc_verifychar(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_uhc_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_uhc_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_gb18030_verifychar(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_gb18030_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_gb18030_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +static int +pg_utf8_verifychar(const unsigned char *s, int len) +{ + int l; + + if ((*s & 0x80) == 0) + { + if (*s == '\0') + return -1; + return 1; + } + else if ((*s & 0xe0) == 0xc0) + l = 2; + else if ((*s & 0xf0) == 0xe0) + l = 3; + else if ((*s & 0xf8) == 0xf0) + l = 4; + else + l = 1; + + if (l > len) + return -1; + + if (!pg_utf8_islegal(s, l)) + return -1; + + return l; +} + +/* + * The fast path of the UTF-8 verifier uses a deterministic finite automaton + * (DFA) for multibyte characters. In a traditional table-driven DFA, the + * input byte and current state are used to compute an index into an array of + * state transitions. Since the address of the next transition is dependent + * on this computation, there is latency in executing the load instruction, + * and the CPU is not kept busy. + * + * Instead, we use a "shift-based" DFA as described by Per Vognsen: + * + * https://gist.github.com/pervognsen/218ea17743e1442e59bb60d29b1aa725 + * + * In a shift-based DFA, the input byte is an index into array of integers + * whose bit pattern encodes the state transitions. To compute the next + * state, we simply right-shift the integer by the current state and apply a + * mask. In this scheme, the address of the transition only depends on the + * input byte, so there is better pipelining. + * + * The naming convention for states and transitions was adopted from a UTF-8 + * to UTF-16/32 transcoder, whose table is reproduced below: + * + * https://github.com/BobSteagall/utf_utils/blob/6b7a465265de2f5fa6133d653df0c9bdd73bbcf8/src/utf_utils.cpp + * + * ILL ASC CR1 CR2 CR3 L2A L3A L3B L3C L4A L4B L4C CLASS / STATE + * ========================================================================== + * err, END, err, err, err, CS1, P3A, CS2, P3B, P4A, CS3, P4B, | BGN/END + * err, err, err, err, err, err, err, err, err, err, err, err, | ERR + * | + * err, err, END, END, END, err, err, err, err, err, err, err, | CS1 + * err, err, CS1, CS1, CS1, err, err, err, err, err, err, err, | CS2 + * err, err, CS2, CS2, CS2, err, err, err, err, err, err, err, | CS3 + * | + * err, err, err, err, CS1, err, err, err, err, err, err, err, | P3A + * err, err, CS1, CS1, err, err, err, err, err, err, err, err, | P3B + * | + * err, err, err, CS2, CS2, err, err, err, err, err, err, err, | P4A + * err, err, CS2, err, err, err, err, err, err, err, err, err, | P4B + * + * In the most straightforward implementation, a shift-based DFA for UTF-8 + * requires 64-bit integers to encode the transitions, but with an SMT solver + * it's possible to find state numbers such that the transitions fit within + * 32-bit integers, as Dougall Johnson demonstrated: + * + * https://gist.github.com/dougallj/166e326de6ad4cf2c94be97a204c025f + * + * This packed representation is the reason for the seemingly odd choice of + * state values below. + */ + +/* Error */ +#define ERR 0 +/* Begin */ +#define BGN 11 +/* Continuation states, expect 1/2/3 continuation bytes */ +#define CS1 16 +#define CS2 1 +#define CS3 5 +/* Partial states, where the first continuation byte has a restricted range */ +#define P3A 6 /* Lead was E0, check for 3-byte overlong */ +#define P3B 20 /* Lead was ED, check for surrogate */ +#define P4A 25 /* Lead was F0, check for 4-byte overlong */ +#define P4B 30 /* Lead was F4, check for too-large */ +/* Begin and End are the same state */ +#define END BGN + +/* the encoded state transitions for the lookup table */ + +/* ASCII */ +#define ASC (END << BGN) +/* 2-byte lead */ +#define L2A (CS1 << BGN) +/* 3-byte lead */ +#define L3A (P3A << BGN) +#define L3B (CS2 << BGN) +#define L3C (P3B << BGN) +/* 4-byte lead */ +#define L4A (P4A << BGN) +#define L4B (CS3 << BGN) +#define L4C (P4B << BGN) +/* continuation byte */ +#define CR1 (END << CS1) | (CS1 << CS2) | (CS2 << CS3) | (CS1 << P3B) | (CS2 << P4B) +#define CR2 (END << CS1) | (CS1 << CS2) | (CS2 << CS3) | (CS1 << P3B) | (CS2 << P4A) +#define CR3 (END << CS1) | (CS1 << CS2) | (CS2 << CS3) | (CS1 << P3A) | (CS2 << P4A) +/* invalid byte */ +#define ILL ERR + +static const uint32 Utf8Transition[256] = +{ + /* ASCII */ + + ILL, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, + + /* continuation bytes */ + + /* 80..8F */ + CR1, CR1, CR1, CR1, CR1, CR1, CR1, CR1, + CR1, CR1, CR1, CR1, CR1, CR1, CR1, CR1, + + /* 90..9F */ + CR2, CR2, CR2, CR2, CR2, CR2, CR2, CR2, + CR2, CR2, CR2, CR2, CR2, CR2, CR2, CR2, + + /* A0..BF */ + CR3, CR3, CR3, CR3, CR3, CR3, CR3, CR3, + CR3, CR3, CR3, CR3, CR3, CR3, CR3, CR3, + CR3, CR3, CR3, CR3, CR3, CR3, CR3, CR3, + CR3, CR3, CR3, CR3, CR3, CR3, CR3, CR3, + + /* leading bytes */ + + /* C0..DF */ + ILL, ILL, L2A, L2A, L2A, L2A, L2A, L2A, + L2A, L2A, L2A, L2A, L2A, L2A, L2A, L2A, + L2A, L2A, L2A, L2A, L2A, L2A, L2A, L2A, + L2A, L2A, L2A, L2A, L2A, L2A, L2A, L2A, + + /* E0..EF */ + L3A, L3B, L3B, L3B, L3B, L3B, L3B, L3B, + L3B, L3B, L3B, L3B, L3B, L3C, L3B, L3B, + + /* F0..FF */ + L4A, L4B, L4B, L4B, L4C, ILL, ILL, ILL, + ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL +}; + +static void +utf8_advance(const unsigned char *s, uint32 *state, int len) +{ + /* Note: We deliberately don't check the state's value here. */ + while (len > 0) + { + /* + * It's important that the mask value is 31: In most instruction sets, + * a shift by a 32-bit operand is understood to be a shift by its mod + * 32, so the compiler should elide the mask operation. + */ + *state = Utf8Transition[*s++] >> (*state & 31); + len--; + } + + *state &= 31; +} + +static int +pg_utf8_verifystr(const unsigned char *s, int len) +{ + const unsigned char *start = s; + const int orig_len = len; + uint32 state = BGN; + +/* + * With a stride of two vector widths, gcc will unroll the loop. Even if + * the compiler can unroll a longer loop, it's not worth it because we + * must fall back to the byte-wise algorithm if we find any non-ASCII. + */ +#define STRIDE_LENGTH (2 * sizeof(Vector8)) + + if (len >= STRIDE_LENGTH) + { + while (len >= STRIDE_LENGTH) + { + /* + * If the chunk is all ASCII, we can skip the full UTF-8 check, + * but we must first check for a non-END state, which means the + * previous chunk ended in the middle of a multibyte sequence. + */ + if (state != END || !is_valid_ascii(s, STRIDE_LENGTH)) + utf8_advance(s, &state, STRIDE_LENGTH); + + s += STRIDE_LENGTH; + len -= STRIDE_LENGTH; + } + + /* The error state persists, so we only need to check for it here. */ + if (state == ERR) + { + /* + * Start over from the beginning with the slow path so we can + * count the valid bytes. + */ + len = orig_len; + s = start; + } + else if (state != END) + { + /* + * The fast path exited in the middle of a multibyte sequence. + * Walk backwards to find the leading byte so that the slow path + * can resume checking from there. We must always backtrack at + * least one byte, since the current byte could be e.g. an ASCII + * byte after a 2-byte lead, which is invalid. + */ + do + { + Assert(s > start); + s--; + len++; + Assert(IS_HIGHBIT_SET(*s)); + } while (pg_utf_mblen(s) <= 1); + } + } + + /* check remaining bytes */ + while (len > 0) + { + int l; + + /* fast path for ASCII-subset characters */ + if (!IS_HIGHBIT_SET(*s)) + { + if (*s == '\0') + break; + l = 1; + } + else + { + l = pg_utf8_verifychar(s, len); + if (l == -1) + break; + } + s += l; + len -= l; + } + + return s - start; +} + +/* + * 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; +} + + +/* + *------------------------------------------------------------------- + * 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_verifychar, pg_ascii_verifystr, 1}, /* PG_SQL_ASCII */ + {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifychar, pg_eucjp_verifystr, 3}, /* PG_EUC_JP */ + {pg_euccn2wchar_with_len, pg_wchar2euc_with_len, pg_euccn_mblen, pg_euccn_dsplen, pg_euccn_verifychar, pg_euccn_verifystr, 2}, /* PG_EUC_CN */ + {pg_euckr2wchar_with_len, pg_wchar2euc_with_len, pg_euckr_mblen, pg_euckr_dsplen, pg_euckr_verifychar, pg_euckr_verifystr, 3}, /* PG_EUC_KR */ + {pg_euctw2wchar_with_len, pg_wchar2euc_with_len, pg_euctw_mblen, pg_euctw_dsplen, pg_euctw_verifychar, pg_euctw_verifystr, 4}, /* PG_EUC_TW */ + {pg_eucjp2wchar_with_len, pg_wchar2euc_with_len, pg_eucjp_mblen, pg_eucjp_dsplen, pg_eucjp_verifychar, pg_eucjp_verifystr, 3}, /* PG_EUC_JIS_2004 */ + {pg_utf2wchar_with_len, pg_wchar2utf_with_len, pg_utf_mblen, pg_utf_dsplen, pg_utf8_verifychar, pg_utf8_verifystr, 4}, /* PG_UTF8 */ + {pg_mule2wchar_with_len, pg_wchar2mule_with_len, pg_mule_mblen, pg_mule_dsplen, pg_mule_verifychar, pg_mule_verifystr, 4}, /* PG_MULE_INTERNAL */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN1 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN2 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN3 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN4 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN5 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN6 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN7 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN8 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN9 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_LATIN10 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1256 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1258 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN866 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN874 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_KOI8R */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1251 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1252 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-5 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-6 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-7 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* ISO-8859-8 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1250 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1253 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1254 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1255 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_WIN1257 */ + {pg_latin12wchar_with_len, pg_wchar2single_with_len, pg_latin1_mblen, pg_latin1_dsplen, pg_latin1_verifychar, pg_latin1_verifystr, 1}, /* PG_KOI8U */ + {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifychar, pg_sjis_verifystr, 2}, /* PG_SJIS */ + {0, 0, pg_big5_mblen, pg_big5_dsplen, pg_big5_verifychar, pg_big5_verifystr, 2}, /* PG_BIG5 */ + {0, 0, pg_gbk_mblen, pg_gbk_dsplen, pg_gbk_verifychar, pg_gbk_verifystr, 2}, /* PG_GBK */ + {0, 0, pg_uhc_mblen, pg_uhc_dsplen, pg_uhc_verifychar, pg_uhc_verifystr, 2}, /* PG_UHC */ + {0, 0, pg_gb18030_mblen, pg_gb18030_dsplen, pg_gb18030_verifychar, pg_gb18030_verifystr, 4}, /* PG_GB18030 */ + {0, 0, pg_johab_mblen, pg_johab_dsplen, pg_johab_verifychar, pg_johab_verifystr, 3}, /* PG_JOHAB */ + {0, 0, pg_sjis_mblen, pg_sjis_dsplen, pg_sjis_verifychar, pg_sjis_verifystr, 2} /* PG_SHIFT_JIS_2004 */ +}; + +/* + * Returns the byte length of a multibyte character. + * + * Caution: when dealing with text that is not certainly valid in the + * specified encoding, the result may exceed the actual remaining + * string length. Callers that are not prepared to deal with that + * should use pg_encoding_mblen_bounded() instead. + */ +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 byte length of a multibyte character; but not more than + * the distance to end of string. + */ +int +pg_encoding_mblen_bounded(int encoding, const char *mbstr) +{ + return strnlen(mbstr, pg_encoding_mblen(encoding, 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 mbverifychar API.) + */ +int +pg_encoding_verifymbchar(int encoding, const char *mbstr, int len) +{ + return (PG_VALID_ENCODING(encoding) ? + pg_wchar_table[encoding].mbverifychar((const unsigned char *) mbstr, len) : + pg_wchar_table[PG_SQL_ASCII].mbverifychar((const unsigned char *) mbstr, len)); +} + +/* + * Verify that a string is valid for the given encoding. + * Returns the number of input bytes (<= len) that form a valid string. + * (See comments above for full details of the mbverifystr API.) + */ +int +pg_encoding_verifymbstr(int encoding, const char *mbstr, int len) +{ + return (PG_VALID_ENCODING(encoding) ? + pg_wchar_table[encoding].mbverifystr((const unsigned char *) mbstr, len) : + pg_wchar_table[PG_SQL_ASCII].mbverifystr((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; +} diff --git a/contrib/libs/libpq/src/include/access/rmgr.h b/contrib/libs/libpq/src/include/access/rmgr.h new file mode 100644 index 0000000000..3b6a497e1b --- /dev/null +++ b/contrib/libs/libpq/src/include/access/rmgr.h @@ -0,0 +1,62 @@ +/* + * rmgr.h + * + * Resource managers definition + * + * src/include/access/rmgr.h + */ +#ifndef RMGR_H +#define RMGR_H + +typedef uint8 RmgrId; + +/* + * Built-in resource managers + * + * The actual numerical values for each rmgr ID are defined by the order + * of entries in rmgrlist.h. + * + * Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG + * file format. + */ +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \ + symname, + +typedef enum RmgrIds +{ +#include "access/rmgrlist.h" + RM_NEXT_ID +} RmgrIds; + +#undef PG_RMGR + +#define RM_MAX_ID UINT8_MAX +#define RM_MAX_BUILTIN_ID (RM_NEXT_ID - 1) +#define RM_MIN_CUSTOM_ID 128 +#define RM_MAX_CUSTOM_ID UINT8_MAX +#define RM_N_IDS (UINT8_MAX + 1) +#define RM_N_BUILTIN_IDS (RM_MAX_BUILTIN_ID + 1) +#define RM_N_CUSTOM_IDS (RM_MAX_CUSTOM_ID - RM_MIN_CUSTOM_ID + 1) + +static inline bool +RmgrIdIsBuiltin(int rmid) +{ + return rmid <= RM_MAX_BUILTIN_ID; +} + +static inline bool +RmgrIdIsCustom(int rmid) +{ + return rmid >= RM_MIN_CUSTOM_ID && rmid <= RM_MAX_CUSTOM_ID; +} + +#define RmgrIdIsValid(rmid) (RmgrIdIsBuiltin((rmid)) || RmgrIdIsCustom((rmid))) + +/* + * RmgrId to use for extensions that require an RmgrId, but are still in + * development and have not reserved their own unique RmgrId yet. See: + * https://wiki.postgresql.org/wiki/CustomWALResourceManagers + */ +#define RM_EXPERIMENTAL_ID 128 + +#endif /* RMGR_H */ diff --git a/contrib/libs/libpq/src/include/access/rmgrlist.h b/contrib/libs/libpq/src/include/access/rmgrlist.h new file mode 100644 index 0000000000..463bcb67c5 --- /dev/null +++ b/contrib/libs/libpq/src/include/access/rmgrlist.h @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------- + * rmgrlist.h + * + * The resource manager list is kept in its own source file for possible + * use by automatic tools. The exact representation of a rmgr is determined + * by the PG_RMGR macro, which is not defined in this file; it can be + * defined by the caller for special purposes. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/rmgrlist.h + *--------------------------------------------------------------------------- + */ + +/* there is deliberately not an #ifndef RMGRLIST_H here */ + +/* + * List of resource manager entries. Note that order of entries defines the + * numerical values of each rmgr's ID, which is stored in WAL records. New + * entries should be added at the end, to avoid changing IDs of existing + * entries. + * + * Changes to this list possibly need an XLOG_PAGE_MAGIC bump. + */ + +/* symbol name, textual name, redo, desc, identify, startup, cleanup, mask, decode */ +PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL, NULL, xlog_decode) +PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL, NULL, xact_decode) +PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL, NULL, standby_decode) +PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL, heap_mask, heap2_decode) +PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL, heap_mask, heap_decode) +PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, btree_xlog_startup, btree_xlog_cleanup, btree_mask, NULL) +PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL, hash_mask, NULL) +PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup, gin_mask, NULL) +PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup, gist_mask, NULL) +PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL, seq_mask, NULL) +PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup, spg_mask, NULL) +PG_RMGR(RM_BRIN_ID, "BRIN", brin_redo, brin_desc, brin_identify, NULL, NULL, brin_mask, NULL) +PG_RMGR(RM_COMMIT_TS_ID, "CommitTs", commit_ts_redo, commit_ts_desc, commit_ts_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_REPLORIGIN_ID, "ReplicationOrigin", replorigin_redo, replorigin_desc, replorigin_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_GENERIC_ID, "Generic", generic_redo, generic_desc, generic_identify, NULL, NULL, generic_mask, NULL) +PG_RMGR(RM_LOGICALMSG_ID, "LogicalMessage", logicalmsg_redo, logicalmsg_desc, logicalmsg_identify, NULL, NULL, NULL, logicalmsg_decode) diff --git a/contrib/libs/libpq/src/include/access/transam.h b/contrib/libs/libpq/src/include/access/transam.h new file mode 100644 index 0000000000..f5af6d3055 --- /dev/null +++ b/contrib/libs/libpq/src/include/access/transam.h @@ -0,0 +1,375 @@ +/*------------------------------------------------------------------------- + * + * transam.h + * postgres transaction access method support code + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/transam.h + * + *------------------------------------------------------------------------- + */ +#ifndef TRANSAM_H +#define TRANSAM_H + +#include "access/xlogdefs.h" + + +/* ---------------- + * Special transaction ID values + * + * BootstrapTransactionId is the XID for "bootstrap" operations, and + * FrozenTransactionId is used for very old tuples. Both should + * always be considered valid. + * + * FirstNormalTransactionId is the first "normal" transaction id. + * Note: if you need to change it, you must change pg_class.h as well. + * ---------------- + */ +#define InvalidTransactionId ((TransactionId) 0) +#define BootstrapTransactionId ((TransactionId) 1) +#define FrozenTransactionId ((TransactionId) 2) +#define FirstNormalTransactionId ((TransactionId) 3) +#define MaxTransactionId ((TransactionId) 0xFFFFFFFF) + +/* ---------------- + * transaction ID manipulation macros + * ---------------- + */ +#define TransactionIdIsValid(xid) ((xid) != InvalidTransactionId) +#define TransactionIdIsNormal(xid) ((xid) >= FirstNormalTransactionId) +#define TransactionIdEquals(id1, id2) ((id1) == (id2)) +#define TransactionIdStore(xid, dest) (*(dest) = (xid)) +#define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId) + +#define EpochFromFullTransactionId(x) ((uint32) ((x).value >> 32)) +#define XidFromFullTransactionId(x) ((uint32) (x).value) +#define U64FromFullTransactionId(x) ((x).value) +#define FullTransactionIdEquals(a, b) ((a).value == (b).value) +#define FullTransactionIdPrecedes(a, b) ((a).value < (b).value) +#define FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value) +#define FullTransactionIdFollows(a, b) ((a).value > (b).value) +#define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value) +#define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x)) +#define InvalidFullTransactionId FullTransactionIdFromEpochAndXid(0, InvalidTransactionId) +#define FirstNormalFullTransactionId FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId) +#define FullTransactionIdIsNormal(x) FullTransactionIdFollowsOrEquals(x, FirstNormalFullTransactionId) + +/* + * A 64 bit value that contains an epoch and a TransactionId. This is + * wrapped in a struct to prevent implicit conversion to/from TransactionId. + * Not all values represent valid normal XIDs. + */ +typedef struct FullTransactionId +{ + uint64 value; +} FullTransactionId; + +static inline FullTransactionId +FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid) +{ + FullTransactionId result; + + result.value = ((uint64) epoch) << 32 | xid; + + return result; +} + +static inline FullTransactionId +FullTransactionIdFromU64(uint64 value) +{ + FullTransactionId result; + + result.value = value; + + return result; +} + +/* advance a transaction ID variable, handling wraparound correctly */ +#define TransactionIdAdvance(dest) \ + do { \ + (dest)++; \ + if ((dest) < FirstNormalTransactionId) \ + (dest) = FirstNormalTransactionId; \ + } while(0) + +/* + * Retreat a FullTransactionId variable, stepping over xids that would appear + * to be special only when viewed as 32bit XIDs. + */ +static inline void +FullTransactionIdRetreat(FullTransactionId *dest) +{ + dest->value--; + + /* + * In contrast to 32bit XIDs don't step over the "actual" special xids. + * For 64bit xids these can't be reached as part of a wraparound as they + * can in the 32bit case. + */ + if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) + return; + + /* + * But we do need to step over XIDs that'd appear special only for 32bit + * XIDs. + */ + while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) + dest->value--; +} + +/* + * Advance a FullTransactionId variable, stepping over xids that would appear + * to be special only when viewed as 32bit XIDs. + */ +static inline void +FullTransactionIdAdvance(FullTransactionId *dest) +{ + dest->value++; + + /* see FullTransactionIdAdvance() */ + if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) + return; + + while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) + dest->value++; +} + +/* back up a transaction ID variable, handling wraparound correctly */ +#define TransactionIdRetreat(dest) \ + do { \ + (dest)--; \ + } while ((dest) < FirstNormalTransactionId) + +/* compare two XIDs already known to be normal; this is a macro for speed */ +#define NormalTransactionIdPrecedes(id1, id2) \ + (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ + (int32) ((id1) - (id2)) < 0) + +/* compare two XIDs already known to be normal; this is a macro for speed */ +#define NormalTransactionIdFollows(id1, id2) \ + (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ + (int32) ((id1) - (id2)) > 0) + +/* ---------- + * Object ID (OID) zero is InvalidOid. + * + * OIDs 1-9999 are reserved for manual assignment (see .dat files in + * src/include/catalog/). Of these, 8000-9999 are reserved for + * development purposes (such as in-progress patches and forks); + * they should not appear in released versions. + * + * OIDs 10000-11999 are reserved for assignment by genbki.pl, for use + * when the .dat files in src/include/catalog/ do not specify an OID + * for a catalog entry that requires one. Note that genbki.pl assigns + * these OIDs independently in each catalog, so they're not guaranteed + * to be globally unique. Furthermore, the bootstrap backend and + * initdb's post-bootstrap processing can also assign OIDs in this range. + * The normal OID-generation logic takes care of any OID conflicts that + * might arise from that. + * + * OIDs 12000-16383 are reserved for unpinned objects created by initdb's + * post-bootstrap processing. initdb forces the OID generator up to + * 12000 as soon as it's made the pinned objects it's responsible for. + * + * OIDs beginning at 16384 are assigned from the OID generator + * during normal multiuser operation. (We force the generator up to + * 16384 as soon as we are in normal operation.) + * + * The choices of 8000, 10000 and 12000 are completely arbitrary, and can be + * moved if we run low on OIDs in any category. Changing the macros below, + * and updating relevant documentation (see bki.sgml and RELEASE_CHANGES), + * should be sufficient to do this. Moving the 16384 boundary between + * initdb-assigned OIDs and user-defined objects would be substantially + * more painful, however, since some user-defined OIDs will appear in + * on-disk data; such a change would probably break pg_upgrade. + * + * NOTE: if the OID generator wraps around, we skip over OIDs 0-16383 + * and resume with 16384. This minimizes the odds of OID conflict, by not + * reassigning OIDs that might have been assigned during initdb. Critically, + * it also ensures that no user-created object will be considered pinned. + * ---------- + */ +#define FirstGenbkiObjectId 10000 +#define FirstUnpinnedObjectId 12000 +#define FirstNormalObjectId 16384 + +/* + * VariableCache is a data structure in shared memory that is used to track + * OID and XID assignment state. For largely historical reasons, there is + * just one struct with different fields that are protected by different + * LWLocks. + * + * Note: xidWrapLimit and oldestXidDB are not "active" values, but are + * used just to generate useful messages when xidWarnLimit or xidStopLimit + * are exceeded. + */ +typedef struct VariableCacheData +{ + /* + * These fields are protected by OidGenLock. + */ + Oid nextOid; /* next OID to assign */ + uint32 oidCount; /* OIDs available before must do XLOG work */ + + /* + * These fields are protected by XidGenLock. + */ + FullTransactionId nextXid; /* next XID to assign */ + + TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ + TransactionId xidVacLimit; /* start forcing autovacuums here */ + TransactionId xidWarnLimit; /* start complaining here */ + TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */ + TransactionId xidWrapLimit; /* where the world ends */ + Oid oldestXidDB; /* database with minimum datfrozenxid */ + + /* + * These fields are protected by CommitTsLock + */ + TransactionId oldestCommitTsXid; + TransactionId newestCommitTsXid; + + /* + * These fields are protected by ProcArrayLock. + */ + FullTransactionId latestCompletedXid; /* newest full XID that has + * committed or aborted */ + + /* + * Number of top-level transactions with xids (i.e. which may have + * modified the database) that completed in some form since the start of + * the server. This currently is solely used to check whether + * GetSnapshotData() needs to recompute the contents of the snapshot, or + * not. There are likely other users of this. Always above 1. + */ + uint64 xactCompletionCount; + + /* + * These fields are protected by XactTruncationLock + */ + TransactionId oldestClogXid; /* oldest it's safe to look up in clog */ + +} VariableCacheData; + +typedef VariableCacheData *VariableCache; + + +/* ---------------- + * extern declarations + * ---------------- + */ + +/* in transam/xact.c */ +extern bool TransactionStartedDuringRecovery(void); + +/* in transam/varsup.c */ +extern PGDLLIMPORT VariableCache ShmemVariableCache; + +/* + * prototypes for functions in transam/transam.c + */ +extern bool TransactionIdDidCommit(TransactionId transactionId); +extern bool TransactionIdDidAbort(TransactionId transactionId); +extern void TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids); +extern void TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn); +extern void TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids); +extern bool TransactionIdPrecedes(TransactionId id1, TransactionId id2); +extern bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2); +extern bool TransactionIdFollows(TransactionId id1, TransactionId id2); +extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2); +extern TransactionId TransactionIdLatest(TransactionId mainxid, + int nxids, const TransactionId *xids); +extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid); + +/* in transam/varsup.c */ +extern FullTransactionId GetNewTransactionId(bool isSubXact); +extern void AdvanceNextFullTransactionIdPastXid(TransactionId xid); +extern FullTransactionId ReadNextFullTransactionId(void); +extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, + Oid oldest_datoid); +extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid); +extern bool ForceTransactionIdLimitUpdate(void); +extern Oid GetNewObjectId(void); +extern void StopGeneratingPinnedObjectIds(void); + +#ifdef USE_ASSERT_CHECKING +extern void AssertTransactionIdInAllowableRange(TransactionId xid); +#else +#define AssertTransactionIdInAllowableRange(xid) ((void)true) +#endif + +/* + * Some frontend programs include this header. For compilers that emit static + * inline functions even when they're unused, that leads to unsatisfied + * external references; hence hide them with #ifndef FRONTEND. + */ +#ifndef FRONTEND + +/* + * For callers that just need the XID part of the next transaction ID. + */ +static inline TransactionId +ReadNextTransactionId(void) +{ + return XidFromFullTransactionId(ReadNextFullTransactionId()); +} + +/* return transaction ID backed up by amount, handling wraparound correctly */ +static inline TransactionId +TransactionIdRetreatedBy(TransactionId xid, uint32 amount) +{ + xid -= amount; + + while (xid < FirstNormalTransactionId) + xid--; + + return xid; +} + +/* return the older of the two IDs */ +static inline TransactionId +TransactionIdOlder(TransactionId a, TransactionId b) +{ + if (!TransactionIdIsValid(a)) + return b; + + if (!TransactionIdIsValid(b)) + return a; + + if (TransactionIdPrecedes(a, b)) + return a; + return b; +} + +/* return the older of the two IDs, assuming they're both normal */ +static inline TransactionId +NormalTransactionIdOlder(TransactionId a, TransactionId b) +{ + Assert(TransactionIdIsNormal(a)); + Assert(TransactionIdIsNormal(b)); + if (NormalTransactionIdPrecedes(a, b)) + return a; + return b; +} + +/* return the newer of the two IDs */ +static inline FullTransactionId +FullTransactionIdNewer(FullTransactionId a, FullTransactionId b) +{ + if (!FullTransactionIdIsValid(a)) + return b; + + if (!FullTransactionIdIsValid(b)) + return a; + + if (FullTransactionIdFollows(a, b)) + return a; + return b; +} + +#endif /* FRONTEND */ + +#endif /* TRANSAM_H */ diff --git a/contrib/libs/libpq/src/include/access/xlog_internal.h b/contrib/libs/libpq/src/include/access/xlog_internal.h new file mode 100644 index 0000000000..b0fd338a00 --- /dev/null +++ b/contrib/libs/libpq/src/include/access/xlog_internal.h @@ -0,0 +1,404 @@ +/* + * xlog_internal.h + * + * PostgreSQL write-ahead log internal declarations + * + * NOTE: this file is intended to contain declarations useful for + * manipulating the XLOG files directly, but it is not supposed to be + * needed by rmgr routines (redo support for individual record types). + * So the XLogRecord typedef and associated stuff appear in xlogrecord.h. + * + * Note: This file must be includable in both frontend and backend contexts, + * to allow stand-alone tools like pg_receivewal to deal with WAL files. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlog_internal.h + */ +#ifndef XLOG_INTERNAL_H +#define XLOG_INTERNAL_H + +#include "access/xlogdefs.h" +#include "access/xlogreader.h" +#include "datatype/timestamp.h" +#include "lib/stringinfo.h" +#include "pgtime.h" +#include "storage/block.h" +#include "storage/relfilelocator.h" + + +/* + * Each page of XLOG file has a header like this: + */ +#define XLOG_PAGE_MAGIC 0xD113 /* can be used as WAL version indicator */ + +typedef struct XLogPageHeaderData +{ + uint16 xlp_magic; /* magic value for correctness checks */ + uint16 xlp_info; /* flag bits, see below */ + TimeLineID xlp_tli; /* TimeLineID of first record on page */ + XLogRecPtr xlp_pageaddr; /* XLOG address of this page */ + + /* + * When there is not enough space on current page for whole record, we + * continue on the next page. xlp_rem_len is the number of bytes + * remaining from a previous page; it tracks xl_tot_len in the initial + * header. Note that the continuation data isn't necessarily aligned. + */ + uint32 xlp_rem_len; /* total len of remaining data for record */ +} XLogPageHeaderData; + +#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData)) + +typedef XLogPageHeaderData *XLogPageHeader; + +/* + * When the XLP_LONG_HEADER flag is set, we store additional fields in the + * page header. (This is ordinarily done just in the first page of an + * XLOG file.) The additional fields serve to identify the file accurately. + */ +typedef struct XLogLongPageHeaderData +{ + XLogPageHeaderData std; /* standard header fields */ + uint64 xlp_sysid; /* system identifier from pg_control */ + uint32 xlp_seg_size; /* just as a cross-check */ + uint32 xlp_xlog_blcksz; /* just as a cross-check */ +} XLogLongPageHeaderData; + +#define SizeOfXLogLongPHD MAXALIGN(sizeof(XLogLongPageHeaderData)) + +typedef XLogLongPageHeaderData *XLogLongPageHeader; + +/* When record crosses page boundary, set this flag in new page's header */ +#define XLP_FIRST_IS_CONTRECORD 0x0001 +/* This flag indicates a "long" page header */ +#define XLP_LONG_HEADER 0x0002 +/* This flag indicates backup blocks starting in this page are optional */ +#define XLP_BKP_REMOVABLE 0x0004 +/* Replaces a missing contrecord; see CreateOverwriteContrecordRecord */ +#define XLP_FIRST_IS_OVERWRITE_CONTRECORD 0x0008 +/* All defined flag bits in xlp_info (used for validity checking of header) */ +#define XLP_ALL_FLAGS 0x000F + +#define XLogPageHeaderSize(hdr) \ + (((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD) + +/* wal_segment_size can range from 1MB to 1GB */ +#define WalSegMinSize 1024 * 1024 +#define WalSegMaxSize 1024 * 1024 * 1024 +/* default number of min and max wal segments */ +#define DEFAULT_MIN_WAL_SEGS 5 +#define DEFAULT_MAX_WAL_SEGS 64 + +/* check that the given size is a valid wal_segment_size */ +#define IsPowerOf2(x) (x > 0 && ((x) & ((x)-1)) == 0) +#define IsValidWalSegSize(size) \ + (IsPowerOf2(size) && \ + ((size) >= WalSegMinSize && (size) <= WalSegMaxSize)) + +#define XLogSegmentsPerXLogId(wal_segsz_bytes) \ + (UINT64CONST(0x100000000) / (wal_segsz_bytes)) + +#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest) \ + (dest) = (segno) * (wal_segsz_bytes) + (offset) + +#define XLogSegmentOffset(xlogptr, wal_segsz_bytes) \ + ((xlogptr) & ((wal_segsz_bytes) - 1)) + +/* + * Compute a segment number from an XLogRecPtr. + * + * For XLByteToSeg, do the computation at face value. For XLByteToPrevSeg, + * a boundary byte is taken to be in the previous segment. This is suitable + * for deciding which segment to write given a pointer to a record end, + * for example. + */ +#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes) \ + logSegNo = (xlrp) / (wal_segsz_bytes) + +#define XLByteToPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \ + logSegNo = ((xlrp) - 1) / (wal_segsz_bytes) + +/* + * Convert values of GUCs measured in megabytes to equiv. segment count. + * Rounds down. + */ +#define XLogMBVarToSegs(mbvar, wal_segsz_bytes) \ + ((mbvar) / ((wal_segsz_bytes) / (1024 * 1024))) + +/* + * Is an XLogRecPtr within a particular XLOG segment? + * + * For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg, + * a boundary byte is taken to be in the previous segment. + */ +#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes) \ + (((xlrp) / (wal_segsz_bytes)) == (logSegNo)) + +#define XLByteInPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \ + ((((xlrp) - 1) / (wal_segsz_bytes)) == (logSegNo)) + +/* Check if an XLogRecPtr value is in a plausible range */ +#define XRecOffIsValid(xlrp) \ + ((xlrp) % XLOG_BLCKSZ >= SizeOfXLogShortPHD) + +/* + * The XLog directory and control file (relative to $PGDATA) + */ +#define XLOGDIR "pg_wal" +#define XLOG_CONTROL_FILE "global/pg_control" + +/* + * These macros encapsulate knowledge about the exact layout of XLog file + * names, timeline history file names, and archive-status file names. + */ +#define MAXFNAMELEN 64 + +/* Length of XLog file name */ +#define XLOG_FNAME_LEN 24 + +/* + * Generate a WAL segment file name. Do not use this function in a helper + * function allocating the result generated. + */ +static inline void +XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes) +{ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, + (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes))); +} + +static inline void +XLogFileNameById(char *fname, TimeLineID tli, uint32 log, uint32 seg) +{ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg); +} + +static inline bool +IsXLogFileName(const char *fname) +{ + return (strlen(fname) == XLOG_FNAME_LEN && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN); +} + +/* + * XLOG segment with .partial suffix. Used by pg_receivewal and at end of + * archive recovery, when we want to archive a WAL segment but it might not + * be complete yet. + */ +static inline bool +IsPartialXLogFileName(const char *fname) +{ + return (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") && + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && + strcmp(fname + XLOG_FNAME_LEN, ".partial") == 0); +} + +static inline void +XLogFromFileName(const char *fname, TimeLineID *tli, XLogSegNo *logSegNo, int wal_segsz_bytes) +{ + uint32 log; + uint32 seg; + + sscanf(fname, "%08X%08X%08X", tli, &log, &seg); + *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; +} + +static inline void +XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes) +{ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, + (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes))); +} + +static inline void +TLHistoryFileName(char *fname, TimeLineID tli) +{ + snprintf(fname, MAXFNAMELEN, "%08X.history", tli); +} + +static inline bool +IsTLHistoryFileName(const char *fname) +{ + return (strlen(fname) == 8 + strlen(".history") && + strspn(fname, "0123456789ABCDEF") == 8 && + strcmp(fname + 8, ".history") == 0); +} + +static inline void +TLHistoryFilePath(char *path, TimeLineID tli) +{ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli); +} + +static inline void +StatusFilePath(char *path, const char *xlog, const char *suffix) +{ + snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix); +} + +static inline void +BackupHistoryFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes) +{ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, + (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes))); +} + +static inline bool +IsBackupHistoryFileName(const char *fname) +{ + return (strlen(fname) > XLOG_FNAME_LEN && + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && + strcmp(fname + strlen(fname) - strlen(".backup"), ".backup") == 0); +} + +static inline void +BackupHistoryFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, XLogRecPtr startpoint, int wal_segsz_bytes) +{ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, + (uint32) (logSegNo / XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (logSegNo % XLogSegmentsPerXLogId(wal_segsz_bytes)), + (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes))); +} + +/* + * Information logged when we detect a change in one of the parameters + * important for Hot Standby. + */ +typedef struct xl_parameter_change +{ + int MaxConnections; + int max_worker_processes; + int max_wal_senders; + int max_prepared_xacts; + int max_locks_per_xact; + int wal_level; + bool wal_log_hints; + bool track_commit_timestamp; +} xl_parameter_change; + +/* logs restore point */ +typedef struct xl_restore_point +{ + TimestampTz rp_time; + char rp_name[MAXFNAMELEN]; +} xl_restore_point; + +/* Overwrite of prior contrecord */ +typedef struct xl_overwrite_contrecord +{ + XLogRecPtr overwritten_lsn; + TimestampTz overwrite_time; +} xl_overwrite_contrecord; + +/* End of recovery mark, when we don't do an END_OF_RECOVERY checkpoint */ +typedef struct xl_end_of_recovery +{ + TimestampTz end_time; + TimeLineID ThisTimeLineID; /* new TLI */ + TimeLineID PrevTimeLineID; /* previous TLI we forked off from */ +} xl_end_of_recovery; + +/* + * The functions in xloginsert.c construct a chain of XLogRecData structs + * to represent the final WAL record. + */ +typedef struct XLogRecData +{ + struct XLogRecData *next; /* next struct in chain, or NULL */ + char *data; /* start of rmgr data to include */ + uint32 len; /* length of rmgr data to include */ +} XLogRecData; + +/* + * Recovery target action. + */ +typedef enum +{ + RECOVERY_TARGET_ACTION_PAUSE, + RECOVERY_TARGET_ACTION_PROMOTE, + RECOVERY_TARGET_ACTION_SHUTDOWN +} RecoveryTargetAction; + +struct LogicalDecodingContext; +struct XLogRecordBuffer; + +/* + * Method table for resource managers. + * + * This struct must be kept in sync with the PG_RMGR definition in + * rmgr.c. + * + * rm_identify must return a name for the record based on xl_info (without + * reference to the rmid). For example, XLOG_BTREE_VACUUM would be named + * "VACUUM". rm_desc can then be called to obtain additional detail for the + * record, if available (e.g. the last block). + * + * rm_mask takes as input a page modified by the resource manager and masks + * out bits that shouldn't be flagged by wal_consistency_checking. + * + * RmgrTable[] is indexed by RmgrId values (see rmgrlist.h). If rm_name is + * NULL, the corresponding RmgrTable entry is considered invalid. + */ +typedef struct RmgrData +{ + const char *rm_name; + void (*rm_redo) (XLogReaderState *record); + void (*rm_desc) (StringInfo buf, XLogReaderState *record); + const char *(*rm_identify) (uint8 info); + void (*rm_startup) (void); + void (*rm_cleanup) (void); + void (*rm_mask) (char *pagedata, BlockNumber blkno); + void (*rm_decode) (struct LogicalDecodingContext *ctx, + struct XLogRecordBuffer *buf); +} RmgrData; + +extern PGDLLIMPORT RmgrData RmgrTable[]; +extern void RmgrStartup(void); +extern void RmgrCleanup(void); +extern void RmgrNotFound(RmgrId rmid); +extern void RegisterCustomRmgr(RmgrId rmid, const RmgrData *rmgr); + +#ifndef FRONTEND +static inline bool +RmgrIdExists(RmgrId rmid) +{ + return RmgrTable[rmid].rm_name != NULL; +} + +static inline RmgrData +GetRmgr(RmgrId rmid) +{ + if (unlikely(!RmgrIdExists(rmid))) + RmgrNotFound(rmid); + return RmgrTable[rmid]; +} +#endif + +/* + * Exported to support xlog switching from checkpointer + */ +extern pg_time_t GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN); +extern XLogRecPtr RequestXLogSwitch(bool mark_unimportant); + +extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli); + +extern void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, + bool detailed_format, StringInfo buf, + uint32 *fpi_len); + +/* + * Exported for the functions in timeline.c and xlogarchive.c. Only valid + * in the startup process. + */ +extern PGDLLIMPORT bool ArchiveRecoveryRequested; +extern PGDLLIMPORT bool InArchiveRecovery; +extern PGDLLIMPORT bool StandbyMode; +extern PGDLLIMPORT char *recoveryRestoreCommand; + +#endif /* XLOG_INTERNAL_H */ diff --git a/contrib/libs/libpq/src/include/access/xlogdefs.h b/contrib/libs/libpq/src/include/access/xlogdefs.h new file mode 100644 index 0000000000..fe794c7740 --- /dev/null +++ b/contrib/libs/libpq/src/include/access/xlogdefs.h @@ -0,0 +1,82 @@ +/* + * xlogdefs.h + * + * Postgres write-ahead log manager record pointer and + * timeline number definitions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogdefs.h + */ +#ifndef XLOG_DEFS_H +#define XLOG_DEFS_H + +#include <fcntl.h> /* need open() flags */ + +/* + * Pointer to a location in the XLOG. These pointers are 64 bits wide, + * because we don't want them ever to overflow. + */ +typedef uint64 XLogRecPtr; + +/* + * Zero is used indicate an invalid pointer. Bootstrap skips the first possible + * WAL segment, initializing the first WAL page at WAL segment size, so no XLOG + * record can begin at zero. + */ +#define InvalidXLogRecPtr 0 +#define XLogRecPtrIsInvalid(r) ((r) == InvalidXLogRecPtr) + +/* + * First LSN to use for "fake" LSNs. + * + * Values smaller than this can be used for special per-AM purposes. + */ +#define FirstNormalUnloggedLSN ((XLogRecPtr) 1000) + +/* + * Handy macro for printing XLogRecPtr in conventional format, e.g., + * + * printf("%X/%X", LSN_FORMAT_ARGS(lsn)); + */ +#define LSN_FORMAT_ARGS(lsn) (AssertVariableIsOfTypeMacro((lsn), XLogRecPtr), (uint32) ((lsn) >> 32)), ((uint32) (lsn)) + +/* + * XLogSegNo - physical log file sequence number. + */ +typedef uint64 XLogSegNo; + +/* + * TimeLineID (TLI) - identifies different database histories to prevent + * confusion after restoring a prior state of a database installation. + * TLI does not change in a normal stop/restart of the database (including + * crash-and-recover cases); but we must assign a new TLI after doing + * a recovery to a prior state, a/k/a point-in-time recovery. This makes + * the new WAL logfile sequence we generate distinguishable from the + * sequence that was generated in the previous incarnation. + */ +typedef uint32 TimeLineID; + +/* + * Replication origin id - this is located in this file to avoid having to + * include origin.h in a bunch of xlog related places. + */ +typedef uint16 RepOriginId; + +/* + * This chunk of hackery attempts to determine which file sync methods + * are available on the current platform, and to choose an appropriate + * default method. + * + * Note that we define our own O_DSYNC on Windows, but not O_SYNC. + */ +#if defined(PLATFORM_DEFAULT_SYNC_METHOD) +#define DEFAULT_SYNC_METHOD PLATFORM_DEFAULT_SYNC_METHOD +#elif defined(O_DSYNC) && (!defined(O_SYNC) || O_DSYNC != O_SYNC) +#define DEFAULT_SYNC_METHOD SYNC_METHOD_OPEN_DSYNC +#else +#define DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC +#endif + +#endif /* XLOG_DEFS_H */ diff --git a/contrib/libs/libpq/src/include/access/xlogreader.h b/contrib/libs/libpq/src/include/access/xlogreader.h new file mode 100644 index 0000000000..da32c7db77 --- /dev/null +++ b/contrib/libs/libpq/src/include/access/xlogreader.h @@ -0,0 +1,444 @@ +/*------------------------------------------------------------------------- + * + * xlogreader.h + * Definitions for the generic XLog reading facility + * + * Portions Copyright (c) 2013-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/access/xlogreader.h + * + * NOTES + * See the definition of the XLogReaderState struct for instructions on + * how to use the XLogReader infrastructure. + * + * The basic idea is to allocate an XLogReaderState via + * XLogReaderAllocate(), position the reader to the first record with + * XLogBeginRead() or XLogFindNextRecord(), and call XLogReadRecord() + * until it returns NULL. + * + * Callers supply a page_read callback if they want to call + * XLogReadRecord or XLogFindNextRecord; it can be passed in as NULL + * otherwise. The WALRead function can be used as a helper to write + * page_read callbacks, but it is not mandatory; callers that use it, + * must supply segment_open callbacks. The segment_close callback + * must always be supplied. + * + * After reading a record with XLogReadRecord(), it's decomposed into + * the per-block and main data parts, and the parts can be accessed + * with the XLogRec* macros and functions. You can also decode a + * record that's already constructed in memory, without reading from + * disk, by calling the DecodeXLogRecord() function. + *------------------------------------------------------------------------- + */ +#ifndef XLOGREADER_H +#define XLOGREADER_H + +#ifndef FRONTEND +#include "access/transam.h" +#endif + +#include "access/xlogrecord.h" +#include "storage/buf.h" + +/* WALOpenSegment represents a WAL segment being read. */ +typedef struct WALOpenSegment +{ + int ws_file; /* segment file descriptor */ + XLogSegNo ws_segno; /* segment number */ + TimeLineID ws_tli; /* timeline ID of the currently open file */ +} WALOpenSegment; + +/* WALSegmentContext carries context information about WAL segments to read */ +typedef struct WALSegmentContext +{ + char ws_dir[MAXPGPATH]; + int ws_segsize; +} WALSegmentContext; + +typedef struct XLogReaderState XLogReaderState; + +/* Function type definitions for various xlogreader interactions */ +typedef int (*XLogPageReadCB) (XLogReaderState *xlogreader, + XLogRecPtr targetPagePtr, + int reqLen, + XLogRecPtr targetRecPtr, + char *readBuf); +typedef void (*WALSegmentOpenCB) (XLogReaderState *xlogreader, + XLogSegNo nextSegNo, + TimeLineID *tli_p); +typedef void (*WALSegmentCloseCB) (XLogReaderState *xlogreader); + +typedef struct XLogReaderRoutine +{ + /* + * Data input callback + * + * This callback shall read at least reqLen valid bytes of the xlog page + * starting at targetPagePtr, and store them in readBuf. The callback + * shall return the number of bytes read (never more than XLOG_BLCKSZ), or + * -1 on failure. The callback shall sleep, if necessary, to wait for the + * requested bytes to become available. The callback will not be invoked + * again for the same page unless more than the returned number of bytes + * are needed. + * + * targetRecPtr is the position of the WAL record we're reading. Usually + * it is equal to targetPagePtr + reqLen, but sometimes xlogreader needs + * to read and verify the page or segment header, before it reads the + * actual WAL record it's interested in. In that case, targetRecPtr can + * be used to determine which timeline to read the page from. + * + * The callback shall set ->seg.ws_tli to the TLI of the file the page was + * read from. + */ + XLogPageReadCB page_read; + + /* + * Callback to open the specified WAL segment for reading. ->seg.ws_file + * shall be set to the file descriptor of the opened segment. In case of + * failure, an error shall be raised by the callback and it shall not + * return. + * + * "nextSegNo" is the number of the segment to be opened. + * + * "tli_p" is an input/output argument. WALRead() uses it to pass the + * timeline in which the new segment should be found, but the callback can + * use it to return the TLI that it actually opened. + */ + WALSegmentOpenCB segment_open; + + /* + * WAL segment close callback. ->seg.ws_file shall be set to a negative + * number. + */ + WALSegmentCloseCB segment_close; +} XLogReaderRoutine; + +#define XL_ROUTINE(...) &(XLogReaderRoutine){__VA_ARGS__} + +typedef struct +{ + /* Is this block ref in use? */ + bool in_use; + + /* Identify the block this refers to */ + RelFileLocator rlocator; + ForkNumber forknum; + BlockNumber blkno; + + /* Prefetching workspace. */ + Buffer prefetch_buffer; + + /* copy of the fork_flags field from the XLogRecordBlockHeader */ + uint8 flags; + + /* Information on full-page image, if any */ + bool has_image; /* has image, even for consistency checking */ + bool apply_image; /* has image that should be restored */ + char *bkp_image; + uint16 hole_offset; + uint16 hole_length; + uint16 bimg_len; + uint8 bimg_info; + + /* Buffer holding the rmgr-specific data associated with this block */ + bool has_data; + char *data; + uint16 data_len; + uint16 data_bufsz; +} DecodedBkpBlock; + +/* + * The decoded contents of a record. This occupies a contiguous region of + * memory, with main_data and blocks[n].data pointing to memory after the + * members declared here. + */ +typedef struct DecodedXLogRecord +{ + /* Private member used for resource management. */ + size_t size; /* total size of decoded record */ + bool oversized; /* outside the regular decode buffer? */ + struct DecodedXLogRecord *next; /* decoded record queue link */ + + /* Public members. */ + XLogRecPtr lsn; /* location */ + XLogRecPtr next_lsn; /* location of next record */ + XLogRecord header; /* header */ + RepOriginId record_origin; + TransactionId toplevel_xid; /* XID of top-level transaction */ + char *main_data; /* record's main data portion */ + uint32 main_data_len; /* main data portion's length */ + int max_block_id; /* highest block_id in use (-1 if none) */ + DecodedBkpBlock blocks[FLEXIBLE_ARRAY_MEMBER]; +} DecodedXLogRecord; + +struct XLogReaderState +{ + /* + * Operational callbacks + */ + XLogReaderRoutine routine; + + /* ---------------------------------------- + * Public parameters + * ---------------------------------------- + */ + + /* + * System identifier of the xlog files we're about to read. Set to zero + * (the default value) if unknown or unimportant. + */ + uint64 system_identifier; + + /* + * Opaque data for callbacks to use. Not used by XLogReader. + */ + void *private_data; + + /* + * Start and end point of last record read. EndRecPtr is also used as the + * position to read next. Calling XLogBeginRead() sets EndRecPtr to the + * starting position and ReadRecPtr to invalid. + * + * Start and end point of last record returned by XLogReadRecord(). These + * are also available as record->lsn and record->next_lsn. + */ + XLogRecPtr ReadRecPtr; /* start of last record read */ + XLogRecPtr EndRecPtr; /* end+1 of last record read */ + + /* + * Set at the end of recovery: the start point of a partial record at the + * end of WAL (InvalidXLogRecPtr if there wasn't one), and the start + * location of its first contrecord that went missing. + */ + XLogRecPtr abortedRecPtr; + XLogRecPtr missingContrecPtr; + /* Set when XLP_FIRST_IS_OVERWRITE_CONTRECORD is found */ + XLogRecPtr overwrittenRecPtr; + + + /* ---------------------------------------- + * Decoded representation of current record + * + * Use XLogRecGet* functions to investigate the record; these fields + * should not be accessed directly. + * ---------------------------------------- + * Start and end point of the last record read and decoded by + * XLogReadRecordInternal(). NextRecPtr is also used as the position to + * decode next. Calling XLogBeginRead() sets NextRecPtr and EndRecPtr to + * the requested starting position. + */ + XLogRecPtr DecodeRecPtr; /* start of last record decoded */ + XLogRecPtr NextRecPtr; /* end+1 of last record decoded */ + XLogRecPtr PrevRecPtr; /* start of previous record decoded */ + + /* Last record returned by XLogReadRecord(). */ + DecodedXLogRecord *record; + + /* ---------------------------------------- + * private/internal state + * ---------------------------------------- + */ + + /* + * Buffer for decoded records. This is a circular buffer, though + * individual records can't be split in the middle, so some space is often + * wasted at the end. Oversized records that don't fit in this space are + * allocated separately. + */ + char *decode_buffer; + size_t decode_buffer_size; + bool free_decode_buffer; /* need to free? */ + char *decode_buffer_head; /* data is read from the head */ + char *decode_buffer_tail; /* new data is written at the tail */ + + /* + * Queue of records that have been decoded. This is a linked list that + * usually consists of consecutive records in decode_buffer, but may also + * contain oversized records allocated with palloc(). + */ + DecodedXLogRecord *decode_queue_head; /* oldest decoded record */ + DecodedXLogRecord *decode_queue_tail; /* newest decoded record */ + + /* + * Buffer for currently read page (XLOG_BLCKSZ bytes, valid up to at least + * readLen bytes) + */ + char *readBuf; + uint32 readLen; + + /* last read XLOG position for data currently in readBuf */ + WALSegmentContext segcxt; + WALOpenSegment seg; + uint32 segoff; + + /* + * beginning of prior page read, and its TLI. Doesn't necessarily + * correspond to what's in readBuf; used for timeline sanity checks. + */ + XLogRecPtr latestPagePtr; + TimeLineID latestPageTLI; + + /* beginning of the WAL record being read. */ + XLogRecPtr currRecPtr; + /* timeline to read it from, 0 if a lookup is required */ + TimeLineID currTLI; + + /* + * Safe point to read to in currTLI if current TLI is historical + * (tliSwitchPoint) or InvalidXLogRecPtr if on current timeline. + * + * Actually set to the start of the segment containing the timeline switch + * that ends currTLI's validity, not the LSN of the switch its self, since + * we can't assume the old segment will be present. + */ + XLogRecPtr currTLIValidUntil; + + /* + * If currTLI is not the most recent known timeline, the next timeline to + * read from when currTLIValidUntil is reached. + */ + TimeLineID nextTLI; + + /* + * Buffer for current ReadRecord result (expandable), used when a record + * crosses a page boundary. + */ + char *readRecordBuf; + uint32 readRecordBufSize; + + /* Buffer to hold error message */ + char *errormsg_buf; + bool errormsg_deferred; + + /* + * Flag to indicate to XLogPageReadCB that it should not block waiting for + * data. + */ + bool nonblocking; +}; + +/* + * Check if XLogNextRecord() has any more queued records or an error to return. + */ +static inline bool +XLogReaderHasQueuedRecordOrError(XLogReaderState *state) +{ + return (state->decode_queue_head != NULL) || state->errormsg_deferred; +} + +/* Get a new XLogReader */ +extern XLogReaderState *XLogReaderAllocate(int wal_segment_size, + const char *waldir, + XLogReaderRoutine *routine, + void *private_data); + +/* Free an XLogReader */ +extern void XLogReaderFree(XLogReaderState *state); + +/* Optionally provide a circular decoding buffer to allow readahead. */ +extern void XLogReaderSetDecodeBuffer(XLogReaderState *state, + void *buffer, + size_t size); + +/* Position the XLogReader to given record */ +extern void XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr); +extern XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr); + +/* Return values from XLogPageReadCB. */ +typedef enum XLogPageReadResult +{ + XLREAD_SUCCESS = 0, /* record is successfully read */ + XLREAD_FAIL = -1, /* failed during reading a record */ + XLREAD_WOULDBLOCK = -2 /* nonblocking mode only, no data */ +} XLogPageReadResult; + +/* Read the next XLog record. Returns NULL on end-of-WAL or failure */ +extern struct XLogRecord *XLogReadRecord(XLogReaderState *state, + char **errormsg); + +/* Consume the next record or error. */ +extern DecodedXLogRecord *XLogNextRecord(XLogReaderState *state, + char **errormsg); + +/* Release the previously returned record, if necessary. */ +extern XLogRecPtr XLogReleasePreviousRecord(XLogReaderState *state); + +/* Try to read ahead, if there is data and space. */ +extern DecodedXLogRecord *XLogReadAhead(XLogReaderState *state, + bool nonblocking); + +/* Validate a page */ +extern bool XLogReaderValidatePageHeader(XLogReaderState *state, + XLogRecPtr recptr, char *phdr); + +/* Forget error produced by XLogReaderValidatePageHeader(). */ +extern void XLogReaderResetError(XLogReaderState *state); + +/* + * Error information from WALRead that both backend and frontend caller can + * process. Currently only errors from pg_pread can be reported. + */ +typedef struct WALReadError +{ + int wre_errno; /* errno set by the last pg_pread() */ + int wre_off; /* Offset we tried to read from. */ + int wre_req; /* Bytes requested to be read. */ + int wre_read; /* Bytes read by the last read(). */ + WALOpenSegment wre_seg; /* Segment we tried to read from. */ +} WALReadError; + +extern bool WALRead(XLogReaderState *state, + char *buf, XLogRecPtr startptr, Size count, + TimeLineID tli, WALReadError *errinfo); + +/* Functions for decoding an XLogRecord */ + +extern size_t DecodeXLogRecordRequiredSpace(size_t xl_tot_len); +extern bool DecodeXLogRecord(XLogReaderState *state, + DecodedXLogRecord *decoded, + XLogRecord *record, + XLogRecPtr lsn, + char **errormsg); + +/* + * Macros that provide access to parts of the record most recently returned by + * XLogReadRecord() or XLogNextRecord(). + */ +#define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len) +#define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev) +#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info) +#define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid) +#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid) +#define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin) +#define XLogRecGetTopXid(decoder) ((decoder)->record->toplevel_xid) +#define XLogRecGetData(decoder) ((decoder)->record->main_data) +#define XLogRecGetDataLen(decoder) ((decoder)->record->main_data_len) +#define XLogRecHasAnyBlockRefs(decoder) ((decoder)->record->max_block_id >= 0) +#define XLogRecMaxBlockId(decoder) ((decoder)->record->max_block_id) +#define XLogRecGetBlock(decoder, i) (&(decoder)->record->blocks[(i)]) +#define XLogRecHasBlockRef(decoder, block_id) \ + (((decoder)->record->max_block_id >= (block_id)) && \ + ((decoder)->record->blocks[block_id].in_use)) +#define XLogRecHasBlockImage(decoder, block_id) \ + ((decoder)->record->blocks[block_id].has_image) +#define XLogRecBlockImageApply(decoder, block_id) \ + ((decoder)->record->blocks[block_id].apply_image) +#define XLogRecHasBlockData(decoder, block_id) \ + ((decoder)->record->blocks[block_id].has_data) + +#ifndef FRONTEND +extern FullTransactionId XLogRecGetFullXid(XLogReaderState *record); +#endif + +extern bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page); +extern char *XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len); +extern void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, + RelFileLocator *rlocator, ForkNumber *forknum, + BlockNumber *blknum); +extern bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, + RelFileLocator *rlocator, ForkNumber *forknum, + BlockNumber *blknum, + Buffer *prefetch_buffer); + +#endif /* XLOGREADER_H */ diff --git a/contrib/libs/libpq/src/include/access/xlogrecord.h b/contrib/libs/libpq/src/include/access/xlogrecord.h new file mode 100644 index 0000000000..f355e08e1d --- /dev/null +++ b/contrib/libs/libpq/src/include/access/xlogrecord.h @@ -0,0 +1,248 @@ +/* + * xlogrecord.h + * + * Definitions for the WAL record format. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogrecord.h + */ +#ifndef XLOGRECORD_H +#define XLOGRECORD_H + +#include "access/rmgr.h" +#include "access/xlogdefs.h" +#include "port/pg_crc32c.h" +#include "storage/block.h" +#include "storage/relfilelocator.h" + +/* + * The overall layout of an XLOG record is: + * Fixed-size header (XLogRecord struct) + * XLogRecordBlockHeader struct + * XLogRecordBlockHeader struct + * ... + * XLogRecordDataHeader[Short|Long] struct + * block data + * block data + * ... + * main data + * + * There can be zero or more XLogRecordBlockHeaders, and 0 or more bytes of + * rmgr-specific data not associated with a block. XLogRecord structs + * always start on MAXALIGN boundaries in the WAL files, but the rest of + * the fields are not aligned. + * + * The XLogRecordBlockHeader, XLogRecordDataHeaderShort and + * XLogRecordDataHeaderLong structs all begin with a single 'id' byte. It's + * used to distinguish between block references, and the main data structs. + */ +typedef struct XLogRecord +{ + uint32 xl_tot_len; /* total len of entire record */ + TransactionId xl_xid; /* xact id */ + XLogRecPtr xl_prev; /* ptr to previous record in log */ + uint8 xl_info; /* flag bits, see below */ + RmgrId xl_rmid; /* resource manager for this record */ + /* 2 bytes of padding here, initialize to zero */ + pg_crc32c xl_crc; /* CRC for this record */ + + /* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */ + +} XLogRecord; + +#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c)) + +/* + * The high 4 bits in xl_info may be used freely by rmgr. The + * XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits can be passed by + * XLogInsert caller. The rest are set internally by XLogInsert. + */ +#define XLR_INFO_MASK 0x0F +#define XLR_RMGR_INFO_MASK 0xF0 + +/* + * XLogReader needs to allocate all the data of a WAL record in a single + * chunk. This means that a single XLogRecord cannot exceed MaxAllocSize + * in length if we ignore any allocation overhead of the XLogReader. + * + * To accommodate some overhead, this value allows for 4M of allocation + * overhead, that should be plenty enough for what + * DecodeXLogRecordRequiredSpace() expects as extra. + */ +#define XLogRecordMaxSize (1020 * 1024 * 1024) + +/* + * If a WAL record modifies any relation files, in ways not covered by the + * usual block references, this flag is set. This is not used for anything + * by PostgreSQL itself, but it allows external tools that read WAL and keep + * track of modified blocks to recognize such special record types. + */ +#define XLR_SPECIAL_REL_UPDATE 0x01 + +/* + * Enforces consistency checks of replayed WAL at recovery. If enabled, + * each record will log a full-page write for each block modified by the + * record and will reuse it afterwards for consistency checks. The caller + * of XLogInsert can use this value if necessary, but if + * wal_consistency_checking is enabled for a rmgr this is set unconditionally. + */ +#define XLR_CHECK_CONSISTENCY 0x02 + +/* + * Header info for block data appended to an XLOG record. + * + * 'data_length' is the length of the rmgr-specific payload data associated + * with this block. It does not include the possible full page image, nor + * XLogRecordBlockHeader struct itself. + * + * Note that we don't attempt to align the XLogRecordBlockHeader struct! + * So, the struct must be copied to aligned local storage before use. + */ +typedef struct XLogRecordBlockHeader +{ + uint8 id; /* block reference ID */ + uint8 fork_flags; /* fork within the relation, and flags */ + uint16 data_length; /* number of payload bytes (not including page + * image) */ + + /* If BKPBLOCK_HAS_IMAGE, an XLogRecordBlockImageHeader struct follows */ + /* If BKPBLOCK_SAME_REL is not set, a RelFileLocator follows */ + /* BlockNumber follows */ +} XLogRecordBlockHeader; + +#define SizeOfXLogRecordBlockHeader (offsetof(XLogRecordBlockHeader, data_length) + sizeof(uint16)) + +/* + * Additional header information when a full-page image is included + * (i.e. when BKPBLOCK_HAS_IMAGE is set). + * + * The XLOG code is aware that PG data pages usually contain an unused "hole" + * in the middle, which contains only zero bytes. Since we know that the + * "hole" is all zeros, we remove it from the stored data (and it's not counted + * in the XLOG record's CRC, either). Hence, the amount of block data actually + * present is (BLCKSZ - <length of "hole" bytes>). + * + * Additionally, when wal_compression is enabled, we will try to compress full + * page images using one of the supported algorithms, after removing the + * "hole". This can reduce the WAL volume, but at some extra cost of CPU spent + * on the compression during WAL logging. In this case, since the "hole" + * length cannot be calculated by subtracting the number of page image bytes + * from BLCKSZ, basically it needs to be stored as an extra information. + * But when no "hole" exists, we can assume that the "hole" length is zero + * and no such an extra information needs to be stored. Note that + * the original version of page image is stored in WAL instead of the + * compressed one if the number of bytes saved by compression is less than + * the length of extra information. Hence, when a page image is successfully + * compressed, the amount of block data actually present is less than + * BLCKSZ - the length of "hole" bytes - the length of extra information. + */ +typedef struct XLogRecordBlockImageHeader +{ + uint16 length; /* number of page image bytes */ + uint16 hole_offset; /* number of bytes before "hole" */ + uint8 bimg_info; /* flag bits, see below */ + + /* + * If BKPIMAGE_HAS_HOLE and BKPIMAGE_COMPRESSED(), an + * XLogRecordBlockCompressHeader struct follows. + */ +} XLogRecordBlockImageHeader; + +#define SizeOfXLogRecordBlockImageHeader \ + (offsetof(XLogRecordBlockImageHeader, bimg_info) + sizeof(uint8)) + +/* Information stored in bimg_info */ +#define BKPIMAGE_HAS_HOLE 0x01 /* page image has "hole" */ +#define BKPIMAGE_APPLY 0x02 /* page image should be restored + * during replay */ +/* compression methods supported */ +#define BKPIMAGE_COMPRESS_PGLZ 0x04 +#define BKPIMAGE_COMPRESS_LZ4 0x08 +#define BKPIMAGE_COMPRESS_ZSTD 0x10 + +#define BKPIMAGE_COMPRESSED(info) \ + ((info & (BKPIMAGE_COMPRESS_PGLZ | BKPIMAGE_COMPRESS_LZ4 | \ + BKPIMAGE_COMPRESS_ZSTD)) != 0) + +/* + * Extra header information used when page image has "hole" and + * is compressed. + */ +typedef struct XLogRecordBlockCompressHeader +{ + uint16 hole_length; /* number of bytes in "hole" */ +} XLogRecordBlockCompressHeader; + +#define SizeOfXLogRecordBlockCompressHeader \ + sizeof(XLogRecordBlockCompressHeader) + +/* + * Maximum size of the header for a block reference. This is used to size a + * temporary buffer for constructing the header. + */ +#define MaxSizeOfXLogRecordBlockHeader \ + (SizeOfXLogRecordBlockHeader + \ + SizeOfXLogRecordBlockImageHeader + \ + SizeOfXLogRecordBlockCompressHeader + \ + sizeof(RelFileLocator) + \ + sizeof(BlockNumber)) + +/* + * The fork number fits in the lower 4 bits in the fork_flags field. The upper + * bits are used for flags. + */ +#define BKPBLOCK_FORK_MASK 0x0F +#define BKPBLOCK_FLAG_MASK 0xF0 +#define BKPBLOCK_HAS_IMAGE 0x10 /* block data is an XLogRecordBlockImage */ +#define BKPBLOCK_HAS_DATA 0x20 +#define BKPBLOCK_WILL_INIT 0x40 /* redo will re-init the page */ +#define BKPBLOCK_SAME_REL 0x80 /* RelFileLocator omitted, same as + * previous */ + +/* + * XLogRecordDataHeaderShort/Long are used for the "main data" portion of + * the record. If the length of the data is less than 256 bytes, the short + * form is used, with a single byte to hold the length. Otherwise the long + * form is used. + * + * (These structs are currently not used in the code, they are here just for + * documentation purposes). + */ +typedef struct XLogRecordDataHeaderShort +{ + uint8 id; /* XLR_BLOCK_ID_DATA_SHORT */ + uint8 data_length; /* number of payload bytes */ +} XLogRecordDataHeaderShort; + +#define SizeOfXLogRecordDataHeaderShort (sizeof(uint8) * 2) + +typedef struct XLogRecordDataHeaderLong +{ + uint8 id; /* XLR_BLOCK_ID_DATA_LONG */ + /* followed by uint32 data_length, unaligned */ +} XLogRecordDataHeaderLong; + +#define SizeOfXLogRecordDataHeaderLong (sizeof(uint8) + sizeof(uint32)) + +/* + * Block IDs used to distinguish different kinds of record fragments. Block + * references are numbered from 0 to XLR_MAX_BLOCK_ID. A rmgr is free to use + * any ID number in that range (although you should stick to small numbers, + * because the WAL machinery is optimized for that case). A few ID + * numbers are reserved to denote the "main" data portion of the record, + * as well as replication-supporting transaction metadata. + * + * The maximum is currently set at 32, quite arbitrarily. Most records only + * need a handful of block references, but there are a few exceptions that + * need more. + */ +#define XLR_MAX_BLOCK_ID 32 + +#define XLR_BLOCK_ID_DATA_SHORT 255 +#define XLR_BLOCK_ID_DATA_LONG 254 +#define XLR_BLOCK_ID_ORIGIN 253 +#define XLR_BLOCK_ID_TOPLEVEL_XID 252 + +#endif /* XLOGRECORD_H */ diff --git a/contrib/libs/libpq/src/include/c.h b/contrib/libs/libpq/src/include/c.h new file mode 100644 index 0000000000..ab459d646e --- /dev/null +++ b/contrib/libs/libpq/src/include/c.h @@ -0,0 +1,1383 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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) compiler characteristics + * 2) bool, true, false + * 3) standard system types + * 4) IsValid macros for system types + * 5) lengthof, 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 usually wrong to put an "extern" declaration here, unless it's + * ifdef'd so that it's seen in only one case or the other. + * 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 */ +#include "pg_config_os.h" /* must be before any system header files */ + +/* System header files that should be available everywhere in Postgres */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <stdarg.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <stdint.h> +#include <sys/types.h> +#include <errno.h> +#if defined(WIN32) || defined(__CYGWIN__) +#include <fcntl.h> /* ensure O_BINARY is available */ +#endif +#include <locale.h> +#ifdef ENABLE_NLS +#include <libintl.h> +#endif + + +/* ---------------------------------------------------------------- + * Section 1: compiler characteristics + * + * type prefixes (const, signed, volatile, inline) are handled in pg_config.h. + * ---------------------------------------------------------------- + */ + +/* + * Disable "inline" if PG_FORCE_DISABLE_INLINE is defined. + * This is used to work around compiler bugs and might also be useful for + * investigatory purposes. + */ +#ifdef PG_FORCE_DISABLE_INLINE +#undef inline +#define inline +#endif + +/* + * Attribute macros + * + * GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html + * GCC: https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html + * Clang: https://clang.llvm.org/docs/AttributeReference.html + * Sunpro: https://docs.oracle.com/cd/E18659_01/html/821-1384/gjzke.html + * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/function_attributes.html + * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/type_attrib.html + */ + +/* + * For compilers which don't support __has_attribute, we just define + * __has_attribute(x) to 0 so that we can define macros for various + * __attribute__s more easily below. + */ +#ifndef __has_attribute +#define __has_attribute(attribute) 0 +#endif + +/* only GCC supports the unused attribute */ +#ifdef __GNUC__ +#define pg_attribute_unused() __attribute__((unused)) +#else +#define pg_attribute_unused() +#endif + +/* + * pg_nodiscard means the compiler should warn if the result of a function + * call is ignored. The name "nodiscard" is chosen in alignment with + * (possibly future) C and C++ standards. For maximum compatibility, use it + * as a function declaration specifier, so it goes before the return type. + */ +#ifdef __GNUC__ +#define pg_nodiscard __attribute__((warn_unused_result)) +#else +#define pg_nodiscard +#endif + +/* + * Place this macro before functions that should be allowed to make misaligned + * accesses. Think twice before using it on non-x86-specific code! + * Testing can be done with "-fsanitize=alignment -fsanitize-trap=alignment" + * on clang, or "-fsanitize=alignment -fno-sanitize-recover=alignment" on gcc. + */ +#if __clang_major__ >= 7 || __GNUC__ >= 8 +#define pg_attribute_no_sanitize_alignment() __attribute__((no_sanitize("alignment"))) +#else +#define pg_attribute_no_sanitize_alignment() +#endif + +/* + * pg_attribute_nonnull means the compiler should warn if the function is + * called with the listed arguments set to NULL. If no arguments are + * listed, the compiler should warn if any pointer arguments are set to NULL. + */ +#if __has_attribute (nonnull) +#define pg_attribute_nonnull(...) __attribute__((nonnull(__VA_ARGS__))) +#else +#define pg_attribute_nonnull(...) +#endif + +/* + * 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 + +/* 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 +#elif defined(_MSC_VER) +/* + * MSVC supports aligned. noreturn is also possible but in MSVC it is + * declared before the definition while pg_attribute_noreturn() macro + * is currently used after the definition. + * + * Packing is also possible but only by wrapping the entire struct definition + * which doesn't fit into our current macro declarations. + */ +#define pg_attribute_aligned(a) __declspec(align(a)) +#define pg_attribute_noreturn() +#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 + +/* + * Use "pg_attribute_always_inline" in place of "inline" for functions that + * we wish to force inlining of, even when the compiler's heuristics would + * choose not to. But, if possible, don't force inlining in unoptimized + * debug builds. + */ +#if (defined(__GNUC__) && __GNUC__ > 3 && defined(__OPTIMIZE__)) || defined(__SUNPRO_C) || defined(__IBMC__) +/* GCC > 3, Sunpro and XLC support always_inline via __attribute__ */ +#define pg_attribute_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +/* MSVC has a special keyword for this */ +#define pg_attribute_always_inline __forceinline +#else +/* Otherwise, the best we can do is to say "inline" */ +#define pg_attribute_always_inline inline +#endif + +/* + * Forcing a function not to be inlined can be useful if it's the slow path of + * a performance-critical function, or should be visible in profiles to allow + * for proper cost attribution. Note that unlike the pg_attribute_XXX macros + * above, this should be placed before the function's return type and name. + */ +/* GCC, Sunpro and XLC support noinline via __attribute__ */ +#if (defined(__GNUC__) && __GNUC__ > 2) || defined(__SUNPRO_C) || defined(__IBMC__) +#define pg_noinline __attribute__((noinline)) +/* msvc via declspec */ +#elif defined(_MSC_VER) +#define pg_noinline __declspec(noinline) +#else +#define pg_noinline +#endif + +/* + * For now, just define pg_attribute_cold and pg_attribute_hot to be empty + * macros on minGW 8.1. There appears to be a compiler bug that results in + * compilation failure. At this time, we still have at least one buildfarm + * animal running that compiler, so this should make that green again. It's + * likely this compiler is not popular enough to warrant keeping this code + * around forever, so let's just remove it once the last buildfarm animal + * upgrades. + */ +#if defined(__MINGW64__) && __GNUC__ == 8 && __GNUC_MINOR__ == 1 + +#define pg_attribute_cold +#define pg_attribute_hot + +#else +/* + * Marking certain functions as "hot" or "cold" can be useful to assist the + * compiler in arranging the assembly code in a more efficient way. + */ +#if __has_attribute (cold) +#define pg_attribute_cold __attribute__((cold)) +#else +#define pg_attribute_cold +#endif + +#if __has_attribute (hot) +#define pg_attribute_hot __attribute__((hot)) +#else +#define pg_attribute_hot +#endif + +#endif /* defined(__MINGW64__) && __GNUC__ == 8 && + * __GNUC_MINOR__ == 1 */ +/* + * 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 + +/* + * Hints to the compiler about the likelihood of a branch. Both likely() and + * unlikely() return the boolean value of the contained expression. + * + * These should only be used sparingly, in very hot code paths. It's very easy + * to mis-estimate likelihoods. + */ +#if __GNUC__ >= 3 +#define likely(x) __builtin_expect((x) != 0, 1) +#define unlikely(x) __builtin_expect((x) != 0, 0) +#else +#define likely(x) ((x) != 0) +#define unlikely(x) ((x) != 0) +#endif + +/* + * CppAsString + * Convert the argument to a string, using the C preprocessor. + * CppAsString2 + * Convert the argument to a string, after one round of macro expansion. + * 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 CppAsString2(x) CppAsString(x) +#define CppConcat(x, y) x##y + +/* + * VA_ARGS_NARGS + * Returns the number of macro arguments it is passed. + * + * An empty argument still counts as an argument, so effectively, this is + * "one more than the number of commas in the argument list". + * + * This works for up to 63 arguments. Internally, VA_ARGS_NARGS_() is passed + * 64+N arguments, and the C99 standard only requires macros to allow up to + * 127 arguments, so we can't portably go higher. The implementation is + * pretty trivial: VA_ARGS_NARGS_() returns its 64th argument, and we set up + * the call so that that is the appropriate one of the list of constants. + * This idea is due to Laurent Deniau. + * + * MSVC has an implementation of __VA_ARGS__ that doesn't conform to the + * standard unless you use the /Zc:preprocessor compiler flag, but that + * isn't available before Visual Studio 2019. For now, use a different + * definition that also works on older compilers. + */ +#ifdef _MSC_VER +#define EXPAND(args) args +#define VA_ARGS_NARGS(...) \ + VA_ARGS_NARGS_ EXPAND((__VA_ARGS__, \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#else + +#define VA_ARGS_NARGS(...) \ + VA_ARGS_NARGS_(__VA_ARGS__, \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#endif + +#define VA_ARGS_NARGS_( \ + _01,_02,_03,_04,_05,_06,_07,_08,_09,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63, N, ...) \ + (N) + +/* + * Generic function pointer. This can be used in the rare cases where it's + * necessary to cast a function pointer to a seemingly incompatible function + * pointer type while avoiding gcc's -Wcast-function-type warnings. + */ +typedef void (*pg_funcptr_t) (void); + +/* + * We require C99, hence the compiler should understand flexible array + * members. However, for documentation purposes we still consider it to be + * project style to write "field[FLEXIBLE_ARRAY_MEMBER]" not just "field[]". + * When computing the size of such an object, use "offsetof(struct s, f)" + * for portability. Don't use "offsetof(struct s, f[0])", as this doesn't + * work with MSVC and with C++ compilers. + */ +#define FLEXIBLE_ARRAY_MEMBER /* empty */ + +/* + * Does the compiler support #pragma GCC system_header? We optionally use it + * to avoid warnings that we can't fix (e.g. in the perl headers). + * See https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html + * + * Headers for which we do not want to show compiler warnings can, + * conditionally, use #pragma GCC system_header to avoid warnings. Obviously + * this should only be used for external headers over which we do not have + * control. + * + * Support for the pragma is tested here, instead of during configure, as gcc + * also warns about the pragma being used in a .c file. It's surprisingly hard + * to get autoconf to use .h as the file-ending. Looks like gcc has + * implemented the pragma since the 2000, so this test should suffice. + * + * + * Alternatively, we could add the include paths for problematic headers with + * -isystem, but that is a larger hammer and is harder to search for. + * + * A more granular alternative would be to use #pragma GCC diagnostic + * push/ignored/pop, but gcc warns about unknown warnings being ignored, so + * every to-be-ignored-temporarily compiler warning would require its own + * pg_config.h symbol and #ifdef. + */ +#ifdef __GNUC__ +#define HAVE_PRAGMA_GCC_SYSTEM_HEADER 1 +#endif + + +/* ---------------------------------------------------------------- + * Section 2: bool, true, false + * ---------------------------------------------------------------- + */ + +/* + * bool + * Boolean value, either true or false. + * + * We use stdbool.h if available and its bool has size 1. That's useful for + * better compiler and debugger output and for compatibility with third-party + * libraries. But PostgreSQL currently cannot deal with bool of other sizes; + * there are static assertions around the code to prevent that. + * + * For C++ compilers, we assume the compiler has a compatible built-in + * definition of bool. + * + * See also the version of this code in src/interfaces/ecpg/include/ecpglib.h. + */ + +#ifndef __cplusplus + +#ifdef PG_USE_STDBOOL +#include <stdbool.h> +#else + +#ifndef bool +typedef unsigned char bool; +#endif + +#ifndef true +#define true ((bool) 1) +#endif + +#ifndef false +#define false ((bool) 0) +#endif + +#endif /* not PG_USE_STDBOOL */ +#endif /* not C++ */ + + +/* ---------------------------------------------------------------- + * 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 +#define INT64CONST(x) (x##L) +#define UINT64CONST(x) (x##UL) +#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 +#define INT64CONST(x) (x##LL) +#define UINT64CONST(x) (x##ULL) +#else +/* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */ +#error must have a working 64-bit integer datatype +#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 limited support for such types. + * E.g. 128bit literals and snprintf are not supported; but math is. + * Also, because we exclude such types when choosing MAXIMUM_ALIGNOF, + * it must be possible to coerce the compiler to allocate them on no + * more than MAXALIGN boundaries. + */ +#if defined(PG_INT128_TYPE) +#if defined(pg_attribute_aligned) || ALIGNOF_PG_INT128_TYPE <= MAXIMUM_ALIGNOF +#define HAVE_INT128 1 + +typedef PG_INT128_TYPE int128 +#if defined(pg_attribute_aligned) + pg_attribute_aligned(MAXIMUM_ALIGNOF) +#endif + ; + +typedef unsigned PG_INT128_TYPE uint128 +#if defined(pg_attribute_aligned) + pg_attribute_aligned(MAXIMUM_ALIGNOF) +#endif + ; + +#endif +#endif + +/* + * stdint.h limits 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 (0xFFFFFFFFU) +#define PG_INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1) +#define PG_INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF) +#define PG_UINT64_MAX UINT64CONST(0xFFFFFFFFFFFFFFFF) + +/* + * We now always use int64 timestamps, but keep this symbol defined for the + * benefit of external code that might test it. + */ +#define HAVE_INT64_TIMESTAMP + +/* + * 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; + +#ifdef USE_FLOAT8_BYVAL +#define FLOAT8PASSBYVAL true +#else +#define FLOAT8PASSBYVAL false +#endif + +/* + * 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) + + +/* ---------------- + * 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 macros VARDATA_ANY, VARSIZE_ANY, VARSIZE_ANY_EXHDR, VARDATA, VARSIZE, + * and SET_VARSIZE 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_ANY_EXHDR(ptr). + */ +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) + + +/* ---------------------------------------------------------------- + * 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 OffsetToPointer(base, offset) \ + ((void *)((char *) base + offset)) + +#define OidIsValid(objectId) ((bool) ((objectId) != InvalidOid)) + +#define RegProcedureIsValid(p) OidIsValid(p) + + +/* ---------------------------------------------------------------- + * Section 5: lengthof, alignment + * ---------------------------------------------------------------- + */ +/* + * lengthof + * Number of elements in an array. + */ +#define lengthof(array) (sizeof (array) / sizeof ((array)[0])) + +/* ---------------- + * 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. + * + * NOTE: MAXIMUM_ALIGNOF, and hence MAXALIGN(), intentionally exclude any + * larger-than-8-byte types the compiler might have. + * ---------------- + */ + +#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)) +#define BUFFERALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_BUFFER, (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)) + + +/* ---------------------------------------------------------------- + * 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) + +#elif defined(FRONTEND) + +#include <assert.h> +#define Assert(p) assert(p) +#define AssertMacro(p) ((void) assert(p)) + +#else /* USE_ASSERT_CHECKING && !FRONTEND */ + +/* + * Assert + * Generates a fatal exception if the given condition is false. + */ +#define Assert(condition) \ + do { \ + if (!(condition)) \ + ExceptionalCondition(#condition, __FILE__, __LINE__); \ + } while (0) + +/* + * AssertMacro is the same as Assert but it's suitable for use in + * expression-like macros, for example: + * + * #define foo(x) (AssertMacro(x != 0), bar(x)) + */ +#define AssertMacro(condition) \ + ((void) ((condition) || \ + (ExceptionalCondition(#condition, __FILE__, __LINE__), 0))) + +#endif /* USE_ASSERT_CHECKING && !FRONTEND */ + +/* + * Check that `ptr' is `bndr' aligned. + */ +#define AssertPointerAlignment(ptr, bndr) \ + Assert(TYPEALIGN(bndr, (uintptr_t)(ptr)) == (uintptr_t)(ptr)) + +/* + * ExceptionalCondition is compiled into the backend whether or not + * USE_ASSERT_CHECKING is defined, so as to support use of extensions + * that are built with that #define with a backend that isn't. Hence, + * we should declare it as long as !FRONTEND. + */ +#ifndef FRONTEND +extern void ExceptionalCondition(const char *conditionName, + const char *fileName, int lineNumber) pg_attribute_noreturn(); +#endif + +/* + * 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). + * + * C11 has _Static_assert(), and most C99 compilers already support that. For + * portability, we wrap it into StaticAssertDecl(). _Static_assert() is a + * "declaration", and so it must be placed where for example a variable + * declaration would be valid. As long as we compile with + * -Wno-declaration-after-statement, that also means it cannot be placed after + * statements in a function. Macros StaticAssertStmt() and StaticAssertExpr() + * make it safe to use as a statement or in an expression, respectively. + * + * For compilers without _Static_assert(), 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. + */ +#ifndef __cplusplus +#ifdef HAVE__STATIC_ASSERT +#define StaticAssertDecl(condition, errmessage) \ + _Static_assert(condition, errmessage) +#define StaticAssertStmt(condition, errmessage) \ + do { _Static_assert(condition, errmessage); } while(0) +#define StaticAssertExpr(condition, errmessage) \ + ((void) ({ StaticAssertStmt(condition, errmessage); true; })) +#else /* !HAVE__STATIC_ASSERT */ +#define StaticAssertDecl(condition, errmessage) \ + extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1]) +#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 */ +#else /* C++ */ +#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410 +#define StaticAssertDecl(condition, errmessage) \ + static_assert(condition, errmessage) +#define StaticAssertStmt(condition, errmessage) \ + static_assert(condition, errmessage) +#define StaticAssertExpr(condition, errmessage) \ + ({ static_assert(condition, errmessage); }) +#else /* !__cpp_static_assert */ +#define StaticAssertDecl(condition, errmessage) \ + extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1]) +#define StaticAssertStmt(condition, errmessage) \ + do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0) +#define StaticAssertExpr(condition, errmessage) \ + ((void) ({ StaticAssertStmt(condition, errmessage); })) +#endif /* __cpp_static_assert */ +#endif /* C++ */ + +#ifdef _MSC_VER +#undef StaticAssertStmt +#undef StaticAssertDecl +#define StaticAssertStmt(condition, errmessage) +#define StaticAssertDecl(condition, errmessage) +#endif + +/* + * 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) \ + (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) \ + (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)) + + +/* 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) + +/* + * Macros for range-checking float values before converting to integer. + * We must be careful here that the boundary values are expressed exactly + * in the float domain. PG_INTnn_MIN is an exact power of 2, so it will + * be represented exactly; but PG_INTnn_MAX isn't, and might get rounded + * off, so avoid using that. + * The input must be rounded to an integer beforehand, typically with rint(), + * else we might draw the wrong conclusion about close-to-the-limit values. + * These macros will do the right thing for Inf, but not necessarily for NaN, + * so check isnan(num) first if that's a possibility. + */ +#define FLOAT4_FITS_IN_INT16(num) \ + ((num) >= (float4) PG_INT16_MIN && (num) < -((float4) PG_INT16_MIN)) +#define FLOAT4_FITS_IN_INT32(num) \ + ((num) >= (float4) PG_INT32_MIN && (num) < -((float4) PG_INT32_MIN)) +#define FLOAT4_FITS_IN_INT64(num) \ + ((num) >= (float4) PG_INT64_MIN && (num) < -((float4) PG_INT64_MIN)) +#define FLOAT8_FITS_IN_INT16(num) \ + ((num) >= (float8) PG_INT16_MIN && (num) < -((float8) PG_INT16_MIN)) +#define FLOAT8_FITS_IN_INT32(num) \ + ((num) >= (float8) PG_INT32_MIN && (num) < -((float8) PG_INT32_MIN)) +#define FLOAT8_FITS_IN_INT64(num) \ + ((num) >= (float8) PG_INT64_MIN && (num) < -((float8) PG_INT64_MIN)) + + +/* ---------------------------------------------------------------- + * Section 8: random stuff + * ---------------------------------------------------------------- + */ + +/* + * Invert the sign of a qsort-style comparison result, ie, exchange negative + * and positive integer values, being careful not to get the wrong answer + * for INT_MIN. The argument should be an integral variable. + */ +#define INVERT_COMPARE_RESULT(var) \ + ((var) = ((var) < 0) ? 1 : -(var)) + +/* + * Use this, not "char buf[BLCKSZ]", to declare a field or local variable + * holding a page buffer, if that page might be accessed as a page. Otherwise + * the variable might be under-aligned, causing problems on alignment-picky + * hardware. We include both "double" and "int64" in the union to ensure that + * the compiler knows the value must be MAXALIGN'ed (cf. configure's + * computation of MAXIMUM_ALIGNOF). + */ +typedef union PGAlignedBlock +{ + char data[BLCKSZ]; + double force_align_d; + int64 force_align_i64; +} PGAlignedBlock; + +/* + * Use this to declare a field or local variable holding a page buffer, if that + * page might be accessed as a page or passed to an SMgr I/O function. If + * allocating using the MemoryContext API, the aligned allocation functions + * should be used with PG_IO_ALIGN_SIZE. This alignment may be more efficient + * for I/O in general, but may be strictly required on some platforms when + * using direct I/O. + */ +typedef union PGIOAlignedBlock +{ +#ifdef pg_attribute_aligned + pg_attribute_aligned(PG_IO_ALIGN_SIZE) +#endif + char data[BLCKSZ]; + double force_align_d; + int64 force_align_i64; +} PGIOAlignedBlock; + +/* Same, but for an XLOG_BLCKSZ-sized buffer */ +typedef union PGAlignedXLogBlock +{ +#ifdef pg_attribute_aligned + pg_attribute_aligned(PG_IO_ALIGN_SIZE) +#endif + char data[XLOG_BLCKSZ]; + double force_align_d; + int64 force_align_i64; +} PGAlignedXLogBlock; + +/* msb for char */ +#define HIGHBIT (0x80) +#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT) + +/* + * 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' + + +#define STATUS_OK (0) +#define STATUS_ERROR (-1) +#define STATUS_EOF (-2) + +/* + * gettext support + */ + +#ifndef ENABLE_NLS +/* stuff we'd otherwise get from <libintl.h> */ +#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 + +#define _(x) gettext(x) + +/* + * 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. + * + * https://www.gnu.org/software/gettext/manual/html_node/Special-cases.html + */ +#define gettext_noop(x) (x) + +/* + * 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. + */ +#ifdef SO_MAJOR_VERSION +#define PG_TEXTDOMAIN(domain) (domain CppAsString2(SO_MAJOR_VERSION) "-" PG_MAJORVERSION) +#else +#define PG_TEXTDOMAIN(domain) (domain "-" PG_MAJORVERSION) +#endif + +/* + * Macro that allows to cast constness and volatile away from an expression, but doesn't + * allow changing the underlying type. Enforcement of the latter + * currently only works for gcc like compilers. + * + * Please note IT IS NOT SAFE to cast constness away if the result will ever + * be modified (it would be undefined behaviour). Doing so anyway can cause + * compiler misoptimizations or runtime crashes (modifying readonly memory). + * It is only safe to use when the result will not be modified, but API + * design or language restrictions prevent you from declaring that + * (e.g. because a function returns both const and non-const variables). + * + * Note that this only works in function scope, not for global variables (it'd + * be nice, but not trivial, to improve that). + */ +#if defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P) +#define unconstify(underlying_type, expr) \ + (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), const underlying_type), \ + "wrong cast"), \ + (underlying_type) (expr)) +#define unvolatize(underlying_type, expr) \ + (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), volatile underlying_type), \ + "wrong cast"), \ + (underlying_type) (expr)) +#else +#define unconstify(underlying_type, expr) \ + ((underlying_type) (expr)) +#define unvolatize(underlying_type, expr) \ + ((underlying_type) (expr)) +#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_FDATASYNC +extern int fdatasync(int fildes); +#endif + +/* + * Thin wrappers that convert strings to exactly 64-bit integers, matching our + * definition of int64. (For the naming, compare that POSIX has + * strtoimax()/strtoumax() which return intmax_t/uintmax_t.) + */ +#ifdef HAVE_LONG_INT_64 +#define strtoi64(str, endptr, base) ((int64) strtol(str, endptr, base)) +#define strtou64(str, endptr, base) ((uint64) strtoul(str, endptr, base)) +#else +#define strtoi64(str, endptr, base) ((int64) strtoll(str, endptr, base)) +#define strtou64(str, endptr, base) ((uint64) strtoull(str, endptr, base)) +#endif + +/* + * Similarly, wrappers around labs()/llabs() matching our int64. + */ +#ifdef HAVE_LONG_INT_64 +#define i64abs(i) labs(i) +#else +#define i64abs(i) llabs(i) +#endif + +/* + * Use "extern PGDLLIMPORT ..." to declare variables that are defined + * in the core backend and need to be accessible by loadable modules. + * No special marking is required on most ports. + */ +#ifndef PGDLLIMPORT +#define PGDLLIMPORT +#endif + +/* + * Use "extern PGDLLEXPORT ..." to declare functions that are defined in + * loadable modules and need to be callable by the core backend or other + * loadable modules. + * If the compiler knows __attribute__((visibility("*"))), we use that, + * unless we already have a platform-specific definition. Otherwise, + * no special marking is required. + */ +#ifndef PGDLLEXPORT +#ifdef HAVE_VISIBILITY_ATTRIBUTE +#define PGDLLEXPORT __attribute__((visibility("default"))) +#else +#define PGDLLEXPORT +#endif +#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. We now support the case only on Windows. However, it seems + * that MinGW-64 has some longstanding issues in its setjmp support, + * so on that toolchain we cheat and use gcc's builtins. + */ +#ifdef WIN32 +#ifdef __MINGW64__ +typedef intptr_t sigjmp_buf[5]; +#define sigsetjmp(x,y) __builtin_setjmp(x) +#define siglongjmp __builtin_longjmp +#else /* !__MINGW64__ */ +#define sigjmp_buf jmp_buf +#define sigsetjmp(x,y) setjmp(x) +#define siglongjmp longjmp +#endif /* __MINGW64__ */ +#endif /* WIN32 */ + +/* /port compatibility functions */ +#include "port.h" + +#endif /* C_H */ diff --git a/contrib/libs/libpq/src/include/catalog/catversion.h b/contrib/libs/libpq/src/include/catalog/catversion.h new file mode 100644 index 0000000000..cc1de6e65a --- /dev/null +++ b/contrib/libs/libpq/src/include/catalog/catversion.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * catversion.h + * "Catalog version number" for PostgreSQL. + * + * The catalog version number is used to flag incompatible changes in + * the PostgreSQL system catalogs. Whenever anyone changes the format of + * a system catalog relation, or adds, deletes, or modifies standard + * catalog entries in such a way that an updated backend wouldn't work + * with an old database (or vice versa), the catalog version number + * should be changed. The version number stored in pg_control by initdb + * is checked against the version number compiled into the backend at + * startup time, so that a backend can refuse to run in an incompatible + * database. + * + * The point of this feature is to provide a finer grain of compatibility + * checking than is possible from looking at the major version number + * stored in PG_VERSION. It shouldn't matter to end users, but during + * development cycles we usually make quite a few incompatible changes + * to the contents of the system catalogs, and we don't want to bump the + * major version number for each one. What we can do instead is bump + * this internal version number. This should save some grief for + * developers who might otherwise waste time tracking down "bugs" that + * are really just code-vs-database incompatibilities. + * + * The rule for developers is: if you commit a change that requires + * an initdb, you should update the catalog version number (as well as + * notifying the pgsql-hackers mailing list, which has been the + * informal practice for a long time). + * + * The catalog version number is placed here since modifying files in + * include/catalog is the most common kind of initdb-forcing change. + * But it could be used to protect any kind of incompatible change in + * database contents or layout, such as altering tuple headers. + * Another common reason for a catversion update is a change in parsetree + * external representation, since serialized parsetrees appear in stored + * rules and new-style SQL functions. Almost any change in primnodes.h or + * parsenodes.h will warrant a catversion update. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/catversion.h + * + *------------------------------------------------------------------------- + */ +#ifndef CATVERSION_H +#define CATVERSION_H + +/* + * We could use anything we wanted for version numbers, but I recommend + * following the "YYYYMMDDN" style often used for DNS zone serial numbers. + * YYYYMMDD are the date of the change, and N is the number of the change + * on that day. (Hopefully we'll never commit ten independent sets of + * catalog changes on the same day...) + */ + +/* yyyymmddN */ +#define CATALOG_VERSION_NO 202307071 + +#endif diff --git a/contrib/libs/libpq/src/include/catalog/pg_control.h b/contrib/libs/libpq/src/include/catalog/pg_control.h new file mode 100644 index 0000000000..dc953977c5 --- /dev/null +++ b/contrib/libs/libpq/src/include/catalog/pg_control.h @@ -0,0 +1,258 @@ +/*------------------------------------------------------------------------- + * + * pg_control.h + * The system control file "pg_control" is not a heap relation. + * However, we define it here so that the format is documented. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_control.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONTROL_H +#define PG_CONTROL_H + +#include "access/transam.h" +#include "access/xlogdefs.h" +#include "pgtime.h" /* for pg_time_t */ +#include "port/pg_crc32c.h" + + +/* Version identifier for this pg_control format */ +#define PG_CONTROL_VERSION 1300 + +/* Nonce key length, see below */ +#define MOCK_AUTH_NONCE_LEN 32 + +/* + * Body of CheckPoint XLOG records. This is declared here because we keep + * a copy of the latest one in pg_control for possible disaster recovery. + * Changing this struct requires a PG_CONTROL_VERSION bump. + */ +typedef struct CheckPoint +{ + XLogRecPtr redo; /* next RecPtr available when we began to + * create CheckPoint (i.e. REDO start point) */ + TimeLineID ThisTimeLineID; /* current TLI */ + TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new + * timeline (equals ThisTimeLineID otherwise) */ + bool fullPageWrites; /* current full_page_writes */ + FullTransactionId nextXid; /* next free transaction ID */ + Oid nextOid; /* next free OID */ + MultiXactId nextMulti; /* next free MultiXactId */ + MultiXactOffset nextMultiOffset; /* next free MultiXact offset */ + TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ + Oid oldestXidDB; /* database with minimum datfrozenxid */ + MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */ + Oid oldestMultiDB; /* database with minimum datminmxid */ + pg_time_t time; /* time stamp of checkpoint */ + TransactionId oldestCommitTsXid; /* oldest Xid with valid commit + * timestamp */ + TransactionId newestCommitTsXid; /* newest Xid with valid commit + * timestamp */ + + /* + * Oldest XID still running. This is only needed to initialize hot standby + * mode from an online checkpoint, so we only bother calculating this for + * online checkpoints and only when wal_level is replica. Otherwise it's + * set to InvalidTransactionId. + */ + TransactionId oldestActiveXid; +} CheckPoint; + +/* XLOG info values for XLOG rmgr */ +#define XLOG_CHECKPOINT_SHUTDOWN 0x00 +#define XLOG_CHECKPOINT_ONLINE 0x10 +#define XLOG_NOOP 0x20 +#define XLOG_NEXTOID 0x30 +#define XLOG_SWITCH 0x40 +#define XLOG_BACKUP_END 0x50 +#define XLOG_PARAMETER_CHANGE 0x60 +#define XLOG_RESTORE_POINT 0x70 +#define XLOG_FPW_CHANGE 0x80 +#define XLOG_END_OF_RECOVERY 0x90 +#define XLOG_FPI_FOR_HINT 0xA0 +#define XLOG_FPI 0xB0 +/* 0xC0 is used in Postgres 9.5-11 */ +#define XLOG_OVERWRITE_CONTRECORD 0xD0 + + +/* + * System status indicator. Note this is stored in pg_control; if you change + * it, you must bump PG_CONTROL_VERSION + */ +typedef enum DBState +{ + DB_STARTUP = 0, + DB_SHUTDOWNED, + DB_SHUTDOWNED_IN_RECOVERY, + DB_SHUTDOWNING, + DB_IN_CRASH_RECOVERY, + DB_IN_ARCHIVE_RECOVERY, + DB_IN_PRODUCTION +} DBState; + +/* + * Contents of pg_control. + */ + +typedef struct ControlFileData +{ + /* + * Unique system identifier --- to ensure we match up xlog files with the + * installation that produced them. + */ + uint64 system_identifier; + + /* + * Version identifier information. Keep these fields at the same offset, + * especially pg_control_version; they won't be real useful if they move + * around. (For historical reasons they must be 8 bytes into the file + * rather than immediately at the front.) + * + * pg_control_version identifies the format of pg_control itself. + * catalog_version_no identifies the format of the system catalogs. + * + * There are additional version identifiers in individual files; for + * example, WAL logs contain per-page magic numbers that can serve as + * version cues for the WAL log. + */ + uint32 pg_control_version; /* PG_CONTROL_VERSION */ + uint32 catalog_version_no; /* see catversion.h */ + + /* + * System status data + */ + DBState state; /* see enum above */ + pg_time_t time; /* time stamp of last pg_control update */ + XLogRecPtr checkPoint; /* last check point record ptr */ + + CheckPoint checkPointCopy; /* copy of last check point record */ + + XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */ + + /* + * These two values determine the minimum point we must recover up to + * before starting up: + * + * minRecoveryPoint is updated to the latest replayed LSN whenever we + * flush a data change during archive recovery. That guards against + * starting archive recovery, aborting it, and restarting with an earlier + * stop location. If we've already flushed data changes from WAL record X + * to disk, we mustn't start up until we reach X again. Zero when not + * doing archive recovery. + * + * backupStartPoint is the redo pointer of the backup start checkpoint, if + * we are recovering from an online backup and haven't reached the end of + * backup yet. It is reset to zero when the end of backup is reached, and + * we mustn't start up before that. A boolean would suffice otherwise, but + * we use the redo pointer as a cross-check when we see an end-of-backup + * record, to make sure the end-of-backup record corresponds the base + * backup we're recovering from. + * + * backupEndPoint is the backup end location, if we are recovering from an + * online backup which was taken from the standby and haven't reached the + * end of backup yet. It is initialized to the minimum recovery point in + * pg_control which was backed up last. It is reset to zero when the end + * of backup is reached, and we mustn't start up before that. + * + * If backupEndRequired is true, we know for sure that we're restoring + * from a backup, and must see a backup-end record before we can safely + * start up. + */ + XLogRecPtr minRecoveryPoint; + TimeLineID minRecoveryPointTLI; + XLogRecPtr backupStartPoint; + XLogRecPtr backupEndPoint; + bool backupEndRequired; + + /* + * Parameter settings that determine if the WAL can be used for archival + * or hot standby. + */ + int wal_level; + bool wal_log_hints; + int MaxConnections; + int max_worker_processes; + int max_wal_senders; + int max_prepared_xacts; + int max_locks_per_xact; + bool track_commit_timestamp; + + /* + * This data is used to check for hardware-architecture compatibility of + * the database and the backend executable. We need not check endianness + * explicitly, since the pg_control version will surely look wrong to a + * machine of different endianness, but we do need to worry about MAXALIGN + * and floating-point format. (Note: storage layout nominally also + * depends on SHORTALIGN and INTALIGN, but in practice these are the same + * on all architectures of interest.) + * + * Testing just one double value is not a very bulletproof test for + * floating-point compatibility, but it will catch most cases. + */ + uint32 maxAlign; /* alignment requirement for tuples */ + double floatFormat; /* constant 1234567.0 */ +#define FLOATFORMAT_VALUE 1234567.0 + + /* + * This data is used to make sure that configuration of this database is + * compatible with the backend executable. + */ + uint32 blcksz; /* data block size for this DB */ + uint32 relseg_size; /* blocks per segment of large relation */ + + uint32 xlog_blcksz; /* block size within WAL files */ + uint32 xlog_seg_size; /* size of each WAL segment */ + + uint32 nameDataLen; /* catalog name field width */ + uint32 indexMaxKeys; /* max number of columns in an index */ + + uint32 toast_max_chunk_size; /* chunk size in TOAST tables */ + uint32 loblksize; /* chunk size in pg_largeobject */ + + bool float8ByVal; /* float8, int8, etc pass-by-value? */ + + /* Are data pages protected by checksums? Zero if no checksum version */ + uint32 data_checksum_version; + + /* + * Random nonce, used in authentication requests that need to proceed + * based on values that are cluster-unique, like a SASL exchange that + * failed at an early stage. + */ + char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN]; + + /* CRC of all above ... MUST BE LAST! */ + pg_crc32c crc; +} ControlFileData; + +/* + * Maximum safe value of sizeof(ControlFileData). For reliability's sake, + * it's critical that pg_control updates be atomic writes. That generally + * means the active data can't be more than one disk sector, which is 512 + * bytes on common hardware. Be very careful about raising this limit. + */ +#define PG_CONTROL_MAX_SAFE_SIZE 512 + +/* + * Physical size of the pg_control file. Note that this is considerably + * bigger than the actually used size (ie, sizeof(ControlFileData)). + * The idea is to keep the physical size constant independent of format + * changes, so that ReadControlFile will deliver a suitable wrong-version + * message instead of a read error if it's looking at an incompatible file. + */ +#define PG_CONTROL_FILE_SIZE 8192 + +/* + * Ensure that the size of the pg_control data structure is sane. + */ +StaticAssertDecl(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE, + "pg_control is too large for atomic disk writes"); +StaticAssertDecl(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE, + "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE"); + +#endif /* PG_CONTROL_H */ diff --git a/contrib/libs/libpq/src/include/common/archive.h b/contrib/libs/libpq/src/include/common/archive.h new file mode 100644 index 0000000000..95196772c9 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/archive.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * archive.h + * Common WAL archive routines + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/archive.h + * + *------------------------------------------------------------------------- + */ +#ifndef ARCHIVE_H +#define ARCHIVE_H + +extern char *BuildRestoreCommand(const char *restoreCommand, + const char *xlogpath, /* %p */ + const char *xlogfname, /* %f */ + const char *lastRestartPointFname); /* %r */ + +#endif /* ARCHIVE_H */ diff --git a/contrib/libs/libpq/src/include/common/base64.h b/contrib/libs/libpq/src/include/common/base64.h new file mode 100644 index 0000000000..5bd8186c79 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/base64.h @@ -0,0 +1,19 @@ +/* + * base64.h + * Encoding and decoding routines for base64 without whitespace + * support. + * + * Portions Copyright (c) 2001-2023, PostgreSQL Global Development Group + * + * src/include/common/base64.h + */ +#ifndef BASE64_H +#define BASE64_H + +/* base 64 */ +extern int pg_b64_encode(const char *src, int len, char *dst, int dstlen); +extern int pg_b64_decode(const char *src, int len, char *dst, int dstlen); +extern int pg_b64_enc_len(int srclen); +extern int pg_b64_dec_len(int srclen); + +#endif /* BASE64_H */ diff --git a/contrib/libs/libpq/src/include/common/checksum_helper.h b/contrib/libs/libpq/src/include/common/checksum_helper.h new file mode 100644 index 0000000000..a74deef67b --- /dev/null +++ b/contrib/libs/libpq/src/include/common/checksum_helper.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * checksum_helper.h + * Compute a checksum of any of various types using common routines + * + * Portions Copyright (c) 2016-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/common/checksum_helper.h + * + *------------------------------------------------------------------------- + */ + +#ifndef CHECKSUM_HELPER_H +#define CHECKSUM_HELPER_H + +#include "common/cryptohash.h" +#include "common/sha2.h" +#include "port/pg_crc32c.h" + +/* + * Supported checksum types. It's not necessarily the case that code using + * these functions needs a cryptographically strong checksum; it may only + * need to detect accidental modification. That's why we include CRC-32C: it's + * much faster than any of the other algorithms. On the other hand, we omit + * MD5 here because any new that does need a cryptographically strong checksum + * should use something better. + */ +typedef enum pg_checksum_type +{ + CHECKSUM_TYPE_NONE, + CHECKSUM_TYPE_CRC32C, + CHECKSUM_TYPE_SHA224, + CHECKSUM_TYPE_SHA256, + CHECKSUM_TYPE_SHA384, + CHECKSUM_TYPE_SHA512 +} pg_checksum_type; + +/* + * This is just a union of all applicable context types. + */ +typedef union pg_checksum_raw_context +{ + pg_crc32c c_crc32c; + pg_cryptohash_ctx *c_sha2; +} pg_checksum_raw_context; + +/* + * This structure provides a convenient way to pass the checksum type and the + * checksum context around together. + */ +typedef struct pg_checksum_context +{ + pg_checksum_type type; + pg_checksum_raw_context raw_context; +} pg_checksum_context; + +/* + * This is the longest possible output for any checksum algorithm supported + * by this file. + */ +#define PG_CHECKSUM_MAX_LENGTH PG_SHA512_DIGEST_LENGTH + +extern bool pg_checksum_parse_type(char *name, pg_checksum_type *); +extern char *pg_checksum_type_name(pg_checksum_type); + +extern int pg_checksum_init(pg_checksum_context *, pg_checksum_type); +extern int pg_checksum_update(pg_checksum_context *, const uint8 *input, + size_t len); +extern int pg_checksum_final(pg_checksum_context *, uint8 *output); + +#endif diff --git a/contrib/libs/libpq/src/include/common/compression.h b/contrib/libs/libpq/src/include/common/compression.h new file mode 100644 index 0000000000..38aae9dd87 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/compression.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * compression.h + * + * Shared definitions for compression methods and specifications. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/common/compression.h + *------------------------------------------------------------------------- + */ + +#ifndef PG_COMPRESSION_H +#define PG_COMPRESSION_H + +/* + * These values are stored in disk, for example in files generated by pg_dump. + * Create the necessary backwards compatibility layers if their order changes. + */ +typedef enum pg_compress_algorithm +{ + PG_COMPRESSION_NONE, + PG_COMPRESSION_GZIP, + PG_COMPRESSION_LZ4, + PG_COMPRESSION_ZSTD +} pg_compress_algorithm; + +#define PG_COMPRESSION_OPTION_WORKERS (1 << 0) +#define PG_COMPRESSION_OPTION_LONG_DISTANCE (1 << 1) + +typedef struct pg_compress_specification +{ + pg_compress_algorithm algorithm; + unsigned options; /* OR of PG_COMPRESSION_OPTION constants */ + int level; + int workers; + bool long_distance; + char *parse_error; /* NULL if parsing was OK, else message */ +} pg_compress_specification; + +extern void parse_compress_options(const char *option, char **algorithm, + char **detail); +extern bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm); +extern const char *get_compress_algorithm_name(pg_compress_algorithm algorithm); + +extern void parse_compress_specification(pg_compress_algorithm algorithm, + char *specification, + pg_compress_specification *result); + +extern char *validate_compress_specification(pg_compress_specification *); + +#endif diff --git a/contrib/libs/libpq/src/include/common/config_info.h b/contrib/libs/libpq/src/include/common/config_info.h new file mode 100644 index 0000000000..a6d076d5e9 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/config_info.h @@ -0,0 +1,21 @@ +/* + * config_info.h + * Common code for pg_config output + * + * Copyright (c) 2016-2023, PostgreSQL Global Development Group + * + * src/include/common/config_info.h + */ +#ifndef COMMON_CONFIG_INFO_H +#define COMMON_CONFIG_INFO_H + +typedef struct ConfigData +{ + char *name; + char *setting; +} ConfigData; + +extern ConfigData *get_configdata(const char *my_exec_path, + size_t *configdata_len); + +#endif /* COMMON_CONFIG_INFO_H */ diff --git a/contrib/libs/libpq/src/include/common/controldata_utils.h b/contrib/libs/libpq/src/include/common/controldata_utils.h new file mode 100644 index 0000000000..49e7c52d31 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/controldata_utils.h @@ -0,0 +1,19 @@ +/* + * controldata_utils.h + * Common code for pg_controldata output + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/controldata_utils.h + */ +#ifndef COMMON_CONTROLDATA_UTILS_H +#define COMMON_CONTROLDATA_UTILS_H + +#include "catalog/pg_control.h" + +extern ControlFileData *get_controlfile(const char *DataDir, bool *crc_ok_p); +extern void update_controlfile(const char *DataDir, + ControlFileData *ControlFile, bool do_sync); + +#endif /* COMMON_CONTROLDATA_UTILS_H */ diff --git a/contrib/libs/libpq/src/include/common/cryptohash.h b/contrib/libs/libpq/src/include/common/cryptohash.h new file mode 100644 index 0000000000..24b6dbebbd --- /dev/null +++ b/contrib/libs/libpq/src/include/common/cryptohash.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * cryptohash.h + * Generic headers for cryptographic hash functions. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/cryptohash.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_CRYPTOHASH_H +#define PG_CRYPTOHASH_H + +/* Context Structures for each hash function */ +typedef enum +{ + PG_MD5 = 0, + PG_SHA1, + PG_SHA224, + PG_SHA256, + PG_SHA384, + PG_SHA512 +} pg_cryptohash_type; + +/* opaque context, private to each cryptohash implementation */ +typedef struct pg_cryptohash_ctx pg_cryptohash_ctx; + +extern pg_cryptohash_ctx *pg_cryptohash_create(pg_cryptohash_type type); +extern int pg_cryptohash_init(pg_cryptohash_ctx *ctx); +extern int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len); +extern int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len); +extern void pg_cryptohash_free(pg_cryptohash_ctx *ctx); +extern const char *pg_cryptohash_error(pg_cryptohash_ctx *ctx); + +#endif /* PG_CRYPTOHASH_H */ diff --git a/contrib/libs/libpq/src/include/common/fe_memutils.h b/contrib/libs/libpq/src/include/common/fe_memutils.h new file mode 100644 index 0000000000..89601cc778 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/fe_memutils.h @@ -0,0 +1,73 @@ +/* + * fe_memutils.h + * memory management support for frontend code + * + * Copyright (c) 2003-2023, 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 *ptr, size_t size); +extern void pg_free(void *ptr); + +/* + * Variants with easier notation and more type safety + */ + +/* + * Allocate space for one object of type "type" + */ +#define pg_malloc_object(type) ((type *) pg_malloc(sizeof(type))) +#define pg_malloc0_object(type) ((type *) pg_malloc0(sizeof(type))) + +/* + * Allocate space for "count" objects of type "type" + */ +#define pg_malloc_array(type, count) ((type *) pg_malloc(sizeof(type) * (count))) +#define pg_malloc0_array(type, count) ((type *) pg_malloc0(sizeof(type) * (count))) + +/* + * Change size of allocation pointed to by "pointer" to have space for "count" + * objects of type "type" + */ +#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc(pointer, sizeof(type) * (count))) + +/* Equivalent functions, deliberately named the same as backend functions */ +extern char *pstrdup(const char *in); +extern char *pnstrdup(const char *in, Size size); +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); + +#define palloc_object(type) ((type *) palloc(sizeof(type))) +#define palloc0_object(type) ((type *) palloc0(sizeof(type))) +#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) +#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) +#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) + +/* 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/contrib/libs/libpq/src/include/common/file_perm.h b/contrib/libs/libpq/src/include/common/file_perm.h new file mode 100644 index 0000000000..978c0d072f --- /dev/null +++ b/contrib/libs/libpq/src/include/common/file_perm.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * File and directory permission definitions + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/file_perm.h + * + *------------------------------------------------------------------------- + */ +#ifndef FILE_PERM_H +#define FILE_PERM_H + +#include <sys/stat.h> + +/* + * Mode mask for data directory permissions that only allows the owner to + * read/write directories and files. + * + * This is the default. + */ +#define PG_MODE_MASK_OWNER (S_IRWXG | S_IRWXO) + +/* + * Mode mask for data directory permissions that also allows group read/execute. + */ +#define PG_MODE_MASK_GROUP (S_IWGRP | S_IRWXO) + +/* Default mode for creating directories */ +#define PG_DIR_MODE_OWNER S_IRWXU + +/* Mode for creating directories that allows group read/execute */ +#define PG_DIR_MODE_GROUP (S_IRWXU | S_IRGRP | S_IXGRP) + +/* Default mode for creating files */ +#define PG_FILE_MODE_OWNER (S_IRUSR | S_IWUSR) + +/* Mode for creating files that allows group read */ +#define PG_FILE_MODE_GROUP (S_IRUSR | S_IWUSR | S_IRGRP) + +/* Modes for creating directories and files in the data directory */ +extern PGDLLIMPORT int pg_dir_create_mode; +extern PGDLLIMPORT int pg_file_create_mode; + +/* Mode mask to pass to umask() */ +extern PGDLLIMPORT int pg_mode_mask; + +/* Set permissions and mask based on the provided mode */ +extern void SetDataDirectoryCreatePerm(int dataDirMode); + +/* Set permissions and mask based on the mode of the data directory */ +extern bool GetDataDirectoryCreatePerm(const char *dataDir); + +#endif /* FILE_PERM_H */ diff --git a/contrib/libs/libpq/src/include/common/file_utils.h b/contrib/libs/libpq/src/include/common/file_utils.h new file mode 100644 index 0000000000..b7efa1226d --- /dev/null +++ b/contrib/libs/libpq/src/include/common/file_utils.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * Assorted utility functions to work on files. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/file_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef FILE_UTILS_H +#define FILE_UTILS_H + +#include <dirent.h> + +typedef enum PGFileType +{ + PGFILETYPE_ERROR, + PGFILETYPE_UNKNOWN, + PGFILETYPE_REG, + PGFILETYPE_DIR, + PGFILETYPE_LNK +} PGFileType; + +struct iovec; /* avoid including port/pg_iovec.h here */ + +#ifdef FRONTEND +extern int fsync_fname(const char *fname, bool isdir); +extern void fsync_pgdata(const char *pg_data, int serverVersion); +extern void fsync_dir_recurse(const char *dir); +extern int durable_rename(const char *oldfile, const char *newfile); +extern int fsync_parent_path(const char *fname); +#endif + +extern PGFileType get_dirent_type(const char *path, + const struct dirent *de, + bool look_through_symlinks, + int elevel); + +extern ssize_t pg_pwritev_with_retry(int fd, + const struct iovec *iov, + int iovcnt, + off_t offset); + +extern ssize_t pg_pwrite_zeros(int fd, size_t size, off_t offset); + +#endif /* FILE_UTILS_H */ diff --git a/contrib/libs/libpq/src/include/common/hashfn.h b/contrib/libs/libpq/src/include/common/hashfn.h new file mode 100644 index 0000000000..5e89aef987 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/hashfn.h @@ -0,0 +1,104 @@ +/* + * Utilities for working with hash values. + * + * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group + */ + +#ifndef HASHFN_H +#define HASHFN_H + + +/* + * Rotate the high 32 bits and the low 32 bits separately. The standard + * hash function sometimes rotates the low 32 bits by one bit when + * combining elements. We want extended hash functions to be compatible with + * that algorithm when the seed is 0, so we can't just do a normal rotation. + * This works, though. + */ +#define ROTATE_HIGH_AND_LOW_32BITS(v) \ + ((((v) << 1) & UINT64CONST(0xfffffffefffffffe)) | \ + (((v) >> 31) & UINT64CONST(0x100000001))) + + +extern uint32 hash_bytes(const unsigned char *k, int keylen); +extern uint64 hash_bytes_extended(const unsigned char *k, + int keylen, uint64 seed); +extern uint32 hash_bytes_uint32(uint32 k); +extern uint64 hash_bytes_uint32_extended(uint32 k, uint64 seed); + +#ifndef FRONTEND +static inline Datum +hash_any(const unsigned char *k, int keylen) +{ + return UInt32GetDatum(hash_bytes(k, keylen)); +} + +static inline Datum +hash_any_extended(const unsigned char *k, int keylen, uint64 seed) +{ + return UInt64GetDatum(hash_bytes_extended(k, keylen, seed)); +} + +static inline Datum +hash_uint32(uint32 k) +{ + return UInt32GetDatum(hash_bytes_uint32(k)); +} + +static inline Datum +hash_uint32_extended(uint32 k, uint64 seed) +{ + return UInt64GetDatum(hash_bytes_uint32_extended(k, seed)); +} +#endif + +extern uint32 string_hash(const void *key, Size keysize); +extern uint32 tag_hash(const void *key, Size keysize); +extern uint32 uint32_hash(const void *key, Size keysize); + +#define oid_hash uint32_hash /* Remove me eventually */ + +/* + * Combine two 32-bit hash values, resulting in another hash value, with + * decent bit mixing. + * + * Similar to boost's hash_combine(). + */ +static inline uint32 +hash_combine(uint32 a, uint32 b) +{ + a ^= b + 0x9e3779b9 + (a << 6) + (a >> 2); + return a; +} + +/* + * Combine two 64-bit hash values, resulting in another hash value, using the + * same kind of technique as hash_combine(). Testing shows that this also + * produces good bit mixing. + */ +static inline uint64 +hash_combine64(uint64 a, uint64 b) +{ + /* 0x49a0f4dd15e5a8e3 is 64bit random data */ + a ^= b + UINT64CONST(0x49a0f4dd15e5a8e3) + (a << 54) + (a >> 7); + return a; +} + +/* + * Simple inline murmur hash implementation hashing a 32 bit integer, for + * performance. + */ +static inline uint32 +murmurhash32(uint32 data) +{ + uint32 h = data; + + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +#endif /* HASHFN_H */ diff --git a/contrib/libs/libpq/src/include/common/hmac.h b/contrib/libs/libpq/src/include/common/hmac.h new file mode 100644 index 0000000000..e0b2ed2024 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/hmac.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * hmac.h + * Generic headers for HMAC + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/hmac.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_HMAC_H +#define PG_HMAC_H + +#include "common/cryptohash.h" + +/* opaque context, private to each HMAC implementation */ +typedef struct pg_hmac_ctx pg_hmac_ctx; + +extern pg_hmac_ctx *pg_hmac_create(pg_cryptohash_type type); +extern int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len); +extern int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len); +extern int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len); +extern void pg_hmac_free(pg_hmac_ctx *ctx); +extern const char *pg_hmac_error(pg_hmac_ctx *ctx); + +#endif /* PG_HMAC_H */ diff --git a/contrib/libs/libpq/src/include/common/ip.h b/contrib/libs/libpq/src/include/common/ip.h new file mode 100644 index 0000000000..9f2ed5fe0a --- /dev/null +++ b/contrib/libs/libpq/src/include/common/ip.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * ip.h + * Definitions for IPv6-aware network access. + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2003-2023, PostgreSQL Global Development Group + * + * src/include/common/ip.h + * + *------------------------------------------------------------------------- + */ +#ifndef IP_H +#define IP_H + +#include <netdb.h> +#include <sys/socket.h> + +#include "libpq/pqcomm.h" /* pgrminclude ignore */ + + +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); + +#endif /* IP_H */ diff --git a/contrib/libs/libpq/src/include/common/jsonapi.h b/contrib/libs/libpq/src/include/common/jsonapi.h new file mode 100644 index 0000000000..4310084b2b --- /dev/null +++ b/contrib/libs/libpq/src/include/common/jsonapi.h @@ -0,0 +1,177 @@ +/*------------------------------------------------------------------------- + * + * jsonapi.h + * Declarations for JSON API support. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/jsonapi.h + * + *------------------------------------------------------------------------- + */ + +#ifndef JSONAPI_H +#define JSONAPI_H + +#include "lib/stringinfo.h" + +typedef enum JsonTokenType +{ + JSON_TOKEN_INVALID, + JSON_TOKEN_STRING, + JSON_TOKEN_NUMBER, + JSON_TOKEN_OBJECT_START, + JSON_TOKEN_OBJECT_END, + JSON_TOKEN_ARRAY_START, + JSON_TOKEN_ARRAY_END, + JSON_TOKEN_COMMA, + JSON_TOKEN_COLON, + JSON_TOKEN_TRUE, + JSON_TOKEN_FALSE, + JSON_TOKEN_NULL, + JSON_TOKEN_END +} JsonTokenType; + +typedef enum JsonParseErrorType +{ + JSON_SUCCESS, + JSON_ESCAPING_INVALID, + JSON_ESCAPING_REQUIRED, + JSON_EXPECTED_ARRAY_FIRST, + JSON_EXPECTED_ARRAY_NEXT, + JSON_EXPECTED_COLON, + JSON_EXPECTED_END, + JSON_EXPECTED_JSON, + JSON_EXPECTED_MORE, + JSON_EXPECTED_OBJECT_FIRST, + JSON_EXPECTED_OBJECT_NEXT, + JSON_EXPECTED_STRING, + JSON_INVALID_TOKEN, + JSON_UNICODE_CODE_POINT_ZERO, + JSON_UNICODE_ESCAPE_FORMAT, + JSON_UNICODE_HIGH_ESCAPE, + JSON_UNICODE_UNTRANSLATABLE, + JSON_UNICODE_HIGH_SURROGATE, + JSON_UNICODE_LOW_SURROGATE, + JSON_SEM_ACTION_FAILED /* error should already be reported */ +} JsonParseErrorType; + + +/* + * All the fields in this structure should be treated as read-only. + * + * If strval is not null, then it should contain the de-escaped value + * of the lexeme if it's a string. Otherwise most of these field names + * should be self-explanatory. + * + * line_number and line_start are principally for use by the parser's + * error reporting routines. + * token_terminator and prev_token_terminator point to the character + * AFTER the end of the token, i.e. where there would be a nul byte + * if we were using nul-terminated strings. + */ +typedef struct JsonLexContext +{ + char *input; + int input_length; + int input_encoding; + char *token_start; + char *token_terminator; + char *prev_token_terminator; + JsonTokenType token_type; + int lex_level; + int line_number; /* line number, starting from 1 */ + char *line_start; /* where that line starts within input */ + StringInfo strval; +} JsonLexContext; + +typedef JsonParseErrorType (*json_struct_action) (void *state); +typedef JsonParseErrorType (*json_ofield_action) (void *state, char *fname, bool isnull); +typedef JsonParseErrorType (*json_aelem_action) (void *state, bool isnull); +typedef JsonParseErrorType (*json_scalar_action) (void *state, char *token, JsonTokenType tokentype); + + +/* + * Semantic Action structure for use in parsing json. + * + * Any of these actions can be NULL, in which case nothing is done at that + * point, Likewise, semstate can be NULL. Using an all-NULL structure amounts + * to doing a pure parse with no side-effects, and is therefore exactly + * what the json input routines do. + * + * The 'fname' and 'token' strings passed to these actions are palloc'd. + * They are not free'd or used further by the parser, so the action function + * is free to do what it wishes with them. + * + * All action functions return JsonParseErrorType. If the result isn't + * JSON_SUCCESS, the parse is abandoned and that error code is returned. + * If it is JSON_SEM_ACTION_FAILED, the action function is responsible + * for having reported the error in some appropriate way. + */ +typedef struct JsonSemAction +{ + void *semstate; + json_struct_action object_start; + json_struct_action object_end; + json_struct_action array_start; + json_struct_action array_end; + json_ofield_action object_field_start; + json_ofield_action object_field_end; + json_aelem_action array_element_start; + json_aelem_action array_element_end; + json_scalar_action scalar; +} JsonSemAction; + +/* + * pg_parse_json will parse the string in the lex calling the + * action functions in sem at the appropriate points. It is + * up to them to keep what state they need in semstate. If they + * need access to the state of the lexer, then its pointer + * should be passed to them as a member of whatever semstate + * points to. If the action pointers are NULL the parser + * does nothing and just continues. + */ +extern JsonParseErrorType pg_parse_json(JsonLexContext *lex, + JsonSemAction *sem); + +/* the null action object used for pure validation */ +extern PGDLLIMPORT JsonSemAction nullSemAction; + +/* + * json_count_array_elements performs a fast secondary parse to determine the + * number of elements in passed array lex context. It should be called from an + * array_start action. + * + * The return value indicates whether any error occurred, while the number + * of elements is stored into *elements (but only if the return value is + * JSON_SUCCESS). + */ +extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex, + int *elements); + +/* + * constructor for JsonLexContext, with or without strval element. + * If supplied, the strval element will contain a de-escaped version of + * the lexeme. However, doing this imposes a performance penalty, so + * it should be avoided if the de-escaped lexeme is not required. + */ +extern JsonLexContext *makeJsonLexContextCstringLen(char *json, + int len, + int encoding, + bool need_escapes); + +/* lex one token */ +extern JsonParseErrorType json_lex(JsonLexContext *lex); + +/* construct an error detail string for a json error */ +extern char *json_errdetail(JsonParseErrorType error, JsonLexContext *lex); + +/* + * Utility function to check if a string is a valid JSON number. + * + * str argument does not need to be nul-terminated. + */ +extern bool IsValidJsonNumber(const char *str, int len); + +#endif /* JSONAPI_H */ diff --git a/contrib/libs/libpq/src/include/common/keywords.h b/contrib/libs/libpq/src/include/common/keywords.h new file mode 100644 index 0000000000..6bb12d8edb --- /dev/null +++ b/contrib/libs/libpq/src/include/common/keywords.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * keywords.h + * PostgreSQL's list of SQL keywords + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/keywords.h + * + *------------------------------------------------------------------------- + */ +#ifndef KEYWORDS_H +#define KEYWORDS_H + +#include "common/kwlookup.h" + +/* Keyword categories --- should match lists in gram.y */ +#define UNRESERVED_KEYWORD 0 +#define COL_NAME_KEYWORD 1 +#define TYPE_FUNC_NAME_KEYWORD 2 +#define RESERVED_KEYWORD 3 + +extern PGDLLIMPORT const ScanKeywordList ScanKeywords; +extern PGDLLIMPORT const uint8 ScanKeywordCategories[]; +extern PGDLLIMPORT const bool ScanKeywordBareLabel[]; + +#endif /* KEYWORDS_H */ diff --git a/contrib/libs/libpq/src/include/common/kwlookup.h b/contrib/libs/libpq/src/include/common/kwlookup.h new file mode 100644 index 0000000000..3fc3faa043 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/kwlookup.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * kwlookup.h + * Key word lookup for PostgreSQL + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/kwlookup.h + * + *------------------------------------------------------------------------- + */ +#ifndef KWLOOKUP_H +#define KWLOOKUP_H + +/* Hash function used by ScanKeywordLookup */ +typedef int (*ScanKeywordHashFunc) (const void *key, size_t keylen); + +/* + * This struct contains the data needed by ScanKeywordLookup to perform a + * search within a set of keywords. The contents are typically generated by + * src/tools/gen_keywordlist.pl from a header containing PG_KEYWORD macros. + */ +typedef struct ScanKeywordList +{ + const char *kw_string; /* all keywords in order, separated by \0 */ + const uint16 *kw_offsets; /* offsets to the start of each keyword */ + ScanKeywordHashFunc hash; /* perfect hash function for keywords */ + int num_keywords; /* number of keywords */ + int max_kw_len; /* length of longest keyword */ +} ScanKeywordList; + + +extern int ScanKeywordLookup(const char *str, const ScanKeywordList *keywords); + +/* Code that wants to retrieve the text of the N'th keyword should use this. */ +static inline const char * +GetScanKeyword(int n, const ScanKeywordList *keywords) +{ + return keywords->kw_string + keywords->kw_offsets[n]; +} + +#endif /* KWLOOKUP_H */ diff --git a/contrib/libs/libpq/src/include/common/link-canary.h b/contrib/libs/libpq/src/include/common/link-canary.h new file mode 100644 index 0000000000..178d123b1a --- /dev/null +++ b/contrib/libs/libpq/src/include/common/link-canary.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * link-canary.h + * Detect whether src/common functions came from frontend or backend. + * + * Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * src/include/common/link-canary.h + * + *------------------------------------------------------------------------- + */ +#ifndef LINK_CANARY_H +#define LINK_CANARY_H + +extern bool pg_link_canary_is_frontend(void); + +#endif /* LINK_CANARY_H */ diff --git a/contrib/libs/libpq/src/include/common/logging.h b/contrib/libs/libpq/src/include/common/logging.h new file mode 100644 index 0000000000..99e888af93 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/logging.h @@ -0,0 +1,156 @@ +/*------------------------------------------------------------------------- + * Logging framework for frontend programs + * + * Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * src/include/common/logging.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMMON_LOGGING_H +#define COMMON_LOGGING_H + +/* + * Log levels are informational only. They do not affect program flow. + */ +enum pg_log_level +{ + /* + * Not initialized yet (not to be used as an actual message log level). + */ + PG_LOG_NOTSET = 0, + + /* + * Low level messages that are normally off by default. + */ + PG_LOG_DEBUG, + + /* + * Any program messages that go to stderr, shown by default. (The + * program's normal output should go to stdout and not use the logging + * system.) + */ + PG_LOG_INFO, + + /* + * Warnings and "almost" errors, depends on the program + */ + PG_LOG_WARNING, + + /* + * Errors + */ + PG_LOG_ERROR, + + /* + * Turn all logging off (not to be used as an actual message log level). + */ + PG_LOG_OFF, +}; + +/* + * __pg_log_level is the minimum log level that will actually be shown. + */ +extern enum pg_log_level __pg_log_level; + +/* + * A log message can have several parts. The primary message is required, + * others are optional. When emitting multiple parts, do so in the order of + * this enum, for consistency. + */ +enum pg_log_part +{ + /* + * The primary message. Try to keep it to one line; follow the backend's + * style guideline for primary messages. + */ + PG_LOG_PRIMARY, + + /* + * Additional detail. Follow the backend's style guideline for detail + * messages. + */ + PG_LOG_DETAIL, + + /* + * Hint (not guaranteed correct) about how to fix the problem. Follow the + * backend's style guideline for hint messages. + */ + PG_LOG_HINT, +}; + +/* + * Kind of a hack to be able to produce the psql output exactly as required by + * the regression tests. + */ +#define PG_LOG_FLAG_TERSE 1 + +void pg_logging_init(const char *argv0); +void pg_logging_config(int new_flags); +void pg_logging_set_level(enum pg_log_level new_level); +void pg_logging_increase_verbosity(void); +void pg_logging_set_pre_callback(void (*cb) (void)); +void pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno)); + +void pg_log_generic(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt,...) + pg_attribute_printf(3, 4); +void pg_log_generic_v(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt, va_list ap) + pg_attribute_printf(3, 0); + +/* + * Preferred style is to use these macros to perform logging; don't call + * pg_log_generic[_v] directly, except perhaps in error interface code. + */ +#define pg_log_error(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_error_detail(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_error_hint(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_warning(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_warning_detail(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_warning_hint(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_info(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_info_detail(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_info_hint(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_debug(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_PRIMARY, __VA_ARGS__); \ + } while(0) + +#define pg_log_debug_detail(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_DETAIL, __VA_ARGS__); \ + } while(0) + +#define pg_log_debug_hint(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_HINT, __VA_ARGS__); \ + } while(0) + +/* + * A common shortcut: pg_log_error() and immediately exit(1). + */ +#define pg_fatal(...) do { \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_PRIMARY, __VA_ARGS__); \ + exit(1); \ + } while(0) + +#endif /* COMMON_LOGGING_H */ diff --git a/contrib/libs/libpq/src/include/common/md5.h b/contrib/libs/libpq/src/include/common/md5.h new file mode 100644 index 0000000000..b6089bacff --- /dev/null +++ b/contrib/libs/libpq/src/include/common/md5.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * md5.h + * Constants and common utilities related to MD5. + * + * These definitions are needed by both frontend and backend code to work + * with MD5-encrypted passwords. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/md5.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_MD5_H +#define PG_MD5_H + +/* Size of result generated by MD5 computation */ +#define MD5_DIGEST_LENGTH 16 +/* Block size for MD5 */ +#define MD5_BLOCK_SIZE 64 + +/* password-related data */ +#define MD5_PASSWD_CHARSET "0123456789abcdef" +#define MD5_PASSWD_LEN 35 + +/* Utilities common to all the MD5 implementations, as of md5_common.c */ +extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum, + const char **errstr); +extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf, + const char **errstr); +extern bool pg_md5_encrypt(const char *passwd, const char *salt, + size_t salt_len, char *buf, + const char **errstr); + +#endif /* PG_MD5_H */ diff --git a/contrib/libs/libpq/src/include/common/openssl.h b/contrib/libs/libpq/src/include/common/openssl.h new file mode 100644 index 0000000000..060675ab33 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/openssl.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * openssl.h + * OpenSSL supporting functionality shared between frontend and backend + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/openssl.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMMON_OPENSSL_H +#define COMMON_OPENSSL_H + +#ifdef USE_OPENSSL +#include <openssl/ssl.h> + +/* + * OpenSSL doesn't provide any very nice way to identify the min/max + * protocol versions the library supports, so we fake it as best we can. + * Note in particular that this doesn't account for restrictions that + * might be specified in the installation's openssl.cnf. + * + * We disable SSLv3 and older in library setup, so TLSv1 is the oldest + * protocol version of interest. + */ +#define MIN_OPENSSL_TLS_VERSION "TLSv1" + +#if defined(TLS1_3_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.3" +#elif defined(TLS1_2_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.2" +#elif defined(TLS1_1_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.1" +#else +#define MAX_OPENSSL_TLS_VERSION "TLSv1" +#endif + +/* src/common/protocol_openssl.c */ +#ifndef SSL_CTX_set_min_proto_version +extern int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version); +extern int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version); +#endif + +#endif /* USE_OPENSSL */ + +#endif /* COMMON_OPENSSL_H */ diff --git a/contrib/libs/libpq/src/include/common/percentrepl.h b/contrib/libs/libpq/src/include/common/percentrepl.h new file mode 100644 index 0000000000..0efb6ecb5b --- /dev/null +++ b/contrib/libs/libpq/src/include/common/percentrepl.h @@ -0,0 +1,18 @@ +/*------------------------------------------------------------------------- + * + * percentrepl.h + * Common routines to replace percent placeholders in strings + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/percentrepl.h + * + *------------------------------------------------------------------------- + */ +#ifndef PERCENTREPL_H +#define PERCENTREPL_H + +extern char *replace_percent_placeholders(const char *instr, const char *param_name, const char *letters,...); + +#endif /* PERCENTREPL_H */ diff --git a/contrib/libs/libpq/src/include/common/pg_lzcompress.h b/contrib/libs/libpq/src/include/common/pg_lzcompress.h new file mode 100644 index 0000000000..2a12b33a00 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/pg_lzcompress.h @@ -0,0 +1,93 @@ +/* ---------- + * pg_lzcompress.h - + * + * Definitions for the builtin LZ compressor + * + * src/include/common/pg_lzcompress.h + * ---------- + */ + +#ifndef _PG_LZCOMPRESS_H_ +#define _PG_LZCOMPRESS_H_ + + +/* ---------- + * PGLZ_MAX_OUTPUT - + * + * Macro to compute the buffer size required by pglz_compress(). + * We allow 4 bytes for overrun before detecting compression failure. + * ---------- + */ +#define PGLZ_MAX_OUTPUT(_dlen) ((_dlen) + 4) + + +/* ---------- + * PGLZ_Strategy - + * + * Some values that control the compression algorithm. + * + * min_input_size Minimum input data size to consider compression. + * + * max_input_size Maximum input data size to consider compression. + * + * min_comp_rate Minimum compression rate (0-99%) to require. + * Regardless of min_comp_rate, the output must be + * smaller than the input, else we don't store + * compressed. + * + * first_success_by Abandon compression if we find no compressible + * data within the first this-many bytes. + * + * match_size_good The initial GOOD match size when starting history + * lookup. When looking up the history to find a + * match that could be expressed as a tag, the + * algorithm does not always walk back entirely. + * A good match fast is usually better than the + * best possible one very late. For each iteration + * in the lookup, this value is lowered so the + * longer the lookup takes, the smaller matches + * are considered good. + * + * match_size_drop The percentage by which match_size_good is lowered + * after each history check. Allowed values are + * 0 (no change until end) to 100 (only check + * latest history entry at all). + * ---------- + */ +typedef struct PGLZ_Strategy +{ + int32 min_input_size; + int32 max_input_size; + int32 min_comp_rate; + int32 first_success_by; + int32 match_size_good; + int32 match_size_drop; +} PGLZ_Strategy; + + +/* ---------- + * The standard strategies + * + * PGLZ_strategy_default Recommended default strategy for TOAST. + * + * PGLZ_strategy_always Try to compress inputs of any length. + * Fallback to uncompressed storage only if + * output would be larger than input. + * ---------- + */ +extern PGDLLIMPORT const PGLZ_Strategy *const PGLZ_strategy_default; +extern PGDLLIMPORT const PGLZ_Strategy *const PGLZ_strategy_always; + + +/* ---------- + * Global function declarations + * ---------- + */ +extern int32 pglz_compress(const char *source, int32 slen, char *dest, + const PGLZ_Strategy *strategy); +extern int32 pglz_decompress(const char *source, int32 slen, char *dest, + int32 rawsize, bool check_complete); +extern int32 pglz_maximum_compressed_size(int32 rawsize, + int32 total_compressed_size); + +#endif /* _PG_LZCOMPRESS_H_ */ diff --git a/contrib/libs/libpq/src/include/common/pg_prng.h b/contrib/libs/libpq/src/include/common/pg_prng.h new file mode 100644 index 0000000000..b5c0b8d288 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/pg_prng.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * Pseudo-Random Number Generator + * + * Copyright (c) 2021-2023, PostgreSQL Global Development Group + * + * src/include/common/pg_prng.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PRNG_H +#define PG_PRNG_H + +/* + * State vector for PRNG generation. Callers should treat this as an + * opaque typedef, but we expose its definition to allow it to be + * embedded in other structs. + */ +typedef struct pg_prng_state +{ + uint64 s0, + s1; +} pg_prng_state; + +/* + * Callers not needing local PRNG series may use this global state vector, + * after initializing it with one of the pg_prng_...seed functions. + */ +extern PGDLLIMPORT pg_prng_state pg_global_prng_state; + +extern void pg_prng_seed(pg_prng_state *state, uint64 seed); +extern void pg_prng_fseed(pg_prng_state *state, double fseed); +extern bool pg_prng_seed_check(pg_prng_state *state); + +/* + * Initialize the PRNG state from the pg_strong_random source, + * taking care that we don't produce all-zeroes. If this returns false, + * caller should initialize the PRNG state from some other random seed, + * using pg_prng_[f]seed. + * + * We implement this as a macro, so that the pg_strong_random() call is + * in the caller. If it were in pg_prng.c, programs using pg_prng.c + * but not needing strong seeding would nonetheless be forced to pull in + * pg_strong_random.c and thence OpenSSL. + */ +#define pg_prng_strong_seed(state) \ + (pg_strong_random((void *) (state), sizeof(pg_prng_state)) ? \ + pg_prng_seed_check(state) : false) + +extern uint64 pg_prng_uint64(pg_prng_state *state); +extern uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax); +extern int64 pg_prng_int64(pg_prng_state *state); +extern int64 pg_prng_int64p(pg_prng_state *state); +extern uint32 pg_prng_uint32(pg_prng_state *state); +extern int32 pg_prng_int32(pg_prng_state *state); +extern int32 pg_prng_int32p(pg_prng_state *state); +extern double pg_prng_double(pg_prng_state *state); +extern double pg_prng_double_normal(pg_prng_state *state); +extern bool pg_prng_bool(pg_prng_state *state); + +#endif /* PG_PRNG_H */ diff --git a/contrib/libs/libpq/src/include/common/relpath.h b/contrib/libs/libpq/src/include/common/relpath.h new file mode 100644 index 0000000000..511c21682e --- /dev/null +++ b/contrib/libs/libpq/src/include/common/relpath.h @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------------- + * + * relpath.h + * Declarations for GetRelationPath() and friends + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/relpath.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELPATH_H +#define RELPATH_H + +/* + * 'pgrminclude ignore' needed here because CppAsString2() does not throw + * an error if the symbol is not defined. + */ +#include "catalog/catversion.h" /* pgrminclude ignore */ + +/* + * RelFileNumber data type identifies the specific relation file name. + */ +typedef Oid RelFileNumber; +#define InvalidRelFileNumber ((RelFileNumber) InvalidOid) +#define RelFileNumberIsValid(relnumber) \ + ((bool) ((relnumber) != InvalidRelFileNumber)) + +/* + * Name of major-version-specific tablespace subdirectories + */ +#define TABLESPACE_VERSION_DIRECTORY "PG_" PG_MAJORVERSION "_" \ + CppAsString2(CATALOG_VERSION_NO) + +/* Characters to allow for an OID in a relation path */ +#define OIDCHARS 10 /* max chars printed by %u */ + +/* + * Stuff for fork names. + * + * The physical storage of a relation consists of one or more forks. + * The main fork is always created, but in addition to that there can be + * additional forks for storing various metadata. ForkNumber is used when + * we need to refer to a specific fork in a relation. + */ +typedef enum ForkNumber +{ + InvalidForkNumber = -1, + MAIN_FORKNUM = 0, + FSM_FORKNUM, + VISIBILITYMAP_FORKNUM, + INIT_FORKNUM + + /* + * NOTE: if you add a new fork, change MAX_FORKNUM and possibly + * FORKNAMECHARS below, and update the forkNames array in + * src/common/relpath.c + */ +} ForkNumber; + +#define MAX_FORKNUM INIT_FORKNUM + +#define FORKNAMECHARS 4 /* max chars for a fork name */ + +extern PGDLLIMPORT const char *const forkNames[]; + +extern ForkNumber forkname_to_number(const char *forkName); +extern int forkname_chars(const char *str, ForkNumber *fork); + +/* + * Stuff for computing filesystem pathnames for relations. + */ +extern char *GetDatabasePath(Oid dbOid, Oid spcOid); + +extern char *GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber, + int backendId, ForkNumber forkNumber); + +/* + * Wrapper macros for GetRelationPath. Beware of multiple + * evaluation of the RelFileLocator or RelFileLocatorBackend argument! + */ + +/* First argument is a RelFileLocator */ +#define relpathbackend(rlocator, backend, forknum) \ + GetRelationPath((rlocator).dbOid, (rlocator).spcOid, (rlocator).relNumber, \ + backend, forknum) + +/* First argument is a RelFileLocator */ +#define relpathperm(rlocator, forknum) \ + relpathbackend(rlocator, InvalidBackendId, forknum) + +/* First argument is a RelFileLocatorBackend */ +#define relpath(rlocator, forknum) \ + relpathbackend((rlocator).locator, (rlocator).backend, forknum) + +#endif /* RELPATH_H */ diff --git a/contrib/libs/libpq/src/include/common/restricted_token.h b/contrib/libs/libpq/src/include/common/restricted_token.h new file mode 100644 index 0000000000..d4077c7661 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/restricted_token.h @@ -0,0 +1,24 @@ +/* + * restricted_token.h + * helper routine to ensure restricted token on Windows + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/restricted_token.h + */ +#ifndef COMMON_RESTRICTED_TOKEN_H +#define COMMON_RESTRICTED_TOKEN_H + +/* + * On Windows make sure that we are running with a restricted token, + * On other platforms do nothing. + */ +void get_restricted_token(void); + +#ifdef WIN32 +/* Create a restricted token and execute the specified process with it. */ +HANDLE CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo); +#endif + +#endif /* COMMON_RESTRICTED_TOKEN_H */ diff --git a/contrib/libs/libpq/src/include/common/saslprep.h b/contrib/libs/libpq/src/include/common/saslprep.h new file mode 100644 index 0000000000..f622db962f --- /dev/null +++ b/contrib/libs/libpq/src/include/common/saslprep.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * saslprep.h + * SASLprep normalization, for SCRAM authentication + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2017-2023, PostgreSQL Global Development Group + * + * src/include/common/saslprep.h + * + *------------------------------------------------------------------------- + */ +#ifndef SASLPREP_H +#define SASLPREP_H + +/* + * Return codes for pg_saslprep() function. + */ +typedef enum +{ + SASLPREP_SUCCESS = 0, + SASLPREP_OOM = -1, /* out of memory (only in frontend) */ + SASLPREP_INVALID_UTF8 = -2, /* input is not a valid UTF-8 string */ + SASLPREP_PROHIBITED = -3 /* output would contain prohibited characters */ +} pg_saslprep_rc; + +extern pg_saslprep_rc pg_saslprep(const char *input, char **output); + +#endif /* SASLPREP_H */ diff --git a/contrib/libs/libpq/src/include/common/scram-common.h b/contrib/libs/libpq/src/include/common/scram-common.h new file mode 100644 index 0000000000..5ccff96ece --- /dev/null +++ b/contrib/libs/libpq/src/include/common/scram-common.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- + * + * scram-common.h + * Declarations for helper functions used for SCRAM authentication + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/scram-common.h + * + *------------------------------------------------------------------------- + */ +#ifndef SCRAM_COMMON_H +#define SCRAM_COMMON_H + +#include "common/cryptohash.h" +#include "common/sha2.h" + +/* Name of SCRAM mechanisms per IANA */ +#define SCRAM_SHA_256_NAME "SCRAM-SHA-256" +#define SCRAM_SHA_256_PLUS_NAME "SCRAM-SHA-256-PLUS" /* with channel binding */ + +/* Length of SCRAM keys (client and server) */ +#define SCRAM_SHA_256_KEY_LEN PG_SHA256_DIGEST_LENGTH + +/* + * Size of buffers used internally by SCRAM routines, that should be the + * maximum of SCRAM_SHA_*_KEY_LEN among the hash methods supported. + */ +#define SCRAM_MAX_KEY_LEN SCRAM_SHA_256_KEY_LEN + +/* + * Size of random nonce generated in the authentication exchange. This + * is in "raw" number of bytes, the actual nonces sent over the wire are + * encoded using only ASCII-printable characters. + */ +#define SCRAM_RAW_NONCE_LEN 18 + +/* + * Length of salt when generating new secrets, in bytes. (It will be stored + * and sent over the wire encoded in Base64.) 16 bytes is what the example in + * RFC 7677 uses. + */ +#define SCRAM_DEFAULT_SALT_LEN 16 + +/* + * Default number of iterations when generating secret. Should be at least + * 4096 per RFC 7677. + */ +#define SCRAM_SHA_256_DEFAULT_ITERATIONS 4096 + +extern int scram_SaltedPassword(const char *password, + pg_cryptohash_type hash_type, int key_length, + const char *salt, int saltlen, int iterations, + uint8 *result, const char **errstr); +extern int scram_H(const uint8 *input, pg_cryptohash_type hash_type, + int key_length, uint8 *result, + const char **errstr); +extern int scram_ClientKey(const uint8 *salted_password, + pg_cryptohash_type hash_type, int key_length, + uint8 *result, const char **errstr); +extern int scram_ServerKey(const uint8 *salted_password, + pg_cryptohash_type hash_type, int key_length, + uint8 *result, const char **errstr); + +extern char *scram_build_secret(pg_cryptohash_type hash_type, int key_length, + const char *salt, int saltlen, int iterations, + const char *password, const char **errstr); + +#endif /* SCRAM_COMMON_H */ diff --git a/contrib/libs/libpq/src/include/common/sha1.h b/contrib/libs/libpq/src/include/common/sha1.h new file mode 100644 index 0000000000..e6933d96bb --- /dev/null +++ b/contrib/libs/libpq/src/include/common/sha1.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * sha1.h + * Constants related to SHA1. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/sha1.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHA1_H +#define PG_SHA1_H + +/* Size of result generated by SHA1 computation */ +#define SHA1_DIGEST_LENGTH 20 +/* Block size for SHA1 */ +#define SHA1_BLOCK_SIZE 64 + +#endif /* PG_SHA1_H */ diff --git a/contrib/libs/libpq/src/include/common/sha2.h b/contrib/libs/libpq/src/include/common/sha2.h new file mode 100644 index 0000000000..9b46cd1a37 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/sha2.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * sha2.h + * Constants related to SHA224, 256, 384 AND 512. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/sha2.h + * + *------------------------------------------------------------------------- + */ + +#ifndef _PG_SHA2_H_ +#define _PG_SHA2_H_ + +/*** SHA224/256/384/512 Various Length Definitions ***********************/ +#define PG_SHA224_BLOCK_LENGTH 64 +#define PG_SHA224_DIGEST_LENGTH 28 +#define PG_SHA224_DIGEST_STRING_LENGTH (PG_SHA224_DIGEST_LENGTH * 2 + 1) +#define PG_SHA256_BLOCK_LENGTH 64 +#define PG_SHA256_DIGEST_LENGTH 32 +#define PG_SHA256_DIGEST_STRING_LENGTH (PG_SHA256_DIGEST_LENGTH * 2 + 1) +#define PG_SHA384_BLOCK_LENGTH 128 +#define PG_SHA384_DIGEST_LENGTH 48 +#define PG_SHA384_DIGEST_STRING_LENGTH (PG_SHA384_DIGEST_LENGTH * 2 + 1) +#define PG_SHA512_BLOCK_LENGTH 128 +#define PG_SHA512_DIGEST_LENGTH 64 +#define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1) + +#endif /* _PG_SHA2_H_ */ diff --git a/contrib/libs/libpq/src/include/common/shortest_dec.h b/contrib/libs/libpq/src/include/common/shortest_dec.h new file mode 100644 index 0000000000..8479b98575 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/shortest_dec.h @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output. + * + * Portions Copyright (c) 2018-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/common/shortest_dec.h + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ +#ifndef SHORTEST_DEC_H +#define SHORTEST_DEC_H + +/*---- + * The length of 25 comes from: + * + * Case 1: -9.9999999999999999e-299 = 24 bytes, plus 1 for null + * + * Case 2: -0.00099999999999999999 = 23 bytes, plus 1 for null + */ +#define DOUBLE_SHORTEST_DECIMAL_LEN 25 + +int double_to_shortest_decimal_bufn(double f, char *result); +int double_to_shortest_decimal_buf(double f, char *result); +char *double_to_shortest_decimal(double f); + +/* + * The length of 16 comes from: + * + * Case 1: -9.99999999e+29 = 15 bytes, plus 1 for null + * + * Case 2: -0.000999999999 = 15 bytes, plus 1 for null + */ +#define FLOAT_SHORTEST_DECIMAL_LEN 16 + +int float_to_shortest_decimal_bufn(float f, char *result); +int float_to_shortest_decimal_buf(float f, char *result); +char *float_to_shortest_decimal(float f); + +#endif /* SHORTEST_DEC_H */ diff --git a/contrib/libs/libpq/src/include/common/string.h b/contrib/libs/libpq/src/include/common/string.h new file mode 100644 index 0000000000..977ef327d0 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/string.h @@ -0,0 +1,44 @@ +/* + * string.h + * string handling helpers + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/string.h + */ +#ifndef COMMON_STRING_H +#define COMMON_STRING_H + +#include <signal.h> + +struct StringInfoData; /* avoid including stringinfo.h here */ + +typedef struct PromptInterruptContext +{ + /* To avoid including <setjmp.h> here, jmpbuf is declared "void *" */ + void *jmpbuf; /* existing longjmp buffer */ + volatile sig_atomic_t *enabled; /* flag that enables longjmp-on-interrupt */ + bool canceled; /* indicates whether cancellation occurred */ +} PromptInterruptContext; + +/* functions in src/common/string.c */ +extern bool pg_str_endswith(const char *str, const char *end); +extern int strtoint(const char *pg_restrict str, char **pg_restrict endptr, + int base); +extern char *pg_clean_ascii(const char *str, int alloc_flags); +extern int pg_strip_crlf(char *str); +extern bool pg_is_ascii(const char *str); + +/* functions in src/common/pg_get_line.c */ +extern char *pg_get_line(FILE *stream, PromptInterruptContext *prompt_ctx); +extern bool pg_get_line_buf(FILE *stream, struct StringInfoData *buf); +extern bool pg_get_line_append(FILE *stream, struct StringInfoData *buf, + PromptInterruptContext *prompt_ctx); + +/* functions in src/common/sprompt.c */ +extern char *simple_prompt(const char *prompt, bool echo); +extern char *simple_prompt_extended(const char *prompt, bool echo, + PromptInterruptContext *prompt_ctx); + +#endif /* COMMON_STRING_H */ diff --git a/contrib/libs/libpq/src/include/common/unicode_east_asian_fw_table.h b/contrib/libs/libpq/src/include/common/unicode_east_asian_fw_table.h new file mode 100644 index 0000000000..f77e6dfd42 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/unicode_east_asian_fw_table.h @@ -0,0 +1,125 @@ +/* generated by src/common/unicode/generate-unicode_east_asian_fw_table.pl, do not edit */ + +static const struct mbinterval east_asian_fw[] = { + {0x1100, 0x115F}, + {0x231A, 0x231B}, + {0x2329, 0x232A}, + {0x23E9, 0x23EC}, + {0x23F0, 0x23F0}, + {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, + {0x2614, 0x2615}, + {0x2648, 0x2653}, + {0x267F, 0x267F}, + {0x2693, 0x2693}, + {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, + {0x26D4, 0x26D4}, + {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, + {0x26F5, 0x26F5}, + {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2705, 0x2705}, + {0x270A, 0x270B}, + {0x2728, 0x2728}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2795, 0x2797}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, + {0x2F00, 0x2FD5}, + {0x2FF0, 0x2FFB}, + {0x3000, 0x303E}, + {0x3041, 0x3096}, + {0x3099, 0x30FF}, + {0x3105, 0x312F}, + {0x3131, 0x318E}, + {0x3190, 0x31E3}, + {0x31F0, 0x321E}, + {0x3220, 0x3247}, + {0x3250, 0x4DBF}, + {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, + {0xA960, 0xA97C}, + {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, + {0xFE10, 0xFE19}, + {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, + {0xFE68, 0xFE6B}, + {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, + {0x16FE0, 0x16FE4}, + {0x16FF0, 0x16FF1}, + {0x17000, 0x187F7}, + {0x18800, 0x18CD5}, + {0x18D00, 0x18D08}, + {0x1AFF0, 0x1AFF3}, + {0x1AFF5, 0x1AFFB}, + {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, + {0x1B132, 0x1B132}, + {0x1B150, 0x1B152}, + {0x1B155, 0x1B155}, + {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, + {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, + {0x1F260, 0x1F265}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, + {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, + {0x1F6D5, 0x1F6D7}, + {0x1F6DC, 0x1F6DF}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6FC}, + {0x1F7E0, 0x1F7EB}, + {0x1F7F0, 0x1F7F0}, + {0x1F90C, 0x1F93A}, + {0x1F93C, 0x1F945}, + {0x1F947, 0x1F9FF}, + {0x1FA70, 0x1FA7C}, + {0x1FA80, 0x1FA88}, + {0x1FA90, 0x1FABD}, + {0x1FABF, 0x1FAC5}, + {0x1FACE, 0x1FADB}, + {0x1FAE0, 0x1FAE8}, + {0x1FAF0, 0x1FAF8}, + {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, +}; diff --git a/contrib/libs/libpq/src/include/common/unicode_nonspacing_table.h b/contrib/libs/libpq/src/include/common/unicode_nonspacing_table.h new file mode 100644 index 0000000000..8d00e127fc --- /dev/null +++ b/contrib/libs/libpq/src/include/common/unicode_nonspacing_table.h @@ -0,0 +1,326 @@ +/* generated by src/common/unicode/generate-unicode_nonspacing_table.pl, do not edit */ + +static const struct mbinterval nonspacing[] = { + {0x00AD, 0x00AD}, + {0x0300, 0x036F}, + {0x0483, 0x0489}, + {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, + {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, + {0x0600, 0x0605}, + {0x0610, 0x061A}, + {0x061C, 0x061C}, + {0x064B, 0x065F}, + {0x0670, 0x0670}, + {0x06D6, 0x06DD}, + {0x06DF, 0x06E4}, + {0x06E7, 0x06E8}, + {0x06EA, 0x06ED}, + {0x070F, 0x070F}, + {0x0711, 0x0711}, + {0x0730, 0x074A}, + {0x07A6, 0x07B0}, + {0x07EB, 0x07F3}, + {0x07FD, 0x07FD}, + {0x0816, 0x0819}, + {0x081B, 0x0823}, + {0x0825, 0x0827}, + {0x0829, 0x082D}, + {0x0859, 0x085B}, + {0x0890, 0x089F}, + {0x08CA, 0x0902}, + {0x093A, 0x093A}, + {0x093C, 0x093C}, + {0x0941, 0x0948}, + {0x094D, 0x094D}, + {0x0951, 0x0957}, + {0x0962, 0x0963}, + {0x0981, 0x0981}, + {0x09BC, 0x09BC}, + {0x09C1, 0x09C4}, + {0x09CD, 0x09CD}, + {0x09E2, 0x09E3}, + {0x09FE, 0x0A02}, + {0x0A3C, 0x0A3C}, + {0x0A41, 0x0A51}, + {0x0A70, 0x0A71}, + {0x0A75, 0x0A75}, + {0x0A81, 0x0A82}, + {0x0ABC, 0x0ABC}, + {0x0AC1, 0x0AC8}, + {0x0ACD, 0x0ACD}, + {0x0AE2, 0x0AE3}, + {0x0AFA, 0x0B01}, + {0x0B3C, 0x0B3C}, + {0x0B3F, 0x0B3F}, + {0x0B41, 0x0B44}, + {0x0B4D, 0x0B56}, + {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, + {0x0BC0, 0x0BC0}, + {0x0BCD, 0x0BCD}, + {0x0C00, 0x0C00}, + {0x0C04, 0x0C04}, + {0x0C3C, 0x0C3C}, + {0x0C3E, 0x0C40}, + {0x0C46, 0x0C56}, + {0x0C62, 0x0C63}, + {0x0C81, 0x0C81}, + {0x0CBC, 0x0CBC}, + {0x0CBF, 0x0CBF}, + {0x0CC6, 0x0CC6}, + {0x0CCC, 0x0CCD}, + {0x0CE2, 0x0CE3}, + {0x0D00, 0x0D01}, + {0x0D3B, 0x0D3C}, + {0x0D41, 0x0D44}, + {0x0D4D, 0x0D4D}, + {0x0D62, 0x0D63}, + {0x0D81, 0x0D81}, + {0x0DCA, 0x0DCA}, + {0x0DD2, 0x0DD6}, + {0x0E31, 0x0E31}, + {0x0E34, 0x0E3A}, + {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, + {0x0EB4, 0x0EBC}, + {0x0EC8, 0x0ECE}, + {0x0F18, 0x0F19}, + {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, + {0x0F71, 0x0F7E}, + {0x0F80, 0x0F84}, + {0x0F86, 0x0F87}, + {0x0F8D, 0x0FBC}, + {0x0FC6, 0x0FC6}, + {0x102D, 0x1030}, + {0x1032, 0x1037}, + {0x1039, 0x103A}, + {0x103D, 0x103E}, + {0x1058, 0x1059}, + {0x105E, 0x1060}, + {0x1071, 0x1074}, + {0x1082, 0x1082}, + {0x1085, 0x1086}, + {0x108D, 0x108D}, + {0x109D, 0x109D}, + {0x135D, 0x135F}, + {0x1712, 0x1714}, + {0x1732, 0x1733}, + {0x1752, 0x1753}, + {0x1772, 0x1773}, + {0x17B4, 0x17B5}, + {0x17B7, 0x17BD}, + {0x17C6, 0x17C6}, + {0x17C9, 0x17D3}, + {0x17DD, 0x17DD}, + {0x180B, 0x180F}, + {0x1885, 0x1886}, + {0x18A9, 0x18A9}, + {0x1920, 0x1922}, + {0x1927, 0x1928}, + {0x1932, 0x1932}, + {0x1939, 0x193B}, + {0x1A17, 0x1A18}, + {0x1A1B, 0x1A1B}, + {0x1A56, 0x1A56}, + {0x1A58, 0x1A60}, + {0x1A62, 0x1A62}, + {0x1A65, 0x1A6C}, + {0x1A73, 0x1A7F}, + {0x1AB0, 0x1B03}, + {0x1B34, 0x1B34}, + {0x1B36, 0x1B3A}, + {0x1B3C, 0x1B3C}, + {0x1B42, 0x1B42}, + {0x1B6B, 0x1B73}, + {0x1B80, 0x1B81}, + {0x1BA2, 0x1BA5}, + {0x1BA8, 0x1BA9}, + {0x1BAB, 0x1BAD}, + {0x1BE6, 0x1BE6}, + {0x1BE8, 0x1BE9}, + {0x1BED, 0x1BED}, + {0x1BEF, 0x1BF1}, + {0x1C2C, 0x1C33}, + {0x1C36, 0x1C37}, + {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE0}, + {0x1CE2, 0x1CE8}, + {0x1CED, 0x1CED}, + {0x1CF4, 0x1CF4}, + {0x1CF8, 0x1CF9}, + {0x1DC0, 0x1DFF}, + {0x200B, 0x200F}, + {0x202A, 0x202E}, + {0x2060, 0x206F}, + {0x20D0, 0x20F0}, + {0x2CEF, 0x2CF1}, + {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, + {0x302A, 0x302D}, + {0x3099, 0x309A}, + {0xA66F, 0xA672}, + {0xA674, 0xA67D}, + {0xA69E, 0xA69F}, + {0xA6F0, 0xA6F1}, + {0xA802, 0xA802}, + {0xA806, 0xA806}, + {0xA80B, 0xA80B}, + {0xA825, 0xA826}, + {0xA82C, 0xA82C}, + {0xA8C4, 0xA8C5}, + {0xA8E0, 0xA8F1}, + {0xA8FF, 0xA8FF}, + {0xA926, 0xA92D}, + {0xA947, 0xA951}, + {0xA980, 0xA982}, + {0xA9B3, 0xA9B3}, + {0xA9B6, 0xA9B9}, + {0xA9BC, 0xA9BD}, + {0xA9E5, 0xA9E5}, + {0xAA29, 0xAA2E}, + {0xAA31, 0xAA32}, + {0xAA35, 0xAA36}, + {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4C}, + {0xAA7C, 0xAA7C}, + {0xAAB0, 0xAAB0}, + {0xAAB2, 0xAAB4}, + {0xAAB7, 0xAAB8}, + {0xAABE, 0xAABF}, + {0xAAC1, 0xAAC1}, + {0xAAEC, 0xAAED}, + {0xAAF6, 0xAAF6}, + {0xABE5, 0xABE5}, + {0xABE8, 0xABE8}, + {0xABED, 0xABED}, + {0xFB1E, 0xFB1E}, + {0xFE00, 0xFE0F}, + {0xFE20, 0xFE2F}, + {0xFEFF, 0xFEFF}, + {0xFFF9, 0xFFFB}, + {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, + {0x10376, 0x1037A}, + {0x10A01, 0x10A0F}, + {0x10A38, 0x10A3F}, + {0x10AE5, 0x10AE6}, + {0x10D24, 0x10D27}, + {0x10EAB, 0x10EAC}, + {0x10EFD, 0x10EFF}, + {0x10F46, 0x10F50}, + {0x10F82, 0x10F85}, + {0x11001, 0x11001}, + {0x11038, 0x11046}, + {0x11070, 0x11070}, + {0x11073, 0x11074}, + {0x1107F, 0x11081}, + {0x110B3, 0x110B6}, + {0x110B9, 0x110BA}, + {0x110BD, 0x110BD}, + {0x110C2, 0x110CD}, + {0x11100, 0x11102}, + {0x11127, 0x1112B}, + {0x1112D, 0x11134}, + {0x11173, 0x11173}, + {0x11180, 0x11181}, + {0x111B6, 0x111BE}, + {0x111C9, 0x111CC}, + {0x111CF, 0x111CF}, + {0x1122F, 0x11231}, + {0x11234, 0x11234}, + {0x11236, 0x11237}, + {0x1123E, 0x1123E}, + {0x11241, 0x11241}, + {0x112DF, 0x112DF}, + {0x112E3, 0x112EA}, + {0x11300, 0x11301}, + {0x1133B, 0x1133C}, + {0x11340, 0x11340}, + {0x11366, 0x11374}, + {0x11438, 0x1143F}, + {0x11442, 0x11444}, + {0x11446, 0x11446}, + {0x1145E, 0x1145E}, + {0x114B3, 0x114B8}, + {0x114BA, 0x114BA}, + {0x114BF, 0x114C0}, + {0x114C2, 0x114C3}, + {0x115B2, 0x115B5}, + {0x115BC, 0x115BD}, + {0x115BF, 0x115C0}, + {0x115DC, 0x115DD}, + {0x11633, 0x1163A}, + {0x1163D, 0x1163D}, + {0x1163F, 0x11640}, + {0x116AB, 0x116AB}, + {0x116AD, 0x116AD}, + {0x116B0, 0x116B5}, + {0x116B7, 0x116B7}, + {0x1171D, 0x1171F}, + {0x11722, 0x11725}, + {0x11727, 0x1172B}, + {0x1182F, 0x11837}, + {0x11839, 0x1183A}, + {0x1193B, 0x1193C}, + {0x1193E, 0x1193E}, + {0x11943, 0x11943}, + {0x119D4, 0x119DB}, + {0x119E0, 0x119E0}, + {0x11A01, 0x11A0A}, + {0x11A33, 0x11A38}, + {0x11A3B, 0x11A3E}, + {0x11A47, 0x11A47}, + {0x11A51, 0x11A56}, + {0x11A59, 0x11A5B}, + {0x11A8A, 0x11A96}, + {0x11A98, 0x11A99}, + {0x11C30, 0x11C3D}, + {0x11C3F, 0x11C3F}, + {0x11C92, 0x11CA7}, + {0x11CAA, 0x11CB0}, + {0x11CB2, 0x11CB3}, + {0x11CB5, 0x11CB6}, + {0x11D31, 0x11D45}, + {0x11D47, 0x11D47}, + {0x11D90, 0x11D91}, + {0x11D95, 0x11D95}, + {0x11D97, 0x11D97}, + {0x11EF3, 0x11EF4}, + {0x11F00, 0x11F01}, + {0x11F36, 0x11F3A}, + {0x11F40, 0x11F40}, + {0x11F42, 0x11F42}, + {0x13430, 0x13440}, + {0x13447, 0x13455}, + {0x16AF0, 0x16AF4}, + {0x16B30, 0x16B36}, + {0x16F4F, 0x16F4F}, + {0x16F8F, 0x16F92}, + {0x16FE4, 0x16FE4}, + {0x1BC9D, 0x1BC9E}, + {0x1BCA0, 0x1CF46}, + {0x1D167, 0x1D169}, + {0x1D173, 0x1D182}, + {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, + {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, + {0x1DA75, 0x1DA75}, + {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DAAF}, + {0x1E000, 0x1E02A}, + {0x1E08F, 0x1E08F}, + {0x1E130, 0x1E136}, + {0x1E2AE, 0x1E2AE}, + {0x1E2EC, 0x1E2EF}, + {0x1E4EC, 0x1E4EF}, + {0x1E8D0, 0x1E8D6}, + {0x1E944, 0x1E94A}, + {0xE0001, 0xE01EF}, +}; diff --git a/contrib/libs/libpq/src/include/common/unicode_norm.h b/contrib/libs/libpq/src/include/common/unicode_norm.h new file mode 100644 index 0000000000..c6627aeb7c --- /dev/null +++ b/contrib/libs/libpq/src/include/common/unicode_norm.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * unicode_norm.h + * Routines for normalizing Unicode strings + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2017-2023, PostgreSQL Global Development Group + * + * src/include/common/unicode_norm.h + * + *------------------------------------------------------------------------- + */ +#ifndef UNICODE_NORM_H +#define UNICODE_NORM_H + +#include "mb/pg_wchar.h" + +typedef enum +{ + UNICODE_NFC = 0, + UNICODE_NFD = 1, + UNICODE_NFKC = 2, + UNICODE_NFKD = 3, +} UnicodeNormalizationForm; + +/* see UAX #15 */ +typedef enum +{ + UNICODE_NORM_QC_NO = 0, + UNICODE_NORM_QC_YES = 1, + UNICODE_NORM_QC_MAYBE = -1, +} UnicodeNormalizationQC; + +extern pg_wchar *unicode_normalize(UnicodeNormalizationForm form, const pg_wchar *input); + +extern UnicodeNormalizationQC unicode_is_normalized_quickcheck(UnicodeNormalizationForm form, const pg_wchar *input); + +#endif /* UNICODE_NORM_H */ diff --git a/contrib/libs/libpq/src/include/common/unicode_norm_table.h b/contrib/libs/libpq/src/include/common/unicode_norm_table.h new file mode 100644 index 0000000000..36b6ca4044 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/unicode_norm_table.h @@ -0,0 +1,9114 @@ +/*------------------------------------------------------------------------- + * + * unicode_norm_table.h + * Composition table used for Unicode normalization + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/unicode_norm_table.h + * + *------------------------------------------------------------------------- + */ + +/* + * File auto-generated by src/common/unicode/generate-unicode_norm_table.pl, + * do not edit. There is deliberately not an #ifndef PG_UNICODE_NORM_TABLE_H + * here. + */ +typedef struct +{ + uint32 codepoint; /* Unicode codepoint */ + uint8 comb_class; /* combining class of character */ + uint8 dec_size_flags; /* size and flags of decomposition code list */ + uint16 dec_index; /* index into UnicodeDecomp_codepoints, or the + * decomposition itself if DECOMP_INLINE */ +} pg_unicode_decomposition; + +#define DECOMP_NO_COMPOSE 0x80 /* don't use for re-composition */ +#define DECOMP_INLINE 0x40 /* decomposition is stored inline in + * dec_index */ +#define DECOMP_COMPAT 0x20 /* compatibility mapping */ + +#define DECOMPOSITION_SIZE(x) ((x)->dec_size_flags & 0x1F) +#define DECOMPOSITION_NO_COMPOSE(x) (((x)->dec_size_flags & (DECOMP_NO_COMPOSE | DECOMP_COMPAT)) != 0) +#define DECOMPOSITION_IS_INLINE(x) (((x)->dec_size_flags & DECOMP_INLINE) != 0) +#define DECOMPOSITION_IS_COMPAT(x) (((x)->dec_size_flags & DECOMP_COMPAT) != 0) + +/* Table of Unicode codepoints and their decompositions */ +static const pg_unicode_decomposition UnicodeDecompMain[6775] = +{ + {0x00A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x00A8, 0, 2 | DECOMP_COMPAT, 0}, + {0x00AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x00AF, 0, 2 | DECOMP_COMPAT, 2}, + {0x00B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x00B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x00B4, 0, 2 | DECOMP_COMPAT, 4}, + {0x00B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x00B8, 0, 2 | DECOMP_COMPAT, 6}, + {0x00B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x00BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x00BC, 0, 3 | DECOMP_COMPAT, 8}, + {0x00BD, 0, 3 | DECOMP_COMPAT, 11}, + {0x00BE, 0, 3 | DECOMP_COMPAT, 14}, + {0x00C0, 0, 2, 17}, + {0x00C1, 0, 2, 19}, + {0x00C2, 0, 2, 21}, + {0x00C3, 0, 2, 23}, + {0x00C4, 0, 2, 25}, + {0x00C5, 0, 2, 27}, + {0x00C7, 0, 2, 29}, + {0x00C8, 0, 2, 31}, + {0x00C9, 0, 2, 33}, + {0x00CA, 0, 2, 35}, + {0x00CB, 0, 2, 37}, + {0x00CC, 0, 2, 39}, + {0x00CD, 0, 2, 41}, + {0x00CE, 0, 2, 43}, + {0x00CF, 0, 2, 45}, + {0x00D1, 0, 2, 47}, + {0x00D2, 0, 2, 49}, + {0x00D3, 0, 2, 51}, + {0x00D4, 0, 2, 53}, + {0x00D5, 0, 2, 55}, + {0x00D6, 0, 2, 57}, + {0x00D9, 0, 2, 59}, + {0x00DA, 0, 2, 61}, + {0x00DB, 0, 2, 63}, + {0x00DC, 0, 2, 65}, + {0x00DD, 0, 2, 67}, + {0x00E0, 0, 2, 69}, + {0x00E1, 0, 2, 71}, + {0x00E2, 0, 2, 73}, + {0x00E3, 0, 2, 75}, + {0x00E4, 0, 2, 77}, + {0x00E5, 0, 2, 79}, + {0x00E7, 0, 2, 81}, + {0x00E8, 0, 2, 83}, + {0x00E9, 0, 2, 85}, + {0x00EA, 0, 2, 87}, + {0x00EB, 0, 2, 89}, + {0x00EC, 0, 2, 91}, + {0x00ED, 0, 2, 93}, + {0x00EE, 0, 2, 95}, + {0x00EF, 0, 2, 97}, + {0x00F1, 0, 2, 99}, + {0x00F2, 0, 2, 101}, + {0x00F3, 0, 2, 103}, + {0x00F4, 0, 2, 105}, + {0x00F5, 0, 2, 107}, + {0x00F6, 0, 2, 109}, + {0x00F9, 0, 2, 111}, + {0x00FA, 0, 2, 113}, + {0x00FB, 0, 2, 115}, + {0x00FC, 0, 2, 117}, + {0x00FD, 0, 2, 119}, + {0x00FF, 0, 2, 121}, + {0x0100, 0, 2, 123}, + {0x0101, 0, 2, 125}, + {0x0102, 0, 2, 127}, + {0x0103, 0, 2, 129}, + {0x0104, 0, 2, 131}, + {0x0105, 0, 2, 133}, + {0x0106, 0, 2, 135}, + {0x0107, 0, 2, 137}, + {0x0108, 0, 2, 139}, + {0x0109, 0, 2, 141}, + {0x010A, 0, 2, 143}, + {0x010B, 0, 2, 145}, + {0x010C, 0, 2, 147}, + {0x010D, 0, 2, 149}, + {0x010E, 0, 2, 151}, + {0x010F, 0, 2, 153}, + {0x0112, 0, 2, 155}, + {0x0113, 0, 2, 157}, + {0x0114, 0, 2, 159}, + {0x0115, 0, 2, 161}, + {0x0116, 0, 2, 163}, + {0x0117, 0, 2, 165}, + {0x0118, 0, 2, 167}, + {0x0119, 0, 2, 169}, + {0x011A, 0, 2, 171}, + {0x011B, 0, 2, 173}, + {0x011C, 0, 2, 175}, + {0x011D, 0, 2, 177}, + {0x011E, 0, 2, 179}, + {0x011F, 0, 2, 181}, + {0x0120, 0, 2, 183}, + {0x0121, 0, 2, 185}, + {0x0122, 0, 2, 187}, + {0x0123, 0, 2, 189}, + {0x0124, 0, 2, 191}, + {0x0125, 0, 2, 193}, + {0x0128, 0, 2, 195}, + {0x0129, 0, 2, 197}, + {0x012A, 0, 2, 199}, + {0x012B, 0, 2, 201}, + {0x012C, 0, 2, 203}, + {0x012D, 0, 2, 205}, + {0x012E, 0, 2, 207}, + {0x012F, 0, 2, 209}, + {0x0130, 0, 2, 211}, + {0x0132, 0, 2 | DECOMP_COMPAT, 213}, + {0x0133, 0, 2 | DECOMP_COMPAT, 215}, + {0x0134, 0, 2, 217}, + {0x0135, 0, 2, 219}, + {0x0136, 0, 2, 221}, + {0x0137, 0, 2, 223}, + {0x0139, 0, 2, 225}, + {0x013A, 0, 2, 227}, + {0x013B, 0, 2, 229}, + {0x013C, 0, 2, 231}, + {0x013D, 0, 2, 233}, + {0x013E, 0, 2, 235}, + {0x013F, 0, 2 | DECOMP_COMPAT, 237}, + {0x0140, 0, 2 | DECOMP_COMPAT, 239}, + {0x0143, 0, 2, 241}, + {0x0144, 0, 2, 243}, + {0x0145, 0, 2, 245}, + {0x0146, 0, 2, 247}, + {0x0147, 0, 2, 249}, + {0x0148, 0, 2, 251}, + {0x0149, 0, 2 | DECOMP_COMPAT, 253}, + {0x014C, 0, 2, 255}, + {0x014D, 0, 2, 257}, + {0x014E, 0, 2, 259}, + {0x014F, 0, 2, 261}, + {0x0150, 0, 2, 263}, + {0x0151, 0, 2, 265}, + {0x0154, 0, 2, 267}, + {0x0155, 0, 2, 269}, + {0x0156, 0, 2, 271}, + {0x0157, 0, 2, 273}, + {0x0158, 0, 2, 275}, + {0x0159, 0, 2, 277}, + {0x015A, 0, 2, 279}, + {0x015B, 0, 2, 281}, + {0x015C, 0, 2, 283}, + {0x015D, 0, 2, 285}, + {0x015E, 0, 2, 287}, + {0x015F, 0, 2, 289}, + {0x0160, 0, 2, 291}, + {0x0161, 0, 2, 293}, + {0x0162, 0, 2, 295}, + {0x0163, 0, 2, 297}, + {0x0164, 0, 2, 299}, + {0x0165, 0, 2, 301}, + {0x0168, 0, 2, 303}, + {0x0169, 0, 2, 305}, + {0x016A, 0, 2, 307}, + {0x016B, 0, 2, 309}, + {0x016C, 0, 2, 311}, + {0x016D, 0, 2, 313}, + {0x016E, 0, 2, 315}, + {0x016F, 0, 2, 317}, + {0x0170, 0, 2, 319}, + {0x0171, 0, 2, 321}, + {0x0172, 0, 2, 323}, + {0x0173, 0, 2, 325}, + {0x0174, 0, 2, 327}, + {0x0175, 0, 2, 329}, + {0x0176, 0, 2, 331}, + {0x0177, 0, 2, 333}, + {0x0178, 0, 2, 335}, + {0x0179, 0, 2, 337}, + {0x017A, 0, 2, 339}, + {0x017B, 0, 2, 341}, + {0x017C, 0, 2, 343}, + {0x017D, 0, 2, 345}, + {0x017E, 0, 2, 347}, + {0x017F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x01A0, 0, 2, 349}, + {0x01A1, 0, 2, 351}, + {0x01AF, 0, 2, 353}, + {0x01B0, 0, 2, 355}, + {0x01C4, 0, 2 | DECOMP_COMPAT, 357}, + {0x01C5, 0, 2 | DECOMP_COMPAT, 359}, + {0x01C6, 0, 2 | DECOMP_COMPAT, 361}, + {0x01C7, 0, 2 | DECOMP_COMPAT, 363}, + {0x01C8, 0, 2 | DECOMP_COMPAT, 365}, + {0x01C9, 0, 2 | DECOMP_COMPAT, 367}, + {0x01CA, 0, 2 | DECOMP_COMPAT, 369}, + {0x01CB, 0, 2 | DECOMP_COMPAT, 371}, + {0x01CC, 0, 2 | DECOMP_COMPAT, 373}, + {0x01CD, 0, 2, 375}, + {0x01CE, 0, 2, 377}, + {0x01CF, 0, 2, 379}, + {0x01D0, 0, 2, 381}, + {0x01D1, 0, 2, 383}, + {0x01D2, 0, 2, 385}, + {0x01D3, 0, 2, 387}, + {0x01D4, 0, 2, 389}, + {0x01D5, 0, 2, 391}, + {0x01D6, 0, 2, 393}, + {0x01D7, 0, 2, 395}, + {0x01D8, 0, 2, 397}, + {0x01D9, 0, 2, 399}, + {0x01DA, 0, 2, 401}, + {0x01DB, 0, 2, 403}, + {0x01DC, 0, 2, 405}, + {0x01DE, 0, 2, 407}, + {0x01DF, 0, 2, 409}, + {0x01E0, 0, 2, 411}, + {0x01E1, 0, 2, 413}, + {0x01E2, 0, 2, 415}, + {0x01E3, 0, 2, 417}, + {0x01E6, 0, 2, 419}, + {0x01E7, 0, 2, 421}, + {0x01E8, 0, 2, 423}, + {0x01E9, 0, 2, 425}, + {0x01EA, 0, 2, 427}, + {0x01EB, 0, 2, 429}, + {0x01EC, 0, 2, 431}, + {0x01ED, 0, 2, 433}, + {0x01EE, 0, 2, 435}, + {0x01EF, 0, 2, 437}, + {0x01F0, 0, 2, 439}, + {0x01F1, 0, 2 | DECOMP_COMPAT, 441}, + {0x01F2, 0, 2 | DECOMP_COMPAT, 443}, + {0x01F3, 0, 2 | DECOMP_COMPAT, 445}, + {0x01F4, 0, 2, 447}, + {0x01F5, 0, 2, 449}, + {0x01F8, 0, 2, 451}, + {0x01F9, 0, 2, 453}, + {0x01FA, 0, 2, 455}, + {0x01FB, 0, 2, 457}, + {0x01FC, 0, 2, 459}, + {0x01FD, 0, 2, 461}, + {0x01FE, 0, 2, 463}, + {0x01FF, 0, 2, 465}, + {0x0200, 0, 2, 467}, + {0x0201, 0, 2, 469}, + {0x0202, 0, 2, 471}, + {0x0203, 0, 2, 473}, + {0x0204, 0, 2, 475}, + {0x0205, 0, 2, 477}, + {0x0206, 0, 2, 479}, + {0x0207, 0, 2, 481}, + {0x0208, 0, 2, 483}, + {0x0209, 0, 2, 485}, + {0x020A, 0, 2, 487}, + {0x020B, 0, 2, 489}, + {0x020C, 0, 2, 491}, + {0x020D, 0, 2, 493}, + {0x020E, 0, 2, 495}, + {0x020F, 0, 2, 497}, + {0x0210, 0, 2, 499}, + {0x0211, 0, 2, 501}, + {0x0212, 0, 2, 503}, + {0x0213, 0, 2, 505}, + {0x0214, 0, 2, 507}, + {0x0215, 0, 2, 509}, + {0x0216, 0, 2, 511}, + {0x0217, 0, 2, 513}, + {0x0218, 0, 2, 515}, + {0x0219, 0, 2, 517}, + {0x021A, 0, 2, 519}, + {0x021B, 0, 2, 521}, + {0x021E, 0, 2, 523}, + {0x021F, 0, 2, 525}, + {0x0226, 0, 2, 527}, + {0x0227, 0, 2, 529}, + {0x0228, 0, 2, 531}, + {0x0229, 0, 2, 533}, + {0x022A, 0, 2, 535}, + {0x022B, 0, 2, 537}, + {0x022C, 0, 2, 539}, + {0x022D, 0, 2, 541}, + {0x022E, 0, 2, 543}, + {0x022F, 0, 2, 545}, + {0x0230, 0, 2, 547}, + {0x0231, 0, 2, 549}, + {0x0232, 0, 2, 551}, + {0x0233, 0, 2, 553}, + {0x02B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x02B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0266}, + {0x02B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x02B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x02B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0279}, + {0x02B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027B}, + {0x02B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0281}, + {0x02B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x02B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x02D8, 0, 2 | DECOMP_COMPAT, 555}, + {0x02D9, 0, 2 | DECOMP_COMPAT, 557}, + {0x02DA, 0, 2 | DECOMP_COMPAT, 559}, + {0x02DB, 0, 2 | DECOMP_COMPAT, 561}, + {0x02DC, 0, 2 | DECOMP_COMPAT, 563}, + {0x02DD, 0, 2 | DECOMP_COMPAT, 565}, + {0x02E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0263}, + {0x02E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x02E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x02E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x02E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0295}, + {0x0300, 230, 0, 0}, + {0x0301, 230, 0, 0}, + {0x0302, 230, 0, 0}, + {0x0303, 230, 0, 0}, + {0x0304, 230, 0, 0}, + {0x0305, 230, 0, 0}, + {0x0306, 230, 0, 0}, + {0x0307, 230, 0, 0}, + {0x0308, 230, 0, 0}, + {0x0309, 230, 0, 0}, + {0x030A, 230, 0, 0}, + {0x030B, 230, 0, 0}, + {0x030C, 230, 0, 0}, + {0x030D, 230, 0, 0}, + {0x030E, 230, 0, 0}, + {0x030F, 230, 0, 0}, + {0x0310, 230, 0, 0}, + {0x0311, 230, 0, 0}, + {0x0312, 230, 0, 0}, + {0x0313, 230, 0, 0}, + {0x0314, 230, 0, 0}, + {0x0315, 232, 0, 0}, + {0x0316, 220, 0, 0}, + {0x0317, 220, 0, 0}, + {0x0318, 220, 0, 0}, + {0x0319, 220, 0, 0}, + {0x031A, 232, 0, 0}, + {0x031B, 216, 0, 0}, + {0x031C, 220, 0, 0}, + {0x031D, 220, 0, 0}, + {0x031E, 220, 0, 0}, + {0x031F, 220, 0, 0}, + {0x0320, 220, 0, 0}, + {0x0321, 202, 0, 0}, + {0x0322, 202, 0, 0}, + {0x0323, 220, 0, 0}, + {0x0324, 220, 0, 0}, + {0x0325, 220, 0, 0}, + {0x0326, 220, 0, 0}, + {0x0327, 202, 0, 0}, + {0x0328, 202, 0, 0}, + {0x0329, 220, 0, 0}, + {0x032A, 220, 0, 0}, + {0x032B, 220, 0, 0}, + {0x032C, 220, 0, 0}, + {0x032D, 220, 0, 0}, + {0x032E, 220, 0, 0}, + {0x032F, 220, 0, 0}, + {0x0330, 220, 0, 0}, + {0x0331, 220, 0, 0}, + {0x0332, 220, 0, 0}, + {0x0333, 220, 0, 0}, + {0x0334, 1, 0, 0}, + {0x0335, 1, 0, 0}, + {0x0336, 1, 0, 0}, + {0x0337, 1, 0, 0}, + {0x0338, 1, 0, 0}, + {0x0339, 220, 0, 0}, + {0x033A, 220, 0, 0}, + {0x033B, 220, 0, 0}, + {0x033C, 220, 0, 0}, + {0x033D, 230, 0, 0}, + {0x033E, 230, 0, 0}, + {0x033F, 230, 0, 0}, + {0x0340, 230, 1 | DECOMP_INLINE, 0x0300}, + {0x0341, 230, 1 | DECOMP_INLINE, 0x0301}, + {0x0342, 230, 0, 0}, + {0x0343, 230, 1 | DECOMP_INLINE, 0x0313}, + {0x0344, 230, 2 | DECOMP_NO_COMPOSE, 567}, /* non-starter decomposition */ + {0x0345, 240, 0, 0}, + {0x0346, 230, 0, 0}, + {0x0347, 220, 0, 0}, + {0x0348, 220, 0, 0}, + {0x0349, 220, 0, 0}, + {0x034A, 230, 0, 0}, + {0x034B, 230, 0, 0}, + {0x034C, 230, 0, 0}, + {0x034D, 220, 0, 0}, + {0x034E, 220, 0, 0}, + {0x0350, 230, 0, 0}, + {0x0351, 230, 0, 0}, + {0x0352, 230, 0, 0}, + {0x0353, 220, 0, 0}, + {0x0354, 220, 0, 0}, + {0x0355, 220, 0, 0}, + {0x0356, 220, 0, 0}, + {0x0357, 230, 0, 0}, + {0x0358, 232, 0, 0}, + {0x0359, 220, 0, 0}, + {0x035A, 220, 0, 0}, + {0x035B, 230, 0, 0}, + {0x035C, 233, 0, 0}, + {0x035D, 234, 0, 0}, + {0x035E, 234, 0, 0}, + {0x035F, 233, 0, 0}, + {0x0360, 234, 0, 0}, + {0x0361, 234, 0, 0}, + {0x0362, 233, 0, 0}, + {0x0363, 230, 0, 0}, + {0x0364, 230, 0, 0}, + {0x0365, 230, 0, 0}, + {0x0366, 230, 0, 0}, + {0x0367, 230, 0, 0}, + {0x0368, 230, 0, 0}, + {0x0369, 230, 0, 0}, + {0x036A, 230, 0, 0}, + {0x036B, 230, 0, 0}, + {0x036C, 230, 0, 0}, + {0x036D, 230, 0, 0}, + {0x036E, 230, 0, 0}, + {0x036F, 230, 0, 0}, + {0x0374, 0, 1 | DECOMP_INLINE, 0x02B9}, + {0x037A, 0, 2 | DECOMP_COMPAT, 569}, + {0x037E, 0, 1 | DECOMP_INLINE, 0x003B}, + {0x0384, 0, 2 | DECOMP_COMPAT, 571}, + {0x0385, 0, 2, 573}, + {0x0386, 0, 2, 575}, + {0x0387, 0, 1 | DECOMP_INLINE, 0x00B7}, + {0x0388, 0, 2, 577}, + {0x0389, 0, 2, 579}, + {0x038A, 0, 2, 581}, + {0x038C, 0, 2, 583}, + {0x038E, 0, 2, 585}, + {0x038F, 0, 2, 587}, + {0x0390, 0, 2, 589}, + {0x03AA, 0, 2, 591}, + {0x03AB, 0, 2, 593}, + {0x03AC, 0, 2, 595}, + {0x03AD, 0, 2, 597}, + {0x03AE, 0, 2, 599}, + {0x03AF, 0, 2, 601}, + {0x03B0, 0, 2, 603}, + {0x03CA, 0, 2, 605}, + {0x03CB, 0, 2, 607}, + {0x03CC, 0, 2, 609}, + {0x03CD, 0, 2, 611}, + {0x03CE, 0, 2, 613}, + {0x03D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x03D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x03D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x03D3, 0, 2, 615}, + {0x03D4, 0, 2, 617}, + {0x03D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x03D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x03F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x03F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x03F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x03F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x03F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x03F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x0400, 0, 2, 619}, + {0x0401, 0, 2, 621}, + {0x0403, 0, 2, 623}, + {0x0407, 0, 2, 625}, + {0x040C, 0, 2, 627}, + {0x040D, 0, 2, 629}, + {0x040E, 0, 2, 631}, + {0x0419, 0, 2, 633}, + {0x0439, 0, 2, 635}, + {0x0450, 0, 2, 637}, + {0x0451, 0, 2, 639}, + {0x0453, 0, 2, 641}, + {0x0457, 0, 2, 643}, + {0x045C, 0, 2, 645}, + {0x045D, 0, 2, 647}, + {0x045E, 0, 2, 649}, + {0x0476, 0, 2, 651}, + {0x0477, 0, 2, 653}, + {0x0483, 230, 0, 0}, + {0x0484, 230, 0, 0}, + {0x0485, 230, 0, 0}, + {0x0486, 230, 0, 0}, + {0x0487, 230, 0, 0}, + {0x04C1, 0, 2, 655}, + {0x04C2, 0, 2, 657}, + {0x04D0, 0, 2, 659}, + {0x04D1, 0, 2, 661}, + {0x04D2, 0, 2, 663}, + {0x04D3, 0, 2, 665}, + {0x04D6, 0, 2, 667}, + {0x04D7, 0, 2, 669}, + {0x04DA, 0, 2, 671}, + {0x04DB, 0, 2, 673}, + {0x04DC, 0, 2, 675}, + {0x04DD, 0, 2, 677}, + {0x04DE, 0, 2, 679}, + {0x04DF, 0, 2, 681}, + {0x04E2, 0, 2, 683}, + {0x04E3, 0, 2, 685}, + {0x04E4, 0, 2, 687}, + {0x04E5, 0, 2, 689}, + {0x04E6, 0, 2, 691}, + {0x04E7, 0, 2, 693}, + {0x04EA, 0, 2, 695}, + {0x04EB, 0, 2, 697}, + {0x04EC, 0, 2, 699}, + {0x04ED, 0, 2, 701}, + {0x04EE, 0, 2, 703}, + {0x04EF, 0, 2, 705}, + {0x04F0, 0, 2, 707}, + {0x04F1, 0, 2, 709}, + {0x04F2, 0, 2, 711}, + {0x04F3, 0, 2, 713}, + {0x04F4, 0, 2, 715}, + {0x04F5, 0, 2, 717}, + {0x04F8, 0, 2, 719}, + {0x04F9, 0, 2, 721}, + {0x0587, 0, 2 | DECOMP_COMPAT, 723}, + {0x0591, 220, 0, 0}, + {0x0592, 230, 0, 0}, + {0x0593, 230, 0, 0}, + {0x0594, 230, 0, 0}, + {0x0595, 230, 0, 0}, + {0x0596, 220, 0, 0}, + {0x0597, 230, 0, 0}, + {0x0598, 230, 0, 0}, + {0x0599, 230, 0, 0}, + {0x059A, 222, 0, 0}, + {0x059B, 220, 0, 0}, + {0x059C, 230, 0, 0}, + {0x059D, 230, 0, 0}, + {0x059E, 230, 0, 0}, + {0x059F, 230, 0, 0}, + {0x05A0, 230, 0, 0}, + {0x05A1, 230, 0, 0}, + {0x05A2, 220, 0, 0}, + {0x05A3, 220, 0, 0}, + {0x05A4, 220, 0, 0}, + {0x05A5, 220, 0, 0}, + {0x05A6, 220, 0, 0}, + {0x05A7, 220, 0, 0}, + {0x05A8, 230, 0, 0}, + {0x05A9, 230, 0, 0}, + {0x05AA, 220, 0, 0}, + {0x05AB, 230, 0, 0}, + {0x05AC, 230, 0, 0}, + {0x05AD, 222, 0, 0}, + {0x05AE, 228, 0, 0}, + {0x05AF, 230, 0, 0}, + {0x05B0, 10, 0, 0}, + {0x05B1, 11, 0, 0}, + {0x05B2, 12, 0, 0}, + {0x05B3, 13, 0, 0}, + {0x05B4, 14, 0, 0}, + {0x05B5, 15, 0, 0}, + {0x05B6, 16, 0, 0}, + {0x05B7, 17, 0, 0}, + {0x05B8, 18, 0, 0}, + {0x05B9, 19, 0, 0}, + {0x05BA, 19, 0, 0}, + {0x05BB, 20, 0, 0}, + {0x05BC, 21, 0, 0}, + {0x05BD, 22, 0, 0}, + {0x05BF, 23, 0, 0}, + {0x05C1, 24, 0, 0}, + {0x05C2, 25, 0, 0}, + {0x05C4, 230, 0, 0}, + {0x05C5, 220, 0, 0}, + {0x05C7, 18, 0, 0}, + {0x0610, 230, 0, 0}, + {0x0611, 230, 0, 0}, + {0x0612, 230, 0, 0}, + {0x0613, 230, 0, 0}, + {0x0614, 230, 0, 0}, + {0x0615, 230, 0, 0}, + {0x0616, 230, 0, 0}, + {0x0617, 230, 0, 0}, + {0x0618, 30, 0, 0}, + {0x0619, 31, 0, 0}, + {0x061A, 32, 0, 0}, + {0x0622, 0, 2, 725}, + {0x0623, 0, 2, 727}, + {0x0624, 0, 2, 729}, + {0x0625, 0, 2, 731}, + {0x0626, 0, 2, 733}, + {0x064B, 27, 0, 0}, + {0x064C, 28, 0, 0}, + {0x064D, 29, 0, 0}, + {0x064E, 30, 0, 0}, + {0x064F, 31, 0, 0}, + {0x0650, 32, 0, 0}, + {0x0651, 33, 0, 0}, + {0x0652, 34, 0, 0}, + {0x0653, 230, 0, 0}, + {0x0654, 230, 0, 0}, + {0x0655, 220, 0, 0}, + {0x0656, 220, 0, 0}, + {0x0657, 230, 0, 0}, + {0x0658, 230, 0, 0}, + {0x0659, 230, 0, 0}, + {0x065A, 230, 0, 0}, + {0x065B, 230, 0, 0}, + {0x065C, 220, 0, 0}, + {0x065D, 230, 0, 0}, + {0x065E, 230, 0, 0}, + {0x065F, 220, 0, 0}, + {0x0670, 35, 0, 0}, + {0x0675, 0, 2 | DECOMP_COMPAT, 735}, + {0x0676, 0, 2 | DECOMP_COMPAT, 737}, + {0x0677, 0, 2 | DECOMP_COMPAT, 739}, + {0x0678, 0, 2 | DECOMP_COMPAT, 741}, + {0x06C0, 0, 2, 743}, + {0x06C2, 0, 2, 745}, + {0x06D3, 0, 2, 747}, + {0x06D6, 230, 0, 0}, + {0x06D7, 230, 0, 0}, + {0x06D8, 230, 0, 0}, + {0x06D9, 230, 0, 0}, + {0x06DA, 230, 0, 0}, + {0x06DB, 230, 0, 0}, + {0x06DC, 230, 0, 0}, + {0x06DF, 230, 0, 0}, + {0x06E0, 230, 0, 0}, + {0x06E1, 230, 0, 0}, + {0x06E2, 230, 0, 0}, + {0x06E3, 220, 0, 0}, + {0x06E4, 230, 0, 0}, + {0x06E7, 230, 0, 0}, + {0x06E8, 230, 0, 0}, + {0x06EA, 220, 0, 0}, + {0x06EB, 230, 0, 0}, + {0x06EC, 230, 0, 0}, + {0x06ED, 220, 0, 0}, + {0x0711, 36, 0, 0}, + {0x0730, 230, 0, 0}, + {0x0731, 220, 0, 0}, + {0x0732, 230, 0, 0}, + {0x0733, 230, 0, 0}, + {0x0734, 220, 0, 0}, + {0x0735, 230, 0, 0}, + {0x0736, 230, 0, 0}, + {0x0737, 220, 0, 0}, + {0x0738, 220, 0, 0}, + {0x0739, 220, 0, 0}, + {0x073A, 230, 0, 0}, + {0x073B, 220, 0, 0}, + {0x073C, 220, 0, 0}, + {0x073D, 230, 0, 0}, + {0x073E, 220, 0, 0}, + {0x073F, 230, 0, 0}, + {0x0740, 230, 0, 0}, + {0x0741, 230, 0, 0}, + {0x0742, 220, 0, 0}, + {0x0743, 230, 0, 0}, + {0x0744, 220, 0, 0}, + {0x0745, 230, 0, 0}, + {0x0746, 220, 0, 0}, + {0x0747, 230, 0, 0}, + {0x0748, 220, 0, 0}, + {0x0749, 230, 0, 0}, + {0x074A, 230, 0, 0}, + {0x07EB, 230, 0, 0}, + {0x07EC, 230, 0, 0}, + {0x07ED, 230, 0, 0}, + {0x07EE, 230, 0, 0}, + {0x07EF, 230, 0, 0}, + {0x07F0, 230, 0, 0}, + {0x07F1, 230, 0, 0}, + {0x07F2, 220, 0, 0}, + {0x07F3, 230, 0, 0}, + {0x07FD, 220, 0, 0}, + {0x0816, 230, 0, 0}, + {0x0817, 230, 0, 0}, + {0x0818, 230, 0, 0}, + {0x0819, 230, 0, 0}, + {0x081B, 230, 0, 0}, + {0x081C, 230, 0, 0}, + {0x081D, 230, 0, 0}, + {0x081E, 230, 0, 0}, + {0x081F, 230, 0, 0}, + {0x0820, 230, 0, 0}, + {0x0821, 230, 0, 0}, + {0x0822, 230, 0, 0}, + {0x0823, 230, 0, 0}, + {0x0825, 230, 0, 0}, + {0x0826, 230, 0, 0}, + {0x0827, 230, 0, 0}, + {0x0829, 230, 0, 0}, + {0x082A, 230, 0, 0}, + {0x082B, 230, 0, 0}, + {0x082C, 230, 0, 0}, + {0x082D, 230, 0, 0}, + {0x0859, 220, 0, 0}, + {0x085A, 220, 0, 0}, + {0x085B, 220, 0, 0}, + {0x0898, 230, 0, 0}, + {0x0899, 220, 0, 0}, + {0x089A, 220, 0, 0}, + {0x089B, 220, 0, 0}, + {0x089C, 230, 0, 0}, + {0x089D, 230, 0, 0}, + {0x089E, 230, 0, 0}, + {0x089F, 230, 0, 0}, + {0x08CA, 230, 0, 0}, + {0x08CB, 230, 0, 0}, + {0x08CC, 230, 0, 0}, + {0x08CD, 230, 0, 0}, + {0x08CE, 230, 0, 0}, + {0x08CF, 220, 0, 0}, + {0x08D0, 220, 0, 0}, + {0x08D1, 220, 0, 0}, + {0x08D2, 220, 0, 0}, + {0x08D3, 220, 0, 0}, + {0x08D4, 230, 0, 0}, + {0x08D5, 230, 0, 0}, + {0x08D6, 230, 0, 0}, + {0x08D7, 230, 0, 0}, + {0x08D8, 230, 0, 0}, + {0x08D9, 230, 0, 0}, + {0x08DA, 230, 0, 0}, + {0x08DB, 230, 0, 0}, + {0x08DC, 230, 0, 0}, + {0x08DD, 230, 0, 0}, + {0x08DE, 230, 0, 0}, + {0x08DF, 230, 0, 0}, + {0x08E0, 230, 0, 0}, + {0x08E1, 230, 0, 0}, + {0x08E3, 220, 0, 0}, + {0x08E4, 230, 0, 0}, + {0x08E5, 230, 0, 0}, + {0x08E6, 220, 0, 0}, + {0x08E7, 230, 0, 0}, + {0x08E8, 230, 0, 0}, + {0x08E9, 220, 0, 0}, + {0x08EA, 230, 0, 0}, + {0x08EB, 230, 0, 0}, + {0x08EC, 230, 0, 0}, + {0x08ED, 220, 0, 0}, + {0x08EE, 220, 0, 0}, + {0x08EF, 220, 0, 0}, + {0x08F0, 27, 0, 0}, + {0x08F1, 28, 0, 0}, + {0x08F2, 29, 0, 0}, + {0x08F3, 230, 0, 0}, + {0x08F4, 230, 0, 0}, + {0x08F5, 230, 0, 0}, + {0x08F6, 220, 0, 0}, + {0x08F7, 230, 0, 0}, + {0x08F8, 230, 0, 0}, + {0x08F9, 220, 0, 0}, + {0x08FA, 220, 0, 0}, + {0x08FB, 230, 0, 0}, + {0x08FC, 230, 0, 0}, + {0x08FD, 230, 0, 0}, + {0x08FE, 230, 0, 0}, + {0x08FF, 230, 0, 0}, + {0x0929, 0, 2, 749}, + {0x0931, 0, 2, 751}, + {0x0934, 0, 2, 753}, + {0x093C, 7, 0, 0}, + {0x094D, 9, 0, 0}, + {0x0951, 230, 0, 0}, + {0x0952, 220, 0, 0}, + {0x0953, 230, 0, 0}, + {0x0954, 230, 0, 0}, + {0x0958, 0, 2 | DECOMP_NO_COMPOSE, 755}, /* in exclusion list */ + {0x0959, 0, 2 | DECOMP_NO_COMPOSE, 757}, /* in exclusion list */ + {0x095A, 0, 2 | DECOMP_NO_COMPOSE, 759}, /* in exclusion list */ + {0x095B, 0, 2 | DECOMP_NO_COMPOSE, 761}, /* in exclusion list */ + {0x095C, 0, 2 | DECOMP_NO_COMPOSE, 763}, /* in exclusion list */ + {0x095D, 0, 2 | DECOMP_NO_COMPOSE, 765}, /* in exclusion list */ + {0x095E, 0, 2 | DECOMP_NO_COMPOSE, 767}, /* in exclusion list */ + {0x095F, 0, 2 | DECOMP_NO_COMPOSE, 769}, /* in exclusion list */ + {0x09BC, 7, 0, 0}, + {0x09CB, 0, 2, 771}, + {0x09CC, 0, 2, 773}, + {0x09CD, 9, 0, 0}, + {0x09DC, 0, 2 | DECOMP_NO_COMPOSE, 775}, /* in exclusion list */ + {0x09DD, 0, 2 | DECOMP_NO_COMPOSE, 777}, /* in exclusion list */ + {0x09DF, 0, 2 | DECOMP_NO_COMPOSE, 779}, /* in exclusion list */ + {0x09FE, 230, 0, 0}, + {0x0A33, 0, 2 | DECOMP_NO_COMPOSE, 781}, /* in exclusion list */ + {0x0A36, 0, 2 | DECOMP_NO_COMPOSE, 783}, /* in exclusion list */ + {0x0A3C, 7, 0, 0}, + {0x0A4D, 9, 0, 0}, + {0x0A59, 0, 2 | DECOMP_NO_COMPOSE, 785}, /* in exclusion list */ + {0x0A5A, 0, 2 | DECOMP_NO_COMPOSE, 787}, /* in exclusion list */ + {0x0A5B, 0, 2 | DECOMP_NO_COMPOSE, 789}, /* in exclusion list */ + {0x0A5E, 0, 2 | DECOMP_NO_COMPOSE, 791}, /* in exclusion list */ + {0x0ABC, 7, 0, 0}, + {0x0ACD, 9, 0, 0}, + {0x0B3C, 7, 0, 0}, + {0x0B48, 0, 2, 793}, + {0x0B4B, 0, 2, 795}, + {0x0B4C, 0, 2, 797}, + {0x0B4D, 9, 0, 0}, + {0x0B5C, 0, 2 | DECOMP_NO_COMPOSE, 799}, /* in exclusion list */ + {0x0B5D, 0, 2 | DECOMP_NO_COMPOSE, 801}, /* in exclusion list */ + {0x0B94, 0, 2, 803}, + {0x0BCA, 0, 2, 805}, + {0x0BCB, 0, 2, 807}, + {0x0BCC, 0, 2, 809}, + {0x0BCD, 9, 0, 0}, + {0x0C3C, 7, 0, 0}, + {0x0C48, 0, 2, 811}, + {0x0C4D, 9, 0, 0}, + {0x0C55, 84, 0, 0}, + {0x0C56, 91, 0, 0}, + {0x0CBC, 7, 0, 0}, + {0x0CC0, 0, 2, 813}, + {0x0CC7, 0, 2, 815}, + {0x0CC8, 0, 2, 817}, + {0x0CCA, 0, 2, 819}, + {0x0CCB, 0, 2, 821}, + {0x0CCD, 9, 0, 0}, + {0x0D3B, 9, 0, 0}, + {0x0D3C, 9, 0, 0}, + {0x0D4A, 0, 2, 823}, + {0x0D4B, 0, 2, 825}, + {0x0D4C, 0, 2, 827}, + {0x0D4D, 9, 0, 0}, + {0x0DCA, 9, 0, 0}, + {0x0DDA, 0, 2, 829}, + {0x0DDC, 0, 2, 831}, + {0x0DDD, 0, 2, 833}, + {0x0DDE, 0, 2, 835}, + {0x0E33, 0, 2 | DECOMP_COMPAT, 837}, + {0x0E38, 103, 0, 0}, + {0x0E39, 103, 0, 0}, + {0x0E3A, 9, 0, 0}, + {0x0E48, 107, 0, 0}, + {0x0E49, 107, 0, 0}, + {0x0E4A, 107, 0, 0}, + {0x0E4B, 107, 0, 0}, + {0x0EB3, 0, 2 | DECOMP_COMPAT, 839}, + {0x0EB8, 118, 0, 0}, + {0x0EB9, 118, 0, 0}, + {0x0EBA, 9, 0, 0}, + {0x0EC8, 122, 0, 0}, + {0x0EC9, 122, 0, 0}, + {0x0ECA, 122, 0, 0}, + {0x0ECB, 122, 0, 0}, + {0x0EDC, 0, 2 | DECOMP_COMPAT, 841}, + {0x0EDD, 0, 2 | DECOMP_COMPAT, 843}, + {0x0F0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0F0B}, + {0x0F18, 220, 0, 0}, + {0x0F19, 220, 0, 0}, + {0x0F35, 220, 0, 0}, + {0x0F37, 220, 0, 0}, + {0x0F39, 216, 0, 0}, + {0x0F43, 0, 2 | DECOMP_NO_COMPOSE, 845}, /* in exclusion list */ + {0x0F4D, 0, 2 | DECOMP_NO_COMPOSE, 847}, /* in exclusion list */ + {0x0F52, 0, 2 | DECOMP_NO_COMPOSE, 849}, /* in exclusion list */ + {0x0F57, 0, 2 | DECOMP_NO_COMPOSE, 851}, /* in exclusion list */ + {0x0F5C, 0, 2 | DECOMP_NO_COMPOSE, 853}, /* in exclusion list */ + {0x0F69, 0, 2 | DECOMP_NO_COMPOSE, 855}, /* in exclusion list */ + {0x0F71, 129, 0, 0}, + {0x0F72, 130, 0, 0}, + {0x0F73, 0, 2 | DECOMP_NO_COMPOSE, 857}, /* non-starter decomposition */ + {0x0F74, 132, 0, 0}, + {0x0F75, 0, 2 | DECOMP_NO_COMPOSE, 859}, /* non-starter decomposition */ + {0x0F76, 0, 2 | DECOMP_NO_COMPOSE, 861}, /* in exclusion list */ + {0x0F77, 0, 2 | DECOMP_COMPAT, 863}, + {0x0F78, 0, 2 | DECOMP_NO_COMPOSE, 865}, /* in exclusion list */ + {0x0F79, 0, 2 | DECOMP_COMPAT, 867}, + {0x0F7A, 130, 0, 0}, + {0x0F7B, 130, 0, 0}, + {0x0F7C, 130, 0, 0}, + {0x0F7D, 130, 0, 0}, + {0x0F80, 130, 0, 0}, + {0x0F81, 0, 2 | DECOMP_NO_COMPOSE, 869}, /* non-starter decomposition */ + {0x0F82, 230, 0, 0}, + {0x0F83, 230, 0, 0}, + {0x0F84, 9, 0, 0}, + {0x0F86, 230, 0, 0}, + {0x0F87, 230, 0, 0}, + {0x0F93, 0, 2 | DECOMP_NO_COMPOSE, 871}, /* in exclusion list */ + {0x0F9D, 0, 2 | DECOMP_NO_COMPOSE, 873}, /* in exclusion list */ + {0x0FA2, 0, 2 | DECOMP_NO_COMPOSE, 875}, /* in exclusion list */ + {0x0FA7, 0, 2 | DECOMP_NO_COMPOSE, 877}, /* in exclusion list */ + {0x0FAC, 0, 2 | DECOMP_NO_COMPOSE, 879}, /* in exclusion list */ + {0x0FB9, 0, 2 | DECOMP_NO_COMPOSE, 881}, /* in exclusion list */ + {0x0FC6, 220, 0, 0}, + {0x1026, 0, 2, 883}, + {0x1037, 7, 0, 0}, + {0x1039, 9, 0, 0}, + {0x103A, 9, 0, 0}, + {0x108D, 220, 0, 0}, + {0x10FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x10DC}, + {0x135D, 230, 0, 0}, + {0x135E, 230, 0, 0}, + {0x135F, 230, 0, 0}, + {0x1714, 9, 0, 0}, + {0x1715, 9, 0, 0}, + {0x1734, 9, 0, 0}, + {0x17D2, 9, 0, 0}, + {0x17DD, 230, 0, 0}, + {0x18A9, 228, 0, 0}, + {0x1939, 222, 0, 0}, + {0x193A, 230, 0, 0}, + {0x193B, 220, 0, 0}, + {0x1A17, 230, 0, 0}, + {0x1A18, 220, 0, 0}, + {0x1A60, 9, 0, 0}, + {0x1A75, 230, 0, 0}, + {0x1A76, 230, 0, 0}, + {0x1A77, 230, 0, 0}, + {0x1A78, 230, 0, 0}, + {0x1A79, 230, 0, 0}, + {0x1A7A, 230, 0, 0}, + {0x1A7B, 230, 0, 0}, + {0x1A7C, 230, 0, 0}, + {0x1A7F, 220, 0, 0}, + {0x1AB0, 230, 0, 0}, + {0x1AB1, 230, 0, 0}, + {0x1AB2, 230, 0, 0}, + {0x1AB3, 230, 0, 0}, + {0x1AB4, 230, 0, 0}, + {0x1AB5, 220, 0, 0}, + {0x1AB6, 220, 0, 0}, + {0x1AB7, 220, 0, 0}, + {0x1AB8, 220, 0, 0}, + {0x1AB9, 220, 0, 0}, + {0x1ABA, 220, 0, 0}, + {0x1ABB, 230, 0, 0}, + {0x1ABC, 230, 0, 0}, + {0x1ABD, 220, 0, 0}, + {0x1ABF, 220, 0, 0}, + {0x1AC0, 220, 0, 0}, + {0x1AC1, 230, 0, 0}, + {0x1AC2, 230, 0, 0}, + {0x1AC3, 220, 0, 0}, + {0x1AC4, 220, 0, 0}, + {0x1AC5, 230, 0, 0}, + {0x1AC6, 230, 0, 0}, + {0x1AC7, 230, 0, 0}, + {0x1AC8, 230, 0, 0}, + {0x1AC9, 230, 0, 0}, + {0x1ACA, 220, 0, 0}, + {0x1ACB, 230, 0, 0}, + {0x1ACC, 230, 0, 0}, + {0x1ACD, 230, 0, 0}, + {0x1ACE, 230, 0, 0}, + {0x1B06, 0, 2, 885}, + {0x1B08, 0, 2, 887}, + {0x1B0A, 0, 2, 889}, + {0x1B0C, 0, 2, 891}, + {0x1B0E, 0, 2, 893}, + {0x1B12, 0, 2, 895}, + {0x1B34, 7, 0, 0}, + {0x1B3B, 0, 2, 897}, + {0x1B3D, 0, 2, 899}, + {0x1B40, 0, 2, 901}, + {0x1B41, 0, 2, 903}, + {0x1B43, 0, 2, 905}, + {0x1B44, 9, 0, 0}, + {0x1B6B, 230, 0, 0}, + {0x1B6C, 220, 0, 0}, + {0x1B6D, 230, 0, 0}, + {0x1B6E, 230, 0, 0}, + {0x1B6F, 230, 0, 0}, + {0x1B70, 230, 0, 0}, + {0x1B71, 230, 0, 0}, + {0x1B72, 230, 0, 0}, + {0x1B73, 230, 0, 0}, + {0x1BAA, 9, 0, 0}, + {0x1BAB, 9, 0, 0}, + {0x1BE6, 7, 0, 0}, + {0x1BF2, 9, 0, 0}, + {0x1BF3, 9, 0, 0}, + {0x1C37, 7, 0, 0}, + {0x1CD0, 230, 0, 0}, + {0x1CD1, 230, 0, 0}, + {0x1CD2, 230, 0, 0}, + {0x1CD4, 1, 0, 0}, + {0x1CD5, 220, 0, 0}, + {0x1CD6, 220, 0, 0}, + {0x1CD7, 220, 0, 0}, + {0x1CD8, 220, 0, 0}, + {0x1CD9, 220, 0, 0}, + {0x1CDA, 230, 0, 0}, + {0x1CDB, 230, 0, 0}, + {0x1CDC, 220, 0, 0}, + {0x1CDD, 220, 0, 0}, + {0x1CDE, 220, 0, 0}, + {0x1CDF, 220, 0, 0}, + {0x1CE0, 230, 0, 0}, + {0x1CE2, 1, 0, 0}, + {0x1CE3, 1, 0, 0}, + {0x1CE4, 1, 0, 0}, + {0x1CE5, 1, 0, 0}, + {0x1CE6, 1, 0, 0}, + {0x1CE7, 1, 0, 0}, + {0x1CE8, 1, 0, 0}, + {0x1CED, 220, 0, 0}, + {0x1CF4, 230, 0, 0}, + {0x1CF8, 230, 0, 0}, + {0x1CF9, 230, 0, 0}, + {0x1D2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00C6}, + {0x1D2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x018E}, + {0x1D33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0222}, + {0x1D3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0250}, + {0x1D45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0251}, + {0x1D46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D02}, + {0x1D47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0259}, + {0x1D4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025B}, + {0x1D4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025C}, + {0x1D4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x014B}, + {0x1D52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0254}, + {0x1D54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D16}, + {0x1D55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D17}, + {0x1D56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D1D}, + {0x1D5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026F}, + {0x1D5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D25}, + {0x1D5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043D}, + {0x1D9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0252}, + {0x1D9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0255}, + {0x1D9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00F0}, + {0x1D9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025C}, + {0x1DA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1DA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025F}, + {0x1DA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0261}, + {0x1DA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0265}, + {0x1DA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0268}, + {0x1DA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0269}, + {0x1DA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026A}, + {0x1DA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D7B}, + {0x1DA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029D}, + {0x1DA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026D}, + {0x1DAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D85}, + {0x1DAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029F}, + {0x1DAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0271}, + {0x1DAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0270}, + {0x1DAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0272}, + {0x1DAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0273}, + {0x1DB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0274}, + {0x1DB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0275}, + {0x1DB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0278}, + {0x1DB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0282}, + {0x1DB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0283}, + {0x1DB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01AB}, + {0x1DB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0289}, + {0x1DB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028A}, + {0x1DB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D1C}, + {0x1DB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028B}, + {0x1DBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028C}, + {0x1DBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1DBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0290}, + {0x1DBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0291}, + {0x1DBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0292}, + {0x1DBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1DC0, 230, 0, 0}, + {0x1DC1, 230, 0, 0}, + {0x1DC2, 220, 0, 0}, + {0x1DC3, 230, 0, 0}, + {0x1DC4, 230, 0, 0}, + {0x1DC5, 230, 0, 0}, + {0x1DC6, 230, 0, 0}, + {0x1DC7, 230, 0, 0}, + {0x1DC8, 230, 0, 0}, + {0x1DC9, 230, 0, 0}, + {0x1DCA, 220, 0, 0}, + {0x1DCB, 230, 0, 0}, + {0x1DCC, 230, 0, 0}, + {0x1DCD, 234, 0, 0}, + {0x1DCE, 214, 0, 0}, + {0x1DCF, 220, 0, 0}, + {0x1DD0, 202, 0, 0}, + {0x1DD1, 230, 0, 0}, + {0x1DD2, 230, 0, 0}, + {0x1DD3, 230, 0, 0}, + {0x1DD4, 230, 0, 0}, + {0x1DD5, 230, 0, 0}, + {0x1DD6, 230, 0, 0}, + {0x1DD7, 230, 0, 0}, + {0x1DD8, 230, 0, 0}, + {0x1DD9, 230, 0, 0}, + {0x1DDA, 230, 0, 0}, + {0x1DDB, 230, 0, 0}, + {0x1DDC, 230, 0, 0}, + {0x1DDD, 230, 0, 0}, + {0x1DDE, 230, 0, 0}, + {0x1DDF, 230, 0, 0}, + {0x1DE0, 230, 0, 0}, + {0x1DE1, 230, 0, 0}, + {0x1DE2, 230, 0, 0}, + {0x1DE3, 230, 0, 0}, + {0x1DE4, 230, 0, 0}, + {0x1DE5, 230, 0, 0}, + {0x1DE6, 230, 0, 0}, + {0x1DE7, 230, 0, 0}, + {0x1DE8, 230, 0, 0}, + {0x1DE9, 230, 0, 0}, + {0x1DEA, 230, 0, 0}, + {0x1DEB, 230, 0, 0}, + {0x1DEC, 230, 0, 0}, + {0x1DED, 230, 0, 0}, + {0x1DEE, 230, 0, 0}, + {0x1DEF, 230, 0, 0}, + {0x1DF0, 230, 0, 0}, + {0x1DF1, 230, 0, 0}, + {0x1DF2, 230, 0, 0}, + {0x1DF3, 230, 0, 0}, + {0x1DF4, 230, 0, 0}, + {0x1DF5, 230, 0, 0}, + {0x1DF6, 232, 0, 0}, + {0x1DF7, 228, 0, 0}, + {0x1DF8, 228, 0, 0}, + {0x1DF9, 220, 0, 0}, + {0x1DFA, 218, 0, 0}, + {0x1DFB, 230, 0, 0}, + {0x1DFC, 233, 0, 0}, + {0x1DFD, 220, 0, 0}, + {0x1DFE, 230, 0, 0}, + {0x1DFF, 220, 0, 0}, + {0x1E00, 0, 2, 907}, + {0x1E01, 0, 2, 909}, + {0x1E02, 0, 2, 911}, + {0x1E03, 0, 2, 913}, + {0x1E04, 0, 2, 915}, + {0x1E05, 0, 2, 917}, + {0x1E06, 0, 2, 919}, + {0x1E07, 0, 2, 921}, + {0x1E08, 0, 2, 923}, + {0x1E09, 0, 2, 925}, + {0x1E0A, 0, 2, 927}, + {0x1E0B, 0, 2, 929}, + {0x1E0C, 0, 2, 931}, + {0x1E0D, 0, 2, 933}, + {0x1E0E, 0, 2, 935}, + {0x1E0F, 0, 2, 937}, + {0x1E10, 0, 2, 939}, + {0x1E11, 0, 2, 941}, + {0x1E12, 0, 2, 943}, + {0x1E13, 0, 2, 945}, + {0x1E14, 0, 2, 947}, + {0x1E15, 0, 2, 949}, + {0x1E16, 0, 2, 951}, + {0x1E17, 0, 2, 953}, + {0x1E18, 0, 2, 955}, + {0x1E19, 0, 2, 957}, + {0x1E1A, 0, 2, 959}, + {0x1E1B, 0, 2, 961}, + {0x1E1C, 0, 2, 963}, + {0x1E1D, 0, 2, 965}, + {0x1E1E, 0, 2, 967}, + {0x1E1F, 0, 2, 969}, + {0x1E20, 0, 2, 971}, + {0x1E21, 0, 2, 973}, + {0x1E22, 0, 2, 975}, + {0x1E23, 0, 2, 977}, + {0x1E24, 0, 2, 979}, + {0x1E25, 0, 2, 981}, + {0x1E26, 0, 2, 983}, + {0x1E27, 0, 2, 985}, + {0x1E28, 0, 2, 987}, + {0x1E29, 0, 2, 989}, + {0x1E2A, 0, 2, 991}, + {0x1E2B, 0, 2, 993}, + {0x1E2C, 0, 2, 995}, + {0x1E2D, 0, 2, 997}, + {0x1E2E, 0, 2, 999}, + {0x1E2F, 0, 2, 1001}, + {0x1E30, 0, 2, 1003}, + {0x1E31, 0, 2, 1005}, + {0x1E32, 0, 2, 1007}, + {0x1E33, 0, 2, 1009}, + {0x1E34, 0, 2, 1011}, + {0x1E35, 0, 2, 1013}, + {0x1E36, 0, 2, 1015}, + {0x1E37, 0, 2, 1017}, + {0x1E38, 0, 2, 1019}, + {0x1E39, 0, 2, 1021}, + {0x1E3A, 0, 2, 1023}, + {0x1E3B, 0, 2, 1025}, + {0x1E3C, 0, 2, 1027}, + {0x1E3D, 0, 2, 1029}, + {0x1E3E, 0, 2, 1031}, + {0x1E3F, 0, 2, 1033}, + {0x1E40, 0, 2, 1035}, + {0x1E41, 0, 2, 1037}, + {0x1E42, 0, 2, 1039}, + {0x1E43, 0, 2, 1041}, + {0x1E44, 0, 2, 1043}, + {0x1E45, 0, 2, 1045}, + {0x1E46, 0, 2, 1047}, + {0x1E47, 0, 2, 1049}, + {0x1E48, 0, 2, 1051}, + {0x1E49, 0, 2, 1053}, + {0x1E4A, 0, 2, 1055}, + {0x1E4B, 0, 2, 1057}, + {0x1E4C, 0, 2, 1059}, + {0x1E4D, 0, 2, 1061}, + {0x1E4E, 0, 2, 1063}, + {0x1E4F, 0, 2, 1065}, + {0x1E50, 0, 2, 1067}, + {0x1E51, 0, 2, 1069}, + {0x1E52, 0, 2, 1071}, + {0x1E53, 0, 2, 1073}, + {0x1E54, 0, 2, 1075}, + {0x1E55, 0, 2, 1077}, + {0x1E56, 0, 2, 1079}, + {0x1E57, 0, 2, 1081}, + {0x1E58, 0, 2, 1083}, + {0x1E59, 0, 2, 1085}, + {0x1E5A, 0, 2, 1087}, + {0x1E5B, 0, 2, 1089}, + {0x1E5C, 0, 2, 1091}, + {0x1E5D, 0, 2, 1093}, + {0x1E5E, 0, 2, 1095}, + {0x1E5F, 0, 2, 1097}, + {0x1E60, 0, 2, 1099}, + {0x1E61, 0, 2, 1101}, + {0x1E62, 0, 2, 1103}, + {0x1E63, 0, 2, 1105}, + {0x1E64, 0, 2, 1107}, + {0x1E65, 0, 2, 1109}, + {0x1E66, 0, 2, 1111}, + {0x1E67, 0, 2, 1113}, + {0x1E68, 0, 2, 1115}, + {0x1E69, 0, 2, 1117}, + {0x1E6A, 0, 2, 1119}, + {0x1E6B, 0, 2, 1121}, + {0x1E6C, 0, 2, 1123}, + {0x1E6D, 0, 2, 1125}, + {0x1E6E, 0, 2, 1127}, + {0x1E6F, 0, 2, 1129}, + {0x1E70, 0, 2, 1131}, + {0x1E71, 0, 2, 1133}, + {0x1E72, 0, 2, 1135}, + {0x1E73, 0, 2, 1137}, + {0x1E74, 0, 2, 1139}, + {0x1E75, 0, 2, 1141}, + {0x1E76, 0, 2, 1143}, + {0x1E77, 0, 2, 1145}, + {0x1E78, 0, 2, 1147}, + {0x1E79, 0, 2, 1149}, + {0x1E7A, 0, 2, 1151}, + {0x1E7B, 0, 2, 1153}, + {0x1E7C, 0, 2, 1155}, + {0x1E7D, 0, 2, 1157}, + {0x1E7E, 0, 2, 1159}, + {0x1E7F, 0, 2, 1161}, + {0x1E80, 0, 2, 1163}, + {0x1E81, 0, 2, 1165}, + {0x1E82, 0, 2, 1167}, + {0x1E83, 0, 2, 1169}, + {0x1E84, 0, 2, 1171}, + {0x1E85, 0, 2, 1173}, + {0x1E86, 0, 2, 1175}, + {0x1E87, 0, 2, 1177}, + {0x1E88, 0, 2, 1179}, + {0x1E89, 0, 2, 1181}, + {0x1E8A, 0, 2, 1183}, + {0x1E8B, 0, 2, 1185}, + {0x1E8C, 0, 2, 1187}, + {0x1E8D, 0, 2, 1189}, + {0x1E8E, 0, 2, 1191}, + {0x1E8F, 0, 2, 1193}, + {0x1E90, 0, 2, 1195}, + {0x1E91, 0, 2, 1197}, + {0x1E92, 0, 2, 1199}, + {0x1E93, 0, 2, 1201}, + {0x1E94, 0, 2, 1203}, + {0x1E95, 0, 2, 1205}, + {0x1E96, 0, 2, 1207}, + {0x1E97, 0, 2, 1209}, + {0x1E98, 0, 2, 1211}, + {0x1E99, 0, 2, 1213}, + {0x1E9A, 0, 2 | DECOMP_COMPAT, 1215}, + {0x1E9B, 0, 2, 1217}, + {0x1EA0, 0, 2, 1219}, + {0x1EA1, 0, 2, 1221}, + {0x1EA2, 0, 2, 1223}, + {0x1EA3, 0, 2, 1225}, + {0x1EA4, 0, 2, 1227}, + {0x1EA5, 0, 2, 1229}, + {0x1EA6, 0, 2, 1231}, + {0x1EA7, 0, 2, 1233}, + {0x1EA8, 0, 2, 1235}, + {0x1EA9, 0, 2, 1237}, + {0x1EAA, 0, 2, 1239}, + {0x1EAB, 0, 2, 1241}, + {0x1EAC, 0, 2, 1243}, + {0x1EAD, 0, 2, 1245}, + {0x1EAE, 0, 2, 1247}, + {0x1EAF, 0, 2, 1249}, + {0x1EB0, 0, 2, 1251}, + {0x1EB1, 0, 2, 1253}, + {0x1EB2, 0, 2, 1255}, + {0x1EB3, 0, 2, 1257}, + {0x1EB4, 0, 2, 1259}, + {0x1EB5, 0, 2, 1261}, + {0x1EB6, 0, 2, 1263}, + {0x1EB7, 0, 2, 1265}, + {0x1EB8, 0, 2, 1267}, + {0x1EB9, 0, 2, 1269}, + {0x1EBA, 0, 2, 1271}, + {0x1EBB, 0, 2, 1273}, + {0x1EBC, 0, 2, 1275}, + {0x1EBD, 0, 2, 1277}, + {0x1EBE, 0, 2, 1279}, + {0x1EBF, 0, 2, 1281}, + {0x1EC0, 0, 2, 1283}, + {0x1EC1, 0, 2, 1285}, + {0x1EC2, 0, 2, 1287}, + {0x1EC3, 0, 2, 1289}, + {0x1EC4, 0, 2, 1291}, + {0x1EC5, 0, 2, 1293}, + {0x1EC6, 0, 2, 1295}, + {0x1EC7, 0, 2, 1297}, + {0x1EC8, 0, 2, 1299}, + {0x1EC9, 0, 2, 1301}, + {0x1ECA, 0, 2, 1303}, + {0x1ECB, 0, 2, 1305}, + {0x1ECC, 0, 2, 1307}, + {0x1ECD, 0, 2, 1309}, + {0x1ECE, 0, 2, 1311}, + {0x1ECF, 0, 2, 1313}, + {0x1ED0, 0, 2, 1315}, + {0x1ED1, 0, 2, 1317}, + {0x1ED2, 0, 2, 1319}, + {0x1ED3, 0, 2, 1321}, + {0x1ED4, 0, 2, 1323}, + {0x1ED5, 0, 2, 1325}, + {0x1ED6, 0, 2, 1327}, + {0x1ED7, 0, 2, 1329}, + {0x1ED8, 0, 2, 1331}, + {0x1ED9, 0, 2, 1333}, + {0x1EDA, 0, 2, 1335}, + {0x1EDB, 0, 2, 1337}, + {0x1EDC, 0, 2, 1339}, + {0x1EDD, 0, 2, 1341}, + {0x1EDE, 0, 2, 1343}, + {0x1EDF, 0, 2, 1345}, + {0x1EE0, 0, 2, 1347}, + {0x1EE1, 0, 2, 1349}, + {0x1EE2, 0, 2, 1351}, + {0x1EE3, 0, 2, 1353}, + {0x1EE4, 0, 2, 1355}, + {0x1EE5, 0, 2, 1357}, + {0x1EE6, 0, 2, 1359}, + {0x1EE7, 0, 2, 1361}, + {0x1EE8, 0, 2, 1363}, + {0x1EE9, 0, 2, 1365}, + {0x1EEA, 0, 2, 1367}, + {0x1EEB, 0, 2, 1369}, + {0x1EEC, 0, 2, 1371}, + {0x1EED, 0, 2, 1373}, + {0x1EEE, 0, 2, 1375}, + {0x1EEF, 0, 2, 1377}, + {0x1EF0, 0, 2, 1379}, + {0x1EF1, 0, 2, 1381}, + {0x1EF2, 0, 2, 1383}, + {0x1EF3, 0, 2, 1385}, + {0x1EF4, 0, 2, 1387}, + {0x1EF5, 0, 2, 1389}, + {0x1EF6, 0, 2, 1391}, + {0x1EF7, 0, 2, 1393}, + {0x1EF8, 0, 2, 1395}, + {0x1EF9, 0, 2, 1397}, + {0x1F00, 0, 2, 1399}, + {0x1F01, 0, 2, 1401}, + {0x1F02, 0, 2, 1403}, + {0x1F03, 0, 2, 1405}, + {0x1F04, 0, 2, 1407}, + {0x1F05, 0, 2, 1409}, + {0x1F06, 0, 2, 1411}, + {0x1F07, 0, 2, 1413}, + {0x1F08, 0, 2, 1415}, + {0x1F09, 0, 2, 1417}, + {0x1F0A, 0, 2, 1419}, + {0x1F0B, 0, 2, 1421}, + {0x1F0C, 0, 2, 1423}, + {0x1F0D, 0, 2, 1425}, + {0x1F0E, 0, 2, 1427}, + {0x1F0F, 0, 2, 1429}, + {0x1F10, 0, 2, 1431}, + {0x1F11, 0, 2, 1433}, + {0x1F12, 0, 2, 1435}, + {0x1F13, 0, 2, 1437}, + {0x1F14, 0, 2, 1439}, + {0x1F15, 0, 2, 1441}, + {0x1F18, 0, 2, 1443}, + {0x1F19, 0, 2, 1445}, + {0x1F1A, 0, 2, 1447}, + {0x1F1B, 0, 2, 1449}, + {0x1F1C, 0, 2, 1451}, + {0x1F1D, 0, 2, 1453}, + {0x1F20, 0, 2, 1455}, + {0x1F21, 0, 2, 1457}, + {0x1F22, 0, 2, 1459}, + {0x1F23, 0, 2, 1461}, + {0x1F24, 0, 2, 1463}, + {0x1F25, 0, 2, 1465}, + {0x1F26, 0, 2, 1467}, + {0x1F27, 0, 2, 1469}, + {0x1F28, 0, 2, 1471}, + {0x1F29, 0, 2, 1473}, + {0x1F2A, 0, 2, 1475}, + {0x1F2B, 0, 2, 1477}, + {0x1F2C, 0, 2, 1479}, + {0x1F2D, 0, 2, 1481}, + {0x1F2E, 0, 2, 1483}, + {0x1F2F, 0, 2, 1485}, + {0x1F30, 0, 2, 1487}, + {0x1F31, 0, 2, 1489}, + {0x1F32, 0, 2, 1491}, + {0x1F33, 0, 2, 1493}, + {0x1F34, 0, 2, 1495}, + {0x1F35, 0, 2, 1497}, + {0x1F36, 0, 2, 1499}, + {0x1F37, 0, 2, 1501}, + {0x1F38, 0, 2, 1503}, + {0x1F39, 0, 2, 1505}, + {0x1F3A, 0, 2, 1507}, + {0x1F3B, 0, 2, 1509}, + {0x1F3C, 0, 2, 1511}, + {0x1F3D, 0, 2, 1513}, + {0x1F3E, 0, 2, 1515}, + {0x1F3F, 0, 2, 1517}, + {0x1F40, 0, 2, 1519}, + {0x1F41, 0, 2, 1521}, + {0x1F42, 0, 2, 1523}, + {0x1F43, 0, 2, 1525}, + {0x1F44, 0, 2, 1527}, + {0x1F45, 0, 2, 1529}, + {0x1F48, 0, 2, 1531}, + {0x1F49, 0, 2, 1533}, + {0x1F4A, 0, 2, 1535}, + {0x1F4B, 0, 2, 1537}, + {0x1F4C, 0, 2, 1539}, + {0x1F4D, 0, 2, 1541}, + {0x1F50, 0, 2, 1543}, + {0x1F51, 0, 2, 1545}, + {0x1F52, 0, 2, 1547}, + {0x1F53, 0, 2, 1549}, + {0x1F54, 0, 2, 1551}, + {0x1F55, 0, 2, 1553}, + {0x1F56, 0, 2, 1555}, + {0x1F57, 0, 2, 1557}, + {0x1F59, 0, 2, 1559}, + {0x1F5B, 0, 2, 1561}, + {0x1F5D, 0, 2, 1563}, + {0x1F5F, 0, 2, 1565}, + {0x1F60, 0, 2, 1567}, + {0x1F61, 0, 2, 1569}, + {0x1F62, 0, 2, 1571}, + {0x1F63, 0, 2, 1573}, + {0x1F64, 0, 2, 1575}, + {0x1F65, 0, 2, 1577}, + {0x1F66, 0, 2, 1579}, + {0x1F67, 0, 2, 1581}, + {0x1F68, 0, 2, 1583}, + {0x1F69, 0, 2, 1585}, + {0x1F6A, 0, 2, 1587}, + {0x1F6B, 0, 2, 1589}, + {0x1F6C, 0, 2, 1591}, + {0x1F6D, 0, 2, 1593}, + {0x1F6E, 0, 2, 1595}, + {0x1F6F, 0, 2, 1597}, + {0x1F70, 0, 2, 1599}, + {0x1F71, 0, 1 | DECOMP_INLINE, 0x03AC}, + {0x1F72, 0, 2, 1601}, + {0x1F73, 0, 1 | DECOMP_INLINE, 0x03AD}, + {0x1F74, 0, 2, 1603}, + {0x1F75, 0, 1 | DECOMP_INLINE, 0x03AE}, + {0x1F76, 0, 2, 1605}, + {0x1F77, 0, 1 | DECOMP_INLINE, 0x03AF}, + {0x1F78, 0, 2, 1607}, + {0x1F79, 0, 1 | DECOMP_INLINE, 0x03CC}, + {0x1F7A, 0, 2, 1609}, + {0x1F7B, 0, 1 | DECOMP_INLINE, 0x03CD}, + {0x1F7C, 0, 2, 1611}, + {0x1F7D, 0, 1 | DECOMP_INLINE, 0x03CE}, + {0x1F80, 0, 2, 1613}, + {0x1F81, 0, 2, 1615}, + {0x1F82, 0, 2, 1617}, + {0x1F83, 0, 2, 1619}, + {0x1F84, 0, 2, 1621}, + {0x1F85, 0, 2, 1623}, + {0x1F86, 0, 2, 1625}, + {0x1F87, 0, 2, 1627}, + {0x1F88, 0, 2, 1629}, + {0x1F89, 0, 2, 1631}, + {0x1F8A, 0, 2, 1633}, + {0x1F8B, 0, 2, 1635}, + {0x1F8C, 0, 2, 1637}, + {0x1F8D, 0, 2, 1639}, + {0x1F8E, 0, 2, 1641}, + {0x1F8F, 0, 2, 1643}, + {0x1F90, 0, 2, 1645}, + {0x1F91, 0, 2, 1647}, + {0x1F92, 0, 2, 1649}, + {0x1F93, 0, 2, 1651}, + {0x1F94, 0, 2, 1653}, + {0x1F95, 0, 2, 1655}, + {0x1F96, 0, 2, 1657}, + {0x1F97, 0, 2, 1659}, + {0x1F98, 0, 2, 1661}, + {0x1F99, 0, 2, 1663}, + {0x1F9A, 0, 2, 1665}, + {0x1F9B, 0, 2, 1667}, + {0x1F9C, 0, 2, 1669}, + {0x1F9D, 0, 2, 1671}, + {0x1F9E, 0, 2, 1673}, + {0x1F9F, 0, 2, 1675}, + {0x1FA0, 0, 2, 1677}, + {0x1FA1, 0, 2, 1679}, + {0x1FA2, 0, 2, 1681}, + {0x1FA3, 0, 2, 1683}, + {0x1FA4, 0, 2, 1685}, + {0x1FA5, 0, 2, 1687}, + {0x1FA6, 0, 2, 1689}, + {0x1FA7, 0, 2, 1691}, + {0x1FA8, 0, 2, 1693}, + {0x1FA9, 0, 2, 1695}, + {0x1FAA, 0, 2, 1697}, + {0x1FAB, 0, 2, 1699}, + {0x1FAC, 0, 2, 1701}, + {0x1FAD, 0, 2, 1703}, + {0x1FAE, 0, 2, 1705}, + {0x1FAF, 0, 2, 1707}, + {0x1FB0, 0, 2, 1709}, + {0x1FB1, 0, 2, 1711}, + {0x1FB2, 0, 2, 1713}, + {0x1FB3, 0, 2, 1715}, + {0x1FB4, 0, 2, 1717}, + {0x1FB6, 0, 2, 1719}, + {0x1FB7, 0, 2, 1721}, + {0x1FB8, 0, 2, 1723}, + {0x1FB9, 0, 2, 1725}, + {0x1FBA, 0, 2, 1727}, + {0x1FBB, 0, 1 | DECOMP_INLINE, 0x0386}, + {0x1FBC, 0, 2, 1729}, + {0x1FBD, 0, 2 | DECOMP_COMPAT, 1731}, + {0x1FBE, 0, 1 | DECOMP_INLINE, 0x03B9}, + {0x1FBF, 0, 2 | DECOMP_COMPAT, 1733}, + {0x1FC0, 0, 2 | DECOMP_COMPAT, 1735}, + {0x1FC1, 0, 2, 1737}, + {0x1FC2, 0, 2, 1739}, + {0x1FC3, 0, 2, 1741}, + {0x1FC4, 0, 2, 1743}, + {0x1FC6, 0, 2, 1745}, + {0x1FC7, 0, 2, 1747}, + {0x1FC8, 0, 2, 1749}, + {0x1FC9, 0, 1 | DECOMP_INLINE, 0x0388}, + {0x1FCA, 0, 2, 1751}, + {0x1FCB, 0, 1 | DECOMP_INLINE, 0x0389}, + {0x1FCC, 0, 2, 1753}, + {0x1FCD, 0, 2, 1755}, + {0x1FCE, 0, 2, 1757}, + {0x1FCF, 0, 2, 1759}, + {0x1FD0, 0, 2, 1761}, + {0x1FD1, 0, 2, 1763}, + {0x1FD2, 0, 2, 1765}, + {0x1FD3, 0, 1 | DECOMP_INLINE, 0x0390}, + {0x1FD6, 0, 2, 1767}, + {0x1FD7, 0, 2, 1769}, + {0x1FD8, 0, 2, 1771}, + {0x1FD9, 0, 2, 1773}, + {0x1FDA, 0, 2, 1775}, + {0x1FDB, 0, 1 | DECOMP_INLINE, 0x038A}, + {0x1FDD, 0, 2, 1777}, + {0x1FDE, 0, 2, 1779}, + {0x1FDF, 0, 2, 1781}, + {0x1FE0, 0, 2, 1783}, + {0x1FE1, 0, 2, 1785}, + {0x1FE2, 0, 2, 1787}, + {0x1FE3, 0, 1 | DECOMP_INLINE, 0x03B0}, + {0x1FE4, 0, 2, 1789}, + {0x1FE5, 0, 2, 1791}, + {0x1FE6, 0, 2, 1793}, + {0x1FE7, 0, 2, 1795}, + {0x1FE8, 0, 2, 1797}, + {0x1FE9, 0, 2, 1799}, + {0x1FEA, 0, 2, 1801}, + {0x1FEB, 0, 1 | DECOMP_INLINE, 0x038E}, + {0x1FEC, 0, 2, 1803}, + {0x1FED, 0, 2, 1805}, + {0x1FEE, 0, 1 | DECOMP_INLINE, 0x0385}, + {0x1FEF, 0, 1 | DECOMP_INLINE, 0x0060}, + {0x1FF2, 0, 2, 1807}, + {0x1FF3, 0, 2, 1809}, + {0x1FF4, 0, 2, 1811}, + {0x1FF6, 0, 2, 1813}, + {0x1FF7, 0, 2, 1815}, + {0x1FF8, 0, 2, 1817}, + {0x1FF9, 0, 1 | DECOMP_INLINE, 0x038C}, + {0x1FFA, 0, 2, 1819}, + {0x1FFB, 0, 1 | DECOMP_INLINE, 0x038F}, + {0x1FFC, 0, 2, 1821}, + {0x1FFD, 0, 1 | DECOMP_INLINE, 0x00B4}, + {0x1FFE, 0, 2 | DECOMP_COMPAT, 1823}, + {0x2000, 0, 1 | DECOMP_INLINE, 0x2002}, + {0x2001, 0, 1 | DECOMP_INLINE, 0x2003}, + {0x2002, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2003, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2004, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2005, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2006, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2007, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2008, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2009, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x200A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2011, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2010}, + {0x2017, 0, 2 | DECOMP_COMPAT, 1825}, + {0x2024, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0x2025, 0, 2 | DECOMP_COMPAT, 1827}, + {0x2026, 0, 3 | DECOMP_COMPAT, 1829}, + {0x202F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2033, 0, 2 | DECOMP_COMPAT, 1832}, + {0x2034, 0, 3 | DECOMP_COMPAT, 1834}, + {0x2036, 0, 2 | DECOMP_COMPAT, 1837}, + {0x2037, 0, 3 | DECOMP_COMPAT, 1839}, + {0x203C, 0, 2 | DECOMP_COMPAT, 1842}, + {0x203E, 0, 2 | DECOMP_COMPAT, 1844}, + {0x2047, 0, 2 | DECOMP_COMPAT, 1846}, + {0x2048, 0, 2 | DECOMP_COMPAT, 1848}, + {0x2049, 0, 2 | DECOMP_COMPAT, 1850}, + {0x2057, 0, 4 | DECOMP_COMPAT, 1852}, + {0x205F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2070, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2071, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2074, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2075, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2076, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2077, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2078, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2079, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x207A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0x207B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2212}, + {0x207C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0x207D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0x207E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0x207F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x2080, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2081, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x2082, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x2083, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x2084, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2085, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2086, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2087, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2088, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2089, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x208A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0x208B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2212}, + {0x208C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0x208D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0x208E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0x2090, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x2091, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2092, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x2093, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x2094, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0259}, + {0x2095, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x2096, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x2097, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x2098, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x2099, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x209A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x209B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x209C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x20A8, 0, 2 | DECOMP_COMPAT, 1856}, + {0x20D0, 230, 0, 0}, + {0x20D1, 230, 0, 0}, + {0x20D2, 1, 0, 0}, + {0x20D3, 1, 0, 0}, + {0x20D4, 230, 0, 0}, + {0x20D5, 230, 0, 0}, + {0x20D6, 230, 0, 0}, + {0x20D7, 230, 0, 0}, + {0x20D8, 1, 0, 0}, + {0x20D9, 1, 0, 0}, + {0x20DA, 1, 0, 0}, + {0x20DB, 230, 0, 0}, + {0x20DC, 230, 0, 0}, + {0x20E1, 230, 0, 0}, + {0x20E5, 1, 0, 0}, + {0x20E6, 1, 0, 0}, + {0x20E7, 230, 0, 0}, + {0x20E8, 220, 0, 0}, + {0x20E9, 230, 0, 0}, + {0x20EA, 1, 0, 0}, + {0x20EB, 1, 0, 0}, + {0x20EC, 220, 0, 0}, + {0x20ED, 220, 0, 0}, + {0x20EE, 220, 0, 0}, + {0x20EF, 220, 0, 0}, + {0x20F0, 230, 0, 0}, + {0x2100, 0, 3 | DECOMP_COMPAT, 1858}, + {0x2101, 0, 3 | DECOMP_COMPAT, 1861}, + {0x2102, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x2103, 0, 2 | DECOMP_COMPAT, 1864}, + {0x2105, 0, 3 | DECOMP_COMPAT, 1866}, + {0x2106, 0, 3 | DECOMP_COMPAT, 1869}, + {0x2107, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0190}, + {0x2109, 0, 2 | DECOMP_COMPAT, 1872}, + {0x210A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x210B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x210F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0127}, + {0x2110, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2111, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2112, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x2113, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x2115, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x2116, 0, 2 | DECOMP_COMPAT, 1874}, + {0x2119, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x211A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x211B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x211C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x211D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x2120, 0, 2 | DECOMP_COMPAT, 1876}, + {0x2121, 0, 3 | DECOMP_COMPAT, 1878}, + {0x2122, 0, 2 | DECOMP_COMPAT, 1881}, + {0x2124, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x2126, 0, 1 | DECOMP_INLINE, 0x03A9}, + {0x2128, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x212A, 0, 1 | DECOMP_INLINE, 0x004B}, + {0x212B, 0, 1 | DECOMP_INLINE, 0x00C5}, + {0x212C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x212D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x212F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2130, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x2131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x2133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x2134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x2135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D0}, + {0x2136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D1}, + {0x2137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D2}, + {0x2138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D3}, + {0x2139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x213B, 0, 3 | DECOMP_COMPAT, 1883}, + {0x213C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x213D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x213E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x213F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x2140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2211}, + {0x2145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x2146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x2147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x2150, 0, 3 | DECOMP_COMPAT, 1886}, + {0x2151, 0, 3 | DECOMP_COMPAT, 1889}, + {0x2152, 0, 4 | DECOMP_COMPAT, 1892}, + {0x2153, 0, 3 | DECOMP_COMPAT, 1896}, + {0x2154, 0, 3 | DECOMP_COMPAT, 1899}, + {0x2155, 0, 3 | DECOMP_COMPAT, 1902}, + {0x2156, 0, 3 | DECOMP_COMPAT, 1905}, + {0x2157, 0, 3 | DECOMP_COMPAT, 1908}, + {0x2158, 0, 3 | DECOMP_COMPAT, 1911}, + {0x2159, 0, 3 | DECOMP_COMPAT, 1914}, + {0x215A, 0, 3 | DECOMP_COMPAT, 1917}, + {0x215B, 0, 3 | DECOMP_COMPAT, 1920}, + {0x215C, 0, 3 | DECOMP_COMPAT, 1923}, + {0x215D, 0, 3 | DECOMP_COMPAT, 1926}, + {0x215E, 0, 3 | DECOMP_COMPAT, 1929}, + {0x215F, 0, 2 | DECOMP_COMPAT, 1932}, + {0x2160, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2161, 0, 2 | DECOMP_COMPAT, 1934}, + {0x2162, 0, 3 | DECOMP_COMPAT, 1936}, + {0x2163, 0, 2 | DECOMP_COMPAT, 1939}, + {0x2164, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x2165, 0, 2 | DECOMP_COMPAT, 1941}, + {0x2166, 0, 3 | DECOMP_COMPAT, 1943}, + {0x2167, 0, 4 | DECOMP_COMPAT, 1946}, + {0x2168, 0, 2 | DECOMP_COMPAT, 1950}, + {0x2169, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x216A, 0, 2 | DECOMP_COMPAT, 1952}, + {0x216B, 0, 3 | DECOMP_COMPAT, 1954}, + {0x216C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x216D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x216E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x216F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x2170, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2171, 0, 2 | DECOMP_COMPAT, 1957}, + {0x2172, 0, 3 | DECOMP_COMPAT, 1959}, + {0x2173, 0, 2 | DECOMP_COMPAT, 1962}, + {0x2174, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x2175, 0, 2 | DECOMP_COMPAT, 1964}, + {0x2176, 0, 3 | DECOMP_COMPAT, 1966}, + {0x2177, 0, 4 | DECOMP_COMPAT, 1969}, + {0x2178, 0, 2 | DECOMP_COMPAT, 1973}, + {0x2179, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x217A, 0, 2 | DECOMP_COMPAT, 1975}, + {0x217B, 0, 3 | DECOMP_COMPAT, 1977}, + {0x217C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x217D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x217E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x217F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x2189, 0, 3 | DECOMP_COMPAT, 1980}, + {0x219A, 0, 2, 1983}, + {0x219B, 0, 2, 1985}, + {0x21AE, 0, 2, 1987}, + {0x21CD, 0, 2, 1989}, + {0x21CE, 0, 2, 1991}, + {0x21CF, 0, 2, 1993}, + {0x2204, 0, 2, 1995}, + {0x2209, 0, 2, 1997}, + {0x220C, 0, 2, 1999}, + {0x2224, 0, 2, 2001}, + {0x2226, 0, 2, 2003}, + {0x222C, 0, 2 | DECOMP_COMPAT, 2005}, + {0x222D, 0, 3 | DECOMP_COMPAT, 2007}, + {0x222F, 0, 2 | DECOMP_COMPAT, 2010}, + {0x2230, 0, 3 | DECOMP_COMPAT, 2012}, + {0x2241, 0, 2, 2015}, + {0x2244, 0, 2, 2017}, + {0x2247, 0, 2, 2019}, + {0x2249, 0, 2, 2021}, + {0x2260, 0, 2, 2023}, + {0x2262, 0, 2, 2025}, + {0x226D, 0, 2, 2027}, + {0x226E, 0, 2, 2029}, + {0x226F, 0, 2, 2031}, + {0x2270, 0, 2, 2033}, + {0x2271, 0, 2, 2035}, + {0x2274, 0, 2, 2037}, + {0x2275, 0, 2, 2039}, + {0x2278, 0, 2, 2041}, + {0x2279, 0, 2, 2043}, + {0x2280, 0, 2, 2045}, + {0x2281, 0, 2, 2047}, + {0x2284, 0, 2, 2049}, + {0x2285, 0, 2, 2051}, + {0x2288, 0, 2, 2053}, + {0x2289, 0, 2, 2055}, + {0x22AC, 0, 2, 2057}, + {0x22AD, 0, 2, 2059}, + {0x22AE, 0, 2, 2061}, + {0x22AF, 0, 2, 2063}, + {0x22E0, 0, 2, 2065}, + {0x22E1, 0, 2, 2067}, + {0x22E2, 0, 2, 2069}, + {0x22E3, 0, 2, 2071}, + {0x22EA, 0, 2, 2073}, + {0x22EB, 0, 2, 2075}, + {0x22EC, 0, 2, 2077}, + {0x22ED, 0, 2, 2079}, + {0x2329, 0, 1 | DECOMP_INLINE, 0x3008}, + {0x232A, 0, 1 | DECOMP_INLINE, 0x3009}, + {0x2460, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x2461, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x2462, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x2463, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2464, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2465, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2466, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2467, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2468, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x2469, 0, 2 | DECOMP_COMPAT, 2081}, + {0x246A, 0, 2 | DECOMP_COMPAT, 2083}, + {0x246B, 0, 2 | DECOMP_COMPAT, 2085}, + {0x246C, 0, 2 | DECOMP_COMPAT, 2087}, + {0x246D, 0, 2 | DECOMP_COMPAT, 2089}, + {0x246E, 0, 2 | DECOMP_COMPAT, 2091}, + {0x246F, 0, 2 | DECOMP_COMPAT, 2093}, + {0x2470, 0, 2 | DECOMP_COMPAT, 2095}, + {0x2471, 0, 2 | DECOMP_COMPAT, 2097}, + {0x2472, 0, 2 | DECOMP_COMPAT, 2099}, + {0x2473, 0, 2 | DECOMP_COMPAT, 2101}, + {0x2474, 0, 3 | DECOMP_COMPAT, 2103}, + {0x2475, 0, 3 | DECOMP_COMPAT, 2106}, + {0x2476, 0, 3 | DECOMP_COMPAT, 2109}, + {0x2477, 0, 3 | DECOMP_COMPAT, 2112}, + {0x2478, 0, 3 | DECOMP_COMPAT, 2115}, + {0x2479, 0, 3 | DECOMP_COMPAT, 2118}, + {0x247A, 0, 3 | DECOMP_COMPAT, 2121}, + {0x247B, 0, 3 | DECOMP_COMPAT, 2124}, + {0x247C, 0, 3 | DECOMP_COMPAT, 2127}, + {0x247D, 0, 4 | DECOMP_COMPAT, 2130}, + {0x247E, 0, 4 | DECOMP_COMPAT, 2134}, + {0x247F, 0, 4 | DECOMP_COMPAT, 2138}, + {0x2480, 0, 4 | DECOMP_COMPAT, 2142}, + {0x2481, 0, 4 | DECOMP_COMPAT, 2146}, + {0x2482, 0, 4 | DECOMP_COMPAT, 2150}, + {0x2483, 0, 4 | DECOMP_COMPAT, 2154}, + {0x2484, 0, 4 | DECOMP_COMPAT, 2158}, + {0x2485, 0, 4 | DECOMP_COMPAT, 2162}, + {0x2486, 0, 4 | DECOMP_COMPAT, 2166}, + {0x2487, 0, 4 | DECOMP_COMPAT, 2170}, + {0x2488, 0, 2 | DECOMP_COMPAT, 2174}, + {0x2489, 0, 2 | DECOMP_COMPAT, 2176}, + {0x248A, 0, 2 | DECOMP_COMPAT, 2178}, + {0x248B, 0, 2 | DECOMP_COMPAT, 2180}, + {0x248C, 0, 2 | DECOMP_COMPAT, 2182}, + {0x248D, 0, 2 | DECOMP_COMPAT, 2184}, + {0x248E, 0, 2 | DECOMP_COMPAT, 2186}, + {0x248F, 0, 2 | DECOMP_COMPAT, 2188}, + {0x2490, 0, 2 | DECOMP_COMPAT, 2190}, + {0x2491, 0, 3 | DECOMP_COMPAT, 2192}, + {0x2492, 0, 3 | DECOMP_COMPAT, 2195}, + {0x2493, 0, 3 | DECOMP_COMPAT, 2198}, + {0x2494, 0, 3 | DECOMP_COMPAT, 2201}, + {0x2495, 0, 3 | DECOMP_COMPAT, 2204}, + {0x2496, 0, 3 | DECOMP_COMPAT, 2207}, + {0x2497, 0, 3 | DECOMP_COMPAT, 2210}, + {0x2498, 0, 3 | DECOMP_COMPAT, 2213}, + {0x2499, 0, 3 | DECOMP_COMPAT, 2216}, + {0x249A, 0, 3 | DECOMP_COMPAT, 2219}, + {0x249B, 0, 3 | DECOMP_COMPAT, 2222}, + {0x249C, 0, 3 | DECOMP_COMPAT, 2225}, + {0x249D, 0, 3 | DECOMP_COMPAT, 2228}, + {0x249E, 0, 3 | DECOMP_COMPAT, 2231}, + {0x249F, 0, 3 | DECOMP_COMPAT, 2234}, + {0x24A0, 0, 3 | DECOMP_COMPAT, 2237}, + {0x24A1, 0, 3 | DECOMP_COMPAT, 2240}, + {0x24A2, 0, 3 | DECOMP_COMPAT, 2243}, + {0x24A3, 0, 3 | DECOMP_COMPAT, 2246}, + {0x24A4, 0, 3 | DECOMP_COMPAT, 2249}, + {0x24A5, 0, 3 | DECOMP_COMPAT, 2252}, + {0x24A6, 0, 3 | DECOMP_COMPAT, 2255}, + {0x24A7, 0, 3 | DECOMP_COMPAT, 2258}, + {0x24A8, 0, 3 | DECOMP_COMPAT, 2261}, + {0x24A9, 0, 3 | DECOMP_COMPAT, 2264}, + {0x24AA, 0, 3 | DECOMP_COMPAT, 2267}, + {0x24AB, 0, 3 | DECOMP_COMPAT, 2270}, + {0x24AC, 0, 3 | DECOMP_COMPAT, 2273}, + {0x24AD, 0, 3 | DECOMP_COMPAT, 2276}, + {0x24AE, 0, 3 | DECOMP_COMPAT, 2279}, + {0x24AF, 0, 3 | DECOMP_COMPAT, 2282}, + {0x24B0, 0, 3 | DECOMP_COMPAT, 2285}, + {0x24B1, 0, 3 | DECOMP_COMPAT, 2288}, + {0x24B2, 0, 3 | DECOMP_COMPAT, 2291}, + {0x24B3, 0, 3 | DECOMP_COMPAT, 2294}, + {0x24B4, 0, 3 | DECOMP_COMPAT, 2297}, + {0x24B5, 0, 3 | DECOMP_COMPAT, 2300}, + {0x24B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x24B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x24B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x24B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x24BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x24BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x24BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x24BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x24BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x24BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x24C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x24C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x24C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x24C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x24C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x24C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x24C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x24C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x24C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x24C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x24CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x24CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x24CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x24CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x24CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x24CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x24D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x24D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x24D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x24D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x24D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x24D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x24D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x24D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x24D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x24D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x24DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x24DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x24DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x24DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x24DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x24DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x24E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x24E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x24E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x24E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x24E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x24E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x24E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x24E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x24E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x24E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x24EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2A0C, 0, 4 | DECOMP_COMPAT, 2303}, + {0x2A74, 0, 3 | DECOMP_COMPAT, 2307}, + {0x2A75, 0, 2 | DECOMP_COMPAT, 2310}, + {0x2A76, 0, 3 | DECOMP_COMPAT, 2312}, + {0x2ADC, 0, 2 | DECOMP_NO_COMPOSE, 2315}, /* in exclusion list */ + {0x2C7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x2C7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x2CEF, 230, 0, 0}, + {0x2CF0, 230, 0, 0}, + {0x2CF1, 230, 0, 0}, + {0x2D6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2D61}, + {0x2D7F, 9, 0, 0}, + {0x2DE0, 230, 0, 0}, + {0x2DE1, 230, 0, 0}, + {0x2DE2, 230, 0, 0}, + {0x2DE3, 230, 0, 0}, + {0x2DE4, 230, 0, 0}, + {0x2DE5, 230, 0, 0}, + {0x2DE6, 230, 0, 0}, + {0x2DE7, 230, 0, 0}, + {0x2DE8, 230, 0, 0}, + {0x2DE9, 230, 0, 0}, + {0x2DEA, 230, 0, 0}, + {0x2DEB, 230, 0, 0}, + {0x2DEC, 230, 0, 0}, + {0x2DED, 230, 0, 0}, + {0x2DEE, 230, 0, 0}, + {0x2DEF, 230, 0, 0}, + {0x2DF0, 230, 0, 0}, + {0x2DF1, 230, 0, 0}, + {0x2DF2, 230, 0, 0}, + {0x2DF3, 230, 0, 0}, + {0x2DF4, 230, 0, 0}, + {0x2DF5, 230, 0, 0}, + {0x2DF6, 230, 0, 0}, + {0x2DF7, 230, 0, 0}, + {0x2DF8, 230, 0, 0}, + {0x2DF9, 230, 0, 0}, + {0x2DFA, 230, 0, 0}, + {0x2DFB, 230, 0, 0}, + {0x2DFC, 230, 0, 0}, + {0x2DFD, 230, 0, 0}, + {0x2DFE, 230, 0, 0}, + {0x2DFF, 230, 0, 0}, + {0x2E9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BCD}, + {0x2EF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F9F}, + {0x2F00, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x2F01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E28}, + {0x2F02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E36}, + {0x2F03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E3F}, + {0x2F04, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E59}, + {0x2F05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E85}, + {0x2F06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x2F07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EA0}, + {0x2F08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EBA}, + {0x2F09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x513F}, + {0x2F0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5165}, + {0x2F0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516B}, + {0x2F0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5182}, + {0x2F0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5196}, + {0x2F0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51AB}, + {0x2F0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51E0}, + {0x2F10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51F5}, + {0x2F11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5200}, + {0x2F12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x529B}, + {0x2F13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x52F9}, + {0x2F14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5315}, + {0x2F15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x531A}, + {0x2F16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5338}, + {0x2F17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x2F18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x535C}, + {0x2F19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5369}, + {0x2F1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5382}, + {0x2F1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53B6}, + {0x2F1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53C8}, + {0x2F1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53E3}, + {0x2F1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56D7}, + {0x2F1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x571F}, + {0x2F20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x58EB}, + {0x2F21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5902}, + {0x2F22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x590A}, + {0x2F23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5915}, + {0x2F24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5927}, + {0x2F25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5973}, + {0x2F26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B50}, + {0x2F27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B80}, + {0x2F28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5BF8}, + {0x2F29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C0F}, + {0x2F2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C22}, + {0x2F2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C38}, + {0x2F2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C6E}, + {0x2F2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C71}, + {0x2F2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DDB}, + {0x2F2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE5}, + {0x2F30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DF1}, + {0x2F31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DFE}, + {0x2F32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E72}, + {0x2F33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7A}, + {0x2F34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7F}, + {0x2F35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5EF4}, + {0x2F36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5EFE}, + {0x2F37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F0B}, + {0x2F38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F13}, + {0x2F39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F50}, + {0x2F3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F61}, + {0x2F3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F73}, + {0x2F3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5FC3}, + {0x2F3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6208}, + {0x2F3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6236}, + {0x2F3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x624B}, + {0x2F40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x652F}, + {0x2F41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6534}, + {0x2F42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6587}, + {0x2F43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6597}, + {0x2F44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65A4}, + {0x2F45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65B9}, + {0x2F46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E0}, + {0x2F47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E5}, + {0x2F48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x66F0}, + {0x2F49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x2F4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6728}, + {0x2F4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B20}, + {0x2F4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B62}, + {0x2F4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B79}, + {0x2F4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BB3}, + {0x2F4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BCB}, + {0x2F50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BD4}, + {0x2F51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BDB}, + {0x2F52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C0F}, + {0x2F53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C14}, + {0x2F54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C34}, + {0x2F55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x706B}, + {0x2F56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x722A}, + {0x2F57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7236}, + {0x2F58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x723B}, + {0x2F59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x723F}, + {0x2F5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7247}, + {0x2F5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7259}, + {0x2F5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x725B}, + {0x2F5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x72AC}, + {0x2F5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7384}, + {0x2F5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7389}, + {0x2F60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x74DC}, + {0x2F61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x74E6}, + {0x2F62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7518}, + {0x2F63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x751F}, + {0x2F64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7528}, + {0x2F65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7530}, + {0x2F66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x758B}, + {0x2F67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7592}, + {0x2F68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7676}, + {0x2F69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x767D}, + {0x2F6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76AE}, + {0x2F6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76BF}, + {0x2F6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76EE}, + {0x2F6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77DB}, + {0x2F6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77E2}, + {0x2F6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77F3}, + {0x2F70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x793A}, + {0x2F71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79B8}, + {0x2F72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79BE}, + {0x2F73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7A74}, + {0x2F74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7ACB}, + {0x2F75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7AF9}, + {0x2F76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7C73}, + {0x2F77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7CF8}, + {0x2F78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F36}, + {0x2F79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F51}, + {0x2F7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F8A}, + {0x2F7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7FBD}, + {0x2F7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8001}, + {0x2F7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x800C}, + {0x2F7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8012}, + {0x2F7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8033}, + {0x2F80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x807F}, + {0x2F81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8089}, + {0x2F82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81E3}, + {0x2F83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81EA}, + {0x2F84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81F3}, + {0x2F85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81FC}, + {0x2F86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x820C}, + {0x2F87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x821B}, + {0x2F88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x821F}, + {0x2F89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x826E}, + {0x2F8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8272}, + {0x2F8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8278}, + {0x2F8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x864D}, + {0x2F8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x866B}, + {0x2F8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8840}, + {0x2F8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x884C}, + {0x2F90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8863}, + {0x2F91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x897E}, + {0x2F92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x898B}, + {0x2F93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x89D2}, + {0x2F94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8A00}, + {0x2F95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C37}, + {0x2F96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C46}, + {0x2F97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C55}, + {0x2F98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C78}, + {0x2F99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C9D}, + {0x2F9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D64}, + {0x2F9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D70}, + {0x2F9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8DB3}, + {0x2F9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8EAB}, + {0x2F9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8ECA}, + {0x2F9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8F9B}, + {0x2FA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8FB0}, + {0x2FA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8FB5}, + {0x2FA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9091}, + {0x2FA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9149}, + {0x2FA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91C6}, + {0x2FA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91CC}, + {0x2FA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91D1}, + {0x2FA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9577}, + {0x2FA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9580}, + {0x2FA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x961C}, + {0x2FAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96B6}, + {0x2FAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96B9}, + {0x2FAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96E8}, + {0x2FAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9751}, + {0x2FAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x975E}, + {0x2FAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9762}, + {0x2FB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9769}, + {0x2FB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97CB}, + {0x2FB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97ED}, + {0x2FB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97F3}, + {0x2FB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9801}, + {0x2FB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98A8}, + {0x2FB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98DB}, + {0x2FB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98DF}, + {0x2FB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9996}, + {0x2FB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9999}, + {0x2FBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x99AC}, + {0x2FBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9AA8}, + {0x2FBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9AD8}, + {0x2FBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ADF}, + {0x2FBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B25}, + {0x2FBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B2F}, + {0x2FC0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B32}, + {0x2FC1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B3C}, + {0x2FC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B5A}, + {0x2FC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9CE5}, + {0x2FC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9E75}, + {0x2FC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9E7F}, + {0x2FC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EA5}, + {0x2FC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EBB}, + {0x2FC8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EC3}, + {0x2FC9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ECD}, + {0x2FCA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ED1}, + {0x2FCB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EF9}, + {0x2FCC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EFD}, + {0x2FCD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F0E}, + {0x2FCE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F13}, + {0x2FCF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F20}, + {0x2FD0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F3B}, + {0x2FD1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F4A}, + {0x2FD2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F52}, + {0x2FD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F8D}, + {0x2FD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F9C}, + {0x2FD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9FA0}, + {0x3000, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x302A, 218, 0, 0}, + {0x302B, 228, 0, 0}, + {0x302C, 232, 0, 0}, + {0x302D, 222, 0, 0}, + {0x302E, 224, 0, 0}, + {0x302F, 224, 0, 0}, + {0x3036, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3012}, + {0x3038, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x3039, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5344}, + {0x303A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5345}, + {0x304C, 0, 2, 2317}, + {0x304E, 0, 2, 2319}, + {0x3050, 0, 2, 2321}, + {0x3052, 0, 2, 2323}, + {0x3054, 0, 2, 2325}, + {0x3056, 0, 2, 2327}, + {0x3058, 0, 2, 2329}, + {0x305A, 0, 2, 2331}, + {0x305C, 0, 2, 2333}, + {0x305E, 0, 2, 2335}, + {0x3060, 0, 2, 2337}, + {0x3062, 0, 2, 2339}, + {0x3065, 0, 2, 2341}, + {0x3067, 0, 2, 2343}, + {0x3069, 0, 2, 2345}, + {0x3070, 0, 2, 2347}, + {0x3071, 0, 2, 2349}, + {0x3073, 0, 2, 2351}, + {0x3074, 0, 2, 2353}, + {0x3076, 0, 2, 2355}, + {0x3077, 0, 2, 2357}, + {0x3079, 0, 2, 2359}, + {0x307A, 0, 2, 2361}, + {0x307C, 0, 2, 2363}, + {0x307D, 0, 2, 2365}, + {0x3094, 0, 2, 2367}, + {0x3099, 8, 0, 0}, + {0x309A, 8, 0, 0}, + {0x309B, 0, 2 | DECOMP_COMPAT, 2369}, + {0x309C, 0, 2 | DECOMP_COMPAT, 2371}, + {0x309E, 0, 2, 2373}, + {0x309F, 0, 2 | DECOMP_COMPAT, 2375}, + {0x30AC, 0, 2, 2377}, + {0x30AE, 0, 2, 2379}, + {0x30B0, 0, 2, 2381}, + {0x30B2, 0, 2, 2383}, + {0x30B4, 0, 2, 2385}, + {0x30B6, 0, 2, 2387}, + {0x30B8, 0, 2, 2389}, + {0x30BA, 0, 2, 2391}, + {0x30BC, 0, 2, 2393}, + {0x30BE, 0, 2, 2395}, + {0x30C0, 0, 2, 2397}, + {0x30C2, 0, 2, 2399}, + {0x30C5, 0, 2, 2401}, + {0x30C7, 0, 2, 2403}, + {0x30C9, 0, 2, 2405}, + {0x30D0, 0, 2, 2407}, + {0x30D1, 0, 2, 2409}, + {0x30D3, 0, 2, 2411}, + {0x30D4, 0, 2, 2413}, + {0x30D6, 0, 2, 2415}, + {0x30D7, 0, 2, 2417}, + {0x30D9, 0, 2, 2419}, + {0x30DA, 0, 2, 2421}, + {0x30DC, 0, 2, 2423}, + {0x30DD, 0, 2, 2425}, + {0x30F4, 0, 2, 2427}, + {0x30F7, 0, 2, 2429}, + {0x30F8, 0, 2, 2431}, + {0x30F9, 0, 2, 2433}, + {0x30FA, 0, 2, 2435}, + {0x30FE, 0, 2, 2437}, + {0x30FF, 0, 2 | DECOMP_COMPAT, 2439}, + {0x3131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1100}, + {0x3132, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1101}, + {0x3133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AA}, + {0x3134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1102}, + {0x3135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AC}, + {0x3136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AD}, + {0x3137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1103}, + {0x3138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1104}, + {0x3139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1105}, + {0x313A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B0}, + {0x313B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B1}, + {0x313C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B2}, + {0x313D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B3}, + {0x313E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B4}, + {0x313F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B5}, + {0x3140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111A}, + {0x3141, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1106}, + {0x3142, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1107}, + {0x3143, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1108}, + {0x3144, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1121}, + {0x3145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1109}, + {0x3146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110A}, + {0x3147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110B}, + {0x3148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110C}, + {0x3149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110D}, + {0x314A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110E}, + {0x314B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110F}, + {0x314C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1110}, + {0x314D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1111}, + {0x314E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1112}, + {0x314F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1161}, + {0x3150, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1162}, + {0x3151, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1163}, + {0x3152, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1164}, + {0x3153, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1165}, + {0x3154, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1166}, + {0x3155, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1167}, + {0x3156, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1168}, + {0x3157, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1169}, + {0x3158, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116A}, + {0x3159, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116B}, + {0x315A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116C}, + {0x315B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116D}, + {0x315C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116E}, + {0x315D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116F}, + {0x315E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1170}, + {0x315F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1171}, + {0x3160, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1172}, + {0x3161, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1173}, + {0x3162, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1174}, + {0x3163, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1175}, + {0x3164, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1160}, + {0x3165, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1114}, + {0x3166, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1115}, + {0x3167, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11C7}, + {0x3168, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11C8}, + {0x3169, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11CC}, + {0x316A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11CE}, + {0x316B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D3}, + {0x316C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D7}, + {0x316D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D9}, + {0x316E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111C}, + {0x316F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11DD}, + {0x3170, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11DF}, + {0x3171, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111D}, + {0x3172, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111E}, + {0x3173, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1120}, + {0x3174, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1122}, + {0x3175, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1123}, + {0x3176, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1127}, + {0x3177, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1129}, + {0x3178, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112B}, + {0x3179, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112C}, + {0x317A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112D}, + {0x317B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112E}, + {0x317C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112F}, + {0x317D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1132}, + {0x317E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1136}, + {0x317F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1140}, + {0x3180, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1147}, + {0x3181, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x114C}, + {0x3182, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11F1}, + {0x3183, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11F2}, + {0x3184, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1157}, + {0x3185, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1158}, + {0x3186, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1159}, + {0x3187, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1184}, + {0x3188, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1185}, + {0x3189, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1188}, + {0x318A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1191}, + {0x318B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1192}, + {0x318C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1194}, + {0x318D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x119E}, + {0x318E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11A1}, + {0x3192, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x3193, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x3194, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x3195, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56DB}, + {0x3196, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0A}, + {0x3197, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x3198, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0B}, + {0x3199, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7532}, + {0x319A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E59}, + {0x319B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E19}, + {0x319C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E01}, + {0x319D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5929}, + {0x319E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5730}, + {0x319F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EBA}, + {0x3200, 0, 3 | DECOMP_COMPAT, 2441}, + {0x3201, 0, 3 | DECOMP_COMPAT, 2444}, + {0x3202, 0, 3 | DECOMP_COMPAT, 2447}, + {0x3203, 0, 3 | DECOMP_COMPAT, 2450}, + {0x3204, 0, 3 | DECOMP_COMPAT, 2453}, + {0x3205, 0, 3 | DECOMP_COMPAT, 2456}, + {0x3206, 0, 3 | DECOMP_COMPAT, 2459}, + {0x3207, 0, 3 | DECOMP_COMPAT, 2462}, + {0x3208, 0, 3 | DECOMP_COMPAT, 2465}, + {0x3209, 0, 3 | DECOMP_COMPAT, 2468}, + {0x320A, 0, 3 | DECOMP_COMPAT, 2471}, + {0x320B, 0, 3 | DECOMP_COMPAT, 2474}, + {0x320C, 0, 3 | DECOMP_COMPAT, 2477}, + {0x320D, 0, 3 | DECOMP_COMPAT, 2480}, + {0x320E, 0, 4 | DECOMP_COMPAT, 2483}, + {0x320F, 0, 4 | DECOMP_COMPAT, 2487}, + {0x3210, 0, 4 | DECOMP_COMPAT, 2491}, + {0x3211, 0, 4 | DECOMP_COMPAT, 2495}, + {0x3212, 0, 4 | DECOMP_COMPAT, 2499}, + {0x3213, 0, 4 | DECOMP_COMPAT, 2503}, + {0x3214, 0, 4 | DECOMP_COMPAT, 2507}, + {0x3215, 0, 4 | DECOMP_COMPAT, 2511}, + {0x3216, 0, 4 | DECOMP_COMPAT, 2515}, + {0x3217, 0, 4 | DECOMP_COMPAT, 2519}, + {0x3218, 0, 4 | DECOMP_COMPAT, 2523}, + {0x3219, 0, 4 | DECOMP_COMPAT, 2527}, + {0x321A, 0, 4 | DECOMP_COMPAT, 2531}, + {0x321B, 0, 4 | DECOMP_COMPAT, 2535}, + {0x321C, 0, 4 | DECOMP_COMPAT, 2539}, + {0x321D, 0, 7 | DECOMP_COMPAT, 2543}, + {0x321E, 0, 6 | DECOMP_COMPAT, 2550}, + {0x3220, 0, 3 | DECOMP_COMPAT, 2556}, + {0x3221, 0, 3 | DECOMP_COMPAT, 2559}, + {0x3222, 0, 3 | DECOMP_COMPAT, 2562}, + {0x3223, 0, 3 | DECOMP_COMPAT, 2565}, + {0x3224, 0, 3 | DECOMP_COMPAT, 2568}, + {0x3225, 0, 3 | DECOMP_COMPAT, 2571}, + {0x3226, 0, 3 | DECOMP_COMPAT, 2574}, + {0x3227, 0, 3 | DECOMP_COMPAT, 2577}, + {0x3228, 0, 3 | DECOMP_COMPAT, 2580}, + {0x3229, 0, 3 | DECOMP_COMPAT, 2583}, + {0x322A, 0, 3 | DECOMP_COMPAT, 2586}, + {0x322B, 0, 3 | DECOMP_COMPAT, 2589}, + {0x322C, 0, 3 | DECOMP_COMPAT, 2592}, + {0x322D, 0, 3 | DECOMP_COMPAT, 2595}, + {0x322E, 0, 3 | DECOMP_COMPAT, 2598}, + {0x322F, 0, 3 | DECOMP_COMPAT, 2601}, + {0x3230, 0, 3 | DECOMP_COMPAT, 2604}, + {0x3231, 0, 3 | DECOMP_COMPAT, 2607}, + {0x3232, 0, 3 | DECOMP_COMPAT, 2610}, + {0x3233, 0, 3 | DECOMP_COMPAT, 2613}, + {0x3234, 0, 3 | DECOMP_COMPAT, 2616}, + {0x3235, 0, 3 | DECOMP_COMPAT, 2619}, + {0x3236, 0, 3 | DECOMP_COMPAT, 2622}, + {0x3237, 0, 3 | DECOMP_COMPAT, 2625}, + {0x3238, 0, 3 | DECOMP_COMPAT, 2628}, + {0x3239, 0, 3 | DECOMP_COMPAT, 2631}, + {0x323A, 0, 3 | DECOMP_COMPAT, 2634}, + {0x323B, 0, 3 | DECOMP_COMPAT, 2637}, + {0x323C, 0, 3 | DECOMP_COMPAT, 2640}, + {0x323D, 0, 3 | DECOMP_COMPAT, 2643}, + {0x323E, 0, 3 | DECOMP_COMPAT, 2646}, + {0x323F, 0, 3 | DECOMP_COMPAT, 2649}, + {0x3240, 0, 3 | DECOMP_COMPAT, 2652}, + {0x3241, 0, 3 | DECOMP_COMPAT, 2655}, + {0x3242, 0, 3 | DECOMP_COMPAT, 2658}, + {0x3243, 0, 3 | DECOMP_COMPAT, 2661}, + {0x3244, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x554F}, + {0x3245, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7C}, + {0x3246, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6587}, + {0x3247, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7B8F}, + {0x3250, 0, 3 | DECOMP_COMPAT, 2664}, + {0x3251, 0, 2 | DECOMP_COMPAT, 2667}, + {0x3252, 0, 2 | DECOMP_COMPAT, 2669}, + {0x3253, 0, 2 | DECOMP_COMPAT, 2671}, + {0x3254, 0, 2 | DECOMP_COMPAT, 2673}, + {0x3255, 0, 2 | DECOMP_COMPAT, 2675}, + {0x3256, 0, 2 | DECOMP_COMPAT, 2677}, + {0x3257, 0, 2 | DECOMP_COMPAT, 2679}, + {0x3258, 0, 2 | DECOMP_COMPAT, 2681}, + {0x3259, 0, 2 | DECOMP_COMPAT, 2683}, + {0x325A, 0, 2 | DECOMP_COMPAT, 2685}, + {0x325B, 0, 2 | DECOMP_COMPAT, 2687}, + {0x325C, 0, 2 | DECOMP_COMPAT, 2689}, + {0x325D, 0, 2 | DECOMP_COMPAT, 2691}, + {0x325E, 0, 2 | DECOMP_COMPAT, 2693}, + {0x325F, 0, 2 | DECOMP_COMPAT, 2695}, + {0x3260, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1100}, + {0x3261, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1102}, + {0x3262, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1103}, + {0x3263, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1105}, + {0x3264, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1106}, + {0x3265, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1107}, + {0x3266, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1109}, + {0x3267, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110B}, + {0x3268, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110C}, + {0x3269, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110E}, + {0x326A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110F}, + {0x326B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1110}, + {0x326C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1111}, + {0x326D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1112}, + {0x326E, 0, 2 | DECOMP_COMPAT, 2697}, + {0x326F, 0, 2 | DECOMP_COMPAT, 2699}, + {0x3270, 0, 2 | DECOMP_COMPAT, 2701}, + {0x3271, 0, 2 | DECOMP_COMPAT, 2703}, + {0x3272, 0, 2 | DECOMP_COMPAT, 2705}, + {0x3273, 0, 2 | DECOMP_COMPAT, 2707}, + {0x3274, 0, 2 | DECOMP_COMPAT, 2709}, + {0x3275, 0, 2 | DECOMP_COMPAT, 2711}, + {0x3276, 0, 2 | DECOMP_COMPAT, 2713}, + {0x3277, 0, 2 | DECOMP_COMPAT, 2715}, + {0x3278, 0, 2 | DECOMP_COMPAT, 2717}, + {0x3279, 0, 2 | DECOMP_COMPAT, 2719}, + {0x327A, 0, 2 | DECOMP_COMPAT, 2721}, + {0x327B, 0, 2 | DECOMP_COMPAT, 2723}, + {0x327C, 0, 5 | DECOMP_COMPAT, 2725}, + {0x327D, 0, 4 | DECOMP_COMPAT, 2730}, + {0x327E, 0, 2 | DECOMP_COMPAT, 2734}, + {0x3280, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x3281, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x3282, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x3283, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56DB}, + {0x3284, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E94}, + {0x3285, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516D}, + {0x3286, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E03}, + {0x3287, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516B}, + {0x3288, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E5D}, + {0x3289, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x328A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x328B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x706B}, + {0x328C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C34}, + {0x328D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6728}, + {0x328E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91D1}, + {0x328F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x571F}, + {0x3290, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E5}, + {0x3291, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x682A}, + {0x3292, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6709}, + {0x3293, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x793E}, + {0x3294, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x540D}, + {0x3295, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7279}, + {0x3296, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CA1}, + {0x3297, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x795D}, + {0x3298, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x52B4}, + {0x3299, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79D8}, + {0x329A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7537}, + {0x329B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5973}, + {0x329C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9069}, + {0x329D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x512A}, + {0x329E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5370}, + {0x329F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6CE8}, + {0x32A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9805}, + {0x32A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4F11}, + {0x32A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5199}, + {0x32A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B63}, + {0x32A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0A}, + {0x32A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x32A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0B}, + {0x32A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE6}, + {0x32A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53F3}, + {0x32A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x533B}, + {0x32AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B97}, + {0x32AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B66}, + {0x32AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76E3}, + {0x32AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4F01}, + {0x32AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CC7}, + {0x32AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5354}, + {0x32B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x591C}, + {0x32B1, 0, 2 | DECOMP_COMPAT, 2736}, + {0x32B2, 0, 2 | DECOMP_COMPAT, 2738}, + {0x32B3, 0, 2 | DECOMP_COMPAT, 2740}, + {0x32B4, 0, 2 | DECOMP_COMPAT, 2742}, + {0x32B5, 0, 2 | DECOMP_COMPAT, 2744}, + {0x32B6, 0, 2 | DECOMP_COMPAT, 2746}, + {0x32B7, 0, 2 | DECOMP_COMPAT, 2748}, + {0x32B8, 0, 2 | DECOMP_COMPAT, 2750}, + {0x32B9, 0, 2 | DECOMP_COMPAT, 2752}, + {0x32BA, 0, 2 | DECOMP_COMPAT, 2754}, + {0x32BB, 0, 2 | DECOMP_COMPAT, 2756}, + {0x32BC, 0, 2 | DECOMP_COMPAT, 2758}, + {0x32BD, 0, 2 | DECOMP_COMPAT, 2760}, + {0x32BE, 0, 2 | DECOMP_COMPAT, 2762}, + {0x32BF, 0, 2 | DECOMP_COMPAT, 2764}, + {0x32C0, 0, 2 | DECOMP_COMPAT, 2766}, + {0x32C1, 0, 2 | DECOMP_COMPAT, 2768}, + {0x32C2, 0, 2 | DECOMP_COMPAT, 2770}, + {0x32C3, 0, 2 | DECOMP_COMPAT, 2772}, + {0x32C4, 0, 2 | DECOMP_COMPAT, 2774}, + {0x32C5, 0, 2 | DECOMP_COMPAT, 2776}, + {0x32C6, 0, 2 | DECOMP_COMPAT, 2778}, + {0x32C7, 0, 2 | DECOMP_COMPAT, 2780}, + {0x32C8, 0, 2 | DECOMP_COMPAT, 2782}, + {0x32C9, 0, 3 | DECOMP_COMPAT, 2784}, + {0x32CA, 0, 3 | DECOMP_COMPAT, 2787}, + {0x32CB, 0, 3 | DECOMP_COMPAT, 2790}, + {0x32CC, 0, 2 | DECOMP_COMPAT, 2793}, + {0x32CD, 0, 3 | DECOMP_COMPAT, 2795}, + {0x32CE, 0, 2 | DECOMP_COMPAT, 2798}, + {0x32CF, 0, 3 | DECOMP_COMPAT, 2800}, + {0x32D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A2}, + {0x32D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A4}, + {0x32D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A6}, + {0x32D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A8}, + {0x32D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AA}, + {0x32D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AB}, + {0x32D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AD}, + {0x32D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AF}, + {0x32D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B1}, + {0x32D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B3}, + {0x32DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0x32DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B7}, + {0x32DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B9}, + {0x32DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BB}, + {0x32DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BD}, + {0x32DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BF}, + {0x32E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C1}, + {0x32E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C4}, + {0x32E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C6}, + {0x32E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C8}, + {0x32E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CA}, + {0x32E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CB}, + {0x32E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CC}, + {0x32E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CD}, + {0x32E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CE}, + {0x32E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CF}, + {0x32EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D2}, + {0x32EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D5}, + {0x32EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D8}, + {0x32ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DB}, + {0x32EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DE}, + {0x32EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DF}, + {0x32F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E0}, + {0x32F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E1}, + {0x32F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E2}, + {0x32F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E4}, + {0x32F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E6}, + {0x32F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E8}, + {0x32F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E9}, + {0x32F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EA}, + {0x32F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EB}, + {0x32F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EC}, + {0x32FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30ED}, + {0x32FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EF}, + {0x32FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F0}, + {0x32FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F1}, + {0x32FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F2}, + {0x32FF, 0, 2 | DECOMP_COMPAT, 2803}, + {0x3300, 0, 4 | DECOMP_COMPAT, 2805}, + {0x3301, 0, 4 | DECOMP_COMPAT, 2809}, + {0x3302, 0, 4 | DECOMP_COMPAT, 2813}, + {0x3303, 0, 3 | DECOMP_COMPAT, 2817}, + {0x3304, 0, 4 | DECOMP_COMPAT, 2820}, + {0x3305, 0, 3 | DECOMP_COMPAT, 2824}, + {0x3306, 0, 3 | DECOMP_COMPAT, 2827}, + {0x3307, 0, 5 | DECOMP_COMPAT, 2830}, + {0x3308, 0, 4 | DECOMP_COMPAT, 2835}, + {0x3309, 0, 3 | DECOMP_COMPAT, 2839}, + {0x330A, 0, 3 | DECOMP_COMPAT, 2842}, + {0x330B, 0, 3 | DECOMP_COMPAT, 2845}, + {0x330C, 0, 4 | DECOMP_COMPAT, 2848}, + {0x330D, 0, 4 | DECOMP_COMPAT, 2852}, + {0x330E, 0, 3 | DECOMP_COMPAT, 2856}, + {0x330F, 0, 3 | DECOMP_COMPAT, 2859}, + {0x3310, 0, 2 | DECOMP_COMPAT, 2862}, + {0x3311, 0, 3 | DECOMP_COMPAT, 2864}, + {0x3312, 0, 4 | DECOMP_COMPAT, 2867}, + {0x3313, 0, 4 | DECOMP_COMPAT, 2871}, + {0x3314, 0, 2 | DECOMP_COMPAT, 2875}, + {0x3315, 0, 5 | DECOMP_COMPAT, 2877}, + {0x3316, 0, 6 | DECOMP_COMPAT, 2882}, + {0x3317, 0, 5 | DECOMP_COMPAT, 2888}, + {0x3318, 0, 3 | DECOMP_COMPAT, 2893}, + {0x3319, 0, 5 | DECOMP_COMPAT, 2896}, + {0x331A, 0, 5 | DECOMP_COMPAT, 2901}, + {0x331B, 0, 4 | DECOMP_COMPAT, 2906}, + {0x331C, 0, 3 | DECOMP_COMPAT, 2910}, + {0x331D, 0, 3 | DECOMP_COMPAT, 2913}, + {0x331E, 0, 3 | DECOMP_COMPAT, 2916}, + {0x331F, 0, 4 | DECOMP_COMPAT, 2919}, + {0x3320, 0, 5 | DECOMP_COMPAT, 2923}, + {0x3321, 0, 4 | DECOMP_COMPAT, 2928}, + {0x3322, 0, 3 | DECOMP_COMPAT, 2932}, + {0x3323, 0, 3 | DECOMP_COMPAT, 2935}, + {0x3324, 0, 3 | DECOMP_COMPAT, 2938}, + {0x3325, 0, 2 | DECOMP_COMPAT, 2941}, + {0x3326, 0, 2 | DECOMP_COMPAT, 2943}, + {0x3327, 0, 2 | DECOMP_COMPAT, 2945}, + {0x3328, 0, 2 | DECOMP_COMPAT, 2947}, + {0x3329, 0, 3 | DECOMP_COMPAT, 2949}, + {0x332A, 0, 3 | DECOMP_COMPAT, 2952}, + {0x332B, 0, 5 | DECOMP_COMPAT, 2955}, + {0x332C, 0, 3 | DECOMP_COMPAT, 2960}, + {0x332D, 0, 4 | DECOMP_COMPAT, 2963}, + {0x332E, 0, 5 | DECOMP_COMPAT, 2967}, + {0x332F, 0, 3 | DECOMP_COMPAT, 2972}, + {0x3330, 0, 2 | DECOMP_COMPAT, 2975}, + {0x3331, 0, 2 | DECOMP_COMPAT, 2977}, + {0x3332, 0, 5 | DECOMP_COMPAT, 2979}, + {0x3333, 0, 4 | DECOMP_COMPAT, 2984}, + {0x3334, 0, 5 | DECOMP_COMPAT, 2988}, + {0x3335, 0, 3 | DECOMP_COMPAT, 2993}, + {0x3336, 0, 5 | DECOMP_COMPAT, 2996}, + {0x3337, 0, 2 | DECOMP_COMPAT, 3001}, + {0x3338, 0, 3 | DECOMP_COMPAT, 3003}, + {0x3339, 0, 3 | DECOMP_COMPAT, 3006}, + {0x333A, 0, 3 | DECOMP_COMPAT, 3009}, + {0x333B, 0, 3 | DECOMP_COMPAT, 3012}, + {0x333C, 0, 3 | DECOMP_COMPAT, 3015}, + {0x333D, 0, 4 | DECOMP_COMPAT, 3018}, + {0x333E, 0, 3 | DECOMP_COMPAT, 3022}, + {0x333F, 0, 2 | DECOMP_COMPAT, 3025}, + {0x3340, 0, 3 | DECOMP_COMPAT, 3027}, + {0x3341, 0, 3 | DECOMP_COMPAT, 3030}, + {0x3342, 0, 3 | DECOMP_COMPAT, 3033}, + {0x3343, 0, 4 | DECOMP_COMPAT, 3036}, + {0x3344, 0, 3 | DECOMP_COMPAT, 3040}, + {0x3345, 0, 3 | DECOMP_COMPAT, 3043}, + {0x3346, 0, 3 | DECOMP_COMPAT, 3046}, + {0x3347, 0, 5 | DECOMP_COMPAT, 3049}, + {0x3348, 0, 4 | DECOMP_COMPAT, 3054}, + {0x3349, 0, 2 | DECOMP_COMPAT, 3058}, + {0x334A, 0, 5 | DECOMP_COMPAT, 3060}, + {0x334B, 0, 2 | DECOMP_COMPAT, 3065}, + {0x334C, 0, 4 | DECOMP_COMPAT, 3067}, + {0x334D, 0, 4 | DECOMP_COMPAT, 3071}, + {0x334E, 0, 3 | DECOMP_COMPAT, 3075}, + {0x334F, 0, 3 | DECOMP_COMPAT, 3078}, + {0x3350, 0, 3 | DECOMP_COMPAT, 3081}, + {0x3351, 0, 4 | DECOMP_COMPAT, 3084}, + {0x3352, 0, 2 | DECOMP_COMPAT, 3088}, + {0x3353, 0, 3 | DECOMP_COMPAT, 3090}, + {0x3354, 0, 4 | DECOMP_COMPAT, 3093}, + {0x3355, 0, 2 | DECOMP_COMPAT, 3097}, + {0x3356, 0, 5 | DECOMP_COMPAT, 3099}, + {0x3357, 0, 3 | DECOMP_COMPAT, 3104}, + {0x3358, 0, 2 | DECOMP_COMPAT, 3107}, + {0x3359, 0, 2 | DECOMP_COMPAT, 3109}, + {0x335A, 0, 2 | DECOMP_COMPAT, 3111}, + {0x335B, 0, 2 | DECOMP_COMPAT, 3113}, + {0x335C, 0, 2 | DECOMP_COMPAT, 3115}, + {0x335D, 0, 2 | DECOMP_COMPAT, 3117}, + {0x335E, 0, 2 | DECOMP_COMPAT, 3119}, + {0x335F, 0, 2 | DECOMP_COMPAT, 3121}, + {0x3360, 0, 2 | DECOMP_COMPAT, 3123}, + {0x3361, 0, 2 | DECOMP_COMPAT, 3125}, + {0x3362, 0, 3 | DECOMP_COMPAT, 3127}, + {0x3363, 0, 3 | DECOMP_COMPAT, 3130}, + {0x3364, 0, 3 | DECOMP_COMPAT, 3133}, + {0x3365, 0, 3 | DECOMP_COMPAT, 3136}, + {0x3366, 0, 3 | DECOMP_COMPAT, 3139}, + {0x3367, 0, 3 | DECOMP_COMPAT, 3142}, + {0x3368, 0, 3 | DECOMP_COMPAT, 3145}, + {0x3369, 0, 3 | DECOMP_COMPAT, 3148}, + {0x336A, 0, 3 | DECOMP_COMPAT, 3151}, + {0x336B, 0, 3 | DECOMP_COMPAT, 3154}, + {0x336C, 0, 3 | DECOMP_COMPAT, 3157}, + {0x336D, 0, 3 | DECOMP_COMPAT, 3160}, + {0x336E, 0, 3 | DECOMP_COMPAT, 3163}, + {0x336F, 0, 3 | DECOMP_COMPAT, 3166}, + {0x3370, 0, 3 | DECOMP_COMPAT, 3169}, + {0x3371, 0, 3 | DECOMP_COMPAT, 3172}, + {0x3372, 0, 2 | DECOMP_COMPAT, 3175}, + {0x3373, 0, 2 | DECOMP_COMPAT, 3177}, + {0x3374, 0, 3 | DECOMP_COMPAT, 3179}, + {0x3375, 0, 2 | DECOMP_COMPAT, 3182}, + {0x3376, 0, 2 | DECOMP_COMPAT, 3184}, + {0x3377, 0, 2 | DECOMP_COMPAT, 3186}, + {0x3378, 0, 3 | DECOMP_COMPAT, 3188}, + {0x3379, 0, 3 | DECOMP_COMPAT, 3191}, + {0x337A, 0, 2 | DECOMP_COMPAT, 3194}, + {0x337B, 0, 2 | DECOMP_COMPAT, 3196}, + {0x337C, 0, 2 | DECOMP_COMPAT, 3198}, + {0x337D, 0, 2 | DECOMP_COMPAT, 3200}, + {0x337E, 0, 2 | DECOMP_COMPAT, 3202}, + {0x337F, 0, 4 | DECOMP_COMPAT, 3204}, + {0x3380, 0, 2 | DECOMP_COMPAT, 3208}, + {0x3381, 0, 2 | DECOMP_COMPAT, 3210}, + {0x3382, 0, 2 | DECOMP_COMPAT, 3212}, + {0x3383, 0, 2 | DECOMP_COMPAT, 3214}, + {0x3384, 0, 2 | DECOMP_COMPAT, 3216}, + {0x3385, 0, 2 | DECOMP_COMPAT, 3218}, + {0x3386, 0, 2 | DECOMP_COMPAT, 3220}, + {0x3387, 0, 2 | DECOMP_COMPAT, 3222}, + {0x3388, 0, 3 | DECOMP_COMPAT, 3224}, + {0x3389, 0, 4 | DECOMP_COMPAT, 3227}, + {0x338A, 0, 2 | DECOMP_COMPAT, 3231}, + {0x338B, 0, 2 | DECOMP_COMPAT, 3233}, + {0x338C, 0, 2 | DECOMP_COMPAT, 3235}, + {0x338D, 0, 2 | DECOMP_COMPAT, 3237}, + {0x338E, 0, 2 | DECOMP_COMPAT, 3239}, + {0x338F, 0, 2 | DECOMP_COMPAT, 3241}, + {0x3390, 0, 2 | DECOMP_COMPAT, 3243}, + {0x3391, 0, 3 | DECOMP_COMPAT, 3245}, + {0x3392, 0, 3 | DECOMP_COMPAT, 3248}, + {0x3393, 0, 3 | DECOMP_COMPAT, 3251}, + {0x3394, 0, 3 | DECOMP_COMPAT, 3254}, + {0x3395, 0, 2 | DECOMP_COMPAT, 3257}, + {0x3396, 0, 2 | DECOMP_COMPAT, 3259}, + {0x3397, 0, 2 | DECOMP_COMPAT, 3261}, + {0x3398, 0, 2 | DECOMP_COMPAT, 3263}, + {0x3399, 0, 2 | DECOMP_COMPAT, 3265}, + {0x339A, 0, 2 | DECOMP_COMPAT, 3267}, + {0x339B, 0, 2 | DECOMP_COMPAT, 3269}, + {0x339C, 0, 2 | DECOMP_COMPAT, 3271}, + {0x339D, 0, 2 | DECOMP_COMPAT, 3273}, + {0x339E, 0, 2 | DECOMP_COMPAT, 3275}, + {0x339F, 0, 3 | DECOMP_COMPAT, 3277}, + {0x33A0, 0, 3 | DECOMP_COMPAT, 3280}, + {0x33A1, 0, 2 | DECOMP_COMPAT, 3283}, + {0x33A2, 0, 3 | DECOMP_COMPAT, 3285}, + {0x33A3, 0, 3 | DECOMP_COMPAT, 3288}, + {0x33A4, 0, 3 | DECOMP_COMPAT, 3291}, + {0x33A5, 0, 2 | DECOMP_COMPAT, 3294}, + {0x33A6, 0, 3 | DECOMP_COMPAT, 3296}, + {0x33A7, 0, 3 | DECOMP_COMPAT, 3299}, + {0x33A8, 0, 4 | DECOMP_COMPAT, 3302}, + {0x33A9, 0, 2 | DECOMP_COMPAT, 3306}, + {0x33AA, 0, 3 | DECOMP_COMPAT, 3308}, + {0x33AB, 0, 3 | DECOMP_COMPAT, 3311}, + {0x33AC, 0, 3 | DECOMP_COMPAT, 3314}, + {0x33AD, 0, 3 | DECOMP_COMPAT, 3317}, + {0x33AE, 0, 5 | DECOMP_COMPAT, 3320}, + {0x33AF, 0, 6 | DECOMP_COMPAT, 3325}, + {0x33B0, 0, 2 | DECOMP_COMPAT, 3331}, + {0x33B1, 0, 2 | DECOMP_COMPAT, 3333}, + {0x33B2, 0, 2 | DECOMP_COMPAT, 3335}, + {0x33B3, 0, 2 | DECOMP_COMPAT, 3337}, + {0x33B4, 0, 2 | DECOMP_COMPAT, 3339}, + {0x33B5, 0, 2 | DECOMP_COMPAT, 3341}, + {0x33B6, 0, 2 | DECOMP_COMPAT, 3343}, + {0x33B7, 0, 2 | DECOMP_COMPAT, 3345}, + {0x33B8, 0, 2 | DECOMP_COMPAT, 3347}, + {0x33B9, 0, 2 | DECOMP_COMPAT, 3349}, + {0x33BA, 0, 2 | DECOMP_COMPAT, 3351}, + {0x33BB, 0, 2 | DECOMP_COMPAT, 3353}, + {0x33BC, 0, 2 | DECOMP_COMPAT, 3355}, + {0x33BD, 0, 2 | DECOMP_COMPAT, 3357}, + {0x33BE, 0, 2 | DECOMP_COMPAT, 3359}, + {0x33BF, 0, 2 | DECOMP_COMPAT, 3361}, + {0x33C0, 0, 2 | DECOMP_COMPAT, 3363}, + {0x33C1, 0, 2 | DECOMP_COMPAT, 3365}, + {0x33C2, 0, 4 | DECOMP_COMPAT, 3367}, + {0x33C3, 0, 2 | DECOMP_COMPAT, 3371}, + {0x33C4, 0, 2 | DECOMP_COMPAT, 3373}, + {0x33C5, 0, 2 | DECOMP_COMPAT, 3375}, + {0x33C6, 0, 4 | DECOMP_COMPAT, 3377}, + {0x33C7, 0, 3 | DECOMP_COMPAT, 3381}, + {0x33C8, 0, 2 | DECOMP_COMPAT, 3384}, + {0x33C9, 0, 2 | DECOMP_COMPAT, 3386}, + {0x33CA, 0, 2 | DECOMP_COMPAT, 3388}, + {0x33CB, 0, 2 | DECOMP_COMPAT, 3390}, + {0x33CC, 0, 2 | DECOMP_COMPAT, 3392}, + {0x33CD, 0, 2 | DECOMP_COMPAT, 3394}, + {0x33CE, 0, 2 | DECOMP_COMPAT, 3396}, + {0x33CF, 0, 2 | DECOMP_COMPAT, 3398}, + {0x33D0, 0, 2 | DECOMP_COMPAT, 3400}, + {0x33D1, 0, 2 | DECOMP_COMPAT, 3402}, + {0x33D2, 0, 3 | DECOMP_COMPAT, 3404}, + {0x33D3, 0, 2 | DECOMP_COMPAT, 3407}, + {0x33D4, 0, 2 | DECOMP_COMPAT, 3409}, + {0x33D5, 0, 3 | DECOMP_COMPAT, 3411}, + {0x33D6, 0, 3 | DECOMP_COMPAT, 3414}, + {0x33D7, 0, 2 | DECOMP_COMPAT, 3417}, + {0x33D8, 0, 4 | DECOMP_COMPAT, 3419}, + {0x33D9, 0, 3 | DECOMP_COMPAT, 3423}, + {0x33DA, 0, 2 | DECOMP_COMPAT, 3426}, + {0x33DB, 0, 2 | DECOMP_COMPAT, 3428}, + {0x33DC, 0, 2 | DECOMP_COMPAT, 3430}, + {0x33DD, 0, 2 | DECOMP_COMPAT, 3432}, + {0x33DE, 0, 3 | DECOMP_COMPAT, 3434}, + {0x33DF, 0, 3 | DECOMP_COMPAT, 3437}, + {0x33E0, 0, 2 | DECOMP_COMPAT, 3440}, + {0x33E1, 0, 2 | DECOMP_COMPAT, 3442}, + {0x33E2, 0, 2 | DECOMP_COMPAT, 3444}, + {0x33E3, 0, 2 | DECOMP_COMPAT, 3446}, + {0x33E4, 0, 2 | DECOMP_COMPAT, 3448}, + {0x33E5, 0, 2 | DECOMP_COMPAT, 3450}, + {0x33E6, 0, 2 | DECOMP_COMPAT, 3452}, + {0x33E7, 0, 2 | DECOMP_COMPAT, 3454}, + {0x33E8, 0, 2 | DECOMP_COMPAT, 3456}, + {0x33E9, 0, 3 | DECOMP_COMPAT, 3458}, + {0x33EA, 0, 3 | DECOMP_COMPAT, 3461}, + {0x33EB, 0, 3 | DECOMP_COMPAT, 3464}, + {0x33EC, 0, 3 | DECOMP_COMPAT, 3467}, + {0x33ED, 0, 3 | DECOMP_COMPAT, 3470}, + {0x33EE, 0, 3 | DECOMP_COMPAT, 3473}, + {0x33EF, 0, 3 | DECOMP_COMPAT, 3476}, + {0x33F0, 0, 3 | DECOMP_COMPAT, 3479}, + {0x33F1, 0, 3 | DECOMP_COMPAT, 3482}, + {0x33F2, 0, 3 | DECOMP_COMPAT, 3485}, + {0x33F3, 0, 3 | DECOMP_COMPAT, 3488}, + {0x33F4, 0, 3 | DECOMP_COMPAT, 3491}, + {0x33F5, 0, 3 | DECOMP_COMPAT, 3494}, + {0x33F6, 0, 3 | DECOMP_COMPAT, 3497}, + {0x33F7, 0, 3 | DECOMP_COMPAT, 3500}, + {0x33F8, 0, 3 | DECOMP_COMPAT, 3503}, + {0x33F9, 0, 3 | DECOMP_COMPAT, 3506}, + {0x33FA, 0, 3 | DECOMP_COMPAT, 3509}, + {0x33FB, 0, 3 | DECOMP_COMPAT, 3512}, + {0x33FC, 0, 3 | DECOMP_COMPAT, 3515}, + {0x33FD, 0, 3 | DECOMP_COMPAT, 3518}, + {0x33FE, 0, 3 | DECOMP_COMPAT, 3521}, + {0x33FF, 0, 3 | DECOMP_COMPAT, 3524}, + {0xA66F, 230, 0, 0}, + {0xA674, 230, 0, 0}, + {0xA675, 230, 0, 0}, + {0xA676, 230, 0, 0}, + {0xA677, 230, 0, 0}, + {0xA678, 230, 0, 0}, + {0xA679, 230, 0, 0}, + {0xA67A, 230, 0, 0}, + {0xA67B, 230, 0, 0}, + {0xA67C, 230, 0, 0}, + {0xA67D, 230, 0, 0}, + {0xA69C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044A}, + {0xA69D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044C}, + {0xA69E, 230, 0, 0}, + {0xA69F, 230, 0, 0}, + {0xA6F0, 230, 0, 0}, + {0xA6F1, 230, 0, 0}, + {0xA770, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA76F}, + {0xA7F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0xA7F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0xA7F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0xA7F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0126}, + {0xA7F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0153}, + {0xA806, 9, 0, 0}, + {0xA82C, 9, 0, 0}, + {0xA8C4, 9, 0, 0}, + {0xA8E0, 230, 0, 0}, + {0xA8E1, 230, 0, 0}, + {0xA8E2, 230, 0, 0}, + {0xA8E3, 230, 0, 0}, + {0xA8E4, 230, 0, 0}, + {0xA8E5, 230, 0, 0}, + {0xA8E6, 230, 0, 0}, + {0xA8E7, 230, 0, 0}, + {0xA8E8, 230, 0, 0}, + {0xA8E9, 230, 0, 0}, + {0xA8EA, 230, 0, 0}, + {0xA8EB, 230, 0, 0}, + {0xA8EC, 230, 0, 0}, + {0xA8ED, 230, 0, 0}, + {0xA8EE, 230, 0, 0}, + {0xA8EF, 230, 0, 0}, + {0xA8F0, 230, 0, 0}, + {0xA8F1, 230, 0, 0}, + {0xA92B, 220, 0, 0}, + {0xA92C, 220, 0, 0}, + {0xA92D, 220, 0, 0}, + {0xA953, 9, 0, 0}, + {0xA9B3, 7, 0, 0}, + {0xA9C0, 9, 0, 0}, + {0xAAB0, 230, 0, 0}, + {0xAAB2, 230, 0, 0}, + {0xAAB3, 230, 0, 0}, + {0xAAB4, 220, 0, 0}, + {0xAAB7, 230, 0, 0}, + {0xAAB8, 230, 0, 0}, + {0xAABE, 230, 0, 0}, + {0xAABF, 230, 0, 0}, + {0xAAC1, 230, 0, 0}, + {0xAAF6, 9, 0, 0}, + {0xAB5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA727}, + {0xAB5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB37}, + {0xAB5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026B}, + {0xAB5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB52}, + {0xAB69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028D}, + {0xABED, 9, 0, 0}, + {0xF900, 0, 1 | DECOMP_INLINE, 0x8C48}, + {0xF901, 0, 1 | DECOMP_INLINE, 0x66F4}, + {0xF902, 0, 1 | DECOMP_INLINE, 0x8ECA}, + {0xF903, 0, 1 | DECOMP_INLINE, 0x8CC8}, + {0xF904, 0, 1 | DECOMP_INLINE, 0x6ED1}, + {0xF905, 0, 1 | DECOMP_INLINE, 0x4E32}, + {0xF906, 0, 1 | DECOMP_INLINE, 0x53E5}, + {0xF907, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xF908, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xF909, 0, 1 | DECOMP_INLINE, 0x5951}, + {0xF90A, 0, 1 | DECOMP_INLINE, 0x91D1}, + {0xF90B, 0, 1 | DECOMP_INLINE, 0x5587}, + {0xF90C, 0, 1 | DECOMP_INLINE, 0x5948}, + {0xF90D, 0, 1 | DECOMP_INLINE, 0x61F6}, + {0xF90E, 0, 1 | DECOMP_INLINE, 0x7669}, + {0xF90F, 0, 1 | DECOMP_INLINE, 0x7F85}, + {0xF910, 0, 1 | DECOMP_INLINE, 0x863F}, + {0xF911, 0, 1 | DECOMP_INLINE, 0x87BA}, + {0xF912, 0, 1 | DECOMP_INLINE, 0x88F8}, + {0xF913, 0, 1 | DECOMP_INLINE, 0x908F}, + {0xF914, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF915, 0, 1 | DECOMP_INLINE, 0x6D1B}, + {0xF916, 0, 1 | DECOMP_INLINE, 0x70D9}, + {0xF917, 0, 1 | DECOMP_INLINE, 0x73DE}, + {0xF918, 0, 1 | DECOMP_INLINE, 0x843D}, + {0xF919, 0, 1 | DECOMP_INLINE, 0x916A}, + {0xF91A, 0, 1 | DECOMP_INLINE, 0x99F1}, + {0xF91B, 0, 1 | DECOMP_INLINE, 0x4E82}, + {0xF91C, 0, 1 | DECOMP_INLINE, 0x5375}, + {0xF91D, 0, 1 | DECOMP_INLINE, 0x6B04}, + {0xF91E, 0, 1 | DECOMP_INLINE, 0x721B}, + {0xF91F, 0, 1 | DECOMP_INLINE, 0x862D}, + {0xF920, 0, 1 | DECOMP_INLINE, 0x9E1E}, + {0xF921, 0, 1 | DECOMP_INLINE, 0x5D50}, + {0xF922, 0, 1 | DECOMP_INLINE, 0x6FEB}, + {0xF923, 0, 1 | DECOMP_INLINE, 0x85CD}, + {0xF924, 0, 1 | DECOMP_INLINE, 0x8964}, + {0xF925, 0, 1 | DECOMP_INLINE, 0x62C9}, + {0xF926, 0, 1 | DECOMP_INLINE, 0x81D8}, + {0xF927, 0, 1 | DECOMP_INLINE, 0x881F}, + {0xF928, 0, 1 | DECOMP_INLINE, 0x5ECA}, + {0xF929, 0, 1 | DECOMP_INLINE, 0x6717}, + {0xF92A, 0, 1 | DECOMP_INLINE, 0x6D6A}, + {0xF92B, 0, 1 | DECOMP_INLINE, 0x72FC}, + {0xF92C, 0, 1 | DECOMP_INLINE, 0x90CE}, + {0xF92D, 0, 1 | DECOMP_INLINE, 0x4F86}, + {0xF92E, 0, 1 | DECOMP_INLINE, 0x51B7}, + {0xF92F, 0, 1 | DECOMP_INLINE, 0x52DE}, + {0xF930, 0, 1 | DECOMP_INLINE, 0x64C4}, + {0xF931, 0, 1 | DECOMP_INLINE, 0x6AD3}, + {0xF932, 0, 1 | DECOMP_INLINE, 0x7210}, + {0xF933, 0, 1 | DECOMP_INLINE, 0x76E7}, + {0xF934, 0, 1 | DECOMP_INLINE, 0x8001}, + {0xF935, 0, 1 | DECOMP_INLINE, 0x8606}, + {0xF936, 0, 1 | DECOMP_INLINE, 0x865C}, + {0xF937, 0, 1 | DECOMP_INLINE, 0x8DEF}, + {0xF938, 0, 1 | DECOMP_INLINE, 0x9732}, + {0xF939, 0, 1 | DECOMP_INLINE, 0x9B6F}, + {0xF93A, 0, 1 | DECOMP_INLINE, 0x9DFA}, + {0xF93B, 0, 1 | DECOMP_INLINE, 0x788C}, + {0xF93C, 0, 1 | DECOMP_INLINE, 0x797F}, + {0xF93D, 0, 1 | DECOMP_INLINE, 0x7DA0}, + {0xF93E, 0, 1 | DECOMP_INLINE, 0x83C9}, + {0xF93F, 0, 1 | DECOMP_INLINE, 0x9304}, + {0xF940, 0, 1 | DECOMP_INLINE, 0x9E7F}, + {0xF941, 0, 1 | DECOMP_INLINE, 0x8AD6}, + {0xF942, 0, 1 | DECOMP_INLINE, 0x58DF}, + {0xF943, 0, 1 | DECOMP_INLINE, 0x5F04}, + {0xF944, 0, 1 | DECOMP_INLINE, 0x7C60}, + {0xF945, 0, 1 | DECOMP_INLINE, 0x807E}, + {0xF946, 0, 1 | DECOMP_INLINE, 0x7262}, + {0xF947, 0, 1 | DECOMP_INLINE, 0x78CA}, + {0xF948, 0, 1 | DECOMP_INLINE, 0x8CC2}, + {0xF949, 0, 1 | DECOMP_INLINE, 0x96F7}, + {0xF94A, 0, 1 | DECOMP_INLINE, 0x58D8}, + {0xF94B, 0, 1 | DECOMP_INLINE, 0x5C62}, + {0xF94C, 0, 1 | DECOMP_INLINE, 0x6A13}, + {0xF94D, 0, 1 | DECOMP_INLINE, 0x6DDA}, + {0xF94E, 0, 1 | DECOMP_INLINE, 0x6F0F}, + {0xF94F, 0, 1 | DECOMP_INLINE, 0x7D2F}, + {0xF950, 0, 1 | DECOMP_INLINE, 0x7E37}, + {0xF951, 0, 1 | DECOMP_INLINE, 0x964B}, + {0xF952, 0, 1 | DECOMP_INLINE, 0x52D2}, + {0xF953, 0, 1 | DECOMP_INLINE, 0x808B}, + {0xF954, 0, 1 | DECOMP_INLINE, 0x51DC}, + {0xF955, 0, 1 | DECOMP_INLINE, 0x51CC}, + {0xF956, 0, 1 | DECOMP_INLINE, 0x7A1C}, + {0xF957, 0, 1 | DECOMP_INLINE, 0x7DBE}, + {0xF958, 0, 1 | DECOMP_INLINE, 0x83F1}, + {0xF959, 0, 1 | DECOMP_INLINE, 0x9675}, + {0xF95A, 0, 1 | DECOMP_INLINE, 0x8B80}, + {0xF95B, 0, 1 | DECOMP_INLINE, 0x62CF}, + {0xF95C, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF95D, 0, 1 | DECOMP_INLINE, 0x8AFE}, + {0xF95E, 0, 1 | DECOMP_INLINE, 0x4E39}, + {0xF95F, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0xF960, 0, 1 | DECOMP_INLINE, 0x6012}, + {0xF961, 0, 1 | DECOMP_INLINE, 0x7387}, + {0xF962, 0, 1 | DECOMP_INLINE, 0x7570}, + {0xF963, 0, 1 | DECOMP_INLINE, 0x5317}, + {0xF964, 0, 1 | DECOMP_INLINE, 0x78FB}, + {0xF965, 0, 1 | DECOMP_INLINE, 0x4FBF}, + {0xF966, 0, 1 | DECOMP_INLINE, 0x5FA9}, + {0xF967, 0, 1 | DECOMP_INLINE, 0x4E0D}, + {0xF968, 0, 1 | DECOMP_INLINE, 0x6CCC}, + {0xF969, 0, 1 | DECOMP_INLINE, 0x6578}, + {0xF96A, 0, 1 | DECOMP_INLINE, 0x7D22}, + {0xF96B, 0, 1 | DECOMP_INLINE, 0x53C3}, + {0xF96C, 0, 1 | DECOMP_INLINE, 0x585E}, + {0xF96D, 0, 1 | DECOMP_INLINE, 0x7701}, + {0xF96E, 0, 1 | DECOMP_INLINE, 0x8449}, + {0xF96F, 0, 1 | DECOMP_INLINE, 0x8AAA}, + {0xF970, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0xF971, 0, 1 | DECOMP_INLINE, 0x8FB0}, + {0xF972, 0, 1 | DECOMP_INLINE, 0x6C88}, + {0xF973, 0, 1 | DECOMP_INLINE, 0x62FE}, + {0xF974, 0, 1 | DECOMP_INLINE, 0x82E5}, + {0xF975, 0, 1 | DECOMP_INLINE, 0x63A0}, + {0xF976, 0, 1 | DECOMP_INLINE, 0x7565}, + {0xF977, 0, 1 | DECOMP_INLINE, 0x4EAE}, + {0xF978, 0, 1 | DECOMP_INLINE, 0x5169}, + {0xF979, 0, 1 | DECOMP_INLINE, 0x51C9}, + {0xF97A, 0, 1 | DECOMP_INLINE, 0x6881}, + {0xF97B, 0, 1 | DECOMP_INLINE, 0x7CE7}, + {0xF97C, 0, 1 | DECOMP_INLINE, 0x826F}, + {0xF97D, 0, 1 | DECOMP_INLINE, 0x8AD2}, + {0xF97E, 0, 1 | DECOMP_INLINE, 0x91CF}, + {0xF97F, 0, 1 | DECOMP_INLINE, 0x52F5}, + {0xF980, 0, 1 | DECOMP_INLINE, 0x5442}, + {0xF981, 0, 1 | DECOMP_INLINE, 0x5973}, + {0xF982, 0, 1 | DECOMP_INLINE, 0x5EEC}, + {0xF983, 0, 1 | DECOMP_INLINE, 0x65C5}, + {0xF984, 0, 1 | DECOMP_INLINE, 0x6FFE}, + {0xF985, 0, 1 | DECOMP_INLINE, 0x792A}, + {0xF986, 0, 1 | DECOMP_INLINE, 0x95AD}, + {0xF987, 0, 1 | DECOMP_INLINE, 0x9A6A}, + {0xF988, 0, 1 | DECOMP_INLINE, 0x9E97}, + {0xF989, 0, 1 | DECOMP_INLINE, 0x9ECE}, + {0xF98A, 0, 1 | DECOMP_INLINE, 0x529B}, + {0xF98B, 0, 1 | DECOMP_INLINE, 0x66C6}, + {0xF98C, 0, 1 | DECOMP_INLINE, 0x6B77}, + {0xF98D, 0, 1 | DECOMP_INLINE, 0x8F62}, + {0xF98E, 0, 1 | DECOMP_INLINE, 0x5E74}, + {0xF98F, 0, 1 | DECOMP_INLINE, 0x6190}, + {0xF990, 0, 1 | DECOMP_INLINE, 0x6200}, + {0xF991, 0, 1 | DECOMP_INLINE, 0x649A}, + {0xF992, 0, 1 | DECOMP_INLINE, 0x6F23}, + {0xF993, 0, 1 | DECOMP_INLINE, 0x7149}, + {0xF994, 0, 1 | DECOMP_INLINE, 0x7489}, + {0xF995, 0, 1 | DECOMP_INLINE, 0x79CA}, + {0xF996, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xF997, 0, 1 | DECOMP_INLINE, 0x806F}, + {0xF998, 0, 1 | DECOMP_INLINE, 0x8F26}, + {0xF999, 0, 1 | DECOMP_INLINE, 0x84EE}, + {0xF99A, 0, 1 | DECOMP_INLINE, 0x9023}, + {0xF99B, 0, 1 | DECOMP_INLINE, 0x934A}, + {0xF99C, 0, 1 | DECOMP_INLINE, 0x5217}, + {0xF99D, 0, 1 | DECOMP_INLINE, 0x52A3}, + {0xF99E, 0, 1 | DECOMP_INLINE, 0x54BD}, + {0xF99F, 0, 1 | DECOMP_INLINE, 0x70C8}, + {0xF9A0, 0, 1 | DECOMP_INLINE, 0x88C2}, + {0xF9A1, 0, 1 | DECOMP_INLINE, 0x8AAA}, + {0xF9A2, 0, 1 | DECOMP_INLINE, 0x5EC9}, + {0xF9A3, 0, 1 | DECOMP_INLINE, 0x5FF5}, + {0xF9A4, 0, 1 | DECOMP_INLINE, 0x637B}, + {0xF9A5, 0, 1 | DECOMP_INLINE, 0x6BAE}, + {0xF9A6, 0, 1 | DECOMP_INLINE, 0x7C3E}, + {0xF9A7, 0, 1 | DECOMP_INLINE, 0x7375}, + {0xF9A8, 0, 1 | DECOMP_INLINE, 0x4EE4}, + {0xF9A9, 0, 1 | DECOMP_INLINE, 0x56F9}, + {0xF9AA, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0xF9AB, 0, 1 | DECOMP_INLINE, 0x5DBA}, + {0xF9AC, 0, 1 | DECOMP_INLINE, 0x601C}, + {0xF9AD, 0, 1 | DECOMP_INLINE, 0x73B2}, + {0xF9AE, 0, 1 | DECOMP_INLINE, 0x7469}, + {0xF9AF, 0, 1 | DECOMP_INLINE, 0x7F9A}, + {0xF9B0, 0, 1 | DECOMP_INLINE, 0x8046}, + {0xF9B1, 0, 1 | DECOMP_INLINE, 0x9234}, + {0xF9B2, 0, 1 | DECOMP_INLINE, 0x96F6}, + {0xF9B3, 0, 1 | DECOMP_INLINE, 0x9748}, + {0xF9B4, 0, 1 | DECOMP_INLINE, 0x9818}, + {0xF9B5, 0, 1 | DECOMP_INLINE, 0x4F8B}, + {0xF9B6, 0, 1 | DECOMP_INLINE, 0x79AE}, + {0xF9B7, 0, 1 | DECOMP_INLINE, 0x91B4}, + {0xF9B8, 0, 1 | DECOMP_INLINE, 0x96B8}, + {0xF9B9, 0, 1 | DECOMP_INLINE, 0x60E1}, + {0xF9BA, 0, 1 | DECOMP_INLINE, 0x4E86}, + {0xF9BB, 0, 1 | DECOMP_INLINE, 0x50DA}, + {0xF9BC, 0, 1 | DECOMP_INLINE, 0x5BEE}, + {0xF9BD, 0, 1 | DECOMP_INLINE, 0x5C3F}, + {0xF9BE, 0, 1 | DECOMP_INLINE, 0x6599}, + {0xF9BF, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF9C0, 0, 1 | DECOMP_INLINE, 0x71CE}, + {0xF9C1, 0, 1 | DECOMP_INLINE, 0x7642}, + {0xF9C2, 0, 1 | DECOMP_INLINE, 0x84FC}, + {0xF9C3, 0, 1 | DECOMP_INLINE, 0x907C}, + {0xF9C4, 0, 1 | DECOMP_INLINE, 0x9F8D}, + {0xF9C5, 0, 1 | DECOMP_INLINE, 0x6688}, + {0xF9C6, 0, 1 | DECOMP_INLINE, 0x962E}, + {0xF9C7, 0, 1 | DECOMP_INLINE, 0x5289}, + {0xF9C8, 0, 1 | DECOMP_INLINE, 0x677B}, + {0xF9C9, 0, 1 | DECOMP_INLINE, 0x67F3}, + {0xF9CA, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0xF9CB, 0, 1 | DECOMP_INLINE, 0x6E9C}, + {0xF9CC, 0, 1 | DECOMP_INLINE, 0x7409}, + {0xF9CD, 0, 1 | DECOMP_INLINE, 0x7559}, + {0xF9CE, 0, 1 | DECOMP_INLINE, 0x786B}, + {0xF9CF, 0, 1 | DECOMP_INLINE, 0x7D10}, + {0xF9D0, 0, 1 | DECOMP_INLINE, 0x985E}, + {0xF9D1, 0, 1 | DECOMP_INLINE, 0x516D}, + {0xF9D2, 0, 1 | DECOMP_INLINE, 0x622E}, + {0xF9D3, 0, 1 | DECOMP_INLINE, 0x9678}, + {0xF9D4, 0, 1 | DECOMP_INLINE, 0x502B}, + {0xF9D5, 0, 1 | DECOMP_INLINE, 0x5D19}, + {0xF9D6, 0, 1 | DECOMP_INLINE, 0x6DEA}, + {0xF9D7, 0, 1 | DECOMP_INLINE, 0x8F2A}, + {0xF9D8, 0, 1 | DECOMP_INLINE, 0x5F8B}, + {0xF9D9, 0, 1 | DECOMP_INLINE, 0x6144}, + {0xF9DA, 0, 1 | DECOMP_INLINE, 0x6817}, + {0xF9DB, 0, 1 | DECOMP_INLINE, 0x7387}, + {0xF9DC, 0, 1 | DECOMP_INLINE, 0x9686}, + {0xF9DD, 0, 1 | DECOMP_INLINE, 0x5229}, + {0xF9DE, 0, 1 | DECOMP_INLINE, 0x540F}, + {0xF9DF, 0, 1 | DECOMP_INLINE, 0x5C65}, + {0xF9E0, 0, 1 | DECOMP_INLINE, 0x6613}, + {0xF9E1, 0, 1 | DECOMP_INLINE, 0x674E}, + {0xF9E2, 0, 1 | DECOMP_INLINE, 0x68A8}, + {0xF9E3, 0, 1 | DECOMP_INLINE, 0x6CE5}, + {0xF9E4, 0, 1 | DECOMP_INLINE, 0x7406}, + {0xF9E5, 0, 1 | DECOMP_INLINE, 0x75E2}, + {0xF9E6, 0, 1 | DECOMP_INLINE, 0x7F79}, + {0xF9E7, 0, 1 | DECOMP_INLINE, 0x88CF}, + {0xF9E8, 0, 1 | DECOMP_INLINE, 0x88E1}, + {0xF9E9, 0, 1 | DECOMP_INLINE, 0x91CC}, + {0xF9EA, 0, 1 | DECOMP_INLINE, 0x96E2}, + {0xF9EB, 0, 1 | DECOMP_INLINE, 0x533F}, + {0xF9EC, 0, 1 | DECOMP_INLINE, 0x6EBA}, + {0xF9ED, 0, 1 | DECOMP_INLINE, 0x541D}, + {0xF9EE, 0, 1 | DECOMP_INLINE, 0x71D0}, + {0xF9EF, 0, 1 | DECOMP_INLINE, 0x7498}, + {0xF9F0, 0, 1 | DECOMP_INLINE, 0x85FA}, + {0xF9F1, 0, 1 | DECOMP_INLINE, 0x96A3}, + {0xF9F2, 0, 1 | DECOMP_INLINE, 0x9C57}, + {0xF9F3, 0, 1 | DECOMP_INLINE, 0x9E9F}, + {0xF9F4, 0, 1 | DECOMP_INLINE, 0x6797}, + {0xF9F5, 0, 1 | DECOMP_INLINE, 0x6DCB}, + {0xF9F6, 0, 1 | DECOMP_INLINE, 0x81E8}, + {0xF9F7, 0, 1 | DECOMP_INLINE, 0x7ACB}, + {0xF9F8, 0, 1 | DECOMP_INLINE, 0x7B20}, + {0xF9F9, 0, 1 | DECOMP_INLINE, 0x7C92}, + {0xF9FA, 0, 1 | DECOMP_INLINE, 0x72C0}, + {0xF9FB, 0, 1 | DECOMP_INLINE, 0x7099}, + {0xF9FC, 0, 1 | DECOMP_INLINE, 0x8B58}, + {0xF9FD, 0, 1 | DECOMP_INLINE, 0x4EC0}, + {0xF9FE, 0, 1 | DECOMP_INLINE, 0x8336}, + {0xF9FF, 0, 1 | DECOMP_INLINE, 0x523A}, + {0xFA00, 0, 1 | DECOMP_INLINE, 0x5207}, + {0xFA01, 0, 1 | DECOMP_INLINE, 0x5EA6}, + {0xFA02, 0, 1 | DECOMP_INLINE, 0x62D3}, + {0xFA03, 0, 1 | DECOMP_INLINE, 0x7CD6}, + {0xFA04, 0, 1 | DECOMP_INLINE, 0x5B85}, + {0xFA05, 0, 1 | DECOMP_INLINE, 0x6D1E}, + {0xFA06, 0, 1 | DECOMP_INLINE, 0x66B4}, + {0xFA07, 0, 1 | DECOMP_INLINE, 0x8F3B}, + {0xFA08, 0, 1 | DECOMP_INLINE, 0x884C}, + {0xFA09, 0, 1 | DECOMP_INLINE, 0x964D}, + {0xFA0A, 0, 1 | DECOMP_INLINE, 0x898B}, + {0xFA0B, 0, 1 | DECOMP_INLINE, 0x5ED3}, + {0xFA0C, 0, 1 | DECOMP_INLINE, 0x5140}, + {0xFA0D, 0, 1 | DECOMP_INLINE, 0x55C0}, + {0xFA10, 0, 1 | DECOMP_INLINE, 0x585A}, + {0xFA12, 0, 1 | DECOMP_INLINE, 0x6674}, + {0xFA15, 0, 1 | DECOMP_INLINE, 0x51DE}, + {0xFA16, 0, 1 | DECOMP_INLINE, 0x732A}, + {0xFA17, 0, 1 | DECOMP_INLINE, 0x76CA}, + {0xFA18, 0, 1 | DECOMP_INLINE, 0x793C}, + {0xFA19, 0, 1 | DECOMP_INLINE, 0x795E}, + {0xFA1A, 0, 1 | DECOMP_INLINE, 0x7965}, + {0xFA1B, 0, 1 | DECOMP_INLINE, 0x798F}, + {0xFA1C, 0, 1 | DECOMP_INLINE, 0x9756}, + {0xFA1D, 0, 1 | DECOMP_INLINE, 0x7CBE}, + {0xFA1E, 0, 1 | DECOMP_INLINE, 0x7FBD}, + {0xFA20, 0, 1 | DECOMP_INLINE, 0x8612}, + {0xFA22, 0, 1 | DECOMP_INLINE, 0x8AF8}, + {0xFA25, 0, 1 | DECOMP_INLINE, 0x9038}, + {0xFA26, 0, 1 | DECOMP_INLINE, 0x90FD}, + {0xFA2A, 0, 1 | DECOMP_INLINE, 0x98EF}, + {0xFA2B, 0, 1 | DECOMP_INLINE, 0x98FC}, + {0xFA2C, 0, 1 | DECOMP_INLINE, 0x9928}, + {0xFA2D, 0, 1 | DECOMP_INLINE, 0x9DB4}, + {0xFA2E, 0, 1 | DECOMP_INLINE, 0x90DE}, + {0xFA2F, 0, 1 | DECOMP_INLINE, 0x96B7}, + {0xFA30, 0, 1 | DECOMP_INLINE, 0x4FAE}, + {0xFA31, 0, 1 | DECOMP_INLINE, 0x50E7}, + {0xFA32, 0, 1 | DECOMP_INLINE, 0x514D}, + {0xFA33, 0, 1 | DECOMP_INLINE, 0x52C9}, + {0xFA34, 0, 1 | DECOMP_INLINE, 0x52E4}, + {0xFA35, 0, 1 | DECOMP_INLINE, 0x5351}, + {0xFA36, 0, 1 | DECOMP_INLINE, 0x559D}, + {0xFA37, 0, 1 | DECOMP_INLINE, 0x5606}, + {0xFA38, 0, 1 | DECOMP_INLINE, 0x5668}, + {0xFA39, 0, 1 | DECOMP_INLINE, 0x5840}, + {0xFA3A, 0, 1 | DECOMP_INLINE, 0x58A8}, + {0xFA3B, 0, 1 | DECOMP_INLINE, 0x5C64}, + {0xFA3C, 0, 1 | DECOMP_INLINE, 0x5C6E}, + {0xFA3D, 0, 1 | DECOMP_INLINE, 0x6094}, + {0xFA3E, 0, 1 | DECOMP_INLINE, 0x6168}, + {0xFA3F, 0, 1 | DECOMP_INLINE, 0x618E}, + {0xFA40, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0xFA41, 0, 1 | DECOMP_INLINE, 0x654F}, + {0xFA42, 0, 1 | DECOMP_INLINE, 0x65E2}, + {0xFA43, 0, 1 | DECOMP_INLINE, 0x6691}, + {0xFA44, 0, 1 | DECOMP_INLINE, 0x6885}, + {0xFA45, 0, 1 | DECOMP_INLINE, 0x6D77}, + {0xFA46, 0, 1 | DECOMP_INLINE, 0x6E1A}, + {0xFA47, 0, 1 | DECOMP_INLINE, 0x6F22}, + {0xFA48, 0, 1 | DECOMP_INLINE, 0x716E}, + {0xFA49, 0, 1 | DECOMP_INLINE, 0x722B}, + {0xFA4A, 0, 1 | DECOMP_INLINE, 0x7422}, + {0xFA4B, 0, 1 | DECOMP_INLINE, 0x7891}, + {0xFA4C, 0, 1 | DECOMP_INLINE, 0x793E}, + {0xFA4D, 0, 1 | DECOMP_INLINE, 0x7949}, + {0xFA4E, 0, 1 | DECOMP_INLINE, 0x7948}, + {0xFA4F, 0, 1 | DECOMP_INLINE, 0x7950}, + {0xFA50, 0, 1 | DECOMP_INLINE, 0x7956}, + {0xFA51, 0, 1 | DECOMP_INLINE, 0x795D}, + {0xFA52, 0, 1 | DECOMP_INLINE, 0x798D}, + {0xFA53, 0, 1 | DECOMP_INLINE, 0x798E}, + {0xFA54, 0, 1 | DECOMP_INLINE, 0x7A40}, + {0xFA55, 0, 1 | DECOMP_INLINE, 0x7A81}, + {0xFA56, 0, 1 | DECOMP_INLINE, 0x7BC0}, + {0xFA57, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xFA58, 0, 1 | DECOMP_INLINE, 0x7E09}, + {0xFA59, 0, 1 | DECOMP_INLINE, 0x7E41}, + {0xFA5A, 0, 1 | DECOMP_INLINE, 0x7F72}, + {0xFA5B, 0, 1 | DECOMP_INLINE, 0x8005}, + {0xFA5C, 0, 1 | DECOMP_INLINE, 0x81ED}, + {0xFA5D, 0, 1 | DECOMP_INLINE, 0x8279}, + {0xFA5E, 0, 1 | DECOMP_INLINE, 0x8279}, + {0xFA5F, 0, 1 | DECOMP_INLINE, 0x8457}, + {0xFA60, 0, 1 | DECOMP_INLINE, 0x8910}, + {0xFA61, 0, 1 | DECOMP_INLINE, 0x8996}, + {0xFA62, 0, 1 | DECOMP_INLINE, 0x8B01}, + {0xFA63, 0, 1 | DECOMP_INLINE, 0x8B39}, + {0xFA64, 0, 1 | DECOMP_INLINE, 0x8CD3}, + {0xFA65, 0, 1 | DECOMP_INLINE, 0x8D08}, + {0xFA66, 0, 1 | DECOMP_INLINE, 0x8FB6}, + {0xFA67, 0, 1 | DECOMP_INLINE, 0x9038}, + {0xFA68, 0, 1 | DECOMP_INLINE, 0x96E3}, + {0xFA69, 0, 1 | DECOMP_INLINE, 0x97FF}, + {0xFA6A, 0, 1 | DECOMP_INLINE, 0x983B}, + {0xFA6B, 0, 1 | DECOMP_INLINE, 0x6075}, + {0xFA6C, 0, 1, 3527}, + {0xFA6D, 0, 1 | DECOMP_INLINE, 0x8218}, + {0xFA70, 0, 1 | DECOMP_INLINE, 0x4E26}, + {0xFA71, 0, 1 | DECOMP_INLINE, 0x51B5}, + {0xFA72, 0, 1 | DECOMP_INLINE, 0x5168}, + {0xFA73, 0, 1 | DECOMP_INLINE, 0x4F80}, + {0xFA74, 0, 1 | DECOMP_INLINE, 0x5145}, + {0xFA75, 0, 1 | DECOMP_INLINE, 0x5180}, + {0xFA76, 0, 1 | DECOMP_INLINE, 0x52C7}, + {0xFA77, 0, 1 | DECOMP_INLINE, 0x52FA}, + {0xFA78, 0, 1 | DECOMP_INLINE, 0x559D}, + {0xFA79, 0, 1 | DECOMP_INLINE, 0x5555}, + {0xFA7A, 0, 1 | DECOMP_INLINE, 0x5599}, + {0xFA7B, 0, 1 | DECOMP_INLINE, 0x55E2}, + {0xFA7C, 0, 1 | DECOMP_INLINE, 0x585A}, + {0xFA7D, 0, 1 | DECOMP_INLINE, 0x58B3}, + {0xFA7E, 0, 1 | DECOMP_INLINE, 0x5944}, + {0xFA7F, 0, 1 | DECOMP_INLINE, 0x5954}, + {0xFA80, 0, 1 | DECOMP_INLINE, 0x5A62}, + {0xFA81, 0, 1 | DECOMP_INLINE, 0x5B28}, + {0xFA82, 0, 1 | DECOMP_INLINE, 0x5ED2}, + {0xFA83, 0, 1 | DECOMP_INLINE, 0x5ED9}, + {0xFA84, 0, 1 | DECOMP_INLINE, 0x5F69}, + {0xFA85, 0, 1 | DECOMP_INLINE, 0x5FAD}, + {0xFA86, 0, 1 | DECOMP_INLINE, 0x60D8}, + {0xFA87, 0, 1 | DECOMP_INLINE, 0x614E}, + {0xFA88, 0, 1 | DECOMP_INLINE, 0x6108}, + {0xFA89, 0, 1 | DECOMP_INLINE, 0x618E}, + {0xFA8A, 0, 1 | DECOMP_INLINE, 0x6160}, + {0xFA8B, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0xFA8C, 0, 1 | DECOMP_INLINE, 0x6234}, + {0xFA8D, 0, 1 | DECOMP_INLINE, 0x63C4}, + {0xFA8E, 0, 1 | DECOMP_INLINE, 0x641C}, + {0xFA8F, 0, 1 | DECOMP_INLINE, 0x6452}, + {0xFA90, 0, 1 | DECOMP_INLINE, 0x6556}, + {0xFA91, 0, 1 | DECOMP_INLINE, 0x6674}, + {0xFA92, 0, 1 | DECOMP_INLINE, 0x6717}, + {0xFA93, 0, 1 | DECOMP_INLINE, 0x671B}, + {0xFA94, 0, 1 | DECOMP_INLINE, 0x6756}, + {0xFA95, 0, 1 | DECOMP_INLINE, 0x6B79}, + {0xFA96, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0xFA97, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0xFA98, 0, 1 | DECOMP_INLINE, 0x6EDB}, + {0xFA99, 0, 1 | DECOMP_INLINE, 0x6ECB}, + {0xFA9A, 0, 1 | DECOMP_INLINE, 0x6F22}, + {0xFA9B, 0, 1 | DECOMP_INLINE, 0x701E}, + {0xFA9C, 0, 1 | DECOMP_INLINE, 0x716E}, + {0xFA9D, 0, 1 | DECOMP_INLINE, 0x77A7}, + {0xFA9E, 0, 1 | DECOMP_INLINE, 0x7235}, + {0xFA9F, 0, 1 | DECOMP_INLINE, 0x72AF}, + {0xFAA0, 0, 1 | DECOMP_INLINE, 0x732A}, + {0xFAA1, 0, 1 | DECOMP_INLINE, 0x7471}, + {0xFAA2, 0, 1 | DECOMP_INLINE, 0x7506}, + {0xFAA3, 0, 1 | DECOMP_INLINE, 0x753B}, + {0xFAA4, 0, 1 | DECOMP_INLINE, 0x761D}, + {0xFAA5, 0, 1 | DECOMP_INLINE, 0x761F}, + {0xFAA6, 0, 1 | DECOMP_INLINE, 0x76CA}, + {0xFAA7, 0, 1 | DECOMP_INLINE, 0x76DB}, + {0xFAA8, 0, 1 | DECOMP_INLINE, 0x76F4}, + {0xFAA9, 0, 1 | DECOMP_INLINE, 0x774A}, + {0xFAAA, 0, 1 | DECOMP_INLINE, 0x7740}, + {0xFAAB, 0, 1 | DECOMP_INLINE, 0x78CC}, + {0xFAAC, 0, 1 | DECOMP_INLINE, 0x7AB1}, + {0xFAAD, 0, 1 | DECOMP_INLINE, 0x7BC0}, + {0xFAAE, 0, 1 | DECOMP_INLINE, 0x7C7B}, + {0xFAAF, 0, 1 | DECOMP_INLINE, 0x7D5B}, + {0xFAB0, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xFAB1, 0, 1 | DECOMP_INLINE, 0x7F3E}, + {0xFAB2, 0, 1 | DECOMP_INLINE, 0x8005}, + {0xFAB3, 0, 1 | DECOMP_INLINE, 0x8352}, + {0xFAB4, 0, 1 | DECOMP_INLINE, 0x83EF}, + {0xFAB5, 0, 1 | DECOMP_INLINE, 0x8779}, + {0xFAB6, 0, 1 | DECOMP_INLINE, 0x8941}, + {0xFAB7, 0, 1 | DECOMP_INLINE, 0x8986}, + {0xFAB8, 0, 1 | DECOMP_INLINE, 0x8996}, + {0xFAB9, 0, 1 | DECOMP_INLINE, 0x8ABF}, + {0xFABA, 0, 1 | DECOMP_INLINE, 0x8AF8}, + {0xFABB, 0, 1 | DECOMP_INLINE, 0x8ACB}, + {0xFABC, 0, 1 | DECOMP_INLINE, 0x8B01}, + {0xFABD, 0, 1 | DECOMP_INLINE, 0x8AFE}, + {0xFABE, 0, 1 | DECOMP_INLINE, 0x8AED}, + {0xFABF, 0, 1 | DECOMP_INLINE, 0x8B39}, + {0xFAC0, 0, 1 | DECOMP_INLINE, 0x8B8A}, + {0xFAC1, 0, 1 | DECOMP_INLINE, 0x8D08}, + {0xFAC2, 0, 1 | DECOMP_INLINE, 0x8F38}, + {0xFAC3, 0, 1 | DECOMP_INLINE, 0x9072}, + {0xFAC4, 0, 1 | DECOMP_INLINE, 0x9199}, + {0xFAC5, 0, 1 | DECOMP_INLINE, 0x9276}, + {0xFAC6, 0, 1 | DECOMP_INLINE, 0x967C}, + {0xFAC7, 0, 1 | DECOMP_INLINE, 0x96E3}, + {0xFAC8, 0, 1 | DECOMP_INLINE, 0x9756}, + {0xFAC9, 0, 1 | DECOMP_INLINE, 0x97DB}, + {0xFACA, 0, 1 | DECOMP_INLINE, 0x97FF}, + {0xFACB, 0, 1 | DECOMP_INLINE, 0x980B}, + {0xFACC, 0, 1 | DECOMP_INLINE, 0x983B}, + {0xFACD, 0, 1 | DECOMP_INLINE, 0x9B12}, + {0xFACE, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xFACF, 0, 1, 3528}, + {0xFAD0, 0, 1, 3529}, + {0xFAD1, 0, 1, 3530}, + {0xFAD2, 0, 1 | DECOMP_INLINE, 0x3B9D}, + {0xFAD3, 0, 1 | DECOMP_INLINE, 0x4018}, + {0xFAD4, 0, 1 | DECOMP_INLINE, 0x4039}, + {0xFAD5, 0, 1, 3531}, + {0xFAD6, 0, 1, 3532}, + {0xFAD7, 0, 1, 3533}, + {0xFAD8, 0, 1 | DECOMP_INLINE, 0x9F43}, + {0xFAD9, 0, 1 | DECOMP_INLINE, 0x9F8E}, + {0xFB00, 0, 2 | DECOMP_COMPAT, 3534}, + {0xFB01, 0, 2 | DECOMP_COMPAT, 3536}, + {0xFB02, 0, 2 | DECOMP_COMPAT, 3538}, + {0xFB03, 0, 3 | DECOMP_COMPAT, 3540}, + {0xFB04, 0, 3 | DECOMP_COMPAT, 3543}, + {0xFB05, 0, 2 | DECOMP_COMPAT, 3546}, + {0xFB06, 0, 2 | DECOMP_COMPAT, 3548}, + {0xFB13, 0, 2 | DECOMP_COMPAT, 3550}, + {0xFB14, 0, 2 | DECOMP_COMPAT, 3552}, + {0xFB15, 0, 2 | DECOMP_COMPAT, 3554}, + {0xFB16, 0, 2 | DECOMP_COMPAT, 3556}, + {0xFB17, 0, 2 | DECOMP_COMPAT, 3558}, + {0xFB1D, 0, 2 | DECOMP_NO_COMPOSE, 3560}, /* in exclusion list */ + {0xFB1E, 26, 0, 0}, + {0xFB1F, 0, 2 | DECOMP_NO_COMPOSE, 3562}, /* in exclusion list */ + {0xFB20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05E2}, + {0xFB21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D0}, + {0xFB22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D3}, + {0xFB23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D4}, + {0xFB24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DB}, + {0xFB25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DC}, + {0xFB26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DD}, + {0xFB27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05E8}, + {0xFB28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05EA}, + {0xFB29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFB2A, 0, 2 | DECOMP_NO_COMPOSE, 3564}, /* in exclusion list */ + {0xFB2B, 0, 2 | DECOMP_NO_COMPOSE, 3566}, /* in exclusion list */ + {0xFB2C, 0, 2 | DECOMP_NO_COMPOSE, 3568}, /* in exclusion list */ + {0xFB2D, 0, 2 | DECOMP_NO_COMPOSE, 3570}, /* in exclusion list */ + {0xFB2E, 0, 2 | DECOMP_NO_COMPOSE, 3572}, /* in exclusion list */ + {0xFB2F, 0, 2 | DECOMP_NO_COMPOSE, 3574}, /* in exclusion list */ + {0xFB30, 0, 2 | DECOMP_NO_COMPOSE, 3576}, /* in exclusion list */ + {0xFB31, 0, 2 | DECOMP_NO_COMPOSE, 3578}, /* in exclusion list */ + {0xFB32, 0, 2 | DECOMP_NO_COMPOSE, 3580}, /* in exclusion list */ + {0xFB33, 0, 2 | DECOMP_NO_COMPOSE, 3582}, /* in exclusion list */ + {0xFB34, 0, 2 | DECOMP_NO_COMPOSE, 3584}, /* in exclusion list */ + {0xFB35, 0, 2 | DECOMP_NO_COMPOSE, 3586}, /* in exclusion list */ + {0xFB36, 0, 2 | DECOMP_NO_COMPOSE, 3588}, /* in exclusion list */ + {0xFB38, 0, 2 | DECOMP_NO_COMPOSE, 3590}, /* in exclusion list */ + {0xFB39, 0, 2 | DECOMP_NO_COMPOSE, 3592}, /* in exclusion list */ + {0xFB3A, 0, 2 | DECOMP_NO_COMPOSE, 3594}, /* in exclusion list */ + {0xFB3B, 0, 2 | DECOMP_NO_COMPOSE, 3596}, /* in exclusion list */ + {0xFB3C, 0, 2 | DECOMP_NO_COMPOSE, 3598}, /* in exclusion list */ + {0xFB3E, 0, 2 | DECOMP_NO_COMPOSE, 3600}, /* in exclusion list */ + {0xFB40, 0, 2 | DECOMP_NO_COMPOSE, 3602}, /* in exclusion list */ + {0xFB41, 0, 2 | DECOMP_NO_COMPOSE, 3604}, /* in exclusion list */ + {0xFB43, 0, 2 | DECOMP_NO_COMPOSE, 3606}, /* in exclusion list */ + {0xFB44, 0, 2 | DECOMP_NO_COMPOSE, 3608}, /* in exclusion list */ + {0xFB46, 0, 2 | DECOMP_NO_COMPOSE, 3610}, /* in exclusion list */ + {0xFB47, 0, 2 | DECOMP_NO_COMPOSE, 3612}, /* in exclusion list */ + {0xFB48, 0, 2 | DECOMP_NO_COMPOSE, 3614}, /* in exclusion list */ + {0xFB49, 0, 2 | DECOMP_NO_COMPOSE, 3616}, /* in exclusion list */ + {0xFB4A, 0, 2 | DECOMP_NO_COMPOSE, 3618}, /* in exclusion list */ + {0xFB4B, 0, 2 | DECOMP_NO_COMPOSE, 3620}, /* in exclusion list */ + {0xFB4C, 0, 2 | DECOMP_NO_COMPOSE, 3622}, /* in exclusion list */ + {0xFB4D, 0, 2 | DECOMP_NO_COMPOSE, 3624}, /* in exclusion list */ + {0xFB4E, 0, 2 | DECOMP_NO_COMPOSE, 3626}, /* in exclusion list */ + {0xFB4F, 0, 2 | DECOMP_COMPAT, 3628}, + {0xFB50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0671}, + {0xFB51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0671}, + {0xFB52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068D}, + {0xFB83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068D}, + {0xFB84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068C}, + {0xFB85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068C}, + {0xFB86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068E}, + {0xFB87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068E}, + {0xFB88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0688}, + {0xFB89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0688}, + {0xFB8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0698}, + {0xFB8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0698}, + {0xFB8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0691}, + {0xFB8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0691}, + {0xFB8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0xFB9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0xFBA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C0}, + {0xFBA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C0}, + {0xFBA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D2}, + {0xFBAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D2}, + {0xFBB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D3}, + {0xFBB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D3}, + {0xFBD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C7}, + {0xFBD8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C7}, + {0xFBD9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C6}, + {0xFBDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C6}, + {0xFBDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C8}, + {0xFBDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C8}, + {0xFBDD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0677}, + {0xFBDE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CB}, + {0xFBDF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CB}, + {0xFBE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C5}, + {0xFBE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C5}, + {0xFBE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C9}, + {0xFBE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C9}, + {0xFBE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFBE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFBEA, 0, 2 | DECOMP_COMPAT, 3630}, + {0xFBEB, 0, 2 | DECOMP_COMPAT, 3632}, + {0xFBEC, 0, 2 | DECOMP_COMPAT, 3634}, + {0xFBED, 0, 2 | DECOMP_COMPAT, 3636}, + {0xFBEE, 0, 2 | DECOMP_COMPAT, 3638}, + {0xFBEF, 0, 2 | DECOMP_COMPAT, 3640}, + {0xFBF0, 0, 2 | DECOMP_COMPAT, 3642}, + {0xFBF1, 0, 2 | DECOMP_COMPAT, 3644}, + {0xFBF2, 0, 2 | DECOMP_COMPAT, 3646}, + {0xFBF3, 0, 2 | DECOMP_COMPAT, 3648}, + {0xFBF4, 0, 2 | DECOMP_COMPAT, 3650}, + {0xFBF5, 0, 2 | DECOMP_COMPAT, 3652}, + {0xFBF6, 0, 2 | DECOMP_COMPAT, 3654}, + {0xFBF7, 0, 2 | DECOMP_COMPAT, 3656}, + {0xFBF8, 0, 2 | DECOMP_COMPAT, 3658}, + {0xFBF9, 0, 2 | DECOMP_COMPAT, 3660}, + {0xFBFA, 0, 2 | DECOMP_COMPAT, 3662}, + {0xFBFB, 0, 2 | DECOMP_COMPAT, 3664}, + {0xFBFC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFC00, 0, 2 | DECOMP_COMPAT, 3666}, + {0xFC01, 0, 2 | DECOMP_COMPAT, 3668}, + {0xFC02, 0, 2 | DECOMP_COMPAT, 3670}, + {0xFC03, 0, 2 | DECOMP_COMPAT, 3672}, + {0xFC04, 0, 2 | DECOMP_COMPAT, 3674}, + {0xFC05, 0, 2 | DECOMP_COMPAT, 3676}, + {0xFC06, 0, 2 | DECOMP_COMPAT, 3678}, + {0xFC07, 0, 2 | DECOMP_COMPAT, 3680}, + {0xFC08, 0, 2 | DECOMP_COMPAT, 3682}, + {0xFC09, 0, 2 | DECOMP_COMPAT, 3684}, + {0xFC0A, 0, 2 | DECOMP_COMPAT, 3686}, + {0xFC0B, 0, 2 | DECOMP_COMPAT, 3688}, + {0xFC0C, 0, 2 | DECOMP_COMPAT, 3690}, + {0xFC0D, 0, 2 | DECOMP_COMPAT, 3692}, + {0xFC0E, 0, 2 | DECOMP_COMPAT, 3694}, + {0xFC0F, 0, 2 | DECOMP_COMPAT, 3696}, + {0xFC10, 0, 2 | DECOMP_COMPAT, 3698}, + {0xFC11, 0, 2 | DECOMP_COMPAT, 3700}, + {0xFC12, 0, 2 | DECOMP_COMPAT, 3702}, + {0xFC13, 0, 2 | DECOMP_COMPAT, 3704}, + {0xFC14, 0, 2 | DECOMP_COMPAT, 3706}, + {0xFC15, 0, 2 | DECOMP_COMPAT, 3708}, + {0xFC16, 0, 2 | DECOMP_COMPAT, 3710}, + {0xFC17, 0, 2 | DECOMP_COMPAT, 3712}, + {0xFC18, 0, 2 | DECOMP_COMPAT, 3714}, + {0xFC19, 0, 2 | DECOMP_COMPAT, 3716}, + {0xFC1A, 0, 2 | DECOMP_COMPAT, 3718}, + {0xFC1B, 0, 2 | DECOMP_COMPAT, 3720}, + {0xFC1C, 0, 2 | DECOMP_COMPAT, 3722}, + {0xFC1D, 0, 2 | DECOMP_COMPAT, 3724}, + {0xFC1E, 0, 2 | DECOMP_COMPAT, 3726}, + {0xFC1F, 0, 2 | DECOMP_COMPAT, 3728}, + {0xFC20, 0, 2 | DECOMP_COMPAT, 3730}, + {0xFC21, 0, 2 | DECOMP_COMPAT, 3732}, + {0xFC22, 0, 2 | DECOMP_COMPAT, 3734}, + {0xFC23, 0, 2 | DECOMP_COMPAT, 3736}, + {0xFC24, 0, 2 | DECOMP_COMPAT, 3738}, + {0xFC25, 0, 2 | DECOMP_COMPAT, 3740}, + {0xFC26, 0, 2 | DECOMP_COMPAT, 3742}, + {0xFC27, 0, 2 | DECOMP_COMPAT, 3744}, + {0xFC28, 0, 2 | DECOMP_COMPAT, 3746}, + {0xFC29, 0, 2 | DECOMP_COMPAT, 3748}, + {0xFC2A, 0, 2 | DECOMP_COMPAT, 3750}, + {0xFC2B, 0, 2 | DECOMP_COMPAT, 3752}, + {0xFC2C, 0, 2 | DECOMP_COMPAT, 3754}, + {0xFC2D, 0, 2 | DECOMP_COMPAT, 3756}, + {0xFC2E, 0, 2 | DECOMP_COMPAT, 3758}, + {0xFC2F, 0, 2 | DECOMP_COMPAT, 3760}, + {0xFC30, 0, 2 | DECOMP_COMPAT, 3762}, + {0xFC31, 0, 2 | DECOMP_COMPAT, 3764}, + {0xFC32, 0, 2 | DECOMP_COMPAT, 3766}, + {0xFC33, 0, 2 | DECOMP_COMPAT, 3768}, + {0xFC34, 0, 2 | DECOMP_COMPAT, 3770}, + {0xFC35, 0, 2 | DECOMP_COMPAT, 3772}, + {0xFC36, 0, 2 | DECOMP_COMPAT, 3774}, + {0xFC37, 0, 2 | DECOMP_COMPAT, 3776}, + {0xFC38, 0, 2 | DECOMP_COMPAT, 3778}, + {0xFC39, 0, 2 | DECOMP_COMPAT, 3780}, + {0xFC3A, 0, 2 | DECOMP_COMPAT, 3782}, + {0xFC3B, 0, 2 | DECOMP_COMPAT, 3784}, + {0xFC3C, 0, 2 | DECOMP_COMPAT, 3786}, + {0xFC3D, 0, 2 | DECOMP_COMPAT, 3788}, + {0xFC3E, 0, 2 | DECOMP_COMPAT, 3790}, + {0xFC3F, 0, 2 | DECOMP_COMPAT, 3792}, + {0xFC40, 0, 2 | DECOMP_COMPAT, 3794}, + {0xFC41, 0, 2 | DECOMP_COMPAT, 3796}, + {0xFC42, 0, 2 | DECOMP_COMPAT, 3798}, + {0xFC43, 0, 2 | DECOMP_COMPAT, 3800}, + {0xFC44, 0, 2 | DECOMP_COMPAT, 3802}, + {0xFC45, 0, 2 | DECOMP_COMPAT, 3804}, + {0xFC46, 0, 2 | DECOMP_COMPAT, 3806}, + {0xFC47, 0, 2 | DECOMP_COMPAT, 3808}, + {0xFC48, 0, 2 | DECOMP_COMPAT, 3810}, + {0xFC49, 0, 2 | DECOMP_COMPAT, 3812}, + {0xFC4A, 0, 2 | DECOMP_COMPAT, 3814}, + {0xFC4B, 0, 2 | DECOMP_COMPAT, 3816}, + {0xFC4C, 0, 2 | DECOMP_COMPAT, 3818}, + {0xFC4D, 0, 2 | DECOMP_COMPAT, 3820}, + {0xFC4E, 0, 2 | DECOMP_COMPAT, 3822}, + {0xFC4F, 0, 2 | DECOMP_COMPAT, 3824}, + {0xFC50, 0, 2 | DECOMP_COMPAT, 3826}, + {0xFC51, 0, 2 | DECOMP_COMPAT, 3828}, + {0xFC52, 0, 2 | DECOMP_COMPAT, 3830}, + {0xFC53, 0, 2 | DECOMP_COMPAT, 3832}, + {0xFC54, 0, 2 | DECOMP_COMPAT, 3834}, + {0xFC55, 0, 2 | DECOMP_COMPAT, 3836}, + {0xFC56, 0, 2 | DECOMP_COMPAT, 3838}, + {0xFC57, 0, 2 | DECOMP_COMPAT, 3840}, + {0xFC58, 0, 2 | DECOMP_COMPAT, 3842}, + {0xFC59, 0, 2 | DECOMP_COMPAT, 3844}, + {0xFC5A, 0, 2 | DECOMP_COMPAT, 3846}, + {0xFC5B, 0, 2 | DECOMP_COMPAT, 3848}, + {0xFC5C, 0, 2 | DECOMP_COMPAT, 3850}, + {0xFC5D, 0, 2 | DECOMP_COMPAT, 3852}, + {0xFC5E, 0, 3 | DECOMP_COMPAT, 3854}, + {0xFC5F, 0, 3 | DECOMP_COMPAT, 3857}, + {0xFC60, 0, 3 | DECOMP_COMPAT, 3860}, + {0xFC61, 0, 3 | DECOMP_COMPAT, 3863}, + {0xFC62, 0, 3 | DECOMP_COMPAT, 3866}, + {0xFC63, 0, 3 | DECOMP_COMPAT, 3869}, + {0xFC64, 0, 2 | DECOMP_COMPAT, 3872}, + {0xFC65, 0, 2 | DECOMP_COMPAT, 3874}, + {0xFC66, 0, 2 | DECOMP_COMPAT, 3876}, + {0xFC67, 0, 2 | DECOMP_COMPAT, 3878}, + {0xFC68, 0, 2 | DECOMP_COMPAT, 3880}, + {0xFC69, 0, 2 | DECOMP_COMPAT, 3882}, + {0xFC6A, 0, 2 | DECOMP_COMPAT, 3884}, + {0xFC6B, 0, 2 | DECOMP_COMPAT, 3886}, + {0xFC6C, 0, 2 | DECOMP_COMPAT, 3888}, + {0xFC6D, 0, 2 | DECOMP_COMPAT, 3890}, + {0xFC6E, 0, 2 | DECOMP_COMPAT, 3892}, + {0xFC6F, 0, 2 | DECOMP_COMPAT, 3894}, + {0xFC70, 0, 2 | DECOMP_COMPAT, 3896}, + {0xFC71, 0, 2 | DECOMP_COMPAT, 3898}, + {0xFC72, 0, 2 | DECOMP_COMPAT, 3900}, + {0xFC73, 0, 2 | DECOMP_COMPAT, 3902}, + {0xFC74, 0, 2 | DECOMP_COMPAT, 3904}, + {0xFC75, 0, 2 | DECOMP_COMPAT, 3906}, + {0xFC76, 0, 2 | DECOMP_COMPAT, 3908}, + {0xFC77, 0, 2 | DECOMP_COMPAT, 3910}, + {0xFC78, 0, 2 | DECOMP_COMPAT, 3912}, + {0xFC79, 0, 2 | DECOMP_COMPAT, 3914}, + {0xFC7A, 0, 2 | DECOMP_COMPAT, 3916}, + {0xFC7B, 0, 2 | DECOMP_COMPAT, 3918}, + {0xFC7C, 0, 2 | DECOMP_COMPAT, 3920}, + {0xFC7D, 0, 2 | DECOMP_COMPAT, 3922}, + {0xFC7E, 0, 2 | DECOMP_COMPAT, 3924}, + {0xFC7F, 0, 2 | DECOMP_COMPAT, 3926}, + {0xFC80, 0, 2 | DECOMP_COMPAT, 3928}, + {0xFC81, 0, 2 | DECOMP_COMPAT, 3930}, + {0xFC82, 0, 2 | DECOMP_COMPAT, 3932}, + {0xFC83, 0, 2 | DECOMP_COMPAT, 3934}, + {0xFC84, 0, 2 | DECOMP_COMPAT, 3936}, + {0xFC85, 0, 2 | DECOMP_COMPAT, 3938}, + {0xFC86, 0, 2 | DECOMP_COMPAT, 3940}, + {0xFC87, 0, 2 | DECOMP_COMPAT, 3942}, + {0xFC88, 0, 2 | DECOMP_COMPAT, 3944}, + {0xFC89, 0, 2 | DECOMP_COMPAT, 3946}, + {0xFC8A, 0, 2 | DECOMP_COMPAT, 3948}, + {0xFC8B, 0, 2 | DECOMP_COMPAT, 3950}, + {0xFC8C, 0, 2 | DECOMP_COMPAT, 3952}, + {0xFC8D, 0, 2 | DECOMP_COMPAT, 3954}, + {0xFC8E, 0, 2 | DECOMP_COMPAT, 3956}, + {0xFC8F, 0, 2 | DECOMP_COMPAT, 3958}, + {0xFC90, 0, 2 | DECOMP_COMPAT, 3960}, + {0xFC91, 0, 2 | DECOMP_COMPAT, 3962}, + {0xFC92, 0, 2 | DECOMP_COMPAT, 3964}, + {0xFC93, 0, 2 | DECOMP_COMPAT, 3966}, + {0xFC94, 0, 2 | DECOMP_COMPAT, 3968}, + {0xFC95, 0, 2 | DECOMP_COMPAT, 3970}, + {0xFC96, 0, 2 | DECOMP_COMPAT, 3972}, + {0xFC97, 0, 2 | DECOMP_COMPAT, 3974}, + {0xFC98, 0, 2 | DECOMP_COMPAT, 3976}, + {0xFC99, 0, 2 | DECOMP_COMPAT, 3978}, + {0xFC9A, 0, 2 | DECOMP_COMPAT, 3980}, + {0xFC9B, 0, 2 | DECOMP_COMPAT, 3982}, + {0xFC9C, 0, 2 | DECOMP_COMPAT, 3984}, + {0xFC9D, 0, 2 | DECOMP_COMPAT, 3986}, + {0xFC9E, 0, 2 | DECOMP_COMPAT, 3988}, + {0xFC9F, 0, 2 | DECOMP_COMPAT, 3990}, + {0xFCA0, 0, 2 | DECOMP_COMPAT, 3992}, + {0xFCA1, 0, 2 | DECOMP_COMPAT, 3994}, + {0xFCA2, 0, 2 | DECOMP_COMPAT, 3996}, + {0xFCA3, 0, 2 | DECOMP_COMPAT, 3998}, + {0xFCA4, 0, 2 | DECOMP_COMPAT, 4000}, + {0xFCA5, 0, 2 | DECOMP_COMPAT, 4002}, + {0xFCA6, 0, 2 | DECOMP_COMPAT, 4004}, + {0xFCA7, 0, 2 | DECOMP_COMPAT, 4006}, + {0xFCA8, 0, 2 | DECOMP_COMPAT, 4008}, + {0xFCA9, 0, 2 | DECOMP_COMPAT, 4010}, + {0xFCAA, 0, 2 | DECOMP_COMPAT, 4012}, + {0xFCAB, 0, 2 | DECOMP_COMPAT, 4014}, + {0xFCAC, 0, 2 | DECOMP_COMPAT, 4016}, + {0xFCAD, 0, 2 | DECOMP_COMPAT, 4018}, + {0xFCAE, 0, 2 | DECOMP_COMPAT, 4020}, + {0xFCAF, 0, 2 | DECOMP_COMPAT, 4022}, + {0xFCB0, 0, 2 | DECOMP_COMPAT, 4024}, + {0xFCB1, 0, 2 | DECOMP_COMPAT, 4026}, + {0xFCB2, 0, 2 | DECOMP_COMPAT, 4028}, + {0xFCB3, 0, 2 | DECOMP_COMPAT, 4030}, + {0xFCB4, 0, 2 | DECOMP_COMPAT, 4032}, + {0xFCB5, 0, 2 | DECOMP_COMPAT, 4034}, + {0xFCB6, 0, 2 | DECOMP_COMPAT, 4036}, + {0xFCB7, 0, 2 | DECOMP_COMPAT, 4038}, + {0xFCB8, 0, 2 | DECOMP_COMPAT, 4040}, + {0xFCB9, 0, 2 | DECOMP_COMPAT, 4042}, + {0xFCBA, 0, 2 | DECOMP_COMPAT, 4044}, + {0xFCBB, 0, 2 | DECOMP_COMPAT, 4046}, + {0xFCBC, 0, 2 | DECOMP_COMPAT, 4048}, + {0xFCBD, 0, 2 | DECOMP_COMPAT, 4050}, + {0xFCBE, 0, 2 | DECOMP_COMPAT, 4052}, + {0xFCBF, 0, 2 | DECOMP_COMPAT, 4054}, + {0xFCC0, 0, 2 | DECOMP_COMPAT, 4056}, + {0xFCC1, 0, 2 | DECOMP_COMPAT, 4058}, + {0xFCC2, 0, 2 | DECOMP_COMPAT, 4060}, + {0xFCC3, 0, 2 | DECOMP_COMPAT, 4062}, + {0xFCC4, 0, 2 | DECOMP_COMPAT, 4064}, + {0xFCC5, 0, 2 | DECOMP_COMPAT, 4066}, + {0xFCC6, 0, 2 | DECOMP_COMPAT, 4068}, + {0xFCC7, 0, 2 | DECOMP_COMPAT, 4070}, + {0xFCC8, 0, 2 | DECOMP_COMPAT, 4072}, + {0xFCC9, 0, 2 | DECOMP_COMPAT, 4074}, + {0xFCCA, 0, 2 | DECOMP_COMPAT, 4076}, + {0xFCCB, 0, 2 | DECOMP_COMPAT, 4078}, + {0xFCCC, 0, 2 | DECOMP_COMPAT, 4080}, + {0xFCCD, 0, 2 | DECOMP_COMPAT, 4082}, + {0xFCCE, 0, 2 | DECOMP_COMPAT, 4084}, + {0xFCCF, 0, 2 | DECOMP_COMPAT, 4086}, + {0xFCD0, 0, 2 | DECOMP_COMPAT, 4088}, + {0xFCD1, 0, 2 | DECOMP_COMPAT, 4090}, + {0xFCD2, 0, 2 | DECOMP_COMPAT, 4092}, + {0xFCD3, 0, 2 | DECOMP_COMPAT, 4094}, + {0xFCD4, 0, 2 | DECOMP_COMPAT, 4096}, + {0xFCD5, 0, 2 | DECOMP_COMPAT, 4098}, + {0xFCD6, 0, 2 | DECOMP_COMPAT, 4100}, + {0xFCD7, 0, 2 | DECOMP_COMPAT, 4102}, + {0xFCD8, 0, 2 | DECOMP_COMPAT, 4104}, + {0xFCD9, 0, 2 | DECOMP_COMPAT, 4106}, + {0xFCDA, 0, 2 | DECOMP_COMPAT, 4108}, + {0xFCDB, 0, 2 | DECOMP_COMPAT, 4110}, + {0xFCDC, 0, 2 | DECOMP_COMPAT, 4112}, + {0xFCDD, 0, 2 | DECOMP_COMPAT, 4114}, + {0xFCDE, 0, 2 | DECOMP_COMPAT, 4116}, + {0xFCDF, 0, 2 | DECOMP_COMPAT, 4118}, + {0xFCE0, 0, 2 | DECOMP_COMPAT, 4120}, + {0xFCE1, 0, 2 | DECOMP_COMPAT, 4122}, + {0xFCE2, 0, 2 | DECOMP_COMPAT, 4124}, + {0xFCE3, 0, 2 | DECOMP_COMPAT, 4126}, + {0xFCE4, 0, 2 | DECOMP_COMPAT, 4128}, + {0xFCE5, 0, 2 | DECOMP_COMPAT, 4130}, + {0xFCE6, 0, 2 | DECOMP_COMPAT, 4132}, + {0xFCE7, 0, 2 | DECOMP_COMPAT, 4134}, + {0xFCE8, 0, 2 | DECOMP_COMPAT, 4136}, + {0xFCE9, 0, 2 | DECOMP_COMPAT, 4138}, + {0xFCEA, 0, 2 | DECOMP_COMPAT, 4140}, + {0xFCEB, 0, 2 | DECOMP_COMPAT, 4142}, + {0xFCEC, 0, 2 | DECOMP_COMPAT, 4144}, + {0xFCED, 0, 2 | DECOMP_COMPAT, 4146}, + {0xFCEE, 0, 2 | DECOMP_COMPAT, 4148}, + {0xFCEF, 0, 2 | DECOMP_COMPAT, 4150}, + {0xFCF0, 0, 2 | DECOMP_COMPAT, 4152}, + {0xFCF1, 0, 2 | DECOMP_COMPAT, 4154}, + {0xFCF2, 0, 3 | DECOMP_COMPAT, 4156}, + {0xFCF3, 0, 3 | DECOMP_COMPAT, 4159}, + {0xFCF4, 0, 3 | DECOMP_COMPAT, 4162}, + {0xFCF5, 0, 2 | DECOMP_COMPAT, 4165}, + {0xFCF6, 0, 2 | DECOMP_COMPAT, 4167}, + {0xFCF7, 0, 2 | DECOMP_COMPAT, 4169}, + {0xFCF8, 0, 2 | DECOMP_COMPAT, 4171}, + {0xFCF9, 0, 2 | DECOMP_COMPAT, 4173}, + {0xFCFA, 0, 2 | DECOMP_COMPAT, 4175}, + {0xFCFB, 0, 2 | DECOMP_COMPAT, 4177}, + {0xFCFC, 0, 2 | DECOMP_COMPAT, 4179}, + {0xFCFD, 0, 2 | DECOMP_COMPAT, 4181}, + {0xFCFE, 0, 2 | DECOMP_COMPAT, 4183}, + {0xFCFF, 0, 2 | DECOMP_COMPAT, 4185}, + {0xFD00, 0, 2 | DECOMP_COMPAT, 4187}, + {0xFD01, 0, 2 | DECOMP_COMPAT, 4189}, + {0xFD02, 0, 2 | DECOMP_COMPAT, 4191}, + {0xFD03, 0, 2 | DECOMP_COMPAT, 4193}, + {0xFD04, 0, 2 | DECOMP_COMPAT, 4195}, + {0xFD05, 0, 2 | DECOMP_COMPAT, 4197}, + {0xFD06, 0, 2 | DECOMP_COMPAT, 4199}, + {0xFD07, 0, 2 | DECOMP_COMPAT, 4201}, + {0xFD08, 0, 2 | DECOMP_COMPAT, 4203}, + {0xFD09, 0, 2 | DECOMP_COMPAT, 4205}, + {0xFD0A, 0, 2 | DECOMP_COMPAT, 4207}, + {0xFD0B, 0, 2 | DECOMP_COMPAT, 4209}, + {0xFD0C, 0, 2 | DECOMP_COMPAT, 4211}, + {0xFD0D, 0, 2 | DECOMP_COMPAT, 4213}, + {0xFD0E, 0, 2 | DECOMP_COMPAT, 4215}, + {0xFD0F, 0, 2 | DECOMP_COMPAT, 4217}, + {0xFD10, 0, 2 | DECOMP_COMPAT, 4219}, + {0xFD11, 0, 2 | DECOMP_COMPAT, 4221}, + {0xFD12, 0, 2 | DECOMP_COMPAT, 4223}, + {0xFD13, 0, 2 | DECOMP_COMPAT, 4225}, + {0xFD14, 0, 2 | DECOMP_COMPAT, 4227}, + {0xFD15, 0, 2 | DECOMP_COMPAT, 4229}, + {0xFD16, 0, 2 | DECOMP_COMPAT, 4231}, + {0xFD17, 0, 2 | DECOMP_COMPAT, 4233}, + {0xFD18, 0, 2 | DECOMP_COMPAT, 4235}, + {0xFD19, 0, 2 | DECOMP_COMPAT, 4237}, + {0xFD1A, 0, 2 | DECOMP_COMPAT, 4239}, + {0xFD1B, 0, 2 | DECOMP_COMPAT, 4241}, + {0xFD1C, 0, 2 | DECOMP_COMPAT, 4243}, + {0xFD1D, 0, 2 | DECOMP_COMPAT, 4245}, + {0xFD1E, 0, 2 | DECOMP_COMPAT, 4247}, + {0xFD1F, 0, 2 | DECOMP_COMPAT, 4249}, + {0xFD20, 0, 2 | DECOMP_COMPAT, 4251}, + {0xFD21, 0, 2 | DECOMP_COMPAT, 4253}, + {0xFD22, 0, 2 | DECOMP_COMPAT, 4255}, + {0xFD23, 0, 2 | DECOMP_COMPAT, 4257}, + {0xFD24, 0, 2 | DECOMP_COMPAT, 4259}, + {0xFD25, 0, 2 | DECOMP_COMPAT, 4261}, + {0xFD26, 0, 2 | DECOMP_COMPAT, 4263}, + {0xFD27, 0, 2 | DECOMP_COMPAT, 4265}, + {0xFD28, 0, 2 | DECOMP_COMPAT, 4267}, + {0xFD29, 0, 2 | DECOMP_COMPAT, 4269}, + {0xFD2A, 0, 2 | DECOMP_COMPAT, 4271}, + {0xFD2B, 0, 2 | DECOMP_COMPAT, 4273}, + {0xFD2C, 0, 2 | DECOMP_COMPAT, 4275}, + {0xFD2D, 0, 2 | DECOMP_COMPAT, 4277}, + {0xFD2E, 0, 2 | DECOMP_COMPAT, 4279}, + {0xFD2F, 0, 2 | DECOMP_COMPAT, 4281}, + {0xFD30, 0, 2 | DECOMP_COMPAT, 4283}, + {0xFD31, 0, 2 | DECOMP_COMPAT, 4285}, + {0xFD32, 0, 2 | DECOMP_COMPAT, 4287}, + {0xFD33, 0, 2 | DECOMP_COMPAT, 4289}, + {0xFD34, 0, 2 | DECOMP_COMPAT, 4291}, + {0xFD35, 0, 2 | DECOMP_COMPAT, 4293}, + {0xFD36, 0, 2 | DECOMP_COMPAT, 4295}, + {0xFD37, 0, 2 | DECOMP_COMPAT, 4297}, + {0xFD38, 0, 2 | DECOMP_COMPAT, 4299}, + {0xFD39, 0, 2 | DECOMP_COMPAT, 4301}, + {0xFD3A, 0, 2 | DECOMP_COMPAT, 4303}, + {0xFD3B, 0, 2 | DECOMP_COMPAT, 4305}, + {0xFD3C, 0, 2 | DECOMP_COMPAT, 4307}, + {0xFD3D, 0, 2 | DECOMP_COMPAT, 4309}, + {0xFD50, 0, 3 | DECOMP_COMPAT, 4311}, + {0xFD51, 0, 3 | DECOMP_COMPAT, 4314}, + {0xFD52, 0, 3 | DECOMP_COMPAT, 4317}, + {0xFD53, 0, 3 | DECOMP_COMPAT, 4320}, + {0xFD54, 0, 3 | DECOMP_COMPAT, 4323}, + {0xFD55, 0, 3 | DECOMP_COMPAT, 4326}, + {0xFD56, 0, 3 | DECOMP_COMPAT, 4329}, + {0xFD57, 0, 3 | DECOMP_COMPAT, 4332}, + {0xFD58, 0, 3 | DECOMP_COMPAT, 4335}, + {0xFD59, 0, 3 | DECOMP_COMPAT, 4338}, + {0xFD5A, 0, 3 | DECOMP_COMPAT, 4341}, + {0xFD5B, 0, 3 | DECOMP_COMPAT, 4344}, + {0xFD5C, 0, 3 | DECOMP_COMPAT, 4347}, + {0xFD5D, 0, 3 | DECOMP_COMPAT, 4350}, + {0xFD5E, 0, 3 | DECOMP_COMPAT, 4353}, + {0xFD5F, 0, 3 | DECOMP_COMPAT, 4356}, + {0xFD60, 0, 3 | DECOMP_COMPAT, 4359}, + {0xFD61, 0, 3 | DECOMP_COMPAT, 4362}, + {0xFD62, 0, 3 | DECOMP_COMPAT, 4365}, + {0xFD63, 0, 3 | DECOMP_COMPAT, 4368}, + {0xFD64, 0, 3 | DECOMP_COMPAT, 4371}, + {0xFD65, 0, 3 | DECOMP_COMPAT, 4374}, + {0xFD66, 0, 3 | DECOMP_COMPAT, 4377}, + {0xFD67, 0, 3 | DECOMP_COMPAT, 4380}, + {0xFD68, 0, 3 | DECOMP_COMPAT, 4383}, + {0xFD69, 0, 3 | DECOMP_COMPAT, 4386}, + {0xFD6A, 0, 3 | DECOMP_COMPAT, 4389}, + {0xFD6B, 0, 3 | DECOMP_COMPAT, 4392}, + {0xFD6C, 0, 3 | DECOMP_COMPAT, 4395}, + {0xFD6D, 0, 3 | DECOMP_COMPAT, 4398}, + {0xFD6E, 0, 3 | DECOMP_COMPAT, 4401}, + {0xFD6F, 0, 3 | DECOMP_COMPAT, 4404}, + {0xFD70, 0, 3 | DECOMP_COMPAT, 4407}, + {0xFD71, 0, 3 | DECOMP_COMPAT, 4410}, + {0xFD72, 0, 3 | DECOMP_COMPAT, 4413}, + {0xFD73, 0, 3 | DECOMP_COMPAT, 4416}, + {0xFD74, 0, 3 | DECOMP_COMPAT, 4419}, + {0xFD75, 0, 3 | DECOMP_COMPAT, 4422}, + {0xFD76, 0, 3 | DECOMP_COMPAT, 4425}, + {0xFD77, 0, 3 | DECOMP_COMPAT, 4428}, + {0xFD78, 0, 3 | DECOMP_COMPAT, 4431}, + {0xFD79, 0, 3 | DECOMP_COMPAT, 4434}, + {0xFD7A, 0, 3 | DECOMP_COMPAT, 4437}, + {0xFD7B, 0, 3 | DECOMP_COMPAT, 4440}, + {0xFD7C, 0, 3 | DECOMP_COMPAT, 4443}, + {0xFD7D, 0, 3 | DECOMP_COMPAT, 4446}, + {0xFD7E, 0, 3 | DECOMP_COMPAT, 4449}, + {0xFD7F, 0, 3 | DECOMP_COMPAT, 4452}, + {0xFD80, 0, 3 | DECOMP_COMPAT, 4455}, + {0xFD81, 0, 3 | DECOMP_COMPAT, 4458}, + {0xFD82, 0, 3 | DECOMP_COMPAT, 4461}, + {0xFD83, 0, 3 | DECOMP_COMPAT, 4464}, + {0xFD84, 0, 3 | DECOMP_COMPAT, 4467}, + {0xFD85, 0, 3 | DECOMP_COMPAT, 4470}, + {0xFD86, 0, 3 | DECOMP_COMPAT, 4473}, + {0xFD87, 0, 3 | DECOMP_COMPAT, 4476}, + {0xFD88, 0, 3 | DECOMP_COMPAT, 4479}, + {0xFD89, 0, 3 | DECOMP_COMPAT, 4482}, + {0xFD8A, 0, 3 | DECOMP_COMPAT, 4485}, + {0xFD8B, 0, 3 | DECOMP_COMPAT, 4488}, + {0xFD8C, 0, 3 | DECOMP_COMPAT, 4491}, + {0xFD8D, 0, 3 | DECOMP_COMPAT, 4494}, + {0xFD8E, 0, 3 | DECOMP_COMPAT, 4497}, + {0xFD8F, 0, 3 | DECOMP_COMPAT, 4500}, + {0xFD92, 0, 3 | DECOMP_COMPAT, 4503}, + {0xFD93, 0, 3 | DECOMP_COMPAT, 4506}, + {0xFD94, 0, 3 | DECOMP_COMPAT, 4509}, + {0xFD95, 0, 3 | DECOMP_COMPAT, 4512}, + {0xFD96, 0, 3 | DECOMP_COMPAT, 4515}, + {0xFD97, 0, 3 | DECOMP_COMPAT, 4518}, + {0xFD98, 0, 3 | DECOMP_COMPAT, 4521}, + {0xFD99, 0, 3 | DECOMP_COMPAT, 4524}, + {0xFD9A, 0, 3 | DECOMP_COMPAT, 4527}, + {0xFD9B, 0, 3 | DECOMP_COMPAT, 4530}, + {0xFD9C, 0, 3 | DECOMP_COMPAT, 4533}, + {0xFD9D, 0, 3 | DECOMP_COMPAT, 4536}, + {0xFD9E, 0, 3 | DECOMP_COMPAT, 4539}, + {0xFD9F, 0, 3 | DECOMP_COMPAT, 4542}, + {0xFDA0, 0, 3 | DECOMP_COMPAT, 4545}, + {0xFDA1, 0, 3 | DECOMP_COMPAT, 4548}, + {0xFDA2, 0, 3 | DECOMP_COMPAT, 4551}, + {0xFDA3, 0, 3 | DECOMP_COMPAT, 4554}, + {0xFDA4, 0, 3 | DECOMP_COMPAT, 4557}, + {0xFDA5, 0, 3 | DECOMP_COMPAT, 4560}, + {0xFDA6, 0, 3 | DECOMP_COMPAT, 4563}, + {0xFDA7, 0, 3 | DECOMP_COMPAT, 4566}, + {0xFDA8, 0, 3 | DECOMP_COMPAT, 4569}, + {0xFDA9, 0, 3 | DECOMP_COMPAT, 4572}, + {0xFDAA, 0, 3 | DECOMP_COMPAT, 4575}, + {0xFDAB, 0, 3 | DECOMP_COMPAT, 4578}, + {0xFDAC, 0, 3 | DECOMP_COMPAT, 4581}, + {0xFDAD, 0, 3 | DECOMP_COMPAT, 4584}, + {0xFDAE, 0, 3 | DECOMP_COMPAT, 4587}, + {0xFDAF, 0, 3 | DECOMP_COMPAT, 4590}, + {0xFDB0, 0, 3 | DECOMP_COMPAT, 4593}, + {0xFDB1, 0, 3 | DECOMP_COMPAT, 4596}, + {0xFDB2, 0, 3 | DECOMP_COMPAT, 4599}, + {0xFDB3, 0, 3 | DECOMP_COMPAT, 4602}, + {0xFDB4, 0, 3 | DECOMP_COMPAT, 4605}, + {0xFDB5, 0, 3 | DECOMP_COMPAT, 4608}, + {0xFDB6, 0, 3 | DECOMP_COMPAT, 4611}, + {0xFDB7, 0, 3 | DECOMP_COMPAT, 4614}, + {0xFDB8, 0, 3 | DECOMP_COMPAT, 4617}, + {0xFDB9, 0, 3 | DECOMP_COMPAT, 4620}, + {0xFDBA, 0, 3 | DECOMP_COMPAT, 4623}, + {0xFDBB, 0, 3 | DECOMP_COMPAT, 4626}, + {0xFDBC, 0, 3 | DECOMP_COMPAT, 4629}, + {0xFDBD, 0, 3 | DECOMP_COMPAT, 4632}, + {0xFDBE, 0, 3 | DECOMP_COMPAT, 4635}, + {0xFDBF, 0, 3 | DECOMP_COMPAT, 4638}, + {0xFDC0, 0, 3 | DECOMP_COMPAT, 4641}, + {0xFDC1, 0, 3 | DECOMP_COMPAT, 4644}, + {0xFDC2, 0, 3 | DECOMP_COMPAT, 4647}, + {0xFDC3, 0, 3 | DECOMP_COMPAT, 4650}, + {0xFDC4, 0, 3 | DECOMP_COMPAT, 4653}, + {0xFDC5, 0, 3 | DECOMP_COMPAT, 4656}, + {0xFDC6, 0, 3 | DECOMP_COMPAT, 4659}, + {0xFDC7, 0, 3 | DECOMP_COMPAT, 4662}, + {0xFDF0, 0, 3 | DECOMP_COMPAT, 4665}, + {0xFDF1, 0, 3 | DECOMP_COMPAT, 4668}, + {0xFDF2, 0, 4 | DECOMP_COMPAT, 4671}, + {0xFDF3, 0, 4 | DECOMP_COMPAT, 4675}, + {0xFDF4, 0, 4 | DECOMP_COMPAT, 4679}, + {0xFDF5, 0, 4 | DECOMP_COMPAT, 4683}, + {0xFDF6, 0, 4 | DECOMP_COMPAT, 4687}, + {0xFDF7, 0, 4 | DECOMP_COMPAT, 4691}, + {0xFDF8, 0, 4 | DECOMP_COMPAT, 4695}, + {0xFDF9, 0, 3 | DECOMP_COMPAT, 4699}, + {0xFDFA, 0, 18 | DECOMP_COMPAT, 4702}, + {0xFDFB, 0, 8 | DECOMP_COMPAT, 4720}, + {0xFDFC, 0, 4 | DECOMP_COMPAT, 4728}, + {0xFE10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFE11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFE12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3002}, + {0xFE13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFE14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFE15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFE16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFE17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3016}, + {0xFE18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3017}, + {0xFE19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2026}, + {0xFE20, 230, 0, 0}, + {0xFE21, 230, 0, 0}, + {0xFE22, 230, 0, 0}, + {0xFE23, 230, 0, 0}, + {0xFE24, 230, 0, 0}, + {0xFE25, 230, 0, 0}, + {0xFE26, 230, 0, 0}, + {0xFE27, 220, 0, 0}, + {0xFE28, 220, 0, 0}, + {0xFE29, 220, 0, 0}, + {0xFE2A, 220, 0, 0}, + {0xFE2B, 220, 0, 0}, + {0xFE2C, 220, 0, 0}, + {0xFE2D, 220, 0, 0}, + {0xFE2E, 230, 0, 0}, + {0xFE2F, 230, 0, 0}, + {0xFE30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2025}, + {0xFE31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2014}, + {0xFE32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2013}, + {0xFE33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFE36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFE37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFE38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFE39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3014}, + {0xFE3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3015}, + {0xFE3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3010}, + {0xFE3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3011}, + {0xFE3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300A}, + {0xFE3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300B}, + {0xFE3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3008}, + {0xFE40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3009}, + {0xFE41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300C}, + {0xFE42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300D}, + {0xFE43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300E}, + {0xFE44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300F}, + {0xFE47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005B}, + {0xFE48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005D}, + {0xFE49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFE51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFE52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0xFE54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFE55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFE56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFE57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFE58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2014}, + {0xFE59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFE5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFE5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFE5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFE5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3014}, + {0xFE5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3015}, + {0xFE5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0023}, + {0xFE60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0026}, + {0xFE61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002A}, + {0xFE62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFE63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002D}, + {0xFE64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003C}, + {0xFE65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003E}, + {0xFE66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0xFE68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005C}, + {0xFE69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0024}, + {0xFE6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0025}, + {0xFE6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0040}, + {0xFE70, 0, 2 | DECOMP_COMPAT, 4732}, + {0xFE71, 0, 2 | DECOMP_COMPAT, 4734}, + {0xFE72, 0, 2 | DECOMP_COMPAT, 4736}, + {0xFE74, 0, 2 | DECOMP_COMPAT, 4738}, + {0xFE76, 0, 2 | DECOMP_COMPAT, 4740}, + {0xFE77, 0, 2 | DECOMP_COMPAT, 4742}, + {0xFE78, 0, 2 | DECOMP_COMPAT, 4744}, + {0xFE79, 0, 2 | DECOMP_COMPAT, 4746}, + {0xFE7A, 0, 2 | DECOMP_COMPAT, 4748}, + {0xFE7B, 0, 2 | DECOMP_COMPAT, 4750}, + {0xFE7C, 0, 2 | DECOMP_COMPAT, 4752}, + {0xFE7D, 0, 2 | DECOMP_COMPAT, 4754}, + {0xFE7E, 0, 2 | DECOMP_COMPAT, 4756}, + {0xFE7F, 0, 2 | DECOMP_COMPAT, 4758}, + {0xFE80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0621}, + {0xFE81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0622}, + {0xFE82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0622}, + {0xFE83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0623}, + {0xFE84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0623}, + {0xFE85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0624}, + {0xFE86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0624}, + {0xFE87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0625}, + {0xFE88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0625}, + {0xFE89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0xFE8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0xFE8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0629}, + {0xFE94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0629}, + {0xFE95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFE9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFE9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFEA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFEA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0xFEAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0xFEAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0xFEAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0xFEAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0xFEAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0xFEAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0xFEB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0xFEB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEC0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEC1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFECE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFECF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFED0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFED1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEDE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEDF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0xFEEE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0xFEEF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFEF0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFEF1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF5, 0, 2 | DECOMP_COMPAT, 4760}, + {0xFEF6, 0, 2 | DECOMP_COMPAT, 4762}, + {0xFEF7, 0, 2 | DECOMP_COMPAT, 4764}, + {0xFEF8, 0, 2 | DECOMP_COMPAT, 4766}, + {0xFEF9, 0, 2 | DECOMP_COMPAT, 4768}, + {0xFEFA, 0, 2 | DECOMP_COMPAT, 4770}, + {0xFEFB, 0, 2 | DECOMP_COMPAT, 4772}, + {0xFEFC, 0, 2 | DECOMP_COMPAT, 4774}, + {0xFF01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFF02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0022}, + {0xFF03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0023}, + {0xFF04, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0024}, + {0xFF05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0025}, + {0xFF06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0026}, + {0xFF07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0027}, + {0xFF08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFF09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFF0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002A}, + {0xFF0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFF0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFF0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002D}, + {0xFF0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0xFF0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002F}, + {0xFF10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0xFF11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0xFF12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0xFF13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0xFF14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0xFF15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0xFF16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0xFF17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0xFF18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0xFF19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0xFF1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFF1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFF1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003C}, + {0xFF1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0xFF1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003E}, + {0xFF1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFF20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0040}, + {0xFF21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0xFF22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0xFF23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0xFF24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0xFF25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0xFF26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0xFF27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0xFF28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0xFF29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0xFF2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0xFF2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0xFF2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0xFF2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0xFF2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0xFF2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0xFF30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0xFF31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0xFF32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0xFF33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0xFF34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0xFF35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0xFF36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0xFF37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0xFF38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0xFF39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0xFF3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0xFF3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005B}, + {0xFF3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005C}, + {0xFF3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005D}, + {0xFF3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005E}, + {0xFF3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFF40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0060}, + {0xFF41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0xFF42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0xFF43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0xFF44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0xFF45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0xFF46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0xFF47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0xFF48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0xFF49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0xFF4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0xFF4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0xFF4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0xFF4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0xFF4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0xFF4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0xFF50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0xFF51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0xFF52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0xFF53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0xFF54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0xFF55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0xFF56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0xFF57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0xFF58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0xFF59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0xFF5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0xFF5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFF5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007C}, + {0xFF5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFF5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007E}, + {0xFF5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2985}, + {0xFF60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2986}, + {0xFF61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3002}, + {0xFF62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300C}, + {0xFF63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300D}, + {0xFF64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFF65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30FB}, + {0xFF66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F2}, + {0xFF67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A1}, + {0xFF68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A3}, + {0xFF69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A5}, + {0xFF6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A7}, + {0xFF6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A9}, + {0xFF6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E3}, + {0xFF6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E5}, + {0xFF6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E7}, + {0xFF6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C3}, + {0xFF70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30FC}, + {0xFF71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A2}, + {0xFF72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A4}, + {0xFF73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A6}, + {0xFF74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A8}, + {0xFF75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AA}, + {0xFF76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AB}, + {0xFF77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AD}, + {0xFF78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AF}, + {0xFF79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B1}, + {0xFF7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B3}, + {0xFF7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0xFF7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B7}, + {0xFF7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B9}, + {0xFF7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BB}, + {0xFF7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BD}, + {0xFF80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BF}, + {0xFF81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C1}, + {0xFF82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C4}, + {0xFF83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C6}, + {0xFF84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C8}, + {0xFF85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CA}, + {0xFF86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CB}, + {0xFF87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CC}, + {0xFF88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CD}, + {0xFF89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CE}, + {0xFF8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CF}, + {0xFF8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D2}, + {0xFF8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D5}, + {0xFF8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D8}, + {0xFF8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DB}, + {0xFF8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DE}, + {0xFF90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DF}, + {0xFF91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E0}, + {0xFF92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E1}, + {0xFF93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E2}, + {0xFF94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E4}, + {0xFF95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E6}, + {0xFF96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E8}, + {0xFF97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E9}, + {0xFF98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EA}, + {0xFF99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EB}, + {0xFF9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EC}, + {0xFF9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30ED}, + {0xFF9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EF}, + {0xFF9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F3}, + {0xFF9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3099}, + {0xFF9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x309A}, + {0xFFA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3164}, + {0xFFA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3131}, + {0xFFA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3132}, + {0xFFA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3133}, + {0xFFA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3134}, + {0xFFA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3135}, + {0xFFA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3136}, + {0xFFA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3137}, + {0xFFA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3138}, + {0xFFA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3139}, + {0xFFAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313A}, + {0xFFAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313B}, + {0xFFAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313C}, + {0xFFAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313D}, + {0xFFAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313E}, + {0xFFAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313F}, + {0xFFB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3140}, + {0xFFB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3141}, + {0xFFB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3142}, + {0xFFB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3143}, + {0xFFB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3144}, + {0xFFB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3145}, + {0xFFB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3146}, + {0xFFB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3147}, + {0xFFB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3148}, + {0xFFB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3149}, + {0xFFBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314A}, + {0xFFBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314B}, + {0xFFBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314C}, + {0xFFBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314D}, + {0xFFBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314E}, + {0xFFC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314F}, + {0xFFC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3150}, + {0xFFC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3151}, + {0xFFC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3152}, + {0xFFC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3153}, + {0xFFC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3154}, + {0xFFCA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3155}, + {0xFFCB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3156}, + {0xFFCC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3157}, + {0xFFCD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3158}, + {0xFFCE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3159}, + {0xFFCF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315A}, + {0xFFD2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315B}, + {0xFFD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315C}, + {0xFFD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315D}, + {0xFFD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315E}, + {0xFFD6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315F}, + {0xFFD7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3160}, + {0xFFDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3161}, + {0xFFDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3162}, + {0xFFDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3163}, + {0xFFE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A2}, + {0xFFE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A3}, + {0xFFE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00AC}, + {0xFFE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00AF}, + {0xFFE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A6}, + {0xFFE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A5}, + {0xFFE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x20A9}, + {0xFFE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2502}, + {0xFFE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2190}, + {0xFFEA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2191}, + {0xFFEB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2192}, + {0xFFEC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2193}, + {0xFFED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x25A0}, + {0xFFEE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x25CB}, + {0x101FD, 220, 0, 0}, + {0x102E0, 220, 0, 0}, + {0x10376, 230, 0, 0}, + {0x10377, 230, 0, 0}, + {0x10378, 230, 0, 0}, + {0x10379, 230, 0, 0}, + {0x1037A, 230, 0, 0}, + {0x10781, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02D0}, + {0x10782, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02D1}, + {0x10783, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00E6}, + {0x10784, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0299}, + {0x10785, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0253}, + {0x10787, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A3}, + {0x10788, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB66}, + {0x10789, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A5}, + {0x1078A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A4}, + {0x1078B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0256}, + {0x1078C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0257}, + {0x1078D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D91}, + {0x1078E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0258}, + {0x1078F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025E}, + {0x10790, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A9}, + {0x10791, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0264}, + {0x10792, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0262}, + {0x10793, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0260}, + {0x10794, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029B}, + {0x10795, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0127}, + {0x10796, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029C}, + {0x10797, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0267}, + {0x10798, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0284}, + {0x10799, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02AA}, + {0x1079A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02AB}, + {0x1079B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026C}, + {0x1079C, 0, 1 | DECOMP_COMPAT, 4776}, + {0x1079D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA78E}, + {0x1079E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026E}, + {0x1079F, 0, 1 | DECOMP_COMPAT, 4777}, + {0x107A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028E}, + {0x107A1, 0, 1 | DECOMP_COMPAT, 4778}, + {0x107A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00F8}, + {0x107A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0276}, + {0x107A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0277}, + {0x107A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x107A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027A}, + {0x107A7, 0, 1 | DECOMP_COMPAT, 4779}, + {0x107A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027D}, + {0x107A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027E}, + {0x107AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0280}, + {0x107AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A8}, + {0x107AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A6}, + {0x107AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB67}, + {0x107AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A7}, + {0x107AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0288}, + {0x107B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2C71}, + {0x107B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028F}, + {0x107B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A1}, + {0x107B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A2}, + {0x107B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0298}, + {0x107B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C0}, + {0x107B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C1}, + {0x107B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C2}, + {0x107B9, 0, 1 | DECOMP_COMPAT, 4780}, + {0x107BA, 0, 1 | DECOMP_COMPAT, 4781}, + {0x10A0D, 220, 0, 0}, + {0x10A0F, 230, 0, 0}, + {0x10A38, 230, 0, 0}, + {0x10A39, 1, 0, 0}, + {0x10A3A, 220, 0, 0}, + {0x10A3F, 9, 0, 0}, + {0x10AE5, 230, 0, 0}, + {0x10AE6, 220, 0, 0}, + {0x10D24, 230, 0, 0}, + {0x10D25, 230, 0, 0}, + {0x10D26, 230, 0, 0}, + {0x10D27, 230, 0, 0}, + {0x10EAB, 230, 0, 0}, + {0x10EAC, 230, 0, 0}, + {0x10EFD, 220, 0, 0}, + {0x10EFE, 220, 0, 0}, + {0x10EFF, 220, 0, 0}, + {0x10F46, 220, 0, 0}, + {0x10F47, 220, 0, 0}, + {0x10F48, 230, 0, 0}, + {0x10F49, 230, 0, 0}, + {0x10F4A, 230, 0, 0}, + {0x10F4B, 220, 0, 0}, + {0x10F4C, 230, 0, 0}, + {0x10F4D, 220, 0, 0}, + {0x10F4E, 220, 0, 0}, + {0x10F4F, 220, 0, 0}, + {0x10F50, 220, 0, 0}, + {0x10F82, 230, 0, 0}, + {0x10F83, 220, 0, 0}, + {0x10F84, 230, 0, 0}, + {0x10F85, 220, 0, 0}, + {0x11046, 9, 0, 0}, + {0x11070, 9, 0, 0}, + {0x1107F, 9, 0, 0}, + {0x1109A, 0, 2, 4782}, + {0x1109C, 0, 2, 4784}, + {0x110AB, 0, 2, 4786}, + {0x110B9, 9, 0, 0}, + {0x110BA, 7, 0, 0}, + {0x11100, 230, 0, 0}, + {0x11101, 230, 0, 0}, + {0x11102, 230, 0, 0}, + {0x1112E, 0, 2, 4788}, + {0x1112F, 0, 2, 4790}, + {0x11133, 9, 0, 0}, + {0x11134, 9, 0, 0}, + {0x11173, 7, 0, 0}, + {0x111C0, 9, 0, 0}, + {0x111CA, 7, 0, 0}, + {0x11235, 9, 0, 0}, + {0x11236, 7, 0, 0}, + {0x112E9, 7, 0, 0}, + {0x112EA, 9, 0, 0}, + {0x1133B, 7, 0, 0}, + {0x1133C, 7, 0, 0}, + {0x1134B, 0, 2, 4792}, + {0x1134C, 0, 2, 4794}, + {0x1134D, 9, 0, 0}, + {0x11366, 230, 0, 0}, + {0x11367, 230, 0, 0}, + {0x11368, 230, 0, 0}, + {0x11369, 230, 0, 0}, + {0x1136A, 230, 0, 0}, + {0x1136B, 230, 0, 0}, + {0x1136C, 230, 0, 0}, + {0x11370, 230, 0, 0}, + {0x11371, 230, 0, 0}, + {0x11372, 230, 0, 0}, + {0x11373, 230, 0, 0}, + {0x11374, 230, 0, 0}, + {0x11442, 9, 0, 0}, + {0x11446, 7, 0, 0}, + {0x1145E, 230, 0, 0}, + {0x114BB, 0, 2, 4796}, + {0x114BC, 0, 2, 4798}, + {0x114BE, 0, 2, 4800}, + {0x114C2, 9, 0, 0}, + {0x114C3, 7, 0, 0}, + {0x115BA, 0, 2, 4802}, + {0x115BB, 0, 2, 4804}, + {0x115BF, 9, 0, 0}, + {0x115C0, 7, 0, 0}, + {0x1163F, 9, 0, 0}, + {0x116B6, 9, 0, 0}, + {0x116B7, 7, 0, 0}, + {0x1172B, 9, 0, 0}, + {0x11839, 9, 0, 0}, + {0x1183A, 7, 0, 0}, + {0x11938, 0, 2, 4806}, + {0x1193D, 9, 0, 0}, + {0x1193E, 9, 0, 0}, + {0x11943, 7, 0, 0}, + {0x119E0, 9, 0, 0}, + {0x11A34, 9, 0, 0}, + {0x11A47, 9, 0, 0}, + {0x11A99, 9, 0, 0}, + {0x11C3F, 9, 0, 0}, + {0x11D42, 7, 0, 0}, + {0x11D44, 9, 0, 0}, + {0x11D45, 9, 0, 0}, + {0x11D97, 9, 0, 0}, + {0x11F41, 9, 0, 0}, + {0x11F42, 9, 0, 0}, + {0x16AF0, 1, 0, 0}, + {0x16AF1, 1, 0, 0}, + {0x16AF2, 1, 0, 0}, + {0x16AF3, 1, 0, 0}, + {0x16AF4, 1, 0, 0}, + {0x16B30, 230, 0, 0}, + {0x16B31, 230, 0, 0}, + {0x16B32, 230, 0, 0}, + {0x16B33, 230, 0, 0}, + {0x16B34, 230, 0, 0}, + {0x16B35, 230, 0, 0}, + {0x16B36, 230, 0, 0}, + {0x16FF0, 6, 0, 0}, + {0x16FF1, 6, 0, 0}, + {0x1BC9E, 1, 0, 0}, + {0x1D15E, 0, 2 | DECOMP_NO_COMPOSE, 4808}, /* in exclusion list */ + {0x1D15F, 0, 2 | DECOMP_NO_COMPOSE, 4810}, /* in exclusion list */ + {0x1D160, 0, 2 | DECOMP_NO_COMPOSE, 4812}, /* in exclusion list */ + {0x1D161, 0, 2 | DECOMP_NO_COMPOSE, 4814}, /* in exclusion list */ + {0x1D162, 0, 2 | DECOMP_NO_COMPOSE, 4816}, /* in exclusion list */ + {0x1D163, 0, 2 | DECOMP_NO_COMPOSE, 4818}, /* in exclusion list */ + {0x1D164, 0, 2 | DECOMP_NO_COMPOSE, 4820}, /* in exclusion list */ + {0x1D165, 216, 0, 0}, + {0x1D166, 216, 0, 0}, + {0x1D167, 1, 0, 0}, + {0x1D168, 1, 0, 0}, + {0x1D169, 1, 0, 0}, + {0x1D16D, 226, 0, 0}, + {0x1D16E, 216, 0, 0}, + {0x1D16F, 216, 0, 0}, + {0x1D170, 216, 0, 0}, + {0x1D171, 216, 0, 0}, + {0x1D172, 216, 0, 0}, + {0x1D17B, 220, 0, 0}, + {0x1D17C, 220, 0, 0}, + {0x1D17D, 220, 0, 0}, + {0x1D17E, 220, 0, 0}, + {0x1D17F, 220, 0, 0}, + {0x1D180, 220, 0, 0}, + {0x1D181, 220, 0, 0}, + {0x1D182, 220, 0, 0}, + {0x1D185, 230, 0, 0}, + {0x1D186, 230, 0, 0}, + {0x1D187, 230, 0, 0}, + {0x1D188, 230, 0, 0}, + {0x1D189, 230, 0, 0}, + {0x1D18A, 220, 0, 0}, + {0x1D18B, 220, 0, 0}, + {0x1D1AA, 230, 0, 0}, + {0x1D1AB, 230, 0, 0}, + {0x1D1AC, 230, 0, 0}, + {0x1D1AD, 230, 0, 0}, + {0x1D1BB, 0, 2 | DECOMP_NO_COMPOSE, 4822}, /* in exclusion list */ + {0x1D1BC, 0, 2 | DECOMP_NO_COMPOSE, 4824}, /* in exclusion list */ + {0x1D1BD, 0, 2 | DECOMP_NO_COMPOSE, 4826}, /* in exclusion list */ + {0x1D1BE, 0, 2 | DECOMP_NO_COMPOSE, 4828}, /* in exclusion list */ + {0x1D1BF, 0, 2 | DECOMP_NO_COMPOSE, 4830}, /* in exclusion list */ + {0x1D1C0, 0, 2 | DECOMP_NO_COMPOSE, 4832}, /* in exclusion list */ + {0x1D242, 230, 0, 0}, + {0x1D243, 230, 0, 0}, + {0x1D244, 230, 0, 0}, + {0x1D400, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D401, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D402, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D403, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D404, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D405, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D406, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D407, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D408, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D409, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D40A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D40B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D40C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D40D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D40E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D40F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D410, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D411, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D412, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D413, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D414, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D415, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D416, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D417, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D418, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D419, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D41A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D41B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D41C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D41D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D41E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D41F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D420, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D421, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D422, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D423, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D424, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D425, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D426, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D427, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D428, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D429, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D42A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D42B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D42C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D42D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D42E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D42F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D430, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D431, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D432, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D433, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D434, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D435, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D436, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D437, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D438, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D439, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D43A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D43B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D43C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D43D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D43E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D43F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D440, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D441, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D442, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D443, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D444, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D445, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D446, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D447, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D448, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D449, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D44A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D44B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D44C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D44D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D44E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D44F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D450, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D451, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D452, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D453, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D454, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D456, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D457, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D458, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D459, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D45A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D45B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D45C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D45D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D45E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D45F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D460, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D461, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D462, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D463, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D464, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D465, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D466, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D467, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D468, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D469, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D46A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D46B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D46C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D46D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D46E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D46F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D470, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D471, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D472, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D473, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D474, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D475, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D476, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D477, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D478, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D479, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D47A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D47B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D47C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D47D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D47E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D47F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D480, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D481, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D482, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D483, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D484, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D485, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D486, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D487, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D488, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D489, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D48A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D48B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D48C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D48D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D48E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D48F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D490, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D491, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D492, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D493, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D494, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D495, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D496, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D497, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D498, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D499, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D49A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D49B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D49C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D49E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D49F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D4A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D4A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D4A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D4A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D4AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D4AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D4AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D4AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D4AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D4B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D4B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D4B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D4B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D4B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D4B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D4B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D4B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D4B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D4B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D4BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D4BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D4BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D4BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D4C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D4C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D4C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D4C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D4C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D4C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D4C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D4C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D4C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D4CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D4CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D4CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D4CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D4CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D4CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D4D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D4D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D4D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D4D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D4D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D4D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D4D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D4D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D4D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D4D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D4DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D4DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D4DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D4DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D4DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D4DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D4E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D4E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D4E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D4E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D4E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D4E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D4E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D4E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D4E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D4E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D4EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D4EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D4EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D4ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D4EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D4EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D4F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D4F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D4F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D4F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D4F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D4F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D4F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D4F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D4F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D4F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D4FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D4FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D4FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D4FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D4FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D4FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D500, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D501, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D502, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D503, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D504, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D505, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D507, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D508, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D509, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D50A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D50D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D50E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D50F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D510, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D511, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D512, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D513, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D514, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D516, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D517, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D518, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D519, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D51A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D51B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D51C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D51E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D51F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D520, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D521, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D522, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D523, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D524, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D525, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D526, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D527, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D528, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D529, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D52A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D52B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D52C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D52D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D52E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D52F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D530, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D531, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D532, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D533, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D534, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D535, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D536, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D537, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D538, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D539, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D53B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D53C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D53D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D53E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D540, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D541, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D542, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D543, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D544, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D546, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D54A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D54B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D54C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D54D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D54E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D54F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D550, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D552, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D553, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D554, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D555, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D556, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D557, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D558, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D559, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D55A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D55B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D55C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D55D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D55E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D55F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D560, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D561, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D562, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D563, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D564, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D565, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D566, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D567, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D568, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D569, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D56A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D56B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D56C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D56D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D56E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D56F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D570, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D571, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D572, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D573, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D574, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D575, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D576, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D577, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D578, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D579, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D57A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D57B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D57C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D57D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D57E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D57F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D580, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D581, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D582, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D583, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D584, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D585, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D586, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D587, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D588, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D589, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D58A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D58B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D58C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D58D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D58E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D58F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D590, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D591, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D592, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D593, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D594, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D595, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D596, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D597, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D598, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D599, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D59A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D59B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D59C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D59D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D59E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D59F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D5A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D5A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D5A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D5A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D5A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D5A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D5A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D5A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D5A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D5A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D5AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D5AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D5AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D5AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D5AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D5AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D5B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D5B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D5B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D5B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D5B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D5B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D5B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D5B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D5B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D5B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D5BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D5BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D5BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D5BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D5BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D5BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D5C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D5C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D5C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D5C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D5C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D5C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D5C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D5C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D5C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D5C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D5CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D5CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D5CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D5CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D5CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D5CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D5D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D5D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D5D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D5D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D5D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D5D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D5D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D5D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D5D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D5D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D5DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D5DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D5DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D5DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D5DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D5DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D5E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D5E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D5E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D5E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D5E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D5E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D5E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D5E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D5E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D5E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D5EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D5EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D5EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D5ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D5EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D5EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D5F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D5F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D5F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D5F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D5F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D5F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D5F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D5F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D5F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D5F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D5FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D5FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D5FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D5FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D5FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D5FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D600, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D601, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D602, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D603, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D604, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D605, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D606, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D607, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D608, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D609, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D60A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D60B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D60C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D60D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D60E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D60F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D610, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D611, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D612, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D613, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D614, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D615, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D616, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D617, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D618, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D619, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D61A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D61B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D61C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D61D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D61E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D61F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D620, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D621, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D622, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D623, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D624, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D625, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D626, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D627, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D628, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D629, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D62A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D62B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D62C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D62D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D62E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D62F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D630, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D631, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D632, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D633, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D634, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D635, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D636, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D637, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D638, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D639, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D63A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D63B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D63C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D63D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D63E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D63F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D640, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D641, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D642, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D643, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D644, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D645, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D646, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D647, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D648, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D649, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D64A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D64B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D64C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D64D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D64E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D64F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D650, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D651, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D652, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D653, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D654, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D655, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D656, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D657, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D658, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D659, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D65A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D65B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D65C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D65D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D65E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D65F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D660, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D661, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D662, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D663, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D664, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D665, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D666, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D667, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D668, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D669, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D66A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D66B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D66C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D66D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D66E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D66F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D670, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D671, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D672, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D673, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D674, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D675, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D676, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D677, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D678, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D679, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D67A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D67B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D67C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D67D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D67E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D67F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D680, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D681, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D682, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D683, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D684, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D685, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D686, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D687, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D688, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D689, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D68A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D68B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D68C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D68D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D68E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D68F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D690, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D691, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D692, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D693, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D694, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D695, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D696, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D697, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D698, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D699, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D69A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D69B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D69C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D69D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D69E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D69F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D6A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D6A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D6A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D6A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D6A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0131}, + {0x1D6A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0237}, + {0x1D6A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D6A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D6AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D6AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D6AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D6AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D6AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D6AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D6B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D6B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D6B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D6B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D6B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D6B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D6B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D6B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D6B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D6B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D6BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D6BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D6BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D6BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D6BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D6BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D6C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D6C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D6C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D6C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D6C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D6C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D6C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D6C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D6C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D6C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D6CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D6CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D6CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D6CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D6CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D6CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D6D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D6D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D6D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D6D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D6D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D6D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D6D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D6D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D6D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D6D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D6DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D6DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D6DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D6DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D6DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D6DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D6E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D6E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D6E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D6E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D6E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D6E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D6E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D6E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D6E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D6E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D6EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D6EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D6EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D6ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D6EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D6EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D6F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D6F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D6F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D6F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D6F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D6F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D6F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D6F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D6F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D6F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D6FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D6FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D6FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D6FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D6FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D6FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D700, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D701, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D702, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D703, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D704, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D705, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D706, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D707, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D708, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D709, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D70A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D70B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D70C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D70D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D70E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D70F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D710, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D711, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D712, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D713, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D714, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D715, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D716, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D717, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D718, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D719, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D71A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D71B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D71C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D71D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D71E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D71F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D720, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D721, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D722, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D723, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D724, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D725, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D726, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D727, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D728, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D729, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D72A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D72B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D72C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D72D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D72E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D72F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D730, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D731, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D732, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D733, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D734, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D735, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D736, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D737, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D738, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D739, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D73A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D73B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D73C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D73D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D73E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D73F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D740, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D741, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D742, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D743, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D744, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D745, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D746, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D747, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D748, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D749, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D74A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D74B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D74C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D74D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D74E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D74F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D750, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D751, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D752, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D753, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D754, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D755, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D756, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D757, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D758, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D759, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D75A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D75B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D75C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D75D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D75E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D75F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D760, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D761, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D762, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D763, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D764, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D765, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D766, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D767, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D768, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D769, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D76A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D76B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D76C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D76D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D76E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D76F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D770, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D771, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D772, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D773, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D774, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D775, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D776, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D777, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D778, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D779, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D77A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D77B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D77C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D77D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D77E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D77F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D780, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D781, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D782, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D783, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D784, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D785, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D786, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D787, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D788, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D789, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D78A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D78B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D78C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D78D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D78E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D78F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D790, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D791, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D792, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D793, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D794, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D795, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D796, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D797, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D798, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D799, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D79A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D79B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D79C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D79D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D79E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D79F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D7A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D7A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D7A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D7A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D7A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D7A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D7A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D7A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D7A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D7A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D7AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D7AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D7AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D7AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D7AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D7AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D7B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D7B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D7B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D7B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D7B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D7B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D7B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D7B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D7B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D7B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D7BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D7BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D7BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D7BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D7BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D7BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D7C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D7C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D7C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D7C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D7C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D7C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D7C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D7C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D7C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D7C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D7CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03DC}, + {0x1D7CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03DD}, + {0x1D7CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1E000, 230, 0, 0}, + {0x1E001, 230, 0, 0}, + {0x1E002, 230, 0, 0}, + {0x1E003, 230, 0, 0}, + {0x1E004, 230, 0, 0}, + {0x1E005, 230, 0, 0}, + {0x1E006, 230, 0, 0}, + {0x1E008, 230, 0, 0}, + {0x1E009, 230, 0, 0}, + {0x1E00A, 230, 0, 0}, + {0x1E00B, 230, 0, 0}, + {0x1E00C, 230, 0, 0}, + {0x1E00D, 230, 0, 0}, + {0x1E00E, 230, 0, 0}, + {0x1E00F, 230, 0, 0}, + {0x1E010, 230, 0, 0}, + {0x1E011, 230, 0, 0}, + {0x1E012, 230, 0, 0}, + {0x1E013, 230, 0, 0}, + {0x1E014, 230, 0, 0}, + {0x1E015, 230, 0, 0}, + {0x1E016, 230, 0, 0}, + {0x1E017, 230, 0, 0}, + {0x1E018, 230, 0, 0}, + {0x1E01B, 230, 0, 0}, + {0x1E01C, 230, 0, 0}, + {0x1E01D, 230, 0, 0}, + {0x1E01E, 230, 0, 0}, + {0x1E01F, 230, 0, 0}, + {0x1E020, 230, 0, 0}, + {0x1E021, 230, 0, 0}, + {0x1E023, 230, 0, 0}, + {0x1E024, 230, 0, 0}, + {0x1E026, 230, 0, 0}, + {0x1E027, 230, 0, 0}, + {0x1E028, 230, 0, 0}, + {0x1E029, 230, 0, 0}, + {0x1E02A, 230, 0, 0}, + {0x1E030, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0430}, + {0x1E031, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0431}, + {0x1E032, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0432}, + {0x1E033, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0433}, + {0x1E034, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0434}, + {0x1E035, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0435}, + {0x1E036, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0436}, + {0x1E037, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0437}, + {0x1E038, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0438}, + {0x1E039, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043A}, + {0x1E03A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043B}, + {0x1E03B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043C}, + {0x1E03C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043E}, + {0x1E03D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043F}, + {0x1E03E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0440}, + {0x1E03F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0441}, + {0x1E040, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0442}, + {0x1E041, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0443}, + {0x1E042, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0444}, + {0x1E043, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0445}, + {0x1E044, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0446}, + {0x1E045, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0447}, + {0x1E046, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0448}, + {0x1E047, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044B}, + {0x1E048, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044D}, + {0x1E049, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044E}, + {0x1E04A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA689}, + {0x1E04B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04D9}, + {0x1E04C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0456}, + {0x1E04D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0458}, + {0x1E04E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04E9}, + {0x1E04F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04AF}, + {0x1E050, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04CF}, + {0x1E051, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0430}, + {0x1E052, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0431}, + {0x1E053, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0432}, + {0x1E054, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0433}, + {0x1E055, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0434}, + {0x1E056, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0435}, + {0x1E057, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0436}, + {0x1E058, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0437}, + {0x1E059, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0438}, + {0x1E05A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043A}, + {0x1E05B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043B}, + {0x1E05C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043E}, + {0x1E05D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043F}, + {0x1E05E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0441}, + {0x1E05F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0443}, + {0x1E060, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0444}, + {0x1E061, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0445}, + {0x1E062, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0446}, + {0x1E063, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0447}, + {0x1E064, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0448}, + {0x1E065, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044A}, + {0x1E066, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044B}, + {0x1E067, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0491}, + {0x1E068, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0456}, + {0x1E069, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0455}, + {0x1E06A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x045F}, + {0x1E06B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04AB}, + {0x1E06C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA651}, + {0x1E06D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x04B1}, + {0x1E08F, 230, 0, 0}, + {0x1E130, 230, 0, 0}, + {0x1E131, 230, 0, 0}, + {0x1E132, 230, 0, 0}, + {0x1E133, 230, 0, 0}, + {0x1E134, 230, 0, 0}, + {0x1E135, 230, 0, 0}, + {0x1E136, 230, 0, 0}, + {0x1E2AE, 230, 0, 0}, + {0x1E2EC, 230, 0, 0}, + {0x1E2ED, 230, 0, 0}, + {0x1E2EE, 230, 0, 0}, + {0x1E2EF, 230, 0, 0}, + {0x1E4EC, 232, 0, 0}, + {0x1E4ED, 232, 0, 0}, + {0x1E4EE, 220, 0, 0}, + {0x1E4EF, 230, 0, 0}, + {0x1E8D0, 220, 0, 0}, + {0x1E8D1, 220, 0, 0}, + {0x1E8D2, 220, 0, 0}, + {0x1E8D3, 220, 0, 0}, + {0x1E8D4, 220, 0, 0}, + {0x1E8D5, 220, 0, 0}, + {0x1E8D6, 220, 0, 0}, + {0x1E944, 230, 0, 0}, + {0x1E945, 230, 0, 0}, + {0x1E946, 230, 0, 0}, + {0x1E947, 230, 0, 0}, + {0x1E948, 230, 0, 0}, + {0x1E949, 230, 0, 0}, + {0x1E94A, 7, 0, 0}, + {0x1EE00, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0x1EE01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EE05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EE06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EE07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EE14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EE19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066E}, + {0x1EE1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0x1EE1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A1}, + {0x1EE1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066F}, + {0x1EE21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0x1EE5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066F}, + {0x1EE61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066E}, + {0x1EE7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A1}, + {0x1EE80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0x1EE81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EE84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EE86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EE87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EE94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EE99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EEA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EEA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EEA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EEA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EEA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EEA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EEA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EEA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EEAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EEAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EEAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EEAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EEAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EEB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EEB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EEB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EEB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EEB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EEB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EEB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EEB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EEB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EEB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EEBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EEBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1F100, 0, 2 | DECOMP_COMPAT, 4834}, + {0x1F101, 0, 2 | DECOMP_COMPAT, 4836}, + {0x1F102, 0, 2 | DECOMP_COMPAT, 4838}, + {0x1F103, 0, 2 | DECOMP_COMPAT, 4840}, + {0x1F104, 0, 2 | DECOMP_COMPAT, 4842}, + {0x1F105, 0, 2 | DECOMP_COMPAT, 4844}, + {0x1F106, 0, 2 | DECOMP_COMPAT, 4846}, + {0x1F107, 0, 2 | DECOMP_COMPAT, 4848}, + {0x1F108, 0, 2 | DECOMP_COMPAT, 4850}, + {0x1F109, 0, 2 | DECOMP_COMPAT, 4852}, + {0x1F10A, 0, 2 | DECOMP_COMPAT, 4854}, + {0x1F110, 0, 3 | DECOMP_COMPAT, 4856}, + {0x1F111, 0, 3 | DECOMP_COMPAT, 4859}, + {0x1F112, 0, 3 | DECOMP_COMPAT, 4862}, + {0x1F113, 0, 3 | DECOMP_COMPAT, 4865}, + {0x1F114, 0, 3 | DECOMP_COMPAT, 4868}, + {0x1F115, 0, 3 | DECOMP_COMPAT, 4871}, + {0x1F116, 0, 3 | DECOMP_COMPAT, 4874}, + {0x1F117, 0, 3 | DECOMP_COMPAT, 4877}, + {0x1F118, 0, 3 | DECOMP_COMPAT, 4880}, + {0x1F119, 0, 3 | DECOMP_COMPAT, 4883}, + {0x1F11A, 0, 3 | DECOMP_COMPAT, 4886}, + {0x1F11B, 0, 3 | DECOMP_COMPAT, 4889}, + {0x1F11C, 0, 3 | DECOMP_COMPAT, 4892}, + {0x1F11D, 0, 3 | DECOMP_COMPAT, 4895}, + {0x1F11E, 0, 3 | DECOMP_COMPAT, 4898}, + {0x1F11F, 0, 3 | DECOMP_COMPAT, 4901}, + {0x1F120, 0, 3 | DECOMP_COMPAT, 4904}, + {0x1F121, 0, 3 | DECOMP_COMPAT, 4907}, + {0x1F122, 0, 3 | DECOMP_COMPAT, 4910}, + {0x1F123, 0, 3 | DECOMP_COMPAT, 4913}, + {0x1F124, 0, 3 | DECOMP_COMPAT, 4916}, + {0x1F125, 0, 3 | DECOMP_COMPAT, 4919}, + {0x1F126, 0, 3 | DECOMP_COMPAT, 4922}, + {0x1F127, 0, 3 | DECOMP_COMPAT, 4925}, + {0x1F128, 0, 3 | DECOMP_COMPAT, 4928}, + {0x1F129, 0, 3 | DECOMP_COMPAT, 4931}, + {0x1F12A, 0, 3 | DECOMP_COMPAT, 4934}, + {0x1F12B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1F12C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1F12D, 0, 2 | DECOMP_COMPAT, 4937}, + {0x1F12E, 0, 2 | DECOMP_COMPAT, 4939}, + {0x1F130, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1F131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1F132, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1F133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1F134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1F135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1F136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1F137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1F138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1F139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1F13A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1F13B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1F13C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1F13D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1F13E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1F13F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1F140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1F141, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1F142, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1F143, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1F144, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1F145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1F146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1F147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1F148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1F149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1F14A, 0, 2 | DECOMP_COMPAT, 4941}, + {0x1F14B, 0, 2 | DECOMP_COMPAT, 4943}, + {0x1F14C, 0, 2 | DECOMP_COMPAT, 4945}, + {0x1F14D, 0, 2 | DECOMP_COMPAT, 4947}, + {0x1F14E, 0, 3 | DECOMP_COMPAT, 4949}, + {0x1F14F, 0, 2 | DECOMP_COMPAT, 4952}, + {0x1F16A, 0, 2 | DECOMP_COMPAT, 4954}, + {0x1F16B, 0, 2 | DECOMP_COMPAT, 4956}, + {0x1F16C, 0, 2 | DECOMP_COMPAT, 4958}, + {0x1F190, 0, 2 | DECOMP_COMPAT, 4960}, + {0x1F200, 0, 2 | DECOMP_COMPAT, 4962}, + {0x1F201, 0, 2 | DECOMP_COMPAT, 4964}, + {0x1F202, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0x1F210, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x624B}, + {0x1F211, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B57}, + {0x1F212, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53CC}, + {0x1F213, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C7}, + {0x1F214, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x1F215, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x591A}, + {0x1F216, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x89E3}, + {0x1F217, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5929}, + {0x1F218, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EA4}, + {0x1F219, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6620}, + {0x1F21A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7121}, + {0x1F21B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6599}, + {0x1F21C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x524D}, + {0x1F21D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F8C}, + {0x1F21E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x518D}, + {0x1F21F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65B0}, + {0x1F220, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x521D}, + {0x1F221, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7D42}, + {0x1F222, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x751F}, + {0x1F223, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CA9}, + {0x1F224, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x58F0}, + {0x1F225, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5439}, + {0x1F226, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6F14}, + {0x1F227, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6295}, + {0x1F228, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6355}, + {0x1F229, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x1F22A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x1F22B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x904A}, + {0x1F22C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE6}, + {0x1F22D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x1F22E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53F3}, + {0x1F22F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6307}, + {0x1F230, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D70}, + {0x1F231, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6253}, + {0x1F232, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7981}, + {0x1F233, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7A7A}, + {0x1F234, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5408}, + {0x1F235, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6E80}, + {0x1F236, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6709}, + {0x1F237, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x1F238, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7533}, + {0x1F239, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5272}, + {0x1F23A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x55B6}, + {0x1F23B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x914D}, + {0x1F240, 0, 3 | DECOMP_COMPAT, 4966}, + {0x1F241, 0, 3 | DECOMP_COMPAT, 4969}, + {0x1F242, 0, 3 | DECOMP_COMPAT, 4972}, + {0x1F243, 0, 3 | DECOMP_COMPAT, 4975}, + {0x1F244, 0, 3 | DECOMP_COMPAT, 4978}, + {0x1F245, 0, 3 | DECOMP_COMPAT, 4981}, + {0x1F246, 0, 3 | DECOMP_COMPAT, 4984}, + {0x1F247, 0, 3 | DECOMP_COMPAT, 4987}, + {0x1F248, 0, 3 | DECOMP_COMPAT, 4990}, + {0x1F250, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F97}, + {0x1F251, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53EF}, + {0x1FBF0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1FBF1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1FBF2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1FBF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1FBF4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1FBF5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1FBF6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1FBF7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1FBF8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1FBF9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x2F800, 0, 1 | DECOMP_INLINE, 0x4E3D}, + {0x2F801, 0, 1 | DECOMP_INLINE, 0x4E38}, + {0x2F802, 0, 1 | DECOMP_INLINE, 0x4E41}, + {0x2F803, 0, 1, 4993}, + {0x2F804, 0, 1 | DECOMP_INLINE, 0x4F60}, + {0x2F805, 0, 1 | DECOMP_INLINE, 0x4FAE}, + {0x2F806, 0, 1 | DECOMP_INLINE, 0x4FBB}, + {0x2F807, 0, 1 | DECOMP_INLINE, 0x5002}, + {0x2F808, 0, 1 | DECOMP_INLINE, 0x507A}, + {0x2F809, 0, 1 | DECOMP_INLINE, 0x5099}, + {0x2F80A, 0, 1 | DECOMP_INLINE, 0x50E7}, + {0x2F80B, 0, 1 | DECOMP_INLINE, 0x50CF}, + {0x2F80C, 0, 1 | DECOMP_INLINE, 0x349E}, + {0x2F80D, 0, 1, 4994}, + {0x2F80E, 0, 1 | DECOMP_INLINE, 0x514D}, + {0x2F80F, 0, 1 | DECOMP_INLINE, 0x5154}, + {0x2F810, 0, 1 | DECOMP_INLINE, 0x5164}, + {0x2F811, 0, 1 | DECOMP_INLINE, 0x5177}, + {0x2F812, 0, 1, 4995}, + {0x2F813, 0, 1 | DECOMP_INLINE, 0x34B9}, + {0x2F814, 0, 1 | DECOMP_INLINE, 0x5167}, + {0x2F815, 0, 1 | DECOMP_INLINE, 0x518D}, + {0x2F816, 0, 1, 4996}, + {0x2F817, 0, 1 | DECOMP_INLINE, 0x5197}, + {0x2F818, 0, 1 | DECOMP_INLINE, 0x51A4}, + {0x2F819, 0, 1 | DECOMP_INLINE, 0x4ECC}, + {0x2F81A, 0, 1 | DECOMP_INLINE, 0x51AC}, + {0x2F81B, 0, 1 | DECOMP_INLINE, 0x51B5}, + {0x2F81C, 0, 1, 4997}, + {0x2F81D, 0, 1 | DECOMP_INLINE, 0x51F5}, + {0x2F81E, 0, 1 | DECOMP_INLINE, 0x5203}, + {0x2F81F, 0, 1 | DECOMP_INLINE, 0x34DF}, + {0x2F820, 0, 1 | DECOMP_INLINE, 0x523B}, + {0x2F821, 0, 1 | DECOMP_INLINE, 0x5246}, + {0x2F822, 0, 1 | DECOMP_INLINE, 0x5272}, + {0x2F823, 0, 1 | DECOMP_INLINE, 0x5277}, + {0x2F824, 0, 1 | DECOMP_INLINE, 0x3515}, + {0x2F825, 0, 1 | DECOMP_INLINE, 0x52C7}, + {0x2F826, 0, 1 | DECOMP_INLINE, 0x52C9}, + {0x2F827, 0, 1 | DECOMP_INLINE, 0x52E4}, + {0x2F828, 0, 1 | DECOMP_INLINE, 0x52FA}, + {0x2F829, 0, 1 | DECOMP_INLINE, 0x5305}, + {0x2F82A, 0, 1 | DECOMP_INLINE, 0x5306}, + {0x2F82B, 0, 1 | DECOMP_INLINE, 0x5317}, + {0x2F82C, 0, 1 | DECOMP_INLINE, 0x5349}, + {0x2F82D, 0, 1 | DECOMP_INLINE, 0x5351}, + {0x2F82E, 0, 1 | DECOMP_INLINE, 0x535A}, + {0x2F82F, 0, 1 | DECOMP_INLINE, 0x5373}, + {0x2F830, 0, 1 | DECOMP_INLINE, 0x537D}, + {0x2F831, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F832, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F833, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F834, 0, 1, 4998}, + {0x2F835, 0, 1 | DECOMP_INLINE, 0x7070}, + {0x2F836, 0, 1 | DECOMP_INLINE, 0x53CA}, + {0x2F837, 0, 1 | DECOMP_INLINE, 0x53DF}, + {0x2F838, 0, 1, 4999}, + {0x2F839, 0, 1 | DECOMP_INLINE, 0x53EB}, + {0x2F83A, 0, 1 | DECOMP_INLINE, 0x53F1}, + {0x2F83B, 0, 1 | DECOMP_INLINE, 0x5406}, + {0x2F83C, 0, 1 | DECOMP_INLINE, 0x549E}, + {0x2F83D, 0, 1 | DECOMP_INLINE, 0x5438}, + {0x2F83E, 0, 1 | DECOMP_INLINE, 0x5448}, + {0x2F83F, 0, 1 | DECOMP_INLINE, 0x5468}, + {0x2F840, 0, 1 | DECOMP_INLINE, 0x54A2}, + {0x2F841, 0, 1 | DECOMP_INLINE, 0x54F6}, + {0x2F842, 0, 1 | DECOMP_INLINE, 0x5510}, + {0x2F843, 0, 1 | DECOMP_INLINE, 0x5553}, + {0x2F844, 0, 1 | DECOMP_INLINE, 0x5563}, + {0x2F845, 0, 1 | DECOMP_INLINE, 0x5584}, + {0x2F846, 0, 1 | DECOMP_INLINE, 0x5584}, + {0x2F847, 0, 1 | DECOMP_INLINE, 0x5599}, + {0x2F848, 0, 1 | DECOMP_INLINE, 0x55AB}, + {0x2F849, 0, 1 | DECOMP_INLINE, 0x55B3}, + {0x2F84A, 0, 1 | DECOMP_INLINE, 0x55C2}, + {0x2F84B, 0, 1 | DECOMP_INLINE, 0x5716}, + {0x2F84C, 0, 1 | DECOMP_INLINE, 0x5606}, + {0x2F84D, 0, 1 | DECOMP_INLINE, 0x5717}, + {0x2F84E, 0, 1 | DECOMP_INLINE, 0x5651}, + {0x2F84F, 0, 1 | DECOMP_INLINE, 0x5674}, + {0x2F850, 0, 1 | DECOMP_INLINE, 0x5207}, + {0x2F851, 0, 1 | DECOMP_INLINE, 0x58EE}, + {0x2F852, 0, 1 | DECOMP_INLINE, 0x57CE}, + {0x2F853, 0, 1 | DECOMP_INLINE, 0x57F4}, + {0x2F854, 0, 1 | DECOMP_INLINE, 0x580D}, + {0x2F855, 0, 1 | DECOMP_INLINE, 0x578B}, + {0x2F856, 0, 1 | DECOMP_INLINE, 0x5832}, + {0x2F857, 0, 1 | DECOMP_INLINE, 0x5831}, + {0x2F858, 0, 1 | DECOMP_INLINE, 0x58AC}, + {0x2F859, 0, 1, 5000}, + {0x2F85A, 0, 1 | DECOMP_INLINE, 0x58F2}, + {0x2F85B, 0, 1 | DECOMP_INLINE, 0x58F7}, + {0x2F85C, 0, 1 | DECOMP_INLINE, 0x5906}, + {0x2F85D, 0, 1 | DECOMP_INLINE, 0x591A}, + {0x2F85E, 0, 1 | DECOMP_INLINE, 0x5922}, + {0x2F85F, 0, 1 | DECOMP_INLINE, 0x5962}, + {0x2F860, 0, 1, 5001}, + {0x2F861, 0, 1, 5002}, + {0x2F862, 0, 1 | DECOMP_INLINE, 0x59EC}, + {0x2F863, 0, 1 | DECOMP_INLINE, 0x5A1B}, + {0x2F864, 0, 1 | DECOMP_INLINE, 0x5A27}, + {0x2F865, 0, 1 | DECOMP_INLINE, 0x59D8}, + {0x2F866, 0, 1 | DECOMP_INLINE, 0x5A66}, + {0x2F867, 0, 1 | DECOMP_INLINE, 0x36EE}, + {0x2F868, 0, 1 | DECOMP_INLINE, 0x36FC}, + {0x2F869, 0, 1 | DECOMP_INLINE, 0x5B08}, + {0x2F86A, 0, 1 | DECOMP_INLINE, 0x5B3E}, + {0x2F86B, 0, 1 | DECOMP_INLINE, 0x5B3E}, + {0x2F86C, 0, 1, 5003}, + {0x2F86D, 0, 1 | DECOMP_INLINE, 0x5BC3}, + {0x2F86E, 0, 1 | DECOMP_INLINE, 0x5BD8}, + {0x2F86F, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0x2F870, 0, 1 | DECOMP_INLINE, 0x5BF3}, + {0x2F871, 0, 1, 5004}, + {0x2F872, 0, 1 | DECOMP_INLINE, 0x5BFF}, + {0x2F873, 0, 1 | DECOMP_INLINE, 0x5C06}, + {0x2F874, 0, 1 | DECOMP_INLINE, 0x5F53}, + {0x2F875, 0, 1 | DECOMP_INLINE, 0x5C22}, + {0x2F876, 0, 1 | DECOMP_INLINE, 0x3781}, + {0x2F877, 0, 1 | DECOMP_INLINE, 0x5C60}, + {0x2F878, 0, 1 | DECOMP_INLINE, 0x5C6E}, + {0x2F879, 0, 1 | DECOMP_INLINE, 0x5CC0}, + {0x2F87A, 0, 1 | DECOMP_INLINE, 0x5C8D}, + {0x2F87B, 0, 1, 5005}, + {0x2F87C, 0, 1 | DECOMP_INLINE, 0x5D43}, + {0x2F87D, 0, 1, 5006}, + {0x2F87E, 0, 1 | DECOMP_INLINE, 0x5D6E}, + {0x2F87F, 0, 1 | DECOMP_INLINE, 0x5D6B}, + {0x2F880, 0, 1 | DECOMP_INLINE, 0x5D7C}, + {0x2F881, 0, 1 | DECOMP_INLINE, 0x5DE1}, + {0x2F882, 0, 1 | DECOMP_INLINE, 0x5DE2}, + {0x2F883, 0, 1 | DECOMP_INLINE, 0x382F}, + {0x2F884, 0, 1 | DECOMP_INLINE, 0x5DFD}, + {0x2F885, 0, 1 | DECOMP_INLINE, 0x5E28}, + {0x2F886, 0, 1 | DECOMP_INLINE, 0x5E3D}, + {0x2F887, 0, 1 | DECOMP_INLINE, 0x5E69}, + {0x2F888, 0, 1 | DECOMP_INLINE, 0x3862}, + {0x2F889, 0, 1, 5007}, + {0x2F88A, 0, 1 | DECOMP_INLINE, 0x387C}, + {0x2F88B, 0, 1 | DECOMP_INLINE, 0x5EB0}, + {0x2F88C, 0, 1 | DECOMP_INLINE, 0x5EB3}, + {0x2F88D, 0, 1 | DECOMP_INLINE, 0x5EB6}, + {0x2F88E, 0, 1 | DECOMP_INLINE, 0x5ECA}, + {0x2F88F, 0, 1, 5008}, + {0x2F890, 0, 1 | DECOMP_INLINE, 0x5EFE}, + {0x2F891, 0, 1, 5009}, + {0x2F892, 0, 1, 5010}, + {0x2F893, 0, 1 | DECOMP_INLINE, 0x8201}, + {0x2F894, 0, 1 | DECOMP_INLINE, 0x5F22}, + {0x2F895, 0, 1 | DECOMP_INLINE, 0x5F22}, + {0x2F896, 0, 1 | DECOMP_INLINE, 0x38C7}, + {0x2F897, 0, 1, 5011}, + {0x2F898, 0, 1, 5012}, + {0x2F899, 0, 1 | DECOMP_INLINE, 0x5F62}, + {0x2F89A, 0, 1 | DECOMP_INLINE, 0x5F6B}, + {0x2F89B, 0, 1 | DECOMP_INLINE, 0x38E3}, + {0x2F89C, 0, 1 | DECOMP_INLINE, 0x5F9A}, + {0x2F89D, 0, 1 | DECOMP_INLINE, 0x5FCD}, + {0x2F89E, 0, 1 | DECOMP_INLINE, 0x5FD7}, + {0x2F89F, 0, 1 | DECOMP_INLINE, 0x5FF9}, + {0x2F8A0, 0, 1 | DECOMP_INLINE, 0x6081}, + {0x2F8A1, 0, 1 | DECOMP_INLINE, 0x393A}, + {0x2F8A2, 0, 1 | DECOMP_INLINE, 0x391C}, + {0x2F8A3, 0, 1 | DECOMP_INLINE, 0x6094}, + {0x2F8A4, 0, 1, 5013}, + {0x2F8A5, 0, 1 | DECOMP_INLINE, 0x60C7}, + {0x2F8A6, 0, 1 | DECOMP_INLINE, 0x6148}, + {0x2F8A7, 0, 1 | DECOMP_INLINE, 0x614C}, + {0x2F8A8, 0, 1 | DECOMP_INLINE, 0x614E}, + {0x2F8A9, 0, 1 | DECOMP_INLINE, 0x614C}, + {0x2F8AA, 0, 1 | DECOMP_INLINE, 0x617A}, + {0x2F8AB, 0, 1 | DECOMP_INLINE, 0x618E}, + {0x2F8AC, 0, 1 | DECOMP_INLINE, 0x61B2}, + {0x2F8AD, 0, 1 | DECOMP_INLINE, 0x61A4}, + {0x2F8AE, 0, 1 | DECOMP_INLINE, 0x61AF}, + {0x2F8AF, 0, 1 | DECOMP_INLINE, 0x61DE}, + {0x2F8B0, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0x2F8B1, 0, 1 | DECOMP_INLINE, 0x61F6}, + {0x2F8B2, 0, 1 | DECOMP_INLINE, 0x6210}, + {0x2F8B3, 0, 1 | DECOMP_INLINE, 0x621B}, + {0x2F8B4, 0, 1 | DECOMP_INLINE, 0x625D}, + {0x2F8B5, 0, 1 | DECOMP_INLINE, 0x62B1}, + {0x2F8B6, 0, 1 | DECOMP_INLINE, 0x62D4}, + {0x2F8B7, 0, 1 | DECOMP_INLINE, 0x6350}, + {0x2F8B8, 0, 1, 5014}, + {0x2F8B9, 0, 1 | DECOMP_INLINE, 0x633D}, + {0x2F8BA, 0, 1 | DECOMP_INLINE, 0x62FC}, + {0x2F8BB, 0, 1 | DECOMP_INLINE, 0x6368}, + {0x2F8BC, 0, 1 | DECOMP_INLINE, 0x6383}, + {0x2F8BD, 0, 1 | DECOMP_INLINE, 0x63E4}, + {0x2F8BE, 0, 1, 5015}, + {0x2F8BF, 0, 1 | DECOMP_INLINE, 0x6422}, + {0x2F8C0, 0, 1 | DECOMP_INLINE, 0x63C5}, + {0x2F8C1, 0, 1 | DECOMP_INLINE, 0x63A9}, + {0x2F8C2, 0, 1 | DECOMP_INLINE, 0x3A2E}, + {0x2F8C3, 0, 1 | DECOMP_INLINE, 0x6469}, + {0x2F8C4, 0, 1 | DECOMP_INLINE, 0x647E}, + {0x2F8C5, 0, 1 | DECOMP_INLINE, 0x649D}, + {0x2F8C6, 0, 1 | DECOMP_INLINE, 0x6477}, + {0x2F8C7, 0, 1 | DECOMP_INLINE, 0x3A6C}, + {0x2F8C8, 0, 1 | DECOMP_INLINE, 0x654F}, + {0x2F8C9, 0, 1 | DECOMP_INLINE, 0x656C}, + {0x2F8CA, 0, 1, 5016}, + {0x2F8CB, 0, 1 | DECOMP_INLINE, 0x65E3}, + {0x2F8CC, 0, 1 | DECOMP_INLINE, 0x66F8}, + {0x2F8CD, 0, 1 | DECOMP_INLINE, 0x6649}, + {0x2F8CE, 0, 1 | DECOMP_INLINE, 0x3B19}, + {0x2F8CF, 0, 1 | DECOMP_INLINE, 0x6691}, + {0x2F8D0, 0, 1 | DECOMP_INLINE, 0x3B08}, + {0x2F8D1, 0, 1 | DECOMP_INLINE, 0x3AE4}, + {0x2F8D2, 0, 1 | DECOMP_INLINE, 0x5192}, + {0x2F8D3, 0, 1 | DECOMP_INLINE, 0x5195}, + {0x2F8D4, 0, 1 | DECOMP_INLINE, 0x6700}, + {0x2F8D5, 0, 1 | DECOMP_INLINE, 0x669C}, + {0x2F8D6, 0, 1 | DECOMP_INLINE, 0x80AD}, + {0x2F8D7, 0, 1 | DECOMP_INLINE, 0x43D9}, + {0x2F8D8, 0, 1 | DECOMP_INLINE, 0x6717}, + {0x2F8D9, 0, 1 | DECOMP_INLINE, 0x671B}, + {0x2F8DA, 0, 1 | DECOMP_INLINE, 0x6721}, + {0x2F8DB, 0, 1 | DECOMP_INLINE, 0x675E}, + {0x2F8DC, 0, 1 | DECOMP_INLINE, 0x6753}, + {0x2F8DD, 0, 1, 5017}, + {0x2F8DE, 0, 1 | DECOMP_INLINE, 0x3B49}, + {0x2F8DF, 0, 1 | DECOMP_INLINE, 0x67FA}, + {0x2F8E0, 0, 1 | DECOMP_INLINE, 0x6785}, + {0x2F8E1, 0, 1 | DECOMP_INLINE, 0x6852}, + {0x2F8E2, 0, 1 | DECOMP_INLINE, 0x6885}, + {0x2F8E3, 0, 1, 5018}, + {0x2F8E4, 0, 1 | DECOMP_INLINE, 0x688E}, + {0x2F8E5, 0, 1 | DECOMP_INLINE, 0x681F}, + {0x2F8E6, 0, 1 | DECOMP_INLINE, 0x6914}, + {0x2F8E7, 0, 1 | DECOMP_INLINE, 0x3B9D}, + {0x2F8E8, 0, 1 | DECOMP_INLINE, 0x6942}, + {0x2F8E9, 0, 1 | DECOMP_INLINE, 0x69A3}, + {0x2F8EA, 0, 1 | DECOMP_INLINE, 0x69EA}, + {0x2F8EB, 0, 1 | DECOMP_INLINE, 0x6AA8}, + {0x2F8EC, 0, 1, 5019}, + {0x2F8ED, 0, 1 | DECOMP_INLINE, 0x6ADB}, + {0x2F8EE, 0, 1 | DECOMP_INLINE, 0x3C18}, + {0x2F8EF, 0, 1 | DECOMP_INLINE, 0x6B21}, + {0x2F8F0, 0, 1, 5020}, + {0x2F8F1, 0, 1 | DECOMP_INLINE, 0x6B54}, + {0x2F8F2, 0, 1 | DECOMP_INLINE, 0x3C4E}, + {0x2F8F3, 0, 1 | DECOMP_INLINE, 0x6B72}, + {0x2F8F4, 0, 1 | DECOMP_INLINE, 0x6B9F}, + {0x2F8F5, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0x2F8F6, 0, 1 | DECOMP_INLINE, 0x6BBB}, + {0x2F8F7, 0, 1, 5021}, + {0x2F8F8, 0, 1, 5022}, + {0x2F8F9, 0, 1, 5023}, + {0x2F8FA, 0, 1 | DECOMP_INLINE, 0x6C4E}, + {0x2F8FB, 0, 1, 5024}, + {0x2F8FC, 0, 1 | DECOMP_INLINE, 0x6CBF}, + {0x2F8FD, 0, 1 | DECOMP_INLINE, 0x6CCD}, + {0x2F8FE, 0, 1 | DECOMP_INLINE, 0x6C67}, + {0x2F8FF, 0, 1 | DECOMP_INLINE, 0x6D16}, + {0x2F900, 0, 1 | DECOMP_INLINE, 0x6D3E}, + {0x2F901, 0, 1 | DECOMP_INLINE, 0x6D77}, + {0x2F902, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0x2F903, 0, 1 | DECOMP_INLINE, 0x6D69}, + {0x2F904, 0, 1 | DECOMP_INLINE, 0x6D78}, + {0x2F905, 0, 1 | DECOMP_INLINE, 0x6D85}, + {0x2F906, 0, 1, 5025}, + {0x2F907, 0, 1 | DECOMP_INLINE, 0x6D34}, + {0x2F908, 0, 1 | DECOMP_INLINE, 0x6E2F}, + {0x2F909, 0, 1 | DECOMP_INLINE, 0x6E6E}, + {0x2F90A, 0, 1 | DECOMP_INLINE, 0x3D33}, + {0x2F90B, 0, 1 | DECOMP_INLINE, 0x6ECB}, + {0x2F90C, 0, 1 | DECOMP_INLINE, 0x6EC7}, + {0x2F90D, 0, 1, 5026}, + {0x2F90E, 0, 1 | DECOMP_INLINE, 0x6DF9}, + {0x2F90F, 0, 1 | DECOMP_INLINE, 0x6F6E}, + {0x2F910, 0, 1, 5027}, + {0x2F911, 0, 1, 5028}, + {0x2F912, 0, 1 | DECOMP_INLINE, 0x6FC6}, + {0x2F913, 0, 1 | DECOMP_INLINE, 0x7039}, + {0x2F914, 0, 1 | DECOMP_INLINE, 0x701E}, + {0x2F915, 0, 1 | DECOMP_INLINE, 0x701B}, + {0x2F916, 0, 1 | DECOMP_INLINE, 0x3D96}, + {0x2F917, 0, 1 | DECOMP_INLINE, 0x704A}, + {0x2F918, 0, 1 | DECOMP_INLINE, 0x707D}, + {0x2F919, 0, 1 | DECOMP_INLINE, 0x7077}, + {0x2F91A, 0, 1 | DECOMP_INLINE, 0x70AD}, + {0x2F91B, 0, 1, 5029}, + {0x2F91C, 0, 1 | DECOMP_INLINE, 0x7145}, + {0x2F91D, 0, 1, 5030}, + {0x2F91E, 0, 1 | DECOMP_INLINE, 0x719C}, + {0x2F91F, 0, 1, 5031}, + {0x2F920, 0, 1 | DECOMP_INLINE, 0x7228}, + {0x2F921, 0, 1 | DECOMP_INLINE, 0x7235}, + {0x2F922, 0, 1 | DECOMP_INLINE, 0x7250}, + {0x2F923, 0, 1, 5032}, + {0x2F924, 0, 1 | DECOMP_INLINE, 0x7280}, + {0x2F925, 0, 1 | DECOMP_INLINE, 0x7295}, + {0x2F926, 0, 1, 5033}, + {0x2F927, 0, 1, 5034}, + {0x2F928, 0, 1 | DECOMP_INLINE, 0x737A}, + {0x2F929, 0, 1 | DECOMP_INLINE, 0x738B}, + {0x2F92A, 0, 1 | DECOMP_INLINE, 0x3EAC}, + {0x2F92B, 0, 1 | DECOMP_INLINE, 0x73A5}, + {0x2F92C, 0, 1 | DECOMP_INLINE, 0x3EB8}, + {0x2F92D, 0, 1 | DECOMP_INLINE, 0x3EB8}, + {0x2F92E, 0, 1 | DECOMP_INLINE, 0x7447}, + {0x2F92F, 0, 1 | DECOMP_INLINE, 0x745C}, + {0x2F930, 0, 1 | DECOMP_INLINE, 0x7471}, + {0x2F931, 0, 1 | DECOMP_INLINE, 0x7485}, + {0x2F932, 0, 1 | DECOMP_INLINE, 0x74CA}, + {0x2F933, 0, 1 | DECOMP_INLINE, 0x3F1B}, + {0x2F934, 0, 1 | DECOMP_INLINE, 0x7524}, + {0x2F935, 0, 1, 5035}, + {0x2F936, 0, 1 | DECOMP_INLINE, 0x753E}, + {0x2F937, 0, 1, 5036}, + {0x2F938, 0, 1 | DECOMP_INLINE, 0x7570}, + {0x2F939, 0, 1, 5037}, + {0x2F93A, 0, 1 | DECOMP_INLINE, 0x7610}, + {0x2F93B, 0, 1, 5038}, + {0x2F93C, 0, 1, 5039}, + {0x2F93D, 0, 1, 5040}, + {0x2F93E, 0, 1 | DECOMP_INLINE, 0x3FFC}, + {0x2F93F, 0, 1 | DECOMP_INLINE, 0x4008}, + {0x2F940, 0, 1 | DECOMP_INLINE, 0x76F4}, + {0x2F941, 0, 1, 5041}, + {0x2F942, 0, 1, 5042}, + {0x2F943, 0, 1, 5043}, + {0x2F944, 0, 1, 5044}, + {0x2F945, 0, 1 | DECOMP_INLINE, 0x771E}, + {0x2F946, 0, 1 | DECOMP_INLINE, 0x771F}, + {0x2F947, 0, 1 | DECOMP_INLINE, 0x771F}, + {0x2F948, 0, 1 | DECOMP_INLINE, 0x774A}, + {0x2F949, 0, 1 | DECOMP_INLINE, 0x4039}, + {0x2F94A, 0, 1 | DECOMP_INLINE, 0x778B}, + {0x2F94B, 0, 1 | DECOMP_INLINE, 0x4046}, + {0x2F94C, 0, 1 | DECOMP_INLINE, 0x4096}, + {0x2F94D, 0, 1, 5045}, + {0x2F94E, 0, 1 | DECOMP_INLINE, 0x784E}, + {0x2F94F, 0, 1 | DECOMP_INLINE, 0x788C}, + {0x2F950, 0, 1 | DECOMP_INLINE, 0x78CC}, + {0x2F951, 0, 1 | DECOMP_INLINE, 0x40E3}, + {0x2F952, 0, 1, 5046}, + {0x2F953, 0, 1 | DECOMP_INLINE, 0x7956}, + {0x2F954, 0, 1, 5047}, + {0x2F955, 0, 1, 5048}, + {0x2F956, 0, 1 | DECOMP_INLINE, 0x798F}, + {0x2F957, 0, 1 | DECOMP_INLINE, 0x79EB}, + {0x2F958, 0, 1 | DECOMP_INLINE, 0x412F}, + {0x2F959, 0, 1 | DECOMP_INLINE, 0x7A40}, + {0x2F95A, 0, 1 | DECOMP_INLINE, 0x7A4A}, + {0x2F95B, 0, 1 | DECOMP_INLINE, 0x7A4F}, + {0x2F95C, 0, 1, 5049}, + {0x2F95D, 0, 1, 5050}, + {0x2F95E, 0, 1, 5051}, + {0x2F95F, 0, 1 | DECOMP_INLINE, 0x7AEE}, + {0x2F960, 0, 1 | DECOMP_INLINE, 0x4202}, + {0x2F961, 0, 1, 5052}, + {0x2F962, 0, 1 | DECOMP_INLINE, 0x7BC6}, + {0x2F963, 0, 1 | DECOMP_INLINE, 0x7BC9}, + {0x2F964, 0, 1 | DECOMP_INLINE, 0x4227}, + {0x2F965, 0, 1, 5053}, + {0x2F966, 0, 1 | DECOMP_INLINE, 0x7CD2}, + {0x2F967, 0, 1 | DECOMP_INLINE, 0x42A0}, + {0x2F968, 0, 1 | DECOMP_INLINE, 0x7CE8}, + {0x2F969, 0, 1 | DECOMP_INLINE, 0x7CE3}, + {0x2F96A, 0, 1 | DECOMP_INLINE, 0x7D00}, + {0x2F96B, 0, 1, 5054}, + {0x2F96C, 0, 1 | DECOMP_INLINE, 0x7D63}, + {0x2F96D, 0, 1 | DECOMP_INLINE, 0x4301}, + {0x2F96E, 0, 1 | DECOMP_INLINE, 0x7DC7}, + {0x2F96F, 0, 1 | DECOMP_INLINE, 0x7E02}, + {0x2F970, 0, 1 | DECOMP_INLINE, 0x7E45}, + {0x2F971, 0, 1 | DECOMP_INLINE, 0x4334}, + {0x2F972, 0, 1, 5055}, + {0x2F973, 0, 1, 5056}, + {0x2F974, 0, 1 | DECOMP_INLINE, 0x4359}, + {0x2F975, 0, 1, 5057}, + {0x2F976, 0, 1 | DECOMP_INLINE, 0x7F7A}, + {0x2F977, 0, 1, 5058}, + {0x2F978, 0, 1 | DECOMP_INLINE, 0x7F95}, + {0x2F979, 0, 1 | DECOMP_INLINE, 0x7FFA}, + {0x2F97A, 0, 1 | DECOMP_INLINE, 0x8005}, + {0x2F97B, 0, 1, 5059}, + {0x2F97C, 0, 1, 5060}, + {0x2F97D, 0, 1 | DECOMP_INLINE, 0x8060}, + {0x2F97E, 0, 1, 5061}, + {0x2F97F, 0, 1 | DECOMP_INLINE, 0x8070}, + {0x2F980, 0, 1, 5062}, + {0x2F981, 0, 1 | DECOMP_INLINE, 0x43D5}, + {0x2F982, 0, 1 | DECOMP_INLINE, 0x80B2}, + {0x2F983, 0, 1 | DECOMP_INLINE, 0x8103}, + {0x2F984, 0, 1 | DECOMP_INLINE, 0x440B}, + {0x2F985, 0, 1 | DECOMP_INLINE, 0x813E}, + {0x2F986, 0, 1 | DECOMP_INLINE, 0x5AB5}, + {0x2F987, 0, 1, 5063}, + {0x2F988, 0, 1, 5064}, + {0x2F989, 0, 1, 5065}, + {0x2F98A, 0, 1, 5066}, + {0x2F98B, 0, 1 | DECOMP_INLINE, 0x8201}, + {0x2F98C, 0, 1 | DECOMP_INLINE, 0x8204}, + {0x2F98D, 0, 1 | DECOMP_INLINE, 0x8F9E}, + {0x2F98E, 0, 1 | DECOMP_INLINE, 0x446B}, + {0x2F98F, 0, 1 | DECOMP_INLINE, 0x8291}, + {0x2F990, 0, 1 | DECOMP_INLINE, 0x828B}, + {0x2F991, 0, 1 | DECOMP_INLINE, 0x829D}, + {0x2F992, 0, 1 | DECOMP_INLINE, 0x52B3}, + {0x2F993, 0, 1 | DECOMP_INLINE, 0x82B1}, + {0x2F994, 0, 1 | DECOMP_INLINE, 0x82B3}, + {0x2F995, 0, 1 | DECOMP_INLINE, 0x82BD}, + {0x2F996, 0, 1 | DECOMP_INLINE, 0x82E6}, + {0x2F997, 0, 1, 5067}, + {0x2F998, 0, 1 | DECOMP_INLINE, 0x82E5}, + {0x2F999, 0, 1 | DECOMP_INLINE, 0x831D}, + {0x2F99A, 0, 1 | DECOMP_INLINE, 0x8363}, + {0x2F99B, 0, 1 | DECOMP_INLINE, 0x83AD}, + {0x2F99C, 0, 1 | DECOMP_INLINE, 0x8323}, + {0x2F99D, 0, 1 | DECOMP_INLINE, 0x83BD}, + {0x2F99E, 0, 1 | DECOMP_INLINE, 0x83E7}, + {0x2F99F, 0, 1 | DECOMP_INLINE, 0x8457}, + {0x2F9A0, 0, 1 | DECOMP_INLINE, 0x8353}, + {0x2F9A1, 0, 1 | DECOMP_INLINE, 0x83CA}, + {0x2F9A2, 0, 1 | DECOMP_INLINE, 0x83CC}, + {0x2F9A3, 0, 1 | DECOMP_INLINE, 0x83DC}, + {0x2F9A4, 0, 1, 5068}, + {0x2F9A5, 0, 1, 5069}, + {0x2F9A6, 0, 1, 5070}, + {0x2F9A7, 0, 1 | DECOMP_INLINE, 0x452B}, + {0x2F9A8, 0, 1 | DECOMP_INLINE, 0x84F1}, + {0x2F9A9, 0, 1 | DECOMP_INLINE, 0x84F3}, + {0x2F9AA, 0, 1 | DECOMP_INLINE, 0x8516}, + {0x2F9AB, 0, 1, 5071}, + {0x2F9AC, 0, 1 | DECOMP_INLINE, 0x8564}, + {0x2F9AD, 0, 1, 5072}, + {0x2F9AE, 0, 1 | DECOMP_INLINE, 0x455D}, + {0x2F9AF, 0, 1 | DECOMP_INLINE, 0x4561}, + {0x2F9B0, 0, 1, 5073}, + {0x2F9B1, 0, 1, 5074}, + {0x2F9B2, 0, 1 | DECOMP_INLINE, 0x456B}, + {0x2F9B3, 0, 1 | DECOMP_INLINE, 0x8650}, + {0x2F9B4, 0, 1 | DECOMP_INLINE, 0x865C}, + {0x2F9B5, 0, 1 | DECOMP_INLINE, 0x8667}, + {0x2F9B6, 0, 1 | DECOMP_INLINE, 0x8669}, + {0x2F9B7, 0, 1 | DECOMP_INLINE, 0x86A9}, + {0x2F9B8, 0, 1 | DECOMP_INLINE, 0x8688}, + {0x2F9B9, 0, 1 | DECOMP_INLINE, 0x870E}, + {0x2F9BA, 0, 1 | DECOMP_INLINE, 0x86E2}, + {0x2F9BB, 0, 1 | DECOMP_INLINE, 0x8779}, + {0x2F9BC, 0, 1 | DECOMP_INLINE, 0x8728}, + {0x2F9BD, 0, 1 | DECOMP_INLINE, 0x876B}, + {0x2F9BE, 0, 1 | DECOMP_INLINE, 0x8786}, + {0x2F9BF, 0, 1 | DECOMP_INLINE, 0x45D7}, + {0x2F9C0, 0, 1 | DECOMP_INLINE, 0x87E1}, + {0x2F9C1, 0, 1 | DECOMP_INLINE, 0x8801}, + {0x2F9C2, 0, 1 | DECOMP_INLINE, 0x45F9}, + {0x2F9C3, 0, 1 | DECOMP_INLINE, 0x8860}, + {0x2F9C4, 0, 1 | DECOMP_INLINE, 0x8863}, + {0x2F9C5, 0, 1, 5075}, + {0x2F9C6, 0, 1 | DECOMP_INLINE, 0x88D7}, + {0x2F9C7, 0, 1 | DECOMP_INLINE, 0x88DE}, + {0x2F9C8, 0, 1 | DECOMP_INLINE, 0x4635}, + {0x2F9C9, 0, 1 | DECOMP_INLINE, 0x88FA}, + {0x2F9CA, 0, 1 | DECOMP_INLINE, 0x34BB}, + {0x2F9CB, 0, 1, 5076}, + {0x2F9CC, 0, 1, 5077}, + {0x2F9CD, 0, 1 | DECOMP_INLINE, 0x46BE}, + {0x2F9CE, 0, 1 | DECOMP_INLINE, 0x46C7}, + {0x2F9CF, 0, 1 | DECOMP_INLINE, 0x8AA0}, + {0x2F9D0, 0, 1 | DECOMP_INLINE, 0x8AED}, + {0x2F9D1, 0, 1 | DECOMP_INLINE, 0x8B8A}, + {0x2F9D2, 0, 1 | DECOMP_INLINE, 0x8C55}, + {0x2F9D3, 0, 1, 5078}, + {0x2F9D4, 0, 1 | DECOMP_INLINE, 0x8CAB}, + {0x2F9D5, 0, 1 | DECOMP_INLINE, 0x8CC1}, + {0x2F9D6, 0, 1 | DECOMP_INLINE, 0x8D1B}, + {0x2F9D7, 0, 1 | DECOMP_INLINE, 0x8D77}, + {0x2F9D8, 0, 1, 5079}, + {0x2F9D9, 0, 1, 5080}, + {0x2F9DA, 0, 1 | DECOMP_INLINE, 0x8DCB}, + {0x2F9DB, 0, 1 | DECOMP_INLINE, 0x8DBC}, + {0x2F9DC, 0, 1 | DECOMP_INLINE, 0x8DF0}, + {0x2F9DD, 0, 1, 5081}, + {0x2F9DE, 0, 1 | DECOMP_INLINE, 0x8ED4}, + {0x2F9DF, 0, 1 | DECOMP_INLINE, 0x8F38}, + {0x2F9E0, 0, 1, 5082}, + {0x2F9E1, 0, 1, 5083}, + {0x2F9E2, 0, 1 | DECOMP_INLINE, 0x9094}, + {0x2F9E3, 0, 1 | DECOMP_INLINE, 0x90F1}, + {0x2F9E4, 0, 1 | DECOMP_INLINE, 0x9111}, + {0x2F9E5, 0, 1, 5084}, + {0x2F9E6, 0, 1 | DECOMP_INLINE, 0x911B}, + {0x2F9E7, 0, 1 | DECOMP_INLINE, 0x9238}, + {0x2F9E8, 0, 1 | DECOMP_INLINE, 0x92D7}, + {0x2F9E9, 0, 1 | DECOMP_INLINE, 0x92D8}, + {0x2F9EA, 0, 1 | DECOMP_INLINE, 0x927C}, + {0x2F9EB, 0, 1 | DECOMP_INLINE, 0x93F9}, + {0x2F9EC, 0, 1 | DECOMP_INLINE, 0x9415}, + {0x2F9ED, 0, 1, 5085}, + {0x2F9EE, 0, 1 | DECOMP_INLINE, 0x958B}, + {0x2F9EF, 0, 1 | DECOMP_INLINE, 0x4995}, + {0x2F9F0, 0, 1 | DECOMP_INLINE, 0x95B7}, + {0x2F9F1, 0, 1, 5086}, + {0x2F9F2, 0, 1 | DECOMP_INLINE, 0x49E6}, + {0x2F9F3, 0, 1 | DECOMP_INLINE, 0x96C3}, + {0x2F9F4, 0, 1 | DECOMP_INLINE, 0x5DB2}, + {0x2F9F5, 0, 1 | DECOMP_INLINE, 0x9723}, + {0x2F9F6, 0, 1, 5087}, + {0x2F9F7, 0, 1, 5088}, + {0x2F9F8, 0, 1 | DECOMP_INLINE, 0x4A6E}, + {0x2F9F9, 0, 1 | DECOMP_INLINE, 0x4A76}, + {0x2F9FA, 0, 1 | DECOMP_INLINE, 0x97E0}, + {0x2F9FB, 0, 1, 5089}, + {0x2F9FC, 0, 1 | DECOMP_INLINE, 0x4AB2}, + {0x2F9FD, 0, 1, 5090}, + {0x2F9FE, 0, 1 | DECOMP_INLINE, 0x980B}, + {0x2F9FF, 0, 1 | DECOMP_INLINE, 0x980B}, + {0x2FA00, 0, 1 | DECOMP_INLINE, 0x9829}, + {0x2FA01, 0, 1, 5091}, + {0x2FA02, 0, 1 | DECOMP_INLINE, 0x98E2}, + {0x2FA03, 0, 1 | DECOMP_INLINE, 0x4B33}, + {0x2FA04, 0, 1 | DECOMP_INLINE, 0x9929}, + {0x2FA05, 0, 1 | DECOMP_INLINE, 0x99A7}, + {0x2FA06, 0, 1 | DECOMP_INLINE, 0x99C2}, + {0x2FA07, 0, 1 | DECOMP_INLINE, 0x99FE}, + {0x2FA08, 0, 1 | DECOMP_INLINE, 0x4BCE}, + {0x2FA09, 0, 1, 5092}, + {0x2FA0A, 0, 1 | DECOMP_INLINE, 0x9B12}, + {0x2FA0B, 0, 1 | DECOMP_INLINE, 0x9C40}, + {0x2FA0C, 0, 1 | DECOMP_INLINE, 0x9CFD}, + {0x2FA0D, 0, 1 | DECOMP_INLINE, 0x4CCE}, + {0x2FA0E, 0, 1 | DECOMP_INLINE, 0x4CED}, + {0x2FA0F, 0, 1 | DECOMP_INLINE, 0x9D67}, + {0x2FA10, 0, 1, 5093}, + {0x2FA11, 0, 1 | DECOMP_INLINE, 0x4CF8}, + {0x2FA12, 0, 1, 5094}, + {0x2FA13, 0, 1, 5095}, + {0x2FA14, 0, 1, 5096}, + {0x2FA15, 0, 1 | DECOMP_INLINE, 0x9EBB}, + {0x2FA16, 0, 1 | DECOMP_INLINE, 0x4D56}, + {0x2FA17, 0, 1 | DECOMP_INLINE, 0x9EF9}, + {0x2FA18, 0, 1 | DECOMP_INLINE, 0x9EFE}, + {0x2FA19, 0, 1 | DECOMP_INLINE, 0x9F05}, + {0x2FA1A, 0, 1 | DECOMP_INLINE, 0x9F0F}, + {0x2FA1B, 0, 1 | DECOMP_INLINE, 0x9F16}, + {0x2FA1C, 0, 1 | DECOMP_INLINE, 0x9F3B}, + {0x2FA1D, 0, 1, 5097} + +}; + +/* codepoints array */ +static const uint32 UnicodeDecomp_codepoints[5098] = +{ + /* 0 */ 0x0020, 0x0308, + /* 2 */ 0x0020, 0x0304, + /* 4 */ 0x0020, 0x0301, + /* 6 */ 0x0020, 0x0327, + /* 8 */ 0x0031, 0x2044, 0x0034, + /* 11 */ 0x0031, 0x2044, 0x0032, + /* 14 */ 0x0033, 0x2044, 0x0034, + /* 17 */ 0x0041, 0x0300, + /* 19 */ 0x0041, 0x0301, + /* 21 */ 0x0041, 0x0302, + /* 23 */ 0x0041, 0x0303, + /* 25 */ 0x0041, 0x0308, + /* 27 */ 0x0041, 0x030A, + /* 29 */ 0x0043, 0x0327, + /* 31 */ 0x0045, 0x0300, + /* 33 */ 0x0045, 0x0301, + /* 35 */ 0x0045, 0x0302, + /* 37 */ 0x0045, 0x0308, + /* 39 */ 0x0049, 0x0300, + /* 41 */ 0x0049, 0x0301, + /* 43 */ 0x0049, 0x0302, + /* 45 */ 0x0049, 0x0308, + /* 47 */ 0x004E, 0x0303, + /* 49 */ 0x004F, 0x0300, + /* 51 */ 0x004F, 0x0301, + /* 53 */ 0x004F, 0x0302, + /* 55 */ 0x004F, 0x0303, + /* 57 */ 0x004F, 0x0308, + /* 59 */ 0x0055, 0x0300, + /* 61 */ 0x0055, 0x0301, + /* 63 */ 0x0055, 0x0302, + /* 65 */ 0x0055, 0x0308, + /* 67 */ 0x0059, 0x0301, + /* 69 */ 0x0061, 0x0300, + /* 71 */ 0x0061, 0x0301, + /* 73 */ 0x0061, 0x0302, + /* 75 */ 0x0061, 0x0303, + /* 77 */ 0x0061, 0x0308, + /* 79 */ 0x0061, 0x030A, + /* 81 */ 0x0063, 0x0327, + /* 83 */ 0x0065, 0x0300, + /* 85 */ 0x0065, 0x0301, + /* 87 */ 0x0065, 0x0302, + /* 89 */ 0x0065, 0x0308, + /* 91 */ 0x0069, 0x0300, + /* 93 */ 0x0069, 0x0301, + /* 95 */ 0x0069, 0x0302, + /* 97 */ 0x0069, 0x0308, + /* 99 */ 0x006E, 0x0303, + /* 101 */ 0x006F, 0x0300, + /* 103 */ 0x006F, 0x0301, + /* 105 */ 0x006F, 0x0302, + /* 107 */ 0x006F, 0x0303, + /* 109 */ 0x006F, 0x0308, + /* 111 */ 0x0075, 0x0300, + /* 113 */ 0x0075, 0x0301, + /* 115 */ 0x0075, 0x0302, + /* 117 */ 0x0075, 0x0308, + /* 119 */ 0x0079, 0x0301, + /* 121 */ 0x0079, 0x0308, + /* 123 */ 0x0041, 0x0304, + /* 125 */ 0x0061, 0x0304, + /* 127 */ 0x0041, 0x0306, + /* 129 */ 0x0061, 0x0306, + /* 131 */ 0x0041, 0x0328, + /* 133 */ 0x0061, 0x0328, + /* 135 */ 0x0043, 0x0301, + /* 137 */ 0x0063, 0x0301, + /* 139 */ 0x0043, 0x0302, + /* 141 */ 0x0063, 0x0302, + /* 143 */ 0x0043, 0x0307, + /* 145 */ 0x0063, 0x0307, + /* 147 */ 0x0043, 0x030C, + /* 149 */ 0x0063, 0x030C, + /* 151 */ 0x0044, 0x030C, + /* 153 */ 0x0064, 0x030C, + /* 155 */ 0x0045, 0x0304, + /* 157 */ 0x0065, 0x0304, + /* 159 */ 0x0045, 0x0306, + /* 161 */ 0x0065, 0x0306, + /* 163 */ 0x0045, 0x0307, + /* 165 */ 0x0065, 0x0307, + /* 167 */ 0x0045, 0x0328, + /* 169 */ 0x0065, 0x0328, + /* 171 */ 0x0045, 0x030C, + /* 173 */ 0x0065, 0x030C, + /* 175 */ 0x0047, 0x0302, + /* 177 */ 0x0067, 0x0302, + /* 179 */ 0x0047, 0x0306, + /* 181 */ 0x0067, 0x0306, + /* 183 */ 0x0047, 0x0307, + /* 185 */ 0x0067, 0x0307, + /* 187 */ 0x0047, 0x0327, + /* 189 */ 0x0067, 0x0327, + /* 191 */ 0x0048, 0x0302, + /* 193 */ 0x0068, 0x0302, + /* 195 */ 0x0049, 0x0303, + /* 197 */ 0x0069, 0x0303, + /* 199 */ 0x0049, 0x0304, + /* 201 */ 0x0069, 0x0304, + /* 203 */ 0x0049, 0x0306, + /* 205 */ 0x0069, 0x0306, + /* 207 */ 0x0049, 0x0328, + /* 209 */ 0x0069, 0x0328, + /* 211 */ 0x0049, 0x0307, + /* 213 */ 0x0049, 0x004A, + /* 215 */ 0x0069, 0x006A, + /* 217 */ 0x004A, 0x0302, + /* 219 */ 0x006A, 0x0302, + /* 221 */ 0x004B, 0x0327, + /* 223 */ 0x006B, 0x0327, + /* 225 */ 0x004C, 0x0301, + /* 227 */ 0x006C, 0x0301, + /* 229 */ 0x004C, 0x0327, + /* 231 */ 0x006C, 0x0327, + /* 233 */ 0x004C, 0x030C, + /* 235 */ 0x006C, 0x030C, + /* 237 */ 0x004C, 0x00B7, + /* 239 */ 0x006C, 0x00B7, + /* 241 */ 0x004E, 0x0301, + /* 243 */ 0x006E, 0x0301, + /* 245 */ 0x004E, 0x0327, + /* 247 */ 0x006E, 0x0327, + /* 249 */ 0x004E, 0x030C, + /* 251 */ 0x006E, 0x030C, + /* 253 */ 0x02BC, 0x006E, + /* 255 */ 0x004F, 0x0304, + /* 257 */ 0x006F, 0x0304, + /* 259 */ 0x004F, 0x0306, + /* 261 */ 0x006F, 0x0306, + /* 263 */ 0x004F, 0x030B, + /* 265 */ 0x006F, 0x030B, + /* 267 */ 0x0052, 0x0301, + /* 269 */ 0x0072, 0x0301, + /* 271 */ 0x0052, 0x0327, + /* 273 */ 0x0072, 0x0327, + /* 275 */ 0x0052, 0x030C, + /* 277 */ 0x0072, 0x030C, + /* 279 */ 0x0053, 0x0301, + /* 281 */ 0x0073, 0x0301, + /* 283 */ 0x0053, 0x0302, + /* 285 */ 0x0073, 0x0302, + /* 287 */ 0x0053, 0x0327, + /* 289 */ 0x0073, 0x0327, + /* 291 */ 0x0053, 0x030C, + /* 293 */ 0x0073, 0x030C, + /* 295 */ 0x0054, 0x0327, + /* 297 */ 0x0074, 0x0327, + /* 299 */ 0x0054, 0x030C, + /* 301 */ 0x0074, 0x030C, + /* 303 */ 0x0055, 0x0303, + /* 305 */ 0x0075, 0x0303, + /* 307 */ 0x0055, 0x0304, + /* 309 */ 0x0075, 0x0304, + /* 311 */ 0x0055, 0x0306, + /* 313 */ 0x0075, 0x0306, + /* 315 */ 0x0055, 0x030A, + /* 317 */ 0x0075, 0x030A, + /* 319 */ 0x0055, 0x030B, + /* 321 */ 0x0075, 0x030B, + /* 323 */ 0x0055, 0x0328, + /* 325 */ 0x0075, 0x0328, + /* 327 */ 0x0057, 0x0302, + /* 329 */ 0x0077, 0x0302, + /* 331 */ 0x0059, 0x0302, + /* 333 */ 0x0079, 0x0302, + /* 335 */ 0x0059, 0x0308, + /* 337 */ 0x005A, 0x0301, + /* 339 */ 0x007A, 0x0301, + /* 341 */ 0x005A, 0x0307, + /* 343 */ 0x007A, 0x0307, + /* 345 */ 0x005A, 0x030C, + /* 347 */ 0x007A, 0x030C, + /* 349 */ 0x004F, 0x031B, + /* 351 */ 0x006F, 0x031B, + /* 353 */ 0x0055, 0x031B, + /* 355 */ 0x0075, 0x031B, + /* 357 */ 0x0044, 0x017D, + /* 359 */ 0x0044, 0x017E, + /* 361 */ 0x0064, 0x017E, + /* 363 */ 0x004C, 0x004A, + /* 365 */ 0x004C, 0x006A, + /* 367 */ 0x006C, 0x006A, + /* 369 */ 0x004E, 0x004A, + /* 371 */ 0x004E, 0x006A, + /* 373 */ 0x006E, 0x006A, + /* 375 */ 0x0041, 0x030C, + /* 377 */ 0x0061, 0x030C, + /* 379 */ 0x0049, 0x030C, + /* 381 */ 0x0069, 0x030C, + /* 383 */ 0x004F, 0x030C, + /* 385 */ 0x006F, 0x030C, + /* 387 */ 0x0055, 0x030C, + /* 389 */ 0x0075, 0x030C, + /* 391 */ 0x00DC, 0x0304, + /* 393 */ 0x00FC, 0x0304, + /* 395 */ 0x00DC, 0x0301, + /* 397 */ 0x00FC, 0x0301, + /* 399 */ 0x00DC, 0x030C, + /* 401 */ 0x00FC, 0x030C, + /* 403 */ 0x00DC, 0x0300, + /* 405 */ 0x00FC, 0x0300, + /* 407 */ 0x00C4, 0x0304, + /* 409 */ 0x00E4, 0x0304, + /* 411 */ 0x0226, 0x0304, + /* 413 */ 0x0227, 0x0304, + /* 415 */ 0x00C6, 0x0304, + /* 417 */ 0x00E6, 0x0304, + /* 419 */ 0x0047, 0x030C, + /* 421 */ 0x0067, 0x030C, + /* 423 */ 0x004B, 0x030C, + /* 425 */ 0x006B, 0x030C, + /* 427 */ 0x004F, 0x0328, + /* 429 */ 0x006F, 0x0328, + /* 431 */ 0x01EA, 0x0304, + /* 433 */ 0x01EB, 0x0304, + /* 435 */ 0x01B7, 0x030C, + /* 437 */ 0x0292, 0x030C, + /* 439 */ 0x006A, 0x030C, + /* 441 */ 0x0044, 0x005A, + /* 443 */ 0x0044, 0x007A, + /* 445 */ 0x0064, 0x007A, + /* 447 */ 0x0047, 0x0301, + /* 449 */ 0x0067, 0x0301, + /* 451 */ 0x004E, 0x0300, + /* 453 */ 0x006E, 0x0300, + /* 455 */ 0x00C5, 0x0301, + /* 457 */ 0x00E5, 0x0301, + /* 459 */ 0x00C6, 0x0301, + /* 461 */ 0x00E6, 0x0301, + /* 463 */ 0x00D8, 0x0301, + /* 465 */ 0x00F8, 0x0301, + /* 467 */ 0x0041, 0x030F, + /* 469 */ 0x0061, 0x030F, + /* 471 */ 0x0041, 0x0311, + /* 473 */ 0x0061, 0x0311, + /* 475 */ 0x0045, 0x030F, + /* 477 */ 0x0065, 0x030F, + /* 479 */ 0x0045, 0x0311, + /* 481 */ 0x0065, 0x0311, + /* 483 */ 0x0049, 0x030F, + /* 485 */ 0x0069, 0x030F, + /* 487 */ 0x0049, 0x0311, + /* 489 */ 0x0069, 0x0311, + /* 491 */ 0x004F, 0x030F, + /* 493 */ 0x006F, 0x030F, + /* 495 */ 0x004F, 0x0311, + /* 497 */ 0x006F, 0x0311, + /* 499 */ 0x0052, 0x030F, + /* 501 */ 0x0072, 0x030F, + /* 503 */ 0x0052, 0x0311, + /* 505 */ 0x0072, 0x0311, + /* 507 */ 0x0055, 0x030F, + /* 509 */ 0x0075, 0x030F, + /* 511 */ 0x0055, 0x0311, + /* 513 */ 0x0075, 0x0311, + /* 515 */ 0x0053, 0x0326, + /* 517 */ 0x0073, 0x0326, + /* 519 */ 0x0054, 0x0326, + /* 521 */ 0x0074, 0x0326, + /* 523 */ 0x0048, 0x030C, + /* 525 */ 0x0068, 0x030C, + /* 527 */ 0x0041, 0x0307, + /* 529 */ 0x0061, 0x0307, + /* 531 */ 0x0045, 0x0327, + /* 533 */ 0x0065, 0x0327, + /* 535 */ 0x00D6, 0x0304, + /* 537 */ 0x00F6, 0x0304, + /* 539 */ 0x00D5, 0x0304, + /* 541 */ 0x00F5, 0x0304, + /* 543 */ 0x004F, 0x0307, + /* 545 */ 0x006F, 0x0307, + /* 547 */ 0x022E, 0x0304, + /* 549 */ 0x022F, 0x0304, + /* 551 */ 0x0059, 0x0304, + /* 553 */ 0x0079, 0x0304, + /* 555 */ 0x0020, 0x0306, + /* 557 */ 0x0020, 0x0307, + /* 559 */ 0x0020, 0x030A, + /* 561 */ 0x0020, 0x0328, + /* 563 */ 0x0020, 0x0303, + /* 565 */ 0x0020, 0x030B, + /* 567 */ 0x0308, 0x0301, + /* 569 */ 0x0020, 0x0345, + /* 571 */ 0x0020, 0x0301, + /* 573 */ 0x00A8, 0x0301, + /* 575 */ 0x0391, 0x0301, + /* 577 */ 0x0395, 0x0301, + /* 579 */ 0x0397, 0x0301, + /* 581 */ 0x0399, 0x0301, + /* 583 */ 0x039F, 0x0301, + /* 585 */ 0x03A5, 0x0301, + /* 587 */ 0x03A9, 0x0301, + /* 589 */ 0x03CA, 0x0301, + /* 591 */ 0x0399, 0x0308, + /* 593 */ 0x03A5, 0x0308, + /* 595 */ 0x03B1, 0x0301, + /* 597 */ 0x03B5, 0x0301, + /* 599 */ 0x03B7, 0x0301, + /* 601 */ 0x03B9, 0x0301, + /* 603 */ 0x03CB, 0x0301, + /* 605 */ 0x03B9, 0x0308, + /* 607 */ 0x03C5, 0x0308, + /* 609 */ 0x03BF, 0x0301, + /* 611 */ 0x03C5, 0x0301, + /* 613 */ 0x03C9, 0x0301, + /* 615 */ 0x03D2, 0x0301, + /* 617 */ 0x03D2, 0x0308, + /* 619 */ 0x0415, 0x0300, + /* 621 */ 0x0415, 0x0308, + /* 623 */ 0x0413, 0x0301, + /* 625 */ 0x0406, 0x0308, + /* 627 */ 0x041A, 0x0301, + /* 629 */ 0x0418, 0x0300, + /* 631 */ 0x0423, 0x0306, + /* 633 */ 0x0418, 0x0306, + /* 635 */ 0x0438, 0x0306, + /* 637 */ 0x0435, 0x0300, + /* 639 */ 0x0435, 0x0308, + /* 641 */ 0x0433, 0x0301, + /* 643 */ 0x0456, 0x0308, + /* 645 */ 0x043A, 0x0301, + /* 647 */ 0x0438, 0x0300, + /* 649 */ 0x0443, 0x0306, + /* 651 */ 0x0474, 0x030F, + /* 653 */ 0x0475, 0x030F, + /* 655 */ 0x0416, 0x0306, + /* 657 */ 0x0436, 0x0306, + /* 659 */ 0x0410, 0x0306, + /* 661 */ 0x0430, 0x0306, + /* 663 */ 0x0410, 0x0308, + /* 665 */ 0x0430, 0x0308, + /* 667 */ 0x0415, 0x0306, + /* 669 */ 0x0435, 0x0306, + /* 671 */ 0x04D8, 0x0308, + /* 673 */ 0x04D9, 0x0308, + /* 675 */ 0x0416, 0x0308, + /* 677 */ 0x0436, 0x0308, + /* 679 */ 0x0417, 0x0308, + /* 681 */ 0x0437, 0x0308, + /* 683 */ 0x0418, 0x0304, + /* 685 */ 0x0438, 0x0304, + /* 687 */ 0x0418, 0x0308, + /* 689 */ 0x0438, 0x0308, + /* 691 */ 0x041E, 0x0308, + /* 693 */ 0x043E, 0x0308, + /* 695 */ 0x04E8, 0x0308, + /* 697 */ 0x04E9, 0x0308, + /* 699 */ 0x042D, 0x0308, + /* 701 */ 0x044D, 0x0308, + /* 703 */ 0x0423, 0x0304, + /* 705 */ 0x0443, 0x0304, + /* 707 */ 0x0423, 0x0308, + /* 709 */ 0x0443, 0x0308, + /* 711 */ 0x0423, 0x030B, + /* 713 */ 0x0443, 0x030B, + /* 715 */ 0x0427, 0x0308, + /* 717 */ 0x0447, 0x0308, + /* 719 */ 0x042B, 0x0308, + /* 721 */ 0x044B, 0x0308, + /* 723 */ 0x0565, 0x0582, + /* 725 */ 0x0627, 0x0653, + /* 727 */ 0x0627, 0x0654, + /* 729 */ 0x0648, 0x0654, + /* 731 */ 0x0627, 0x0655, + /* 733 */ 0x064A, 0x0654, + /* 735 */ 0x0627, 0x0674, + /* 737 */ 0x0648, 0x0674, + /* 739 */ 0x06C7, 0x0674, + /* 741 */ 0x064A, 0x0674, + /* 743 */ 0x06D5, 0x0654, + /* 745 */ 0x06C1, 0x0654, + /* 747 */ 0x06D2, 0x0654, + /* 749 */ 0x0928, 0x093C, + /* 751 */ 0x0930, 0x093C, + /* 753 */ 0x0933, 0x093C, + /* 755 */ 0x0915, 0x093C, + /* 757 */ 0x0916, 0x093C, + /* 759 */ 0x0917, 0x093C, + /* 761 */ 0x091C, 0x093C, + /* 763 */ 0x0921, 0x093C, + /* 765 */ 0x0922, 0x093C, + /* 767 */ 0x092B, 0x093C, + /* 769 */ 0x092F, 0x093C, + /* 771 */ 0x09C7, 0x09BE, + /* 773 */ 0x09C7, 0x09D7, + /* 775 */ 0x09A1, 0x09BC, + /* 777 */ 0x09A2, 0x09BC, + /* 779 */ 0x09AF, 0x09BC, + /* 781 */ 0x0A32, 0x0A3C, + /* 783 */ 0x0A38, 0x0A3C, + /* 785 */ 0x0A16, 0x0A3C, + /* 787 */ 0x0A17, 0x0A3C, + /* 789 */ 0x0A1C, 0x0A3C, + /* 791 */ 0x0A2B, 0x0A3C, + /* 793 */ 0x0B47, 0x0B56, + /* 795 */ 0x0B47, 0x0B3E, + /* 797 */ 0x0B47, 0x0B57, + /* 799 */ 0x0B21, 0x0B3C, + /* 801 */ 0x0B22, 0x0B3C, + /* 803 */ 0x0B92, 0x0BD7, + /* 805 */ 0x0BC6, 0x0BBE, + /* 807 */ 0x0BC7, 0x0BBE, + /* 809 */ 0x0BC6, 0x0BD7, + /* 811 */ 0x0C46, 0x0C56, + /* 813 */ 0x0CBF, 0x0CD5, + /* 815 */ 0x0CC6, 0x0CD5, + /* 817 */ 0x0CC6, 0x0CD6, + /* 819 */ 0x0CC6, 0x0CC2, + /* 821 */ 0x0CCA, 0x0CD5, + /* 823 */ 0x0D46, 0x0D3E, + /* 825 */ 0x0D47, 0x0D3E, + /* 827 */ 0x0D46, 0x0D57, + /* 829 */ 0x0DD9, 0x0DCA, + /* 831 */ 0x0DD9, 0x0DCF, + /* 833 */ 0x0DDC, 0x0DCA, + /* 835 */ 0x0DD9, 0x0DDF, + /* 837 */ 0x0E4D, 0x0E32, + /* 839 */ 0x0ECD, 0x0EB2, + /* 841 */ 0x0EAB, 0x0E99, + /* 843 */ 0x0EAB, 0x0EA1, + /* 845 */ 0x0F42, 0x0FB7, + /* 847 */ 0x0F4C, 0x0FB7, + /* 849 */ 0x0F51, 0x0FB7, + /* 851 */ 0x0F56, 0x0FB7, + /* 853 */ 0x0F5B, 0x0FB7, + /* 855 */ 0x0F40, 0x0FB5, + /* 857 */ 0x0F71, 0x0F72, + /* 859 */ 0x0F71, 0x0F74, + /* 861 */ 0x0FB2, 0x0F80, + /* 863 */ 0x0FB2, 0x0F81, + /* 865 */ 0x0FB3, 0x0F80, + /* 867 */ 0x0FB3, 0x0F81, + /* 869 */ 0x0F71, 0x0F80, + /* 871 */ 0x0F92, 0x0FB7, + /* 873 */ 0x0F9C, 0x0FB7, + /* 875 */ 0x0FA1, 0x0FB7, + /* 877 */ 0x0FA6, 0x0FB7, + /* 879 */ 0x0FAB, 0x0FB7, + /* 881 */ 0x0F90, 0x0FB5, + /* 883 */ 0x1025, 0x102E, + /* 885 */ 0x1B05, 0x1B35, + /* 887 */ 0x1B07, 0x1B35, + /* 889 */ 0x1B09, 0x1B35, + /* 891 */ 0x1B0B, 0x1B35, + /* 893 */ 0x1B0D, 0x1B35, + /* 895 */ 0x1B11, 0x1B35, + /* 897 */ 0x1B3A, 0x1B35, + /* 899 */ 0x1B3C, 0x1B35, + /* 901 */ 0x1B3E, 0x1B35, + /* 903 */ 0x1B3F, 0x1B35, + /* 905 */ 0x1B42, 0x1B35, + /* 907 */ 0x0041, 0x0325, + /* 909 */ 0x0061, 0x0325, + /* 911 */ 0x0042, 0x0307, + /* 913 */ 0x0062, 0x0307, + /* 915 */ 0x0042, 0x0323, + /* 917 */ 0x0062, 0x0323, + /* 919 */ 0x0042, 0x0331, + /* 921 */ 0x0062, 0x0331, + /* 923 */ 0x00C7, 0x0301, + /* 925 */ 0x00E7, 0x0301, + /* 927 */ 0x0044, 0x0307, + /* 929 */ 0x0064, 0x0307, + /* 931 */ 0x0044, 0x0323, + /* 933 */ 0x0064, 0x0323, + /* 935 */ 0x0044, 0x0331, + /* 937 */ 0x0064, 0x0331, + /* 939 */ 0x0044, 0x0327, + /* 941 */ 0x0064, 0x0327, + /* 943 */ 0x0044, 0x032D, + /* 945 */ 0x0064, 0x032D, + /* 947 */ 0x0112, 0x0300, + /* 949 */ 0x0113, 0x0300, + /* 951 */ 0x0112, 0x0301, + /* 953 */ 0x0113, 0x0301, + /* 955 */ 0x0045, 0x032D, + /* 957 */ 0x0065, 0x032D, + /* 959 */ 0x0045, 0x0330, + /* 961 */ 0x0065, 0x0330, + /* 963 */ 0x0228, 0x0306, + /* 965 */ 0x0229, 0x0306, + /* 967 */ 0x0046, 0x0307, + /* 969 */ 0x0066, 0x0307, + /* 971 */ 0x0047, 0x0304, + /* 973 */ 0x0067, 0x0304, + /* 975 */ 0x0048, 0x0307, + /* 977 */ 0x0068, 0x0307, + /* 979 */ 0x0048, 0x0323, + /* 981 */ 0x0068, 0x0323, + /* 983 */ 0x0048, 0x0308, + /* 985 */ 0x0068, 0x0308, + /* 987 */ 0x0048, 0x0327, + /* 989 */ 0x0068, 0x0327, + /* 991 */ 0x0048, 0x032E, + /* 993 */ 0x0068, 0x032E, + /* 995 */ 0x0049, 0x0330, + /* 997 */ 0x0069, 0x0330, + /* 999 */ 0x00CF, 0x0301, + /* 1001 */ 0x00EF, 0x0301, + /* 1003 */ 0x004B, 0x0301, + /* 1005 */ 0x006B, 0x0301, + /* 1007 */ 0x004B, 0x0323, + /* 1009 */ 0x006B, 0x0323, + /* 1011 */ 0x004B, 0x0331, + /* 1013 */ 0x006B, 0x0331, + /* 1015 */ 0x004C, 0x0323, + /* 1017 */ 0x006C, 0x0323, + /* 1019 */ 0x1E36, 0x0304, + /* 1021 */ 0x1E37, 0x0304, + /* 1023 */ 0x004C, 0x0331, + /* 1025 */ 0x006C, 0x0331, + /* 1027 */ 0x004C, 0x032D, + /* 1029 */ 0x006C, 0x032D, + /* 1031 */ 0x004D, 0x0301, + /* 1033 */ 0x006D, 0x0301, + /* 1035 */ 0x004D, 0x0307, + /* 1037 */ 0x006D, 0x0307, + /* 1039 */ 0x004D, 0x0323, + /* 1041 */ 0x006D, 0x0323, + /* 1043 */ 0x004E, 0x0307, + /* 1045 */ 0x006E, 0x0307, + /* 1047 */ 0x004E, 0x0323, + /* 1049 */ 0x006E, 0x0323, + /* 1051 */ 0x004E, 0x0331, + /* 1053 */ 0x006E, 0x0331, + /* 1055 */ 0x004E, 0x032D, + /* 1057 */ 0x006E, 0x032D, + /* 1059 */ 0x00D5, 0x0301, + /* 1061 */ 0x00F5, 0x0301, + /* 1063 */ 0x00D5, 0x0308, + /* 1065 */ 0x00F5, 0x0308, + /* 1067 */ 0x014C, 0x0300, + /* 1069 */ 0x014D, 0x0300, + /* 1071 */ 0x014C, 0x0301, + /* 1073 */ 0x014D, 0x0301, + /* 1075 */ 0x0050, 0x0301, + /* 1077 */ 0x0070, 0x0301, + /* 1079 */ 0x0050, 0x0307, + /* 1081 */ 0x0070, 0x0307, + /* 1083 */ 0x0052, 0x0307, + /* 1085 */ 0x0072, 0x0307, + /* 1087 */ 0x0052, 0x0323, + /* 1089 */ 0x0072, 0x0323, + /* 1091 */ 0x1E5A, 0x0304, + /* 1093 */ 0x1E5B, 0x0304, + /* 1095 */ 0x0052, 0x0331, + /* 1097 */ 0x0072, 0x0331, + /* 1099 */ 0x0053, 0x0307, + /* 1101 */ 0x0073, 0x0307, + /* 1103 */ 0x0053, 0x0323, + /* 1105 */ 0x0073, 0x0323, + /* 1107 */ 0x015A, 0x0307, + /* 1109 */ 0x015B, 0x0307, + /* 1111 */ 0x0160, 0x0307, + /* 1113 */ 0x0161, 0x0307, + /* 1115 */ 0x1E62, 0x0307, + /* 1117 */ 0x1E63, 0x0307, + /* 1119 */ 0x0054, 0x0307, + /* 1121 */ 0x0074, 0x0307, + /* 1123 */ 0x0054, 0x0323, + /* 1125 */ 0x0074, 0x0323, + /* 1127 */ 0x0054, 0x0331, + /* 1129 */ 0x0074, 0x0331, + /* 1131 */ 0x0054, 0x032D, + /* 1133 */ 0x0074, 0x032D, + /* 1135 */ 0x0055, 0x0324, + /* 1137 */ 0x0075, 0x0324, + /* 1139 */ 0x0055, 0x0330, + /* 1141 */ 0x0075, 0x0330, + /* 1143 */ 0x0055, 0x032D, + /* 1145 */ 0x0075, 0x032D, + /* 1147 */ 0x0168, 0x0301, + /* 1149 */ 0x0169, 0x0301, + /* 1151 */ 0x016A, 0x0308, + /* 1153 */ 0x016B, 0x0308, + /* 1155 */ 0x0056, 0x0303, + /* 1157 */ 0x0076, 0x0303, + /* 1159 */ 0x0056, 0x0323, + /* 1161 */ 0x0076, 0x0323, + /* 1163 */ 0x0057, 0x0300, + /* 1165 */ 0x0077, 0x0300, + /* 1167 */ 0x0057, 0x0301, + /* 1169 */ 0x0077, 0x0301, + /* 1171 */ 0x0057, 0x0308, + /* 1173 */ 0x0077, 0x0308, + /* 1175 */ 0x0057, 0x0307, + /* 1177 */ 0x0077, 0x0307, + /* 1179 */ 0x0057, 0x0323, + /* 1181 */ 0x0077, 0x0323, + /* 1183 */ 0x0058, 0x0307, + /* 1185 */ 0x0078, 0x0307, + /* 1187 */ 0x0058, 0x0308, + /* 1189 */ 0x0078, 0x0308, + /* 1191 */ 0x0059, 0x0307, + /* 1193 */ 0x0079, 0x0307, + /* 1195 */ 0x005A, 0x0302, + /* 1197 */ 0x007A, 0x0302, + /* 1199 */ 0x005A, 0x0323, + /* 1201 */ 0x007A, 0x0323, + /* 1203 */ 0x005A, 0x0331, + /* 1205 */ 0x007A, 0x0331, + /* 1207 */ 0x0068, 0x0331, + /* 1209 */ 0x0074, 0x0308, + /* 1211 */ 0x0077, 0x030A, + /* 1213 */ 0x0079, 0x030A, + /* 1215 */ 0x0061, 0x02BE, + /* 1217 */ 0x017F, 0x0307, + /* 1219 */ 0x0041, 0x0323, + /* 1221 */ 0x0061, 0x0323, + /* 1223 */ 0x0041, 0x0309, + /* 1225 */ 0x0061, 0x0309, + /* 1227 */ 0x00C2, 0x0301, + /* 1229 */ 0x00E2, 0x0301, + /* 1231 */ 0x00C2, 0x0300, + /* 1233 */ 0x00E2, 0x0300, + /* 1235 */ 0x00C2, 0x0309, + /* 1237 */ 0x00E2, 0x0309, + /* 1239 */ 0x00C2, 0x0303, + /* 1241 */ 0x00E2, 0x0303, + /* 1243 */ 0x1EA0, 0x0302, + /* 1245 */ 0x1EA1, 0x0302, + /* 1247 */ 0x0102, 0x0301, + /* 1249 */ 0x0103, 0x0301, + /* 1251 */ 0x0102, 0x0300, + /* 1253 */ 0x0103, 0x0300, + /* 1255 */ 0x0102, 0x0309, + /* 1257 */ 0x0103, 0x0309, + /* 1259 */ 0x0102, 0x0303, + /* 1261 */ 0x0103, 0x0303, + /* 1263 */ 0x1EA0, 0x0306, + /* 1265 */ 0x1EA1, 0x0306, + /* 1267 */ 0x0045, 0x0323, + /* 1269 */ 0x0065, 0x0323, + /* 1271 */ 0x0045, 0x0309, + /* 1273 */ 0x0065, 0x0309, + /* 1275 */ 0x0045, 0x0303, + /* 1277 */ 0x0065, 0x0303, + /* 1279 */ 0x00CA, 0x0301, + /* 1281 */ 0x00EA, 0x0301, + /* 1283 */ 0x00CA, 0x0300, + /* 1285 */ 0x00EA, 0x0300, + /* 1287 */ 0x00CA, 0x0309, + /* 1289 */ 0x00EA, 0x0309, + /* 1291 */ 0x00CA, 0x0303, + /* 1293 */ 0x00EA, 0x0303, + /* 1295 */ 0x1EB8, 0x0302, + /* 1297 */ 0x1EB9, 0x0302, + /* 1299 */ 0x0049, 0x0309, + /* 1301 */ 0x0069, 0x0309, + /* 1303 */ 0x0049, 0x0323, + /* 1305 */ 0x0069, 0x0323, + /* 1307 */ 0x004F, 0x0323, + /* 1309 */ 0x006F, 0x0323, + /* 1311 */ 0x004F, 0x0309, + /* 1313 */ 0x006F, 0x0309, + /* 1315 */ 0x00D4, 0x0301, + /* 1317 */ 0x00F4, 0x0301, + /* 1319 */ 0x00D4, 0x0300, + /* 1321 */ 0x00F4, 0x0300, + /* 1323 */ 0x00D4, 0x0309, + /* 1325 */ 0x00F4, 0x0309, + /* 1327 */ 0x00D4, 0x0303, + /* 1329 */ 0x00F4, 0x0303, + /* 1331 */ 0x1ECC, 0x0302, + /* 1333 */ 0x1ECD, 0x0302, + /* 1335 */ 0x01A0, 0x0301, + /* 1337 */ 0x01A1, 0x0301, + /* 1339 */ 0x01A0, 0x0300, + /* 1341 */ 0x01A1, 0x0300, + /* 1343 */ 0x01A0, 0x0309, + /* 1345 */ 0x01A1, 0x0309, + /* 1347 */ 0x01A0, 0x0303, + /* 1349 */ 0x01A1, 0x0303, + /* 1351 */ 0x01A0, 0x0323, + /* 1353 */ 0x01A1, 0x0323, + /* 1355 */ 0x0055, 0x0323, + /* 1357 */ 0x0075, 0x0323, + /* 1359 */ 0x0055, 0x0309, + /* 1361 */ 0x0075, 0x0309, + /* 1363 */ 0x01AF, 0x0301, + /* 1365 */ 0x01B0, 0x0301, + /* 1367 */ 0x01AF, 0x0300, + /* 1369 */ 0x01B0, 0x0300, + /* 1371 */ 0x01AF, 0x0309, + /* 1373 */ 0x01B0, 0x0309, + /* 1375 */ 0x01AF, 0x0303, + /* 1377 */ 0x01B0, 0x0303, + /* 1379 */ 0x01AF, 0x0323, + /* 1381 */ 0x01B0, 0x0323, + /* 1383 */ 0x0059, 0x0300, + /* 1385 */ 0x0079, 0x0300, + /* 1387 */ 0x0059, 0x0323, + /* 1389 */ 0x0079, 0x0323, + /* 1391 */ 0x0059, 0x0309, + /* 1393 */ 0x0079, 0x0309, + /* 1395 */ 0x0059, 0x0303, + /* 1397 */ 0x0079, 0x0303, + /* 1399 */ 0x03B1, 0x0313, + /* 1401 */ 0x03B1, 0x0314, + /* 1403 */ 0x1F00, 0x0300, + /* 1405 */ 0x1F01, 0x0300, + /* 1407 */ 0x1F00, 0x0301, + /* 1409 */ 0x1F01, 0x0301, + /* 1411 */ 0x1F00, 0x0342, + /* 1413 */ 0x1F01, 0x0342, + /* 1415 */ 0x0391, 0x0313, + /* 1417 */ 0x0391, 0x0314, + /* 1419 */ 0x1F08, 0x0300, + /* 1421 */ 0x1F09, 0x0300, + /* 1423 */ 0x1F08, 0x0301, + /* 1425 */ 0x1F09, 0x0301, + /* 1427 */ 0x1F08, 0x0342, + /* 1429 */ 0x1F09, 0x0342, + /* 1431 */ 0x03B5, 0x0313, + /* 1433 */ 0x03B5, 0x0314, + /* 1435 */ 0x1F10, 0x0300, + /* 1437 */ 0x1F11, 0x0300, + /* 1439 */ 0x1F10, 0x0301, + /* 1441 */ 0x1F11, 0x0301, + /* 1443 */ 0x0395, 0x0313, + /* 1445 */ 0x0395, 0x0314, + /* 1447 */ 0x1F18, 0x0300, + /* 1449 */ 0x1F19, 0x0300, + /* 1451 */ 0x1F18, 0x0301, + /* 1453 */ 0x1F19, 0x0301, + /* 1455 */ 0x03B7, 0x0313, + /* 1457 */ 0x03B7, 0x0314, + /* 1459 */ 0x1F20, 0x0300, + /* 1461 */ 0x1F21, 0x0300, + /* 1463 */ 0x1F20, 0x0301, + /* 1465 */ 0x1F21, 0x0301, + /* 1467 */ 0x1F20, 0x0342, + /* 1469 */ 0x1F21, 0x0342, + /* 1471 */ 0x0397, 0x0313, + /* 1473 */ 0x0397, 0x0314, + /* 1475 */ 0x1F28, 0x0300, + /* 1477 */ 0x1F29, 0x0300, + /* 1479 */ 0x1F28, 0x0301, + /* 1481 */ 0x1F29, 0x0301, + /* 1483 */ 0x1F28, 0x0342, + /* 1485 */ 0x1F29, 0x0342, + /* 1487 */ 0x03B9, 0x0313, + /* 1489 */ 0x03B9, 0x0314, + /* 1491 */ 0x1F30, 0x0300, + /* 1493 */ 0x1F31, 0x0300, + /* 1495 */ 0x1F30, 0x0301, + /* 1497 */ 0x1F31, 0x0301, + /* 1499 */ 0x1F30, 0x0342, + /* 1501 */ 0x1F31, 0x0342, + /* 1503 */ 0x0399, 0x0313, + /* 1505 */ 0x0399, 0x0314, + /* 1507 */ 0x1F38, 0x0300, + /* 1509 */ 0x1F39, 0x0300, + /* 1511 */ 0x1F38, 0x0301, + /* 1513 */ 0x1F39, 0x0301, + /* 1515 */ 0x1F38, 0x0342, + /* 1517 */ 0x1F39, 0x0342, + /* 1519 */ 0x03BF, 0x0313, + /* 1521 */ 0x03BF, 0x0314, + /* 1523 */ 0x1F40, 0x0300, + /* 1525 */ 0x1F41, 0x0300, + /* 1527 */ 0x1F40, 0x0301, + /* 1529 */ 0x1F41, 0x0301, + /* 1531 */ 0x039F, 0x0313, + /* 1533 */ 0x039F, 0x0314, + /* 1535 */ 0x1F48, 0x0300, + /* 1537 */ 0x1F49, 0x0300, + /* 1539 */ 0x1F48, 0x0301, + /* 1541 */ 0x1F49, 0x0301, + /* 1543 */ 0x03C5, 0x0313, + /* 1545 */ 0x03C5, 0x0314, + /* 1547 */ 0x1F50, 0x0300, + /* 1549 */ 0x1F51, 0x0300, + /* 1551 */ 0x1F50, 0x0301, + /* 1553 */ 0x1F51, 0x0301, + /* 1555 */ 0x1F50, 0x0342, + /* 1557 */ 0x1F51, 0x0342, + /* 1559 */ 0x03A5, 0x0314, + /* 1561 */ 0x1F59, 0x0300, + /* 1563 */ 0x1F59, 0x0301, + /* 1565 */ 0x1F59, 0x0342, + /* 1567 */ 0x03C9, 0x0313, + /* 1569 */ 0x03C9, 0x0314, + /* 1571 */ 0x1F60, 0x0300, + /* 1573 */ 0x1F61, 0x0300, + /* 1575 */ 0x1F60, 0x0301, + /* 1577 */ 0x1F61, 0x0301, + /* 1579 */ 0x1F60, 0x0342, + /* 1581 */ 0x1F61, 0x0342, + /* 1583 */ 0x03A9, 0x0313, + /* 1585 */ 0x03A9, 0x0314, + /* 1587 */ 0x1F68, 0x0300, + /* 1589 */ 0x1F69, 0x0300, + /* 1591 */ 0x1F68, 0x0301, + /* 1593 */ 0x1F69, 0x0301, + /* 1595 */ 0x1F68, 0x0342, + /* 1597 */ 0x1F69, 0x0342, + /* 1599 */ 0x03B1, 0x0300, + /* 1601 */ 0x03B5, 0x0300, + /* 1603 */ 0x03B7, 0x0300, + /* 1605 */ 0x03B9, 0x0300, + /* 1607 */ 0x03BF, 0x0300, + /* 1609 */ 0x03C5, 0x0300, + /* 1611 */ 0x03C9, 0x0300, + /* 1613 */ 0x1F00, 0x0345, + /* 1615 */ 0x1F01, 0x0345, + /* 1617 */ 0x1F02, 0x0345, + /* 1619 */ 0x1F03, 0x0345, + /* 1621 */ 0x1F04, 0x0345, + /* 1623 */ 0x1F05, 0x0345, + /* 1625 */ 0x1F06, 0x0345, + /* 1627 */ 0x1F07, 0x0345, + /* 1629 */ 0x1F08, 0x0345, + /* 1631 */ 0x1F09, 0x0345, + /* 1633 */ 0x1F0A, 0x0345, + /* 1635 */ 0x1F0B, 0x0345, + /* 1637 */ 0x1F0C, 0x0345, + /* 1639 */ 0x1F0D, 0x0345, + /* 1641 */ 0x1F0E, 0x0345, + /* 1643 */ 0x1F0F, 0x0345, + /* 1645 */ 0x1F20, 0x0345, + /* 1647 */ 0x1F21, 0x0345, + /* 1649 */ 0x1F22, 0x0345, + /* 1651 */ 0x1F23, 0x0345, + /* 1653 */ 0x1F24, 0x0345, + /* 1655 */ 0x1F25, 0x0345, + /* 1657 */ 0x1F26, 0x0345, + /* 1659 */ 0x1F27, 0x0345, + /* 1661 */ 0x1F28, 0x0345, + /* 1663 */ 0x1F29, 0x0345, + /* 1665 */ 0x1F2A, 0x0345, + /* 1667 */ 0x1F2B, 0x0345, + /* 1669 */ 0x1F2C, 0x0345, + /* 1671 */ 0x1F2D, 0x0345, + /* 1673 */ 0x1F2E, 0x0345, + /* 1675 */ 0x1F2F, 0x0345, + /* 1677 */ 0x1F60, 0x0345, + /* 1679 */ 0x1F61, 0x0345, + /* 1681 */ 0x1F62, 0x0345, + /* 1683 */ 0x1F63, 0x0345, + /* 1685 */ 0x1F64, 0x0345, + /* 1687 */ 0x1F65, 0x0345, + /* 1689 */ 0x1F66, 0x0345, + /* 1691 */ 0x1F67, 0x0345, + /* 1693 */ 0x1F68, 0x0345, + /* 1695 */ 0x1F69, 0x0345, + /* 1697 */ 0x1F6A, 0x0345, + /* 1699 */ 0x1F6B, 0x0345, + /* 1701 */ 0x1F6C, 0x0345, + /* 1703 */ 0x1F6D, 0x0345, + /* 1705 */ 0x1F6E, 0x0345, + /* 1707 */ 0x1F6F, 0x0345, + /* 1709 */ 0x03B1, 0x0306, + /* 1711 */ 0x03B1, 0x0304, + /* 1713 */ 0x1F70, 0x0345, + /* 1715 */ 0x03B1, 0x0345, + /* 1717 */ 0x03AC, 0x0345, + /* 1719 */ 0x03B1, 0x0342, + /* 1721 */ 0x1FB6, 0x0345, + /* 1723 */ 0x0391, 0x0306, + /* 1725 */ 0x0391, 0x0304, + /* 1727 */ 0x0391, 0x0300, + /* 1729 */ 0x0391, 0x0345, + /* 1731 */ 0x0020, 0x0313, + /* 1733 */ 0x0020, 0x0313, + /* 1735 */ 0x0020, 0x0342, + /* 1737 */ 0x00A8, 0x0342, + /* 1739 */ 0x1F74, 0x0345, + /* 1741 */ 0x03B7, 0x0345, + /* 1743 */ 0x03AE, 0x0345, + /* 1745 */ 0x03B7, 0x0342, + /* 1747 */ 0x1FC6, 0x0345, + /* 1749 */ 0x0395, 0x0300, + /* 1751 */ 0x0397, 0x0300, + /* 1753 */ 0x0397, 0x0345, + /* 1755 */ 0x1FBF, 0x0300, + /* 1757 */ 0x1FBF, 0x0301, + /* 1759 */ 0x1FBF, 0x0342, + /* 1761 */ 0x03B9, 0x0306, + /* 1763 */ 0x03B9, 0x0304, + /* 1765 */ 0x03CA, 0x0300, + /* 1767 */ 0x03B9, 0x0342, + /* 1769 */ 0x03CA, 0x0342, + /* 1771 */ 0x0399, 0x0306, + /* 1773 */ 0x0399, 0x0304, + /* 1775 */ 0x0399, 0x0300, + /* 1777 */ 0x1FFE, 0x0300, + /* 1779 */ 0x1FFE, 0x0301, + /* 1781 */ 0x1FFE, 0x0342, + /* 1783 */ 0x03C5, 0x0306, + /* 1785 */ 0x03C5, 0x0304, + /* 1787 */ 0x03CB, 0x0300, + /* 1789 */ 0x03C1, 0x0313, + /* 1791 */ 0x03C1, 0x0314, + /* 1793 */ 0x03C5, 0x0342, + /* 1795 */ 0x03CB, 0x0342, + /* 1797 */ 0x03A5, 0x0306, + /* 1799 */ 0x03A5, 0x0304, + /* 1801 */ 0x03A5, 0x0300, + /* 1803 */ 0x03A1, 0x0314, + /* 1805 */ 0x00A8, 0x0300, + /* 1807 */ 0x1F7C, 0x0345, + /* 1809 */ 0x03C9, 0x0345, + /* 1811 */ 0x03CE, 0x0345, + /* 1813 */ 0x03C9, 0x0342, + /* 1815 */ 0x1FF6, 0x0345, + /* 1817 */ 0x039F, 0x0300, + /* 1819 */ 0x03A9, 0x0300, + /* 1821 */ 0x03A9, 0x0345, + /* 1823 */ 0x0020, 0x0314, + /* 1825 */ 0x0020, 0x0333, + /* 1827 */ 0x002E, 0x002E, + /* 1829 */ 0x002E, 0x002E, 0x002E, + /* 1832 */ 0x2032, 0x2032, + /* 1834 */ 0x2032, 0x2032, 0x2032, + /* 1837 */ 0x2035, 0x2035, + /* 1839 */ 0x2035, 0x2035, 0x2035, + /* 1842 */ 0x0021, 0x0021, + /* 1844 */ 0x0020, 0x0305, + /* 1846 */ 0x003F, 0x003F, + /* 1848 */ 0x003F, 0x0021, + /* 1850 */ 0x0021, 0x003F, + /* 1852 */ 0x2032, 0x2032, 0x2032, 0x2032, + /* 1856 */ 0x0052, 0x0073, + /* 1858 */ 0x0061, 0x002F, 0x0063, + /* 1861 */ 0x0061, 0x002F, 0x0073, + /* 1864 */ 0x00B0, 0x0043, + /* 1866 */ 0x0063, 0x002F, 0x006F, + /* 1869 */ 0x0063, 0x002F, 0x0075, + /* 1872 */ 0x00B0, 0x0046, + /* 1874 */ 0x004E, 0x006F, + /* 1876 */ 0x0053, 0x004D, + /* 1878 */ 0x0054, 0x0045, 0x004C, + /* 1881 */ 0x0054, 0x004D, + /* 1883 */ 0x0046, 0x0041, 0x0058, + /* 1886 */ 0x0031, 0x2044, 0x0037, + /* 1889 */ 0x0031, 0x2044, 0x0039, + /* 1892 */ 0x0031, 0x2044, 0x0031, 0x0030, + /* 1896 */ 0x0031, 0x2044, 0x0033, + /* 1899 */ 0x0032, 0x2044, 0x0033, + /* 1902 */ 0x0031, 0x2044, 0x0035, + /* 1905 */ 0x0032, 0x2044, 0x0035, + /* 1908 */ 0x0033, 0x2044, 0x0035, + /* 1911 */ 0x0034, 0x2044, 0x0035, + /* 1914 */ 0x0031, 0x2044, 0x0036, + /* 1917 */ 0x0035, 0x2044, 0x0036, + /* 1920 */ 0x0031, 0x2044, 0x0038, + /* 1923 */ 0x0033, 0x2044, 0x0038, + /* 1926 */ 0x0035, 0x2044, 0x0038, + /* 1929 */ 0x0037, 0x2044, 0x0038, + /* 1932 */ 0x0031, 0x2044, + /* 1934 */ 0x0049, 0x0049, + /* 1936 */ 0x0049, 0x0049, 0x0049, + /* 1939 */ 0x0049, 0x0056, + /* 1941 */ 0x0056, 0x0049, + /* 1943 */ 0x0056, 0x0049, 0x0049, + /* 1946 */ 0x0056, 0x0049, 0x0049, 0x0049, + /* 1950 */ 0x0049, 0x0058, + /* 1952 */ 0x0058, 0x0049, + /* 1954 */ 0x0058, 0x0049, 0x0049, + /* 1957 */ 0x0069, 0x0069, + /* 1959 */ 0x0069, 0x0069, 0x0069, + /* 1962 */ 0x0069, 0x0076, + /* 1964 */ 0x0076, 0x0069, + /* 1966 */ 0x0076, 0x0069, 0x0069, + /* 1969 */ 0x0076, 0x0069, 0x0069, 0x0069, + /* 1973 */ 0x0069, 0x0078, + /* 1975 */ 0x0078, 0x0069, + /* 1977 */ 0x0078, 0x0069, 0x0069, + /* 1980 */ 0x0030, 0x2044, 0x0033, + /* 1983 */ 0x2190, 0x0338, + /* 1985 */ 0x2192, 0x0338, + /* 1987 */ 0x2194, 0x0338, + /* 1989 */ 0x21D0, 0x0338, + /* 1991 */ 0x21D4, 0x0338, + /* 1993 */ 0x21D2, 0x0338, + /* 1995 */ 0x2203, 0x0338, + /* 1997 */ 0x2208, 0x0338, + /* 1999 */ 0x220B, 0x0338, + /* 2001 */ 0x2223, 0x0338, + /* 2003 */ 0x2225, 0x0338, + /* 2005 */ 0x222B, 0x222B, + /* 2007 */ 0x222B, 0x222B, 0x222B, + /* 2010 */ 0x222E, 0x222E, + /* 2012 */ 0x222E, 0x222E, 0x222E, + /* 2015 */ 0x223C, 0x0338, + /* 2017 */ 0x2243, 0x0338, + /* 2019 */ 0x2245, 0x0338, + /* 2021 */ 0x2248, 0x0338, + /* 2023 */ 0x003D, 0x0338, + /* 2025 */ 0x2261, 0x0338, + /* 2027 */ 0x224D, 0x0338, + /* 2029 */ 0x003C, 0x0338, + /* 2031 */ 0x003E, 0x0338, + /* 2033 */ 0x2264, 0x0338, + /* 2035 */ 0x2265, 0x0338, + /* 2037 */ 0x2272, 0x0338, + /* 2039 */ 0x2273, 0x0338, + /* 2041 */ 0x2276, 0x0338, + /* 2043 */ 0x2277, 0x0338, + /* 2045 */ 0x227A, 0x0338, + /* 2047 */ 0x227B, 0x0338, + /* 2049 */ 0x2282, 0x0338, + /* 2051 */ 0x2283, 0x0338, + /* 2053 */ 0x2286, 0x0338, + /* 2055 */ 0x2287, 0x0338, + /* 2057 */ 0x22A2, 0x0338, + /* 2059 */ 0x22A8, 0x0338, + /* 2061 */ 0x22A9, 0x0338, + /* 2063 */ 0x22AB, 0x0338, + /* 2065 */ 0x227C, 0x0338, + /* 2067 */ 0x227D, 0x0338, + /* 2069 */ 0x2291, 0x0338, + /* 2071 */ 0x2292, 0x0338, + /* 2073 */ 0x22B2, 0x0338, + /* 2075 */ 0x22B3, 0x0338, + /* 2077 */ 0x22B4, 0x0338, + /* 2079 */ 0x22B5, 0x0338, + /* 2081 */ 0x0031, 0x0030, + /* 2083 */ 0x0031, 0x0031, + /* 2085 */ 0x0031, 0x0032, + /* 2087 */ 0x0031, 0x0033, + /* 2089 */ 0x0031, 0x0034, + /* 2091 */ 0x0031, 0x0035, + /* 2093 */ 0x0031, 0x0036, + /* 2095 */ 0x0031, 0x0037, + /* 2097 */ 0x0031, 0x0038, + /* 2099 */ 0x0031, 0x0039, + /* 2101 */ 0x0032, 0x0030, + /* 2103 */ 0x0028, 0x0031, 0x0029, + /* 2106 */ 0x0028, 0x0032, 0x0029, + /* 2109 */ 0x0028, 0x0033, 0x0029, + /* 2112 */ 0x0028, 0x0034, 0x0029, + /* 2115 */ 0x0028, 0x0035, 0x0029, + /* 2118 */ 0x0028, 0x0036, 0x0029, + /* 2121 */ 0x0028, 0x0037, 0x0029, + /* 2124 */ 0x0028, 0x0038, 0x0029, + /* 2127 */ 0x0028, 0x0039, 0x0029, + /* 2130 */ 0x0028, 0x0031, 0x0030, 0x0029, + /* 2134 */ 0x0028, 0x0031, 0x0031, 0x0029, + /* 2138 */ 0x0028, 0x0031, 0x0032, 0x0029, + /* 2142 */ 0x0028, 0x0031, 0x0033, 0x0029, + /* 2146 */ 0x0028, 0x0031, 0x0034, 0x0029, + /* 2150 */ 0x0028, 0x0031, 0x0035, 0x0029, + /* 2154 */ 0x0028, 0x0031, 0x0036, 0x0029, + /* 2158 */ 0x0028, 0x0031, 0x0037, 0x0029, + /* 2162 */ 0x0028, 0x0031, 0x0038, 0x0029, + /* 2166 */ 0x0028, 0x0031, 0x0039, 0x0029, + /* 2170 */ 0x0028, 0x0032, 0x0030, 0x0029, + /* 2174 */ 0x0031, 0x002E, + /* 2176 */ 0x0032, 0x002E, + /* 2178 */ 0x0033, 0x002E, + /* 2180 */ 0x0034, 0x002E, + /* 2182 */ 0x0035, 0x002E, + /* 2184 */ 0x0036, 0x002E, + /* 2186 */ 0x0037, 0x002E, + /* 2188 */ 0x0038, 0x002E, + /* 2190 */ 0x0039, 0x002E, + /* 2192 */ 0x0031, 0x0030, 0x002E, + /* 2195 */ 0x0031, 0x0031, 0x002E, + /* 2198 */ 0x0031, 0x0032, 0x002E, + /* 2201 */ 0x0031, 0x0033, 0x002E, + /* 2204 */ 0x0031, 0x0034, 0x002E, + /* 2207 */ 0x0031, 0x0035, 0x002E, + /* 2210 */ 0x0031, 0x0036, 0x002E, + /* 2213 */ 0x0031, 0x0037, 0x002E, + /* 2216 */ 0x0031, 0x0038, 0x002E, + /* 2219 */ 0x0031, 0x0039, 0x002E, + /* 2222 */ 0x0032, 0x0030, 0x002E, + /* 2225 */ 0x0028, 0x0061, 0x0029, + /* 2228 */ 0x0028, 0x0062, 0x0029, + /* 2231 */ 0x0028, 0x0063, 0x0029, + /* 2234 */ 0x0028, 0x0064, 0x0029, + /* 2237 */ 0x0028, 0x0065, 0x0029, + /* 2240 */ 0x0028, 0x0066, 0x0029, + /* 2243 */ 0x0028, 0x0067, 0x0029, + /* 2246 */ 0x0028, 0x0068, 0x0029, + /* 2249 */ 0x0028, 0x0069, 0x0029, + /* 2252 */ 0x0028, 0x006A, 0x0029, + /* 2255 */ 0x0028, 0x006B, 0x0029, + /* 2258 */ 0x0028, 0x006C, 0x0029, + /* 2261 */ 0x0028, 0x006D, 0x0029, + /* 2264 */ 0x0028, 0x006E, 0x0029, + /* 2267 */ 0x0028, 0x006F, 0x0029, + /* 2270 */ 0x0028, 0x0070, 0x0029, + /* 2273 */ 0x0028, 0x0071, 0x0029, + /* 2276 */ 0x0028, 0x0072, 0x0029, + /* 2279 */ 0x0028, 0x0073, 0x0029, + /* 2282 */ 0x0028, 0x0074, 0x0029, + /* 2285 */ 0x0028, 0x0075, 0x0029, + /* 2288 */ 0x0028, 0x0076, 0x0029, + /* 2291 */ 0x0028, 0x0077, 0x0029, + /* 2294 */ 0x0028, 0x0078, 0x0029, + /* 2297 */ 0x0028, 0x0079, 0x0029, + /* 2300 */ 0x0028, 0x007A, 0x0029, + /* 2303 */ 0x222B, 0x222B, 0x222B, 0x222B, + /* 2307 */ 0x003A, 0x003A, 0x003D, + /* 2310 */ 0x003D, 0x003D, + /* 2312 */ 0x003D, 0x003D, 0x003D, + /* 2315 */ 0x2ADD, 0x0338, + /* 2317 */ 0x304B, 0x3099, + /* 2319 */ 0x304D, 0x3099, + /* 2321 */ 0x304F, 0x3099, + /* 2323 */ 0x3051, 0x3099, + /* 2325 */ 0x3053, 0x3099, + /* 2327 */ 0x3055, 0x3099, + /* 2329 */ 0x3057, 0x3099, + /* 2331 */ 0x3059, 0x3099, + /* 2333 */ 0x305B, 0x3099, + /* 2335 */ 0x305D, 0x3099, + /* 2337 */ 0x305F, 0x3099, + /* 2339 */ 0x3061, 0x3099, + /* 2341 */ 0x3064, 0x3099, + /* 2343 */ 0x3066, 0x3099, + /* 2345 */ 0x3068, 0x3099, + /* 2347 */ 0x306F, 0x3099, + /* 2349 */ 0x306F, 0x309A, + /* 2351 */ 0x3072, 0x3099, + /* 2353 */ 0x3072, 0x309A, + /* 2355 */ 0x3075, 0x3099, + /* 2357 */ 0x3075, 0x309A, + /* 2359 */ 0x3078, 0x3099, + /* 2361 */ 0x3078, 0x309A, + /* 2363 */ 0x307B, 0x3099, + /* 2365 */ 0x307B, 0x309A, + /* 2367 */ 0x3046, 0x3099, + /* 2369 */ 0x0020, 0x3099, + /* 2371 */ 0x0020, 0x309A, + /* 2373 */ 0x309D, 0x3099, + /* 2375 */ 0x3088, 0x308A, + /* 2377 */ 0x30AB, 0x3099, + /* 2379 */ 0x30AD, 0x3099, + /* 2381 */ 0x30AF, 0x3099, + /* 2383 */ 0x30B1, 0x3099, + /* 2385 */ 0x30B3, 0x3099, + /* 2387 */ 0x30B5, 0x3099, + /* 2389 */ 0x30B7, 0x3099, + /* 2391 */ 0x30B9, 0x3099, + /* 2393 */ 0x30BB, 0x3099, + /* 2395 */ 0x30BD, 0x3099, + /* 2397 */ 0x30BF, 0x3099, + /* 2399 */ 0x30C1, 0x3099, + /* 2401 */ 0x30C4, 0x3099, + /* 2403 */ 0x30C6, 0x3099, + /* 2405 */ 0x30C8, 0x3099, + /* 2407 */ 0x30CF, 0x3099, + /* 2409 */ 0x30CF, 0x309A, + /* 2411 */ 0x30D2, 0x3099, + /* 2413 */ 0x30D2, 0x309A, + /* 2415 */ 0x30D5, 0x3099, + /* 2417 */ 0x30D5, 0x309A, + /* 2419 */ 0x30D8, 0x3099, + /* 2421 */ 0x30D8, 0x309A, + /* 2423 */ 0x30DB, 0x3099, + /* 2425 */ 0x30DB, 0x309A, + /* 2427 */ 0x30A6, 0x3099, + /* 2429 */ 0x30EF, 0x3099, + /* 2431 */ 0x30F0, 0x3099, + /* 2433 */ 0x30F1, 0x3099, + /* 2435 */ 0x30F2, 0x3099, + /* 2437 */ 0x30FD, 0x3099, + /* 2439 */ 0x30B3, 0x30C8, + /* 2441 */ 0x0028, 0x1100, 0x0029, + /* 2444 */ 0x0028, 0x1102, 0x0029, + /* 2447 */ 0x0028, 0x1103, 0x0029, + /* 2450 */ 0x0028, 0x1105, 0x0029, + /* 2453 */ 0x0028, 0x1106, 0x0029, + /* 2456 */ 0x0028, 0x1107, 0x0029, + /* 2459 */ 0x0028, 0x1109, 0x0029, + /* 2462 */ 0x0028, 0x110B, 0x0029, + /* 2465 */ 0x0028, 0x110C, 0x0029, + /* 2468 */ 0x0028, 0x110E, 0x0029, + /* 2471 */ 0x0028, 0x110F, 0x0029, + /* 2474 */ 0x0028, 0x1110, 0x0029, + /* 2477 */ 0x0028, 0x1111, 0x0029, + /* 2480 */ 0x0028, 0x1112, 0x0029, + /* 2483 */ 0x0028, 0x1100, 0x1161, 0x0029, + /* 2487 */ 0x0028, 0x1102, 0x1161, 0x0029, + /* 2491 */ 0x0028, 0x1103, 0x1161, 0x0029, + /* 2495 */ 0x0028, 0x1105, 0x1161, 0x0029, + /* 2499 */ 0x0028, 0x1106, 0x1161, 0x0029, + /* 2503 */ 0x0028, 0x1107, 0x1161, 0x0029, + /* 2507 */ 0x0028, 0x1109, 0x1161, 0x0029, + /* 2511 */ 0x0028, 0x110B, 0x1161, 0x0029, + /* 2515 */ 0x0028, 0x110C, 0x1161, 0x0029, + /* 2519 */ 0x0028, 0x110E, 0x1161, 0x0029, + /* 2523 */ 0x0028, 0x110F, 0x1161, 0x0029, + /* 2527 */ 0x0028, 0x1110, 0x1161, 0x0029, + /* 2531 */ 0x0028, 0x1111, 0x1161, 0x0029, + /* 2535 */ 0x0028, 0x1112, 0x1161, 0x0029, + /* 2539 */ 0x0028, 0x110C, 0x116E, 0x0029, + /* 2543 */ 0x0028, 0x110B, 0x1169, 0x110C, 0x1165, 0x11AB, 0x0029, + /* 2550 */ 0x0028, 0x110B, 0x1169, 0x1112, 0x116E, 0x0029, + /* 2556 */ 0x0028, 0x4E00, 0x0029, + /* 2559 */ 0x0028, 0x4E8C, 0x0029, + /* 2562 */ 0x0028, 0x4E09, 0x0029, + /* 2565 */ 0x0028, 0x56DB, 0x0029, + /* 2568 */ 0x0028, 0x4E94, 0x0029, + /* 2571 */ 0x0028, 0x516D, 0x0029, + /* 2574 */ 0x0028, 0x4E03, 0x0029, + /* 2577 */ 0x0028, 0x516B, 0x0029, + /* 2580 */ 0x0028, 0x4E5D, 0x0029, + /* 2583 */ 0x0028, 0x5341, 0x0029, + /* 2586 */ 0x0028, 0x6708, 0x0029, + /* 2589 */ 0x0028, 0x706B, 0x0029, + /* 2592 */ 0x0028, 0x6C34, 0x0029, + /* 2595 */ 0x0028, 0x6728, 0x0029, + /* 2598 */ 0x0028, 0x91D1, 0x0029, + /* 2601 */ 0x0028, 0x571F, 0x0029, + /* 2604 */ 0x0028, 0x65E5, 0x0029, + /* 2607 */ 0x0028, 0x682A, 0x0029, + /* 2610 */ 0x0028, 0x6709, 0x0029, + /* 2613 */ 0x0028, 0x793E, 0x0029, + /* 2616 */ 0x0028, 0x540D, 0x0029, + /* 2619 */ 0x0028, 0x7279, 0x0029, + /* 2622 */ 0x0028, 0x8CA1, 0x0029, + /* 2625 */ 0x0028, 0x795D, 0x0029, + /* 2628 */ 0x0028, 0x52B4, 0x0029, + /* 2631 */ 0x0028, 0x4EE3, 0x0029, + /* 2634 */ 0x0028, 0x547C, 0x0029, + /* 2637 */ 0x0028, 0x5B66, 0x0029, + /* 2640 */ 0x0028, 0x76E3, 0x0029, + /* 2643 */ 0x0028, 0x4F01, 0x0029, + /* 2646 */ 0x0028, 0x8CC7, 0x0029, + /* 2649 */ 0x0028, 0x5354, 0x0029, + /* 2652 */ 0x0028, 0x796D, 0x0029, + /* 2655 */ 0x0028, 0x4F11, 0x0029, + /* 2658 */ 0x0028, 0x81EA, 0x0029, + /* 2661 */ 0x0028, 0x81F3, 0x0029, + /* 2664 */ 0x0050, 0x0054, 0x0045, + /* 2667 */ 0x0032, 0x0031, + /* 2669 */ 0x0032, 0x0032, + /* 2671 */ 0x0032, 0x0033, + /* 2673 */ 0x0032, 0x0034, + /* 2675 */ 0x0032, 0x0035, + /* 2677 */ 0x0032, 0x0036, + /* 2679 */ 0x0032, 0x0037, + /* 2681 */ 0x0032, 0x0038, + /* 2683 */ 0x0032, 0x0039, + /* 2685 */ 0x0033, 0x0030, + /* 2687 */ 0x0033, 0x0031, + /* 2689 */ 0x0033, 0x0032, + /* 2691 */ 0x0033, 0x0033, + /* 2693 */ 0x0033, 0x0034, + /* 2695 */ 0x0033, 0x0035, + /* 2697 */ 0x1100, 0x1161, + /* 2699 */ 0x1102, 0x1161, + /* 2701 */ 0x1103, 0x1161, + /* 2703 */ 0x1105, 0x1161, + /* 2705 */ 0x1106, 0x1161, + /* 2707 */ 0x1107, 0x1161, + /* 2709 */ 0x1109, 0x1161, + /* 2711 */ 0x110B, 0x1161, + /* 2713 */ 0x110C, 0x1161, + /* 2715 */ 0x110E, 0x1161, + /* 2717 */ 0x110F, 0x1161, + /* 2719 */ 0x1110, 0x1161, + /* 2721 */ 0x1111, 0x1161, + /* 2723 */ 0x1112, 0x1161, + /* 2725 */ 0x110E, 0x1161, 0x11B7, 0x1100, 0x1169, + /* 2730 */ 0x110C, 0x116E, 0x110B, 0x1174, + /* 2734 */ 0x110B, 0x116E, + /* 2736 */ 0x0033, 0x0036, + /* 2738 */ 0x0033, 0x0037, + /* 2740 */ 0x0033, 0x0038, + /* 2742 */ 0x0033, 0x0039, + /* 2744 */ 0x0034, 0x0030, + /* 2746 */ 0x0034, 0x0031, + /* 2748 */ 0x0034, 0x0032, + /* 2750 */ 0x0034, 0x0033, + /* 2752 */ 0x0034, 0x0034, + /* 2754 */ 0x0034, 0x0035, + /* 2756 */ 0x0034, 0x0036, + /* 2758 */ 0x0034, 0x0037, + /* 2760 */ 0x0034, 0x0038, + /* 2762 */ 0x0034, 0x0039, + /* 2764 */ 0x0035, 0x0030, + /* 2766 */ 0x0031, 0x6708, + /* 2768 */ 0x0032, 0x6708, + /* 2770 */ 0x0033, 0x6708, + /* 2772 */ 0x0034, 0x6708, + /* 2774 */ 0x0035, 0x6708, + /* 2776 */ 0x0036, 0x6708, + /* 2778 */ 0x0037, 0x6708, + /* 2780 */ 0x0038, 0x6708, + /* 2782 */ 0x0039, 0x6708, + /* 2784 */ 0x0031, 0x0030, 0x6708, + /* 2787 */ 0x0031, 0x0031, 0x6708, + /* 2790 */ 0x0031, 0x0032, 0x6708, + /* 2793 */ 0x0048, 0x0067, + /* 2795 */ 0x0065, 0x0072, 0x0067, + /* 2798 */ 0x0065, 0x0056, + /* 2800 */ 0x004C, 0x0054, 0x0044, + /* 2803 */ 0x4EE4, 0x548C, + /* 2805 */ 0x30A2, 0x30D1, 0x30FC, 0x30C8, + /* 2809 */ 0x30A2, 0x30EB, 0x30D5, 0x30A1, + /* 2813 */ 0x30A2, 0x30F3, 0x30DA, 0x30A2, + /* 2817 */ 0x30A2, 0x30FC, 0x30EB, + /* 2820 */ 0x30A4, 0x30CB, 0x30F3, 0x30B0, + /* 2824 */ 0x30A4, 0x30F3, 0x30C1, + /* 2827 */ 0x30A6, 0x30A9, 0x30F3, + /* 2830 */ 0x30A8, 0x30B9, 0x30AF, 0x30FC, 0x30C9, + /* 2835 */ 0x30A8, 0x30FC, 0x30AB, 0x30FC, + /* 2839 */ 0x30AA, 0x30F3, 0x30B9, + /* 2842 */ 0x30AA, 0x30FC, 0x30E0, + /* 2845 */ 0x30AB, 0x30A4, 0x30EA, + /* 2848 */ 0x30AB, 0x30E9, 0x30C3, 0x30C8, + /* 2852 */ 0x30AB, 0x30ED, 0x30EA, 0x30FC, + /* 2856 */ 0x30AC, 0x30ED, 0x30F3, + /* 2859 */ 0x30AC, 0x30F3, 0x30DE, + /* 2862 */ 0x30AE, 0x30AC, + /* 2864 */ 0x30AE, 0x30CB, 0x30FC, + /* 2867 */ 0x30AD, 0x30E5, 0x30EA, 0x30FC, + /* 2871 */ 0x30AE, 0x30EB, 0x30C0, 0x30FC, + /* 2875 */ 0x30AD, 0x30ED, + /* 2877 */ 0x30AD, 0x30ED, 0x30B0, 0x30E9, 0x30E0, + /* 2882 */ 0x30AD, 0x30ED, 0x30E1, 0x30FC, 0x30C8, 0x30EB, + /* 2888 */ 0x30AD, 0x30ED, 0x30EF, 0x30C3, 0x30C8, + /* 2893 */ 0x30B0, 0x30E9, 0x30E0, + /* 2896 */ 0x30B0, 0x30E9, 0x30E0, 0x30C8, 0x30F3, + /* 2901 */ 0x30AF, 0x30EB, 0x30BC, 0x30A4, 0x30ED, + /* 2906 */ 0x30AF, 0x30ED, 0x30FC, 0x30CD, + /* 2910 */ 0x30B1, 0x30FC, 0x30B9, + /* 2913 */ 0x30B3, 0x30EB, 0x30CA, + /* 2916 */ 0x30B3, 0x30FC, 0x30DD, + /* 2919 */ 0x30B5, 0x30A4, 0x30AF, 0x30EB, + /* 2923 */ 0x30B5, 0x30F3, 0x30C1, 0x30FC, 0x30E0, + /* 2928 */ 0x30B7, 0x30EA, 0x30F3, 0x30B0, + /* 2932 */ 0x30BB, 0x30F3, 0x30C1, + /* 2935 */ 0x30BB, 0x30F3, 0x30C8, + /* 2938 */ 0x30C0, 0x30FC, 0x30B9, + /* 2941 */ 0x30C7, 0x30B7, + /* 2943 */ 0x30C9, 0x30EB, + /* 2945 */ 0x30C8, 0x30F3, + /* 2947 */ 0x30CA, 0x30CE, + /* 2949 */ 0x30CE, 0x30C3, 0x30C8, + /* 2952 */ 0x30CF, 0x30A4, 0x30C4, + /* 2955 */ 0x30D1, 0x30FC, 0x30BB, 0x30F3, 0x30C8, + /* 2960 */ 0x30D1, 0x30FC, 0x30C4, + /* 2963 */ 0x30D0, 0x30FC, 0x30EC, 0x30EB, + /* 2967 */ 0x30D4, 0x30A2, 0x30B9, 0x30C8, 0x30EB, + /* 2972 */ 0x30D4, 0x30AF, 0x30EB, + /* 2975 */ 0x30D4, 0x30B3, + /* 2977 */ 0x30D3, 0x30EB, + /* 2979 */ 0x30D5, 0x30A1, 0x30E9, 0x30C3, 0x30C9, + /* 2984 */ 0x30D5, 0x30A3, 0x30FC, 0x30C8, + /* 2988 */ 0x30D6, 0x30C3, 0x30B7, 0x30A7, 0x30EB, + /* 2993 */ 0x30D5, 0x30E9, 0x30F3, + /* 2996 */ 0x30D8, 0x30AF, 0x30BF, 0x30FC, 0x30EB, + /* 3001 */ 0x30DA, 0x30BD, + /* 3003 */ 0x30DA, 0x30CB, 0x30D2, + /* 3006 */ 0x30D8, 0x30EB, 0x30C4, + /* 3009 */ 0x30DA, 0x30F3, 0x30B9, + /* 3012 */ 0x30DA, 0x30FC, 0x30B8, + /* 3015 */ 0x30D9, 0x30FC, 0x30BF, + /* 3018 */ 0x30DD, 0x30A4, 0x30F3, 0x30C8, + /* 3022 */ 0x30DC, 0x30EB, 0x30C8, + /* 3025 */ 0x30DB, 0x30F3, + /* 3027 */ 0x30DD, 0x30F3, 0x30C9, + /* 3030 */ 0x30DB, 0x30FC, 0x30EB, + /* 3033 */ 0x30DB, 0x30FC, 0x30F3, + /* 3036 */ 0x30DE, 0x30A4, 0x30AF, 0x30ED, + /* 3040 */ 0x30DE, 0x30A4, 0x30EB, + /* 3043 */ 0x30DE, 0x30C3, 0x30CF, + /* 3046 */ 0x30DE, 0x30EB, 0x30AF, + /* 3049 */ 0x30DE, 0x30F3, 0x30B7, 0x30E7, 0x30F3, + /* 3054 */ 0x30DF, 0x30AF, 0x30ED, 0x30F3, + /* 3058 */ 0x30DF, 0x30EA, + /* 3060 */ 0x30DF, 0x30EA, 0x30D0, 0x30FC, 0x30EB, + /* 3065 */ 0x30E1, 0x30AC, + /* 3067 */ 0x30E1, 0x30AC, 0x30C8, 0x30F3, + /* 3071 */ 0x30E1, 0x30FC, 0x30C8, 0x30EB, + /* 3075 */ 0x30E4, 0x30FC, 0x30C9, + /* 3078 */ 0x30E4, 0x30FC, 0x30EB, + /* 3081 */ 0x30E6, 0x30A2, 0x30F3, + /* 3084 */ 0x30EA, 0x30C3, 0x30C8, 0x30EB, + /* 3088 */ 0x30EA, 0x30E9, + /* 3090 */ 0x30EB, 0x30D4, 0x30FC, + /* 3093 */ 0x30EB, 0x30FC, 0x30D6, 0x30EB, + /* 3097 */ 0x30EC, 0x30E0, + /* 3099 */ 0x30EC, 0x30F3, 0x30C8, 0x30B2, 0x30F3, + /* 3104 */ 0x30EF, 0x30C3, 0x30C8, + /* 3107 */ 0x0030, 0x70B9, + /* 3109 */ 0x0031, 0x70B9, + /* 3111 */ 0x0032, 0x70B9, + /* 3113 */ 0x0033, 0x70B9, + /* 3115 */ 0x0034, 0x70B9, + /* 3117 */ 0x0035, 0x70B9, + /* 3119 */ 0x0036, 0x70B9, + /* 3121 */ 0x0037, 0x70B9, + /* 3123 */ 0x0038, 0x70B9, + /* 3125 */ 0x0039, 0x70B9, + /* 3127 */ 0x0031, 0x0030, 0x70B9, + /* 3130 */ 0x0031, 0x0031, 0x70B9, + /* 3133 */ 0x0031, 0x0032, 0x70B9, + /* 3136 */ 0x0031, 0x0033, 0x70B9, + /* 3139 */ 0x0031, 0x0034, 0x70B9, + /* 3142 */ 0x0031, 0x0035, 0x70B9, + /* 3145 */ 0x0031, 0x0036, 0x70B9, + /* 3148 */ 0x0031, 0x0037, 0x70B9, + /* 3151 */ 0x0031, 0x0038, 0x70B9, + /* 3154 */ 0x0031, 0x0039, 0x70B9, + /* 3157 */ 0x0032, 0x0030, 0x70B9, + /* 3160 */ 0x0032, 0x0031, 0x70B9, + /* 3163 */ 0x0032, 0x0032, 0x70B9, + /* 3166 */ 0x0032, 0x0033, 0x70B9, + /* 3169 */ 0x0032, 0x0034, 0x70B9, + /* 3172 */ 0x0068, 0x0050, 0x0061, + /* 3175 */ 0x0064, 0x0061, + /* 3177 */ 0x0041, 0x0055, + /* 3179 */ 0x0062, 0x0061, 0x0072, + /* 3182 */ 0x006F, 0x0056, + /* 3184 */ 0x0070, 0x0063, + /* 3186 */ 0x0064, 0x006D, + /* 3188 */ 0x0064, 0x006D, 0x00B2, + /* 3191 */ 0x0064, 0x006D, 0x00B3, + /* 3194 */ 0x0049, 0x0055, + /* 3196 */ 0x5E73, 0x6210, + /* 3198 */ 0x662D, 0x548C, + /* 3200 */ 0x5927, 0x6B63, + /* 3202 */ 0x660E, 0x6CBB, + /* 3204 */ 0x682A, 0x5F0F, 0x4F1A, 0x793E, + /* 3208 */ 0x0070, 0x0041, + /* 3210 */ 0x006E, 0x0041, + /* 3212 */ 0x03BC, 0x0041, + /* 3214 */ 0x006D, 0x0041, + /* 3216 */ 0x006B, 0x0041, + /* 3218 */ 0x004B, 0x0042, + /* 3220 */ 0x004D, 0x0042, + /* 3222 */ 0x0047, 0x0042, + /* 3224 */ 0x0063, 0x0061, 0x006C, + /* 3227 */ 0x006B, 0x0063, 0x0061, 0x006C, + /* 3231 */ 0x0070, 0x0046, + /* 3233 */ 0x006E, 0x0046, + /* 3235 */ 0x03BC, 0x0046, + /* 3237 */ 0x03BC, 0x0067, + /* 3239 */ 0x006D, 0x0067, + /* 3241 */ 0x006B, 0x0067, + /* 3243 */ 0x0048, 0x007A, + /* 3245 */ 0x006B, 0x0048, 0x007A, + /* 3248 */ 0x004D, 0x0048, 0x007A, + /* 3251 */ 0x0047, 0x0048, 0x007A, + /* 3254 */ 0x0054, 0x0048, 0x007A, + /* 3257 */ 0x03BC, 0x2113, + /* 3259 */ 0x006D, 0x2113, + /* 3261 */ 0x0064, 0x2113, + /* 3263 */ 0x006B, 0x2113, + /* 3265 */ 0x0066, 0x006D, + /* 3267 */ 0x006E, 0x006D, + /* 3269 */ 0x03BC, 0x006D, + /* 3271 */ 0x006D, 0x006D, + /* 3273 */ 0x0063, 0x006D, + /* 3275 */ 0x006B, 0x006D, + /* 3277 */ 0x006D, 0x006D, 0x00B2, + /* 3280 */ 0x0063, 0x006D, 0x00B2, + /* 3283 */ 0x006D, 0x00B2, + /* 3285 */ 0x006B, 0x006D, 0x00B2, + /* 3288 */ 0x006D, 0x006D, 0x00B3, + /* 3291 */ 0x0063, 0x006D, 0x00B3, + /* 3294 */ 0x006D, 0x00B3, + /* 3296 */ 0x006B, 0x006D, 0x00B3, + /* 3299 */ 0x006D, 0x2215, 0x0073, + /* 3302 */ 0x006D, 0x2215, 0x0073, 0x00B2, + /* 3306 */ 0x0050, 0x0061, + /* 3308 */ 0x006B, 0x0050, 0x0061, + /* 3311 */ 0x004D, 0x0050, 0x0061, + /* 3314 */ 0x0047, 0x0050, 0x0061, + /* 3317 */ 0x0072, 0x0061, 0x0064, + /* 3320 */ 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, + /* 3325 */ 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0x00B2, + /* 3331 */ 0x0070, 0x0073, + /* 3333 */ 0x006E, 0x0073, + /* 3335 */ 0x03BC, 0x0073, + /* 3337 */ 0x006D, 0x0073, + /* 3339 */ 0x0070, 0x0056, + /* 3341 */ 0x006E, 0x0056, + /* 3343 */ 0x03BC, 0x0056, + /* 3345 */ 0x006D, 0x0056, + /* 3347 */ 0x006B, 0x0056, + /* 3349 */ 0x004D, 0x0056, + /* 3351 */ 0x0070, 0x0057, + /* 3353 */ 0x006E, 0x0057, + /* 3355 */ 0x03BC, 0x0057, + /* 3357 */ 0x006D, 0x0057, + /* 3359 */ 0x006B, 0x0057, + /* 3361 */ 0x004D, 0x0057, + /* 3363 */ 0x006B, 0x03A9, + /* 3365 */ 0x004D, 0x03A9, + /* 3367 */ 0x0061, 0x002E, 0x006D, 0x002E, + /* 3371 */ 0x0042, 0x0071, + /* 3373 */ 0x0063, 0x0063, + /* 3375 */ 0x0063, 0x0064, + /* 3377 */ 0x0043, 0x2215, 0x006B, 0x0067, + /* 3381 */ 0x0043, 0x006F, 0x002E, + /* 3384 */ 0x0064, 0x0042, + /* 3386 */ 0x0047, 0x0079, + /* 3388 */ 0x0068, 0x0061, + /* 3390 */ 0x0048, 0x0050, + /* 3392 */ 0x0069, 0x006E, + /* 3394 */ 0x004B, 0x004B, + /* 3396 */ 0x004B, 0x004D, + /* 3398 */ 0x006B, 0x0074, + /* 3400 */ 0x006C, 0x006D, + /* 3402 */ 0x006C, 0x006E, + /* 3404 */ 0x006C, 0x006F, 0x0067, + /* 3407 */ 0x006C, 0x0078, + /* 3409 */ 0x006D, 0x0062, + /* 3411 */ 0x006D, 0x0069, 0x006C, + /* 3414 */ 0x006D, 0x006F, 0x006C, + /* 3417 */ 0x0050, 0x0048, + /* 3419 */ 0x0070, 0x002E, 0x006D, 0x002E, + /* 3423 */ 0x0050, 0x0050, 0x004D, + /* 3426 */ 0x0050, 0x0052, + /* 3428 */ 0x0073, 0x0072, + /* 3430 */ 0x0053, 0x0076, + /* 3432 */ 0x0057, 0x0062, + /* 3434 */ 0x0056, 0x2215, 0x006D, + /* 3437 */ 0x0041, 0x2215, 0x006D, + /* 3440 */ 0x0031, 0x65E5, + /* 3442 */ 0x0032, 0x65E5, + /* 3444 */ 0x0033, 0x65E5, + /* 3446 */ 0x0034, 0x65E5, + /* 3448 */ 0x0035, 0x65E5, + /* 3450 */ 0x0036, 0x65E5, + /* 3452 */ 0x0037, 0x65E5, + /* 3454 */ 0x0038, 0x65E5, + /* 3456 */ 0x0039, 0x65E5, + /* 3458 */ 0x0031, 0x0030, 0x65E5, + /* 3461 */ 0x0031, 0x0031, 0x65E5, + /* 3464 */ 0x0031, 0x0032, 0x65E5, + /* 3467 */ 0x0031, 0x0033, 0x65E5, + /* 3470 */ 0x0031, 0x0034, 0x65E5, + /* 3473 */ 0x0031, 0x0035, 0x65E5, + /* 3476 */ 0x0031, 0x0036, 0x65E5, + /* 3479 */ 0x0031, 0x0037, 0x65E5, + /* 3482 */ 0x0031, 0x0038, 0x65E5, + /* 3485 */ 0x0031, 0x0039, 0x65E5, + /* 3488 */ 0x0032, 0x0030, 0x65E5, + /* 3491 */ 0x0032, 0x0031, 0x65E5, + /* 3494 */ 0x0032, 0x0032, 0x65E5, + /* 3497 */ 0x0032, 0x0033, 0x65E5, + /* 3500 */ 0x0032, 0x0034, 0x65E5, + /* 3503 */ 0x0032, 0x0035, 0x65E5, + /* 3506 */ 0x0032, 0x0036, 0x65E5, + /* 3509 */ 0x0032, 0x0037, 0x65E5, + /* 3512 */ 0x0032, 0x0038, 0x65E5, + /* 3515 */ 0x0032, 0x0039, 0x65E5, + /* 3518 */ 0x0033, 0x0030, 0x65E5, + /* 3521 */ 0x0033, 0x0031, 0x65E5, + /* 3524 */ 0x0067, 0x0061, 0x006C, + /* 3527 */ 0x242EE, + /* 3528 */ 0x2284A, + /* 3529 */ 0x22844, + /* 3530 */ 0x233D5, + /* 3531 */ 0x25249, + /* 3532 */ 0x25CD0, + /* 3533 */ 0x27ED3, + /* 3534 */ 0x0066, 0x0066, + /* 3536 */ 0x0066, 0x0069, + /* 3538 */ 0x0066, 0x006C, + /* 3540 */ 0x0066, 0x0066, 0x0069, + /* 3543 */ 0x0066, 0x0066, 0x006C, + /* 3546 */ 0x017F, 0x0074, + /* 3548 */ 0x0073, 0x0074, + /* 3550 */ 0x0574, 0x0576, + /* 3552 */ 0x0574, 0x0565, + /* 3554 */ 0x0574, 0x056B, + /* 3556 */ 0x057E, 0x0576, + /* 3558 */ 0x0574, 0x056D, + /* 3560 */ 0x05D9, 0x05B4, + /* 3562 */ 0x05F2, 0x05B7, + /* 3564 */ 0x05E9, 0x05C1, + /* 3566 */ 0x05E9, 0x05C2, + /* 3568 */ 0xFB49, 0x05C1, + /* 3570 */ 0xFB49, 0x05C2, + /* 3572 */ 0x05D0, 0x05B7, + /* 3574 */ 0x05D0, 0x05B8, + /* 3576 */ 0x05D0, 0x05BC, + /* 3578 */ 0x05D1, 0x05BC, + /* 3580 */ 0x05D2, 0x05BC, + /* 3582 */ 0x05D3, 0x05BC, + /* 3584 */ 0x05D4, 0x05BC, + /* 3586 */ 0x05D5, 0x05BC, + /* 3588 */ 0x05D6, 0x05BC, + /* 3590 */ 0x05D8, 0x05BC, + /* 3592 */ 0x05D9, 0x05BC, + /* 3594 */ 0x05DA, 0x05BC, + /* 3596 */ 0x05DB, 0x05BC, + /* 3598 */ 0x05DC, 0x05BC, + /* 3600 */ 0x05DE, 0x05BC, + /* 3602 */ 0x05E0, 0x05BC, + /* 3604 */ 0x05E1, 0x05BC, + /* 3606 */ 0x05E3, 0x05BC, + /* 3608 */ 0x05E4, 0x05BC, + /* 3610 */ 0x05E6, 0x05BC, + /* 3612 */ 0x05E7, 0x05BC, + /* 3614 */ 0x05E8, 0x05BC, + /* 3616 */ 0x05E9, 0x05BC, + /* 3618 */ 0x05EA, 0x05BC, + /* 3620 */ 0x05D5, 0x05B9, + /* 3622 */ 0x05D1, 0x05BF, + /* 3624 */ 0x05DB, 0x05BF, + /* 3626 */ 0x05E4, 0x05BF, + /* 3628 */ 0x05D0, 0x05DC, + /* 3630 */ 0x0626, 0x0627, + /* 3632 */ 0x0626, 0x0627, + /* 3634 */ 0x0626, 0x06D5, + /* 3636 */ 0x0626, 0x06D5, + /* 3638 */ 0x0626, 0x0648, + /* 3640 */ 0x0626, 0x0648, + /* 3642 */ 0x0626, 0x06C7, + /* 3644 */ 0x0626, 0x06C7, + /* 3646 */ 0x0626, 0x06C6, + /* 3648 */ 0x0626, 0x06C6, + /* 3650 */ 0x0626, 0x06C8, + /* 3652 */ 0x0626, 0x06C8, + /* 3654 */ 0x0626, 0x06D0, + /* 3656 */ 0x0626, 0x06D0, + /* 3658 */ 0x0626, 0x06D0, + /* 3660 */ 0x0626, 0x0649, + /* 3662 */ 0x0626, 0x0649, + /* 3664 */ 0x0626, 0x0649, + /* 3666 */ 0x0626, 0x062C, + /* 3668 */ 0x0626, 0x062D, + /* 3670 */ 0x0626, 0x0645, + /* 3672 */ 0x0626, 0x0649, + /* 3674 */ 0x0626, 0x064A, + /* 3676 */ 0x0628, 0x062C, + /* 3678 */ 0x0628, 0x062D, + /* 3680 */ 0x0628, 0x062E, + /* 3682 */ 0x0628, 0x0645, + /* 3684 */ 0x0628, 0x0649, + /* 3686 */ 0x0628, 0x064A, + /* 3688 */ 0x062A, 0x062C, + /* 3690 */ 0x062A, 0x062D, + /* 3692 */ 0x062A, 0x062E, + /* 3694 */ 0x062A, 0x0645, + /* 3696 */ 0x062A, 0x0649, + /* 3698 */ 0x062A, 0x064A, + /* 3700 */ 0x062B, 0x062C, + /* 3702 */ 0x062B, 0x0645, + /* 3704 */ 0x062B, 0x0649, + /* 3706 */ 0x062B, 0x064A, + /* 3708 */ 0x062C, 0x062D, + /* 3710 */ 0x062C, 0x0645, + /* 3712 */ 0x062D, 0x062C, + /* 3714 */ 0x062D, 0x0645, + /* 3716 */ 0x062E, 0x062C, + /* 3718 */ 0x062E, 0x062D, + /* 3720 */ 0x062E, 0x0645, + /* 3722 */ 0x0633, 0x062C, + /* 3724 */ 0x0633, 0x062D, + /* 3726 */ 0x0633, 0x062E, + /* 3728 */ 0x0633, 0x0645, + /* 3730 */ 0x0635, 0x062D, + /* 3732 */ 0x0635, 0x0645, + /* 3734 */ 0x0636, 0x062C, + /* 3736 */ 0x0636, 0x062D, + /* 3738 */ 0x0636, 0x062E, + /* 3740 */ 0x0636, 0x0645, + /* 3742 */ 0x0637, 0x062D, + /* 3744 */ 0x0637, 0x0645, + /* 3746 */ 0x0638, 0x0645, + /* 3748 */ 0x0639, 0x062C, + /* 3750 */ 0x0639, 0x0645, + /* 3752 */ 0x063A, 0x062C, + /* 3754 */ 0x063A, 0x0645, + /* 3756 */ 0x0641, 0x062C, + /* 3758 */ 0x0641, 0x062D, + /* 3760 */ 0x0641, 0x062E, + /* 3762 */ 0x0641, 0x0645, + /* 3764 */ 0x0641, 0x0649, + /* 3766 */ 0x0641, 0x064A, + /* 3768 */ 0x0642, 0x062D, + /* 3770 */ 0x0642, 0x0645, + /* 3772 */ 0x0642, 0x0649, + /* 3774 */ 0x0642, 0x064A, + /* 3776 */ 0x0643, 0x0627, + /* 3778 */ 0x0643, 0x062C, + /* 3780 */ 0x0643, 0x062D, + /* 3782 */ 0x0643, 0x062E, + /* 3784 */ 0x0643, 0x0644, + /* 3786 */ 0x0643, 0x0645, + /* 3788 */ 0x0643, 0x0649, + /* 3790 */ 0x0643, 0x064A, + /* 3792 */ 0x0644, 0x062C, + /* 3794 */ 0x0644, 0x062D, + /* 3796 */ 0x0644, 0x062E, + /* 3798 */ 0x0644, 0x0645, + /* 3800 */ 0x0644, 0x0649, + /* 3802 */ 0x0644, 0x064A, + /* 3804 */ 0x0645, 0x062C, + /* 3806 */ 0x0645, 0x062D, + /* 3808 */ 0x0645, 0x062E, + /* 3810 */ 0x0645, 0x0645, + /* 3812 */ 0x0645, 0x0649, + /* 3814 */ 0x0645, 0x064A, + /* 3816 */ 0x0646, 0x062C, + /* 3818 */ 0x0646, 0x062D, + /* 3820 */ 0x0646, 0x062E, + /* 3822 */ 0x0646, 0x0645, + /* 3824 */ 0x0646, 0x0649, + /* 3826 */ 0x0646, 0x064A, + /* 3828 */ 0x0647, 0x062C, + /* 3830 */ 0x0647, 0x0645, + /* 3832 */ 0x0647, 0x0649, + /* 3834 */ 0x0647, 0x064A, + /* 3836 */ 0x064A, 0x062C, + /* 3838 */ 0x064A, 0x062D, + /* 3840 */ 0x064A, 0x062E, + /* 3842 */ 0x064A, 0x0645, + /* 3844 */ 0x064A, 0x0649, + /* 3846 */ 0x064A, 0x064A, + /* 3848 */ 0x0630, 0x0670, + /* 3850 */ 0x0631, 0x0670, + /* 3852 */ 0x0649, 0x0670, + /* 3854 */ 0x0020, 0x064C, 0x0651, + /* 3857 */ 0x0020, 0x064D, 0x0651, + /* 3860 */ 0x0020, 0x064E, 0x0651, + /* 3863 */ 0x0020, 0x064F, 0x0651, + /* 3866 */ 0x0020, 0x0650, 0x0651, + /* 3869 */ 0x0020, 0x0651, 0x0670, + /* 3872 */ 0x0626, 0x0631, + /* 3874 */ 0x0626, 0x0632, + /* 3876 */ 0x0626, 0x0645, + /* 3878 */ 0x0626, 0x0646, + /* 3880 */ 0x0626, 0x0649, + /* 3882 */ 0x0626, 0x064A, + /* 3884 */ 0x0628, 0x0631, + /* 3886 */ 0x0628, 0x0632, + /* 3888 */ 0x0628, 0x0645, + /* 3890 */ 0x0628, 0x0646, + /* 3892 */ 0x0628, 0x0649, + /* 3894 */ 0x0628, 0x064A, + /* 3896 */ 0x062A, 0x0631, + /* 3898 */ 0x062A, 0x0632, + /* 3900 */ 0x062A, 0x0645, + /* 3902 */ 0x062A, 0x0646, + /* 3904 */ 0x062A, 0x0649, + /* 3906 */ 0x062A, 0x064A, + /* 3908 */ 0x062B, 0x0631, + /* 3910 */ 0x062B, 0x0632, + /* 3912 */ 0x062B, 0x0645, + /* 3914 */ 0x062B, 0x0646, + /* 3916 */ 0x062B, 0x0649, + /* 3918 */ 0x062B, 0x064A, + /* 3920 */ 0x0641, 0x0649, + /* 3922 */ 0x0641, 0x064A, + /* 3924 */ 0x0642, 0x0649, + /* 3926 */ 0x0642, 0x064A, + /* 3928 */ 0x0643, 0x0627, + /* 3930 */ 0x0643, 0x0644, + /* 3932 */ 0x0643, 0x0645, + /* 3934 */ 0x0643, 0x0649, + /* 3936 */ 0x0643, 0x064A, + /* 3938 */ 0x0644, 0x0645, + /* 3940 */ 0x0644, 0x0649, + /* 3942 */ 0x0644, 0x064A, + /* 3944 */ 0x0645, 0x0627, + /* 3946 */ 0x0645, 0x0645, + /* 3948 */ 0x0646, 0x0631, + /* 3950 */ 0x0646, 0x0632, + /* 3952 */ 0x0646, 0x0645, + /* 3954 */ 0x0646, 0x0646, + /* 3956 */ 0x0646, 0x0649, + /* 3958 */ 0x0646, 0x064A, + /* 3960 */ 0x0649, 0x0670, + /* 3962 */ 0x064A, 0x0631, + /* 3964 */ 0x064A, 0x0632, + /* 3966 */ 0x064A, 0x0645, + /* 3968 */ 0x064A, 0x0646, + /* 3970 */ 0x064A, 0x0649, + /* 3972 */ 0x064A, 0x064A, + /* 3974 */ 0x0626, 0x062C, + /* 3976 */ 0x0626, 0x062D, + /* 3978 */ 0x0626, 0x062E, + /* 3980 */ 0x0626, 0x0645, + /* 3982 */ 0x0626, 0x0647, + /* 3984 */ 0x0628, 0x062C, + /* 3986 */ 0x0628, 0x062D, + /* 3988 */ 0x0628, 0x062E, + /* 3990 */ 0x0628, 0x0645, + /* 3992 */ 0x0628, 0x0647, + /* 3994 */ 0x062A, 0x062C, + /* 3996 */ 0x062A, 0x062D, + /* 3998 */ 0x062A, 0x062E, + /* 4000 */ 0x062A, 0x0645, + /* 4002 */ 0x062A, 0x0647, + /* 4004 */ 0x062B, 0x0645, + /* 4006 */ 0x062C, 0x062D, + /* 4008 */ 0x062C, 0x0645, + /* 4010 */ 0x062D, 0x062C, + /* 4012 */ 0x062D, 0x0645, + /* 4014 */ 0x062E, 0x062C, + /* 4016 */ 0x062E, 0x0645, + /* 4018 */ 0x0633, 0x062C, + /* 4020 */ 0x0633, 0x062D, + /* 4022 */ 0x0633, 0x062E, + /* 4024 */ 0x0633, 0x0645, + /* 4026 */ 0x0635, 0x062D, + /* 4028 */ 0x0635, 0x062E, + /* 4030 */ 0x0635, 0x0645, + /* 4032 */ 0x0636, 0x062C, + /* 4034 */ 0x0636, 0x062D, + /* 4036 */ 0x0636, 0x062E, + /* 4038 */ 0x0636, 0x0645, + /* 4040 */ 0x0637, 0x062D, + /* 4042 */ 0x0638, 0x0645, + /* 4044 */ 0x0639, 0x062C, + /* 4046 */ 0x0639, 0x0645, + /* 4048 */ 0x063A, 0x062C, + /* 4050 */ 0x063A, 0x0645, + /* 4052 */ 0x0641, 0x062C, + /* 4054 */ 0x0641, 0x062D, + /* 4056 */ 0x0641, 0x062E, + /* 4058 */ 0x0641, 0x0645, + /* 4060 */ 0x0642, 0x062D, + /* 4062 */ 0x0642, 0x0645, + /* 4064 */ 0x0643, 0x062C, + /* 4066 */ 0x0643, 0x062D, + /* 4068 */ 0x0643, 0x062E, + /* 4070 */ 0x0643, 0x0644, + /* 4072 */ 0x0643, 0x0645, + /* 4074 */ 0x0644, 0x062C, + /* 4076 */ 0x0644, 0x062D, + /* 4078 */ 0x0644, 0x062E, + /* 4080 */ 0x0644, 0x0645, + /* 4082 */ 0x0644, 0x0647, + /* 4084 */ 0x0645, 0x062C, + /* 4086 */ 0x0645, 0x062D, + /* 4088 */ 0x0645, 0x062E, + /* 4090 */ 0x0645, 0x0645, + /* 4092 */ 0x0646, 0x062C, + /* 4094 */ 0x0646, 0x062D, + /* 4096 */ 0x0646, 0x062E, + /* 4098 */ 0x0646, 0x0645, + /* 4100 */ 0x0646, 0x0647, + /* 4102 */ 0x0647, 0x062C, + /* 4104 */ 0x0647, 0x0645, + /* 4106 */ 0x0647, 0x0670, + /* 4108 */ 0x064A, 0x062C, + /* 4110 */ 0x064A, 0x062D, + /* 4112 */ 0x064A, 0x062E, + /* 4114 */ 0x064A, 0x0645, + /* 4116 */ 0x064A, 0x0647, + /* 4118 */ 0x0626, 0x0645, + /* 4120 */ 0x0626, 0x0647, + /* 4122 */ 0x0628, 0x0645, + /* 4124 */ 0x0628, 0x0647, + /* 4126 */ 0x062A, 0x0645, + /* 4128 */ 0x062A, 0x0647, + /* 4130 */ 0x062B, 0x0645, + /* 4132 */ 0x062B, 0x0647, + /* 4134 */ 0x0633, 0x0645, + /* 4136 */ 0x0633, 0x0647, + /* 4138 */ 0x0634, 0x0645, + /* 4140 */ 0x0634, 0x0647, + /* 4142 */ 0x0643, 0x0644, + /* 4144 */ 0x0643, 0x0645, + /* 4146 */ 0x0644, 0x0645, + /* 4148 */ 0x0646, 0x0645, + /* 4150 */ 0x0646, 0x0647, + /* 4152 */ 0x064A, 0x0645, + /* 4154 */ 0x064A, 0x0647, + /* 4156 */ 0x0640, 0x064E, 0x0651, + /* 4159 */ 0x0640, 0x064F, 0x0651, + /* 4162 */ 0x0640, 0x0650, 0x0651, + /* 4165 */ 0x0637, 0x0649, + /* 4167 */ 0x0637, 0x064A, + /* 4169 */ 0x0639, 0x0649, + /* 4171 */ 0x0639, 0x064A, + /* 4173 */ 0x063A, 0x0649, + /* 4175 */ 0x063A, 0x064A, + /* 4177 */ 0x0633, 0x0649, + /* 4179 */ 0x0633, 0x064A, + /* 4181 */ 0x0634, 0x0649, + /* 4183 */ 0x0634, 0x064A, + /* 4185 */ 0x062D, 0x0649, + /* 4187 */ 0x062D, 0x064A, + /* 4189 */ 0x062C, 0x0649, + /* 4191 */ 0x062C, 0x064A, + /* 4193 */ 0x062E, 0x0649, + /* 4195 */ 0x062E, 0x064A, + /* 4197 */ 0x0635, 0x0649, + /* 4199 */ 0x0635, 0x064A, + /* 4201 */ 0x0636, 0x0649, + /* 4203 */ 0x0636, 0x064A, + /* 4205 */ 0x0634, 0x062C, + /* 4207 */ 0x0634, 0x062D, + /* 4209 */ 0x0634, 0x062E, + /* 4211 */ 0x0634, 0x0645, + /* 4213 */ 0x0634, 0x0631, + /* 4215 */ 0x0633, 0x0631, + /* 4217 */ 0x0635, 0x0631, + /* 4219 */ 0x0636, 0x0631, + /* 4221 */ 0x0637, 0x0649, + /* 4223 */ 0x0637, 0x064A, + /* 4225 */ 0x0639, 0x0649, + /* 4227 */ 0x0639, 0x064A, + /* 4229 */ 0x063A, 0x0649, + /* 4231 */ 0x063A, 0x064A, + /* 4233 */ 0x0633, 0x0649, + /* 4235 */ 0x0633, 0x064A, + /* 4237 */ 0x0634, 0x0649, + /* 4239 */ 0x0634, 0x064A, + /* 4241 */ 0x062D, 0x0649, + /* 4243 */ 0x062D, 0x064A, + /* 4245 */ 0x062C, 0x0649, + /* 4247 */ 0x062C, 0x064A, + /* 4249 */ 0x062E, 0x0649, + /* 4251 */ 0x062E, 0x064A, + /* 4253 */ 0x0635, 0x0649, + /* 4255 */ 0x0635, 0x064A, + /* 4257 */ 0x0636, 0x0649, + /* 4259 */ 0x0636, 0x064A, + /* 4261 */ 0x0634, 0x062C, + /* 4263 */ 0x0634, 0x062D, + /* 4265 */ 0x0634, 0x062E, + /* 4267 */ 0x0634, 0x0645, + /* 4269 */ 0x0634, 0x0631, + /* 4271 */ 0x0633, 0x0631, + /* 4273 */ 0x0635, 0x0631, + /* 4275 */ 0x0636, 0x0631, + /* 4277 */ 0x0634, 0x062C, + /* 4279 */ 0x0634, 0x062D, + /* 4281 */ 0x0634, 0x062E, + /* 4283 */ 0x0634, 0x0645, + /* 4285 */ 0x0633, 0x0647, + /* 4287 */ 0x0634, 0x0647, + /* 4289 */ 0x0637, 0x0645, + /* 4291 */ 0x0633, 0x062C, + /* 4293 */ 0x0633, 0x062D, + /* 4295 */ 0x0633, 0x062E, + /* 4297 */ 0x0634, 0x062C, + /* 4299 */ 0x0634, 0x062D, + /* 4301 */ 0x0634, 0x062E, + /* 4303 */ 0x0637, 0x0645, + /* 4305 */ 0x0638, 0x0645, + /* 4307 */ 0x0627, 0x064B, + /* 4309 */ 0x0627, 0x064B, + /* 4311 */ 0x062A, 0x062C, 0x0645, + /* 4314 */ 0x062A, 0x062D, 0x062C, + /* 4317 */ 0x062A, 0x062D, 0x062C, + /* 4320 */ 0x062A, 0x062D, 0x0645, + /* 4323 */ 0x062A, 0x062E, 0x0645, + /* 4326 */ 0x062A, 0x0645, 0x062C, + /* 4329 */ 0x062A, 0x0645, 0x062D, + /* 4332 */ 0x062A, 0x0645, 0x062E, + /* 4335 */ 0x062C, 0x0645, 0x062D, + /* 4338 */ 0x062C, 0x0645, 0x062D, + /* 4341 */ 0x062D, 0x0645, 0x064A, + /* 4344 */ 0x062D, 0x0645, 0x0649, + /* 4347 */ 0x0633, 0x062D, 0x062C, + /* 4350 */ 0x0633, 0x062C, 0x062D, + /* 4353 */ 0x0633, 0x062C, 0x0649, + /* 4356 */ 0x0633, 0x0645, 0x062D, + /* 4359 */ 0x0633, 0x0645, 0x062D, + /* 4362 */ 0x0633, 0x0645, 0x062C, + /* 4365 */ 0x0633, 0x0645, 0x0645, + /* 4368 */ 0x0633, 0x0645, 0x0645, + /* 4371 */ 0x0635, 0x062D, 0x062D, + /* 4374 */ 0x0635, 0x062D, 0x062D, + /* 4377 */ 0x0635, 0x0645, 0x0645, + /* 4380 */ 0x0634, 0x062D, 0x0645, + /* 4383 */ 0x0634, 0x062D, 0x0645, + /* 4386 */ 0x0634, 0x062C, 0x064A, + /* 4389 */ 0x0634, 0x0645, 0x062E, + /* 4392 */ 0x0634, 0x0645, 0x062E, + /* 4395 */ 0x0634, 0x0645, 0x0645, + /* 4398 */ 0x0634, 0x0645, 0x0645, + /* 4401 */ 0x0636, 0x062D, 0x0649, + /* 4404 */ 0x0636, 0x062E, 0x0645, + /* 4407 */ 0x0636, 0x062E, 0x0645, + /* 4410 */ 0x0637, 0x0645, 0x062D, + /* 4413 */ 0x0637, 0x0645, 0x062D, + /* 4416 */ 0x0637, 0x0645, 0x0645, + /* 4419 */ 0x0637, 0x0645, 0x064A, + /* 4422 */ 0x0639, 0x062C, 0x0645, + /* 4425 */ 0x0639, 0x0645, 0x0645, + /* 4428 */ 0x0639, 0x0645, 0x0645, + /* 4431 */ 0x0639, 0x0645, 0x0649, + /* 4434 */ 0x063A, 0x0645, 0x0645, + /* 4437 */ 0x063A, 0x0645, 0x064A, + /* 4440 */ 0x063A, 0x0645, 0x0649, + /* 4443 */ 0x0641, 0x062E, 0x0645, + /* 4446 */ 0x0641, 0x062E, 0x0645, + /* 4449 */ 0x0642, 0x0645, 0x062D, + /* 4452 */ 0x0642, 0x0645, 0x0645, + /* 4455 */ 0x0644, 0x062D, 0x0645, + /* 4458 */ 0x0644, 0x062D, 0x064A, + /* 4461 */ 0x0644, 0x062D, 0x0649, + /* 4464 */ 0x0644, 0x062C, 0x062C, + /* 4467 */ 0x0644, 0x062C, 0x062C, + /* 4470 */ 0x0644, 0x062E, 0x0645, + /* 4473 */ 0x0644, 0x062E, 0x0645, + /* 4476 */ 0x0644, 0x0645, 0x062D, + /* 4479 */ 0x0644, 0x0645, 0x062D, + /* 4482 */ 0x0645, 0x062D, 0x062C, + /* 4485 */ 0x0645, 0x062D, 0x0645, + /* 4488 */ 0x0645, 0x062D, 0x064A, + /* 4491 */ 0x0645, 0x062C, 0x062D, + /* 4494 */ 0x0645, 0x062C, 0x0645, + /* 4497 */ 0x0645, 0x062E, 0x062C, + /* 4500 */ 0x0645, 0x062E, 0x0645, + /* 4503 */ 0x0645, 0x062C, 0x062E, + /* 4506 */ 0x0647, 0x0645, 0x062C, + /* 4509 */ 0x0647, 0x0645, 0x0645, + /* 4512 */ 0x0646, 0x062D, 0x0645, + /* 4515 */ 0x0646, 0x062D, 0x0649, + /* 4518 */ 0x0646, 0x062C, 0x0645, + /* 4521 */ 0x0646, 0x062C, 0x0645, + /* 4524 */ 0x0646, 0x062C, 0x0649, + /* 4527 */ 0x0646, 0x0645, 0x064A, + /* 4530 */ 0x0646, 0x0645, 0x0649, + /* 4533 */ 0x064A, 0x0645, 0x0645, + /* 4536 */ 0x064A, 0x0645, 0x0645, + /* 4539 */ 0x0628, 0x062E, 0x064A, + /* 4542 */ 0x062A, 0x062C, 0x064A, + /* 4545 */ 0x062A, 0x062C, 0x0649, + /* 4548 */ 0x062A, 0x062E, 0x064A, + /* 4551 */ 0x062A, 0x062E, 0x0649, + /* 4554 */ 0x062A, 0x0645, 0x064A, + /* 4557 */ 0x062A, 0x0645, 0x0649, + /* 4560 */ 0x062C, 0x0645, 0x064A, + /* 4563 */ 0x062C, 0x062D, 0x0649, + /* 4566 */ 0x062C, 0x0645, 0x0649, + /* 4569 */ 0x0633, 0x062E, 0x0649, + /* 4572 */ 0x0635, 0x062D, 0x064A, + /* 4575 */ 0x0634, 0x062D, 0x064A, + /* 4578 */ 0x0636, 0x062D, 0x064A, + /* 4581 */ 0x0644, 0x062C, 0x064A, + /* 4584 */ 0x0644, 0x0645, 0x064A, + /* 4587 */ 0x064A, 0x062D, 0x064A, + /* 4590 */ 0x064A, 0x062C, 0x064A, + /* 4593 */ 0x064A, 0x0645, 0x064A, + /* 4596 */ 0x0645, 0x0645, 0x064A, + /* 4599 */ 0x0642, 0x0645, 0x064A, + /* 4602 */ 0x0646, 0x062D, 0x064A, + /* 4605 */ 0x0642, 0x0645, 0x062D, + /* 4608 */ 0x0644, 0x062D, 0x0645, + /* 4611 */ 0x0639, 0x0645, 0x064A, + /* 4614 */ 0x0643, 0x0645, 0x064A, + /* 4617 */ 0x0646, 0x062C, 0x062D, + /* 4620 */ 0x0645, 0x062E, 0x064A, + /* 4623 */ 0x0644, 0x062C, 0x0645, + /* 4626 */ 0x0643, 0x0645, 0x0645, + /* 4629 */ 0x0644, 0x062C, 0x0645, + /* 4632 */ 0x0646, 0x062C, 0x062D, + /* 4635 */ 0x062C, 0x062D, 0x064A, + /* 4638 */ 0x062D, 0x062C, 0x064A, + /* 4641 */ 0x0645, 0x062C, 0x064A, + /* 4644 */ 0x0641, 0x0645, 0x064A, + /* 4647 */ 0x0628, 0x062D, 0x064A, + /* 4650 */ 0x0643, 0x0645, 0x0645, + /* 4653 */ 0x0639, 0x062C, 0x0645, + /* 4656 */ 0x0635, 0x0645, 0x0645, + /* 4659 */ 0x0633, 0x062E, 0x064A, + /* 4662 */ 0x0646, 0x062C, 0x064A, + /* 4665 */ 0x0635, 0x0644, 0x06D2, + /* 4668 */ 0x0642, 0x0644, 0x06D2, + /* 4671 */ 0x0627, 0x0644, 0x0644, 0x0647, + /* 4675 */ 0x0627, 0x0643, 0x0628, 0x0631, + /* 4679 */ 0x0645, 0x062D, 0x0645, 0x062F, + /* 4683 */ 0x0635, 0x0644, 0x0639, 0x0645, + /* 4687 */ 0x0631, 0x0633, 0x0648, 0x0644, + /* 4691 */ 0x0639, 0x0644, 0x064A, 0x0647, + /* 4695 */ 0x0648, 0x0633, 0x0644, 0x0645, + /* 4699 */ 0x0635, 0x0644, 0x0649, + /* 4702 */ 0x0635, 0x0644, 0x0649, 0x0020, 0x0627, 0x0644, 0x0644, 0x0647, 0x0020, 0x0639, 0x0644, 0x064A, 0x0647, 0x0020, 0x0648, 0x0633, 0x0644, 0x0645, + /* 4720 */ 0x062C, 0x0644, 0x0020, 0x062C, 0x0644, 0x0627, 0x0644, 0x0647, + /* 4728 */ 0x0631, 0x06CC, 0x0627, 0x0644, + /* 4732 */ 0x0020, 0x064B, + /* 4734 */ 0x0640, 0x064B, + /* 4736 */ 0x0020, 0x064C, + /* 4738 */ 0x0020, 0x064D, + /* 4740 */ 0x0020, 0x064E, + /* 4742 */ 0x0640, 0x064E, + /* 4744 */ 0x0020, 0x064F, + /* 4746 */ 0x0640, 0x064F, + /* 4748 */ 0x0020, 0x0650, + /* 4750 */ 0x0640, 0x0650, + /* 4752 */ 0x0020, 0x0651, + /* 4754 */ 0x0640, 0x0651, + /* 4756 */ 0x0020, 0x0652, + /* 4758 */ 0x0640, 0x0652, + /* 4760 */ 0x0644, 0x0622, + /* 4762 */ 0x0644, 0x0622, + /* 4764 */ 0x0644, 0x0623, + /* 4766 */ 0x0644, 0x0623, + /* 4768 */ 0x0644, 0x0625, + /* 4770 */ 0x0644, 0x0625, + /* 4772 */ 0x0644, 0x0627, + /* 4774 */ 0x0644, 0x0627, + /* 4776 */ 0x1DF04, + /* 4777 */ 0x1DF05, + /* 4778 */ 0x1DF06, + /* 4779 */ 0x1DF08, + /* 4780 */ 0x1DF0A, + /* 4781 */ 0x1DF1E, + /* 4782 */ 0x11099, 0x110BA, + /* 4784 */ 0x1109B, 0x110BA, + /* 4786 */ 0x110A5, 0x110BA, + /* 4788 */ 0x11131, 0x11127, + /* 4790 */ 0x11132, 0x11127, + /* 4792 */ 0x11347, 0x1133E, + /* 4794 */ 0x11347, 0x11357, + /* 4796 */ 0x114B9, 0x114BA, + /* 4798 */ 0x114B9, 0x114B0, + /* 4800 */ 0x114B9, 0x114BD, + /* 4802 */ 0x115B8, 0x115AF, + /* 4804 */ 0x115B9, 0x115AF, + /* 4806 */ 0x11935, 0x11930, + /* 4808 */ 0x1D157, 0x1D165, + /* 4810 */ 0x1D158, 0x1D165, + /* 4812 */ 0x1D15F, 0x1D16E, + /* 4814 */ 0x1D15F, 0x1D16F, + /* 4816 */ 0x1D15F, 0x1D170, + /* 4818 */ 0x1D15F, 0x1D171, + /* 4820 */ 0x1D15F, 0x1D172, + /* 4822 */ 0x1D1B9, 0x1D165, + /* 4824 */ 0x1D1BA, 0x1D165, + /* 4826 */ 0x1D1BB, 0x1D16E, + /* 4828 */ 0x1D1BC, 0x1D16E, + /* 4830 */ 0x1D1BB, 0x1D16F, + /* 4832 */ 0x1D1BC, 0x1D16F, + /* 4834 */ 0x0030, 0x002E, + /* 4836 */ 0x0030, 0x002C, + /* 4838 */ 0x0031, 0x002C, + /* 4840 */ 0x0032, 0x002C, + /* 4842 */ 0x0033, 0x002C, + /* 4844 */ 0x0034, 0x002C, + /* 4846 */ 0x0035, 0x002C, + /* 4848 */ 0x0036, 0x002C, + /* 4850 */ 0x0037, 0x002C, + /* 4852 */ 0x0038, 0x002C, + /* 4854 */ 0x0039, 0x002C, + /* 4856 */ 0x0028, 0x0041, 0x0029, + /* 4859 */ 0x0028, 0x0042, 0x0029, + /* 4862 */ 0x0028, 0x0043, 0x0029, + /* 4865 */ 0x0028, 0x0044, 0x0029, + /* 4868 */ 0x0028, 0x0045, 0x0029, + /* 4871 */ 0x0028, 0x0046, 0x0029, + /* 4874 */ 0x0028, 0x0047, 0x0029, + /* 4877 */ 0x0028, 0x0048, 0x0029, + /* 4880 */ 0x0028, 0x0049, 0x0029, + /* 4883 */ 0x0028, 0x004A, 0x0029, + /* 4886 */ 0x0028, 0x004B, 0x0029, + /* 4889 */ 0x0028, 0x004C, 0x0029, + /* 4892 */ 0x0028, 0x004D, 0x0029, + /* 4895 */ 0x0028, 0x004E, 0x0029, + /* 4898 */ 0x0028, 0x004F, 0x0029, + /* 4901 */ 0x0028, 0x0050, 0x0029, + /* 4904 */ 0x0028, 0x0051, 0x0029, + /* 4907 */ 0x0028, 0x0052, 0x0029, + /* 4910 */ 0x0028, 0x0053, 0x0029, + /* 4913 */ 0x0028, 0x0054, 0x0029, + /* 4916 */ 0x0028, 0x0055, 0x0029, + /* 4919 */ 0x0028, 0x0056, 0x0029, + /* 4922 */ 0x0028, 0x0057, 0x0029, + /* 4925 */ 0x0028, 0x0058, 0x0029, + /* 4928 */ 0x0028, 0x0059, 0x0029, + /* 4931 */ 0x0028, 0x005A, 0x0029, + /* 4934 */ 0x3014, 0x0053, 0x3015, + /* 4937 */ 0x0043, 0x0044, + /* 4939 */ 0x0057, 0x005A, + /* 4941 */ 0x0048, 0x0056, + /* 4943 */ 0x004D, 0x0056, + /* 4945 */ 0x0053, 0x0044, + /* 4947 */ 0x0053, 0x0053, + /* 4949 */ 0x0050, 0x0050, 0x0056, + /* 4952 */ 0x0057, 0x0043, + /* 4954 */ 0x004D, 0x0043, + /* 4956 */ 0x004D, 0x0044, + /* 4958 */ 0x004D, 0x0052, + /* 4960 */ 0x0044, 0x004A, + /* 4962 */ 0x307B, 0x304B, + /* 4964 */ 0x30B3, 0x30B3, + /* 4966 */ 0x3014, 0x672C, 0x3015, + /* 4969 */ 0x3014, 0x4E09, 0x3015, + /* 4972 */ 0x3014, 0x4E8C, 0x3015, + /* 4975 */ 0x3014, 0x5B89, 0x3015, + /* 4978 */ 0x3014, 0x70B9, 0x3015, + /* 4981 */ 0x3014, 0x6253, 0x3015, + /* 4984 */ 0x3014, 0x76D7, 0x3015, + /* 4987 */ 0x3014, 0x52DD, 0x3015, + /* 4990 */ 0x3014, 0x6557, 0x3015, + /* 4993 */ 0x20122, + /* 4994 */ 0x2063A, + /* 4995 */ 0x2051C, + /* 4996 */ 0x2054B, + /* 4997 */ 0x291DF, + /* 4998 */ 0x20A2C, + /* 4999 */ 0x20B63, + /* 5000 */ 0x214E4, + /* 5001 */ 0x216A8, + /* 5002 */ 0x216EA, + /* 5003 */ 0x219C8, + /* 5004 */ 0x21B18, + /* 5005 */ 0x21DE4, + /* 5006 */ 0x21DE6, + /* 5007 */ 0x22183, + /* 5008 */ 0x2A392, + /* 5009 */ 0x22331, + /* 5010 */ 0x22331, + /* 5011 */ 0x232B8, + /* 5012 */ 0x261DA, + /* 5013 */ 0x226D4, + /* 5014 */ 0x22B0C, + /* 5015 */ 0x22BF1, + /* 5016 */ 0x2300A, + /* 5017 */ 0x233C3, + /* 5018 */ 0x2346D, + /* 5019 */ 0x236A3, + /* 5020 */ 0x238A7, + /* 5021 */ 0x23A8D, + /* 5022 */ 0x21D0B, + /* 5023 */ 0x23AFA, + /* 5024 */ 0x23CBC, + /* 5025 */ 0x23D1E, + /* 5026 */ 0x23ED1, + /* 5027 */ 0x23F5E, + /* 5028 */ 0x23F8E, + /* 5029 */ 0x20525, + /* 5030 */ 0x24263, + /* 5031 */ 0x243AB, + /* 5032 */ 0x24608, + /* 5033 */ 0x24735, + /* 5034 */ 0x24814, + /* 5035 */ 0x24C36, + /* 5036 */ 0x24C92, + /* 5037 */ 0x2219F, + /* 5038 */ 0x24FA1, + /* 5039 */ 0x24FB8, + /* 5040 */ 0x25044, + /* 5041 */ 0x250F3, + /* 5042 */ 0x250F2, + /* 5043 */ 0x25119, + /* 5044 */ 0x25133, + /* 5045 */ 0x2541D, + /* 5046 */ 0x25626, + /* 5047 */ 0x2569A, + /* 5048 */ 0x256C5, + /* 5049 */ 0x2597C, + /* 5050 */ 0x25AA7, + /* 5051 */ 0x25AA7, + /* 5052 */ 0x25BAB, + /* 5053 */ 0x25C80, + /* 5054 */ 0x25F86, + /* 5055 */ 0x26228, + /* 5056 */ 0x26247, + /* 5057 */ 0x262D9, + /* 5058 */ 0x2633E, + /* 5059 */ 0x264DA, + /* 5060 */ 0x26523, + /* 5061 */ 0x265A8, + /* 5062 */ 0x2335F, + /* 5063 */ 0x267A7, + /* 5064 */ 0x267B5, + /* 5065 */ 0x23393, + /* 5066 */ 0x2339C, + /* 5067 */ 0x26B3C, + /* 5068 */ 0x26C36, + /* 5069 */ 0x26D6B, + /* 5070 */ 0x26CD5, + /* 5071 */ 0x273CA, + /* 5072 */ 0x26F2C, + /* 5073 */ 0x26FB1, + /* 5074 */ 0x270D2, + /* 5075 */ 0x27667, + /* 5076 */ 0x278AE, + /* 5077 */ 0x27966, + /* 5078 */ 0x27CA8, + /* 5079 */ 0x27F2F, + /* 5080 */ 0x20804, + /* 5081 */ 0x208DE, + /* 5082 */ 0x285D2, + /* 5083 */ 0x285ED, + /* 5084 */ 0x2872E, + /* 5085 */ 0x28BFA, + /* 5086 */ 0x28D77, + /* 5087 */ 0x29145, + /* 5088 */ 0x2921A, + /* 5089 */ 0x2940A, + /* 5090 */ 0x29496, + /* 5091 */ 0x295B6, + /* 5092 */ 0x29B30, + /* 5093 */ 0x2A0CE, + /* 5094 */ 0x2A105, + /* 5095 */ 0x2A20E, + /* 5096 */ 0x2A291, + /* 5097 */ 0x2A600 +}; diff --git a/contrib/libs/libpq/src/include/common/username.h b/contrib/libs/libpq/src/include/common/username.h new file mode 100644 index 0000000000..fd07df64c1 --- /dev/null +++ b/contrib/libs/libpq/src/include/common/username.h @@ -0,0 +1,15 @@ +/* + * username.h + * lookup effective username + * + * Copyright (c) 2003-2023, PostgreSQL Global Development Group + * + * src/include/common/username.h + */ +#ifndef USERNAME_H +#define USERNAME_H + +extern const char *get_user_name(char **errstr); +extern const char *get_user_name_or_exit(const char *progname); + +#endif /* USERNAME_H */ diff --git a/contrib/libs/libpq/src/include/datatype/timestamp.h b/contrib/libs/libpq/src/include/datatype/timestamp.h new file mode 100644 index 0000000000..ab8ccf89ca --- /dev/null +++ b/contrib/libs/libpq/src/include/datatype/timestamp.h @@ -0,0 +1,243 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Timestamp and Interval typedefs and related macros. + * + * Note: this file must be includable in both frontend and backend contexts. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/datatype/timestamp.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATATYPE_TIMESTAMP_H +#define DATATYPE_TIMESTAMP_H + +/* + * Timestamp represents absolute time. + * + * Interval represents delta time. Keep track of months (and years), days, + * and hours/minutes/seconds separately since the elapsed time spanned is + * unknown until instantiated relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + * + * Timestamps, as well as the h/m/s fields of intervals, are stored as + * int64 values with units of microseconds. (Once upon a time they were + * double values with units of seconds.) + * + * TimeOffset and fsec_t are convenience typedefs for temporary variables. + * Do not use fsec_t in values stored on-disk. + * Also, fsec_t is only meant for *fractional* seconds; beware of overflow + * if the value you need to store could be many seconds. + */ + +typedef int64 Timestamp; +typedef int64 TimestampTz; +typedef int64 TimeOffset; +typedef int32 fsec_t; /* fractional seconds (in microseconds) */ + + +/* + * Storage format for type interval. + */ +typedef struct +{ + TimeOffset time; /* all time units other than days, months and + * years */ + int32 day; /* days, after time for alignment */ + int32 month; /* months and years, after time for alignment */ +} Interval; + +/* + * Data structure representing a broken-down interval. + * + * For historical reasons, this is modeled on struct pg_tm for timestamps. + * Unlike the situation for timestamps, there's no magic interpretation + * needed for months or years: they're just zero or not. Note that fields + * can be negative; however, because of the divisions done while converting + * from struct Interval, only tm_mday could be INT_MIN. This is important + * because we may need to negate the values in some code paths. + */ +struct pg_itm +{ + int tm_usec; + int tm_sec; + int tm_min; + int64 tm_hour; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + +/* + * Data structure for decoding intervals. We could just use struct pg_itm, + * but then the requirement for tm_usec to be 64 bits would propagate to + * places where it's not really needed. Also, omitting the fields that + * aren't used during decoding seems like a good error-prevention measure. + */ +struct pg_itm_in +{ + int64 tm_usec; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + + +/* Limits on the "precision" option (typmod) for these data types */ +#define MAX_TIMESTAMP_PRECISION 6 +#define MAX_INTERVAL_PRECISION 6 + +/* + * Round off to MAX_TIMESTAMP_PRECISION decimal places. + * Note: this is also used for rounding off intervals. + */ +#define TS_PREC_INV 1000000.0 +#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) + + +/* + * Assorted constants for datetime-related calculations + */ + +#define DAYS_PER_YEAR 365.25 /* assumes leap year every four years */ +#define MONTHS_PER_YEAR 12 +/* + * DAYS_PER_MONTH is very imprecise. The more accurate value is + * 365.2425/12 = 30.436875, or '30 days 10:29:06'. Right now we only + * return an integral number of days, but someday perhaps we should + * also return a 'time' value to be used as well. ISO 8601 suggests + * 30 days. + */ +#define DAYS_PER_MONTH 30 /* assumes exactly 30 days per month */ +#define HOURS_PER_DAY 24 /* assume no daylight savings time changes */ + +/* + * This doesn't adjust for uneven daylight savings time intervals or leap + * seconds, and it crudely estimates leap years. A more accurate value + * for days per years is 365.2422. + */ +#define SECS_PER_YEAR (36525 * 864) /* avoid floating-point computation */ +#define SECS_PER_DAY 86400 +#define SECS_PER_HOUR 3600 +#define SECS_PER_MINUTE 60 +#define MINS_PER_HOUR 60 + +#define USECS_PER_DAY INT64CONST(86400000000) +#define USECS_PER_HOUR INT64CONST(3600000000) +#define USECS_PER_MINUTE INT64CONST(60000000) +#define USECS_PER_SEC INT64CONST(1000000) + +/* + * We allow numeric timezone offsets up to 15:59:59 either way from Greenwich. + * Currently, the record holders for wackiest offsets in actual use are zones + * Asia/Manila, at -15:56:00 until 1844, and America/Metlakatla, at +15:13:42 + * until 1867. If we were to reject such values we would fail to dump and + * restore old timestamptz values with these zone settings. + */ +#define MAX_TZDISP_HOUR 15 /* maximum allowed hour part */ +#define TZDISP_LIMIT ((MAX_TZDISP_HOUR + 1) * SECS_PER_HOUR) + +/* + * We reserve the minimum and maximum integer values to represent + * timestamp (or timestamptz) -infinity and +infinity. + */ +#define TIMESTAMP_MINUS_INFINITY PG_INT64_MIN +#define TIMESTAMP_INFINITY PG_INT64_MAX + +/* + * Historically these alias for infinity have been used. + */ +#define DT_NOBEGIN TIMESTAMP_MINUS_INFINITY +#define DT_NOEND TIMESTAMP_INFINITY + +#define TIMESTAMP_NOBEGIN(j) \ + do {(j) = DT_NOBEGIN;} while (0) + +#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) + +#define TIMESTAMP_NOEND(j) \ + do {(j) = DT_NOEND;} while (0) + +#define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND) + +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) + + +/* + * Julian date support. + * + * date2j() and j2date() nominally handle the Julian date range 0..INT_MAX, + * or 4714-11-24 BC to 5874898-06-03 AD. In practice, date2j() will work and + * give correct negative Julian dates for dates before 4714-11-24 BC as well. + * We rely on it to do so back to 4714-11-01 BC. Allowing at least one day's + * slop is necessary so that timestamp rotation doesn't produce dates that + * would be rejected on input. For example, '4714-11-24 00:00 GMT BC' is a + * legal timestamptz value, but in zones east of Greenwich it would print as + * sometime in the afternoon of 4714-11-23 BC; if we couldn't process such a + * date we'd have a dump/reload failure. So the idea is for IS_VALID_JULIAN + * to accept a slightly wider range of dates than we really support, and + * then we apply the exact checks in IS_VALID_DATE or IS_VALID_TIMESTAMP, + * after timezone rotation if any. To save a few cycles, we can make + * IS_VALID_JULIAN check only to the month boundary, since its exact cutoffs + * are not very critical in this scheme. + * + * It is correct that JULIAN_MINYEAR is -4713, not -4714; it is defined to + * allow easy comparison to tm_year values, in which we follow the convention + * that tm_year <= 0 represents abs(tm_year)+1 BC. + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (24) +#define JULIAN_MAXYEAR (5874898) +#define JULIAN_MAXMONTH (6) +#define JULIAN_MAXDAY (3) + +#define IS_VALID_JULIAN(y,m,d) \ + (((y) > JULIAN_MINYEAR || \ + ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \ + ((y) < JULIAN_MAXYEAR || \ + ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH)))) + +/* Julian-date equivalents of Day 0 in Unix and Postgres reckoning */ +#define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */ +#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */ + +/* + * Range limits for dates and timestamps. + * + * We have traditionally allowed Julian day zero as a valid datetime value, + * so that is the lower bound for both dates and timestamps. + * + * The upper limit for dates is 5874897-12-31, which is a bit less than what + * the Julian-date code can allow. For timestamps, the upper limit is + * 294276-12-31. The int64 overflow limit would be a few days later; again, + * leaving some slop avoids worries about corner-case overflow, and provides + * a simpler user-visible definition. + */ + +/* First allowed date, and first disallowed date, in Julian-date form */ +#define DATETIME_MIN_JULIAN (0) +#define DATE_END_JULIAN (2147483494) /* == date2j(JULIAN_MAXYEAR, 1, 1) */ +#define TIMESTAMP_END_JULIAN (109203528) /* == date2j(294277, 1, 1) */ + +/* Timestamp limits */ +#define MIN_TIMESTAMP INT64CONST(-211813488000000000) +/* == (DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ +#define END_TIMESTAMP INT64CONST(9223371331200000000) +/* == (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ + +/* Range-check a date (given in Postgres, not Julian, numbering) */ +#define IS_VALID_DATE(d) \ + ((DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) <= (d) && \ + (d) < (DATE_END_JULIAN - POSTGRES_EPOCH_JDATE)) + +/* Range-check a timestamp */ +#define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP) + +#endif /* DATATYPE_TIMESTAMP_H */ diff --git a/contrib/libs/libpq/src/include/lib/sort_template.h b/contrib/libs/libpq/src/include/lib/sort_template.h new file mode 100644 index 0000000000..1edd05c7d3 --- /dev/null +++ b/contrib/libs/libpq/src/include/lib/sort_template.h @@ -0,0 +1,432 @@ +/*------------------------------------------------------------------------- + * + * sort_template.h + * + * A template for a sort algorithm that supports varying degrees of + * specialization. + * + * Copyright (c) 2021-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1992-1994, Regents of the University of California + * + * Usage notes: + * + * To generate functions specialized for a type, the following parameter + * macros should be #define'd before this file is included. + * + * - ST_SORT - the name of a sort function to be generated + * - ST_ELEMENT_TYPE - type of the referenced elements + * - ST_DECLARE - if defined the functions and types are declared + * - ST_DEFINE - if defined the functions and types are defined + * - ST_SCOPE - scope (e.g. extern, static inline) for functions + * - ST_CHECK_FOR_INTERRUPTS - if defined the sort is interruptible + * + * Instead of ST_ELEMENT_TYPE, ST_ELEMENT_TYPE_VOID can be defined. Then + * the generated functions will automatically gain an "element_size" + * parameter. This allows us to generate a traditional qsort function. + * + * One of the following macros must be defined, to show how to compare + * elements. The first two options are arbitrary expressions depending + * on whether an extra pass-through argument is desired, and the third + * option should be defined if the sort function should receive a + * function pointer at runtime. + * + * - ST_COMPARE(a, b) - a simple comparison expression + * - ST_COMPARE(a, b, arg) - variant that takes an extra argument + * - ST_COMPARE_RUNTIME_POINTER - sort function takes a function pointer + * + * To say that the comparator and therefore also sort function should + * receive an extra pass-through argument, specify the type of the + * argument. + * + * - ST_COMPARE_ARG_TYPE - type of extra argument + * + * The prototype of the generated sort function is: + * + * void ST_SORT(ST_ELEMENT_TYPE *data, size_t n, + * [size_t element_size,] + * [ST_SORT_compare_function compare,] + * [ST_COMPARE_ARG_TYPE *arg]); + * + * ST_SORT_compare_function is a function pointer of the following type: + * + * int (*)(const ST_ELEMENT_TYPE *a, const ST_ELEMENT_TYPE *b, + * [ST_COMPARE_ARG_TYPE *arg]) + * + * HISTORY + * + * Modifications from vanilla NetBSD source: + * - Add do ... while() macro fix + * - Remove __inline, _DIAGASSERTs, __P + * - Remove ill-considered "swap_cnt" switch to insertion sort, in favor + * of a simple check for presorted input. + * - Take care to recurse on the smaller partition, to bound stack usage + * - Convert into a header that can generate specialized functions + * + * IDENTIFICATION + * src/include/lib/sort_template.h + * + *------------------------------------------------------------------------- + */ + +/* $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $ */ + +/*- + * Copyright (c) 1992, 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. + */ + +/* + * Qsort routine based on J. L. Bentley and M. D. McIlroy, + * "Engineering a sort function", + * Software--Practice and Experience 23 (1993) 1249-1265. + * + * We have modified their original by adding a check for already-sorted + * input, which seems to be a win per discussions on pgsql-hackers around + * 2006-03-21. + * + * Also, we recurse on the smaller partition and iterate on the larger one, + * which ensures we cannot recurse more than log(N) levels (since the + * partition recursed to is surely no more than half of the input). Bentley + * and McIlroy explicitly rejected doing this on the grounds that it's "not + * worth the effort", but we have seen crashes in the field due to stack + * overrun, so that judgment seems wrong. + */ + +#define ST_MAKE_PREFIX(a) CppConcat(a,_) +#define ST_MAKE_NAME(a,b) ST_MAKE_NAME_(ST_MAKE_PREFIX(a),b) +#define ST_MAKE_NAME_(a,b) CppConcat(a,b) + +/* + * If the element type is void, we'll also need an element_size argument + * because we don't know the size. + */ +#ifdef ST_ELEMENT_TYPE_VOID +#define ST_ELEMENT_TYPE void +#define ST_SORT_PROTO_ELEMENT_SIZE , size_t element_size +#define ST_SORT_INVOKE_ELEMENT_SIZE , element_size +#else +#define ST_SORT_PROTO_ELEMENT_SIZE +#define ST_SORT_INVOKE_ELEMENT_SIZE +#endif + +/* + * If the user wants to be able to pass in compare functions at runtime, + * we'll need to make that an argument of the sort and med3 functions. + */ +#ifdef ST_COMPARE_RUNTIME_POINTER +/* + * The type of the comparator function pointer that ST_SORT will take, unless + * you've already declared a type name manually and want to use that instead of + * having a new one defined. + */ +#ifndef ST_COMPARATOR_TYPE_NAME +#define ST_COMPARATOR_TYPE_NAME ST_MAKE_NAME(ST_SORT, compare_function) +#endif +#define ST_COMPARE compare +#ifndef ST_COMPARE_ARG_TYPE +#define ST_SORT_PROTO_COMPARE , ST_COMPARATOR_TYPE_NAME compare +#define ST_SORT_INVOKE_COMPARE , compare +#else +#define ST_SORT_PROTO_COMPARE , ST_COMPARATOR_TYPE_NAME compare +#define ST_SORT_INVOKE_COMPARE , compare +#endif +#else +#define ST_SORT_PROTO_COMPARE +#define ST_SORT_INVOKE_COMPARE +#endif + +/* + * If the user wants to use a compare function or expression that takes an + * extra argument, we'll need to make that an argument of the sort, compare and + * med3 functions. + */ +#ifdef ST_COMPARE_ARG_TYPE +#define ST_SORT_PROTO_ARG , ST_COMPARE_ARG_TYPE *arg +#define ST_SORT_INVOKE_ARG , arg +#else +#define ST_SORT_PROTO_ARG +#define ST_SORT_INVOKE_ARG +#endif + +#ifdef ST_DECLARE + +#ifdef ST_COMPARE_RUNTIME_POINTER +typedef int (*ST_COMPARATOR_TYPE_NAME) (const ST_ELEMENT_TYPE *, + const ST_ELEMENT_TYPE * ST_SORT_PROTO_ARG); +#endif + +/* Declare the sort function. Note optional arguments at end. */ +ST_SCOPE void ST_SORT(ST_ELEMENT_TYPE * first, size_t n + ST_SORT_PROTO_ELEMENT_SIZE + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG); + +#endif + +#ifdef ST_DEFINE + +/* sort private helper functions */ +#define ST_MED3 ST_MAKE_NAME(ST_SORT, med3) +#define ST_SWAP ST_MAKE_NAME(ST_SORT, swap) +#define ST_SWAPN ST_MAKE_NAME(ST_SORT, swapn) + +/* Users expecting to run very large sorts may need them to be interruptible. */ +#ifdef ST_CHECK_FOR_INTERRUPTS +#define DO_CHECK_FOR_INTERRUPTS() CHECK_FOR_INTERRUPTS() +#else +#define DO_CHECK_FOR_INTERRUPTS() +#endif + +/* + * Create wrapper macros that know how to invoke compare, med3 and sort with + * the right arguments. + */ +#ifdef ST_COMPARE_RUNTIME_POINTER +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_) ST_SORT_INVOKE_ARG) +#elif defined(ST_COMPARE_ARG_TYPE) +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_), arg) +#else +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_)) +#endif +#define DO_MED3(a_, b_, c_) \ + ST_MED3((a_), (b_), (c_) \ + ST_SORT_INVOKE_COMPARE \ + ST_SORT_INVOKE_ARG) +#define DO_SORT(a_, n_) \ + ST_SORT((a_), (n_) \ + ST_SORT_INVOKE_ELEMENT_SIZE \ + ST_SORT_INVOKE_COMPARE \ + ST_SORT_INVOKE_ARG) + +/* + * If we're working with void pointers, we'll use pointer arithmetic based on + * uint8, and use the runtime element_size to step through the array and swap + * elements. Otherwise we'll work with ST_ELEMENT_TYPE. + */ +#ifndef ST_ELEMENT_TYPE_VOID +#define ST_POINTER_TYPE ST_ELEMENT_TYPE +#define ST_POINTER_STEP 1 +#define DO_SWAPN(a_, b_, n_) ST_SWAPN((a_), (b_), (n_)) +#define DO_SWAP(a_, b_) ST_SWAP((a_), (b_)) +#else +#define ST_POINTER_TYPE uint8 +#define ST_POINTER_STEP element_size +#define DO_SWAPN(a_, b_, n_) ST_SWAPN((a_), (b_), (n_)) +#define DO_SWAP(a_, b_) DO_SWAPN((a_), (b_), element_size) +#endif + +/* + * Find the median of three values. Currently, performance seems to be best + * if the comparator is inlined here, but the med3 function is not inlined + * in the qsort function. + */ +static pg_noinline ST_ELEMENT_TYPE * +ST_MED3(ST_ELEMENT_TYPE * a, + ST_ELEMENT_TYPE * b, + ST_ELEMENT_TYPE * c + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG) +{ + return DO_COMPARE(a, b) < 0 ? + (DO_COMPARE(b, c) < 0 ? b : (DO_COMPARE(a, c) < 0 ? c : a)) + : (DO_COMPARE(b, c) > 0 ? b : (DO_COMPARE(a, c) < 0 ? a : c)); +} + +static inline void +ST_SWAP(ST_POINTER_TYPE * a, ST_POINTER_TYPE * b) +{ + ST_POINTER_TYPE tmp = *a; + + *a = *b; + *b = tmp; +} + +static inline void +ST_SWAPN(ST_POINTER_TYPE * a, ST_POINTER_TYPE * b, size_t n) +{ + for (size_t i = 0; i < n; ++i) + ST_SWAP(&a[i], &b[i]); +} + +/* + * Sort an array. + */ +ST_SCOPE void +ST_SORT(ST_ELEMENT_TYPE * data, size_t n + ST_SORT_PROTO_ELEMENT_SIZE + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG) +{ + ST_POINTER_TYPE *a = (ST_POINTER_TYPE *) data, + *pa, + *pb, + *pc, + *pd, + *pl, + *pm, + *pn; + size_t d1, + d2; + int r, + presorted; + +loop: + DO_CHECK_FOR_INTERRUPTS(); + if (n < 7) + { + for (pm = a + ST_POINTER_STEP; pm < a + n * ST_POINTER_STEP; + pm += ST_POINTER_STEP) + for (pl = pm; pl > a && DO_COMPARE(pl - ST_POINTER_STEP, pl) > 0; + pl -= ST_POINTER_STEP) + DO_SWAP(pl, pl - ST_POINTER_STEP); + return; + } + presorted = 1; + for (pm = a + ST_POINTER_STEP; pm < a + n * ST_POINTER_STEP; + pm += ST_POINTER_STEP) + { + DO_CHECK_FOR_INTERRUPTS(); + if (DO_COMPARE(pm - ST_POINTER_STEP, pm) > 0) + { + presorted = 0; + break; + } + } + if (presorted) + return; + pm = a + (n / 2) * ST_POINTER_STEP; + if (n > 7) + { + pl = a; + pn = a + (n - 1) * ST_POINTER_STEP; + if (n > 40) + { + size_t d = (n / 8) * ST_POINTER_STEP; + + pl = DO_MED3(pl, pl + d, pl + 2 * d); + pm = DO_MED3(pm - d, pm, pm + d); + pn = DO_MED3(pn - 2 * d, pn - d, pn); + } + pm = DO_MED3(pl, pm, pn); + } + DO_SWAP(a, pm); + pa = pb = a + ST_POINTER_STEP; + pc = pd = a + (n - 1) * ST_POINTER_STEP; + for (;;) + { + while (pb <= pc && (r = DO_COMPARE(pb, a)) <= 0) + { + if (r == 0) + { + DO_SWAP(pa, pb); + pa += ST_POINTER_STEP; + } + pb += ST_POINTER_STEP; + DO_CHECK_FOR_INTERRUPTS(); + } + while (pb <= pc && (r = DO_COMPARE(pc, a)) >= 0) + { + if (r == 0) + { + DO_SWAP(pc, pd); + pd -= ST_POINTER_STEP; + } + pc -= ST_POINTER_STEP; + DO_CHECK_FOR_INTERRUPTS(); + } + if (pb > pc) + break; + DO_SWAP(pb, pc); + pb += ST_POINTER_STEP; + pc -= ST_POINTER_STEP; + } + pn = a + n * ST_POINTER_STEP; + d1 = Min(pa - a, pb - pa); + DO_SWAPN(a, pb - d1, d1); + d1 = Min(pd - pc, pn - pd - ST_POINTER_STEP); + DO_SWAPN(pb, pn - d1, d1); + d1 = pb - pa; + d2 = pd - pc; + if (d1 <= d2) + { + /* Recurse on left partition, then iterate on right partition */ + if (d1 > ST_POINTER_STEP) + DO_SORT(a, d1 / ST_POINTER_STEP); + if (d2 > ST_POINTER_STEP) + { + /* Iterate rather than recurse to save stack space */ + /* DO_SORT(pn - d2, d2 / ST_POINTER_STEP) */ + a = pn - d2; + n = d2 / ST_POINTER_STEP; + goto loop; + } + } + else + { + /* Recurse on right partition, then iterate on left partition */ + if (d2 > ST_POINTER_STEP) + DO_SORT(pn - d2, d2 / ST_POINTER_STEP); + if (d1 > ST_POINTER_STEP) + { + /* Iterate rather than recurse to save stack space */ + /* DO_SORT(a, d1 / ST_POINTER_STEP) */ + n = d1 / ST_POINTER_STEP; + goto loop; + } + } +} +#endif + +#undef DO_CHECK_FOR_INTERRUPTS +#undef DO_COMPARE +#undef DO_MED3 +#undef DO_SORT +#undef DO_SWAP +#undef DO_SWAPN +#undef ST_CHECK_FOR_INTERRUPTS +#undef ST_COMPARATOR_TYPE_NAME +#undef ST_COMPARE +#undef ST_COMPARE_ARG_TYPE +#undef ST_COMPARE_RUNTIME_POINTER +#undef ST_ELEMENT_TYPE +#undef ST_ELEMENT_TYPE_VOID +#undef ST_MAKE_NAME +#undef ST_MAKE_NAME_ +#undef ST_MAKE_PREFIX +#undef ST_MED3 +#undef ST_POINTER_STEP +#undef ST_POINTER_TYPE +#undef ST_SCOPE +#undef ST_SORT +#undef ST_SORT_INVOKE_ARG +#undef ST_SORT_INVOKE_COMPARE +#undef ST_SORT_INVOKE_ELEMENT_SIZE +#undef ST_SORT_PROTO_ARG +#undef ST_SORT_PROTO_COMPARE +#undef ST_SORT_PROTO_ELEMENT_SIZE +#undef ST_SWAP +#undef ST_SWAPN diff --git a/contrib/libs/libpq/src/include/lib/stringinfo.h b/contrib/libs/libpq/src/include/lib/stringinfo.h new file mode 100644 index 0000000000..36a416f8e0 --- /dev/null +++ b/contrib/libs/libpq/src/include/lib/stringinfo.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------- + * + * stringinfo.h + * Declarations/definitions for "StringInfo" functions. + * + * StringInfo provides an extensible string data type (currently limited to a + * length of 1GB). It can be used to buffer either ordinary C strings + * (null-terminated text) or arbitrary binary data. All storage is allocated + * with palloc() (falling back to malloc in frontend code). + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/lib/stringinfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef STRINGINFO_H +#define STRINGINFO_H + +/*------------------------- + * StringInfoData holds information about an extensible string. + * data is the current buffer for the string (allocated with palloc). + * 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. + * cursor is initialized to zero by makeStringInfo or initStringInfo, + * but is not otherwise touched by the stringinfo.c routines. + * Some routines use it to scan through a StringInfo. + *------------------------- + */ +typedef struct StringInfoData +{ + char *data; + int len; + int maxlen; + int cursor; +} StringInfoData; + +typedef StringInfoData *StringInfo; + + +/*------------------------ + * There are two ways to create a StringInfo object initially: + * + * StringInfo stringptr = makeStringInfo(); + * Both the StringInfoData and the data buffer are palloc'd. + * + * StringInfoData string; + * initStringInfo(&string); + * The data buffer is palloc'd but the StringInfoData is just local. + * This is the easiest approach for a StringInfo object that will + * only live as long as the current routine. + * + * To destroy a StringInfo, pfree() the data buffer, and then pfree() the + * StringInfoData if it was palloc'd. There's no special support for this. + * + * NOTE: some routines build up a string using StringInfo, and then + * release the StringInfoData but return the data string itself to their + * caller. At that point the data string looks like a plain palloc'd + * string. + *------------------------- + */ + +/*------------------------ + * makeStringInfo + * Create an empty 'StringInfoData' & return a pointer to it. + */ +extern StringInfo makeStringInfo(void); + +/*------------------------ + * initStringInfo + * Initialize a StringInfoData struct (with previously undefined contents) + * to describe an empty string. + */ +extern void initStringInfo(StringInfo str); + +/*------------------------ + * resetStringInfo + * Clears the current content of the StringInfo, if any. The + * StringInfo remains valid. + */ +extern void resetStringInfo(StringInfo str); + +/*------------------------ + * appendStringInfo + * Format text data under the control of fmt (an sprintf-style 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 appendStringInfo(StringInfo str, const char *fmt,...) pg_attribute_printf(2, 3); + +/*------------------------ + * appendStringInfoVA + * Attempt to format text data under the control of fmt (an sprintf-style + * format string) and append it to whatever is already in str. If successful + * return zero; if not (because there's not enough space), return an estimate + * of the space needed, without modifying str. Typically the caller should + * pass the return value to enlargeStringInfo() before trying again; see + * appendStringInfo for standard usage pattern. + */ +extern int appendStringInfoVA(StringInfo str, const char *fmt, va_list args) pg_attribute_printf(2, 0); + +/*------------------------ + * appendStringInfoString + * Append a null-terminated string to str. + * Like appendStringInfo(str, "%s", s) but faster. + */ +extern void appendStringInfoString(StringInfo str, const char *s); + +/*------------------------ + * appendStringInfoChar + * Append a single byte to str. + * Like appendStringInfo(str, "%c", ch) but much faster. + */ +extern void appendStringInfoChar(StringInfo str, char ch); + +/*------------------------ + * appendStringInfoCharMacro + * As above, but a macro for even more speed where it matters. + * Caution: str argument will be evaluated multiple times. + */ +#define appendStringInfoCharMacro(str,ch) \ + (((str)->len + 1 >= (str)->maxlen) ? \ + appendStringInfoChar(str, ch) : \ + (void)((str)->data[(str)->len] = (ch), (str)->data[++(str)->len] = '\0')) + +/*------------------------ + * appendStringInfoSpaces + * Append a given number of spaces to str. + */ +extern void appendStringInfoSpaces(StringInfo str, int count); + +/*------------------------ + * appendBinaryStringInfo + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. + */ +extern void appendBinaryStringInfo(StringInfo str, + const void *data, int datalen); + +/*------------------------ + * appendBinaryStringInfoNT + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. Does not ensure a trailing null-byte exists. + */ +extern void appendBinaryStringInfoNT(StringInfo str, + const void *data, int datalen); + +/*------------------------ + * enlargeStringInfo + * Make sure a StringInfo's buffer can hold at least 'needed' more bytes. + */ +extern void enlargeStringInfo(StringInfo str, int needed); + +#endif /* STRINGINFO_H */ diff --git a/contrib/libs/libpq/src/include/libpq/libpq-fs.h b/contrib/libs/libpq/src/include/libpq/libpq-fs.h new file mode 100644 index 0000000000..f89e0f9e3f --- /dev/null +++ b/contrib/libs/libpq/src/include/libpq/libpq-fs.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * libpq-fs.h + * definitions for using Inversion file system routines (ie, large objects) + * + * + * Portions Copyright (c) 1996-2023, 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/contrib/libs/libpq/src/include/libpq/pqcomm.h b/contrib/libs/libpq/src/include/libpq/pqcomm.h new file mode 100644 index 0000000000..c85090259d --- /dev/null +++ b/contrib/libs/libpq/src/include/libpq/pqcomm.h @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 <sys/socket.h> +#include <sys/un.h> +#include <netdb.h> +#include <netinet/in.h> + +typedef struct +{ + struct sockaddr_storage addr; + socklen_t salen; +} SockAddr; + +typedef struct +{ + int family; + SockAddr addr; +} AddrInfo; + +/* Configure the UNIX socket location for the well known port. */ + +#define UNIXSOCK_PATH(path, port, sockdir) \ + (AssertMacro(sockdir), \ + AssertMacro(*(sockdir) != '\0'), \ + snprintf(path, sizeof(path), "%s/.s.PGSQL.%d", \ + (sockdir), (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) + +/* + * A host that looks either like an absolute path or starts with @ is + * interpreted as a Unix-domain socket address. + */ +static inline bool +is_unixsock_path(const char *path) +{ + return is_absolute_path(path) || path[0] == '@'; +} + +/* + * 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. + * (Only protocol version 3 is currently supported) + */ + +#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,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; + +extern PGDLLIMPORT 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 */ +/* 6 is available. It was used for SCM creds, not supported any more. */ +#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 /* Begin SASL authentication */ +#define AUTH_REQ_SASL_CONT 11 /* Continue SASL authentication */ +#define AUTH_REQ_SASL_FIN 12 /* Final SASL message */ +#define AUTH_REQ_MAX AUTH_REQ_SASL_FIN /* maximum AUTH_REQ_* value */ + +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 or GSSAPI negotiation request to + * get a secure channel. + */ +#define NEGOTIATE_SSL_CODE PG_PROTOCOL(1234,5679) +#define NEGOTIATE_GSS_CODE PG_PROTOCOL(1234,5680) + +#endif /* PQCOMM_H */ diff --git a/contrib/libs/libpq/src/include/mb/pg_wchar.h b/contrib/libs/libpq/src/include/mb/pg_wchar.h new file mode 100644 index 0000000000..25276b199f --- /dev/null +++ b/contrib/libs/libpq/src/include/mb/pg_wchar.h @@ -0,0 +1,772 @@ +/*------------------------------------------------------------------------- + * + * pg_wchar.h + * multibyte-character support + * + * Portions Copyright (c) 1996-2023, 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 frontends, 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 + +#include "port/simd.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 src/common/encnames.c), and + * in the pg_wchar_table[] array (in src/common/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_enc2name_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) + +/* + * When converting strings between different encodings, we assume that space + * for converted result is 4-to-1 growth in the worst case. The rate for + * currently supported encoding pairs are within 3 (SJIS JIS X0201 half width + * kana -> UTF8 is the worst case). So "4" should be enough for the moment. + * + * Note that this is not the same as the maximum character width in any + * particular encoding. + */ +#define MAX_CONVERSION_GROWTH 4 + +/* + * Maximum byte length of a string that's required in any encoding to convert + * at least one character to any other encoding. In other words, if you feed + * MAX_CONVERSION_INPUT_LENGTH bytes to any encoding conversion function, it + * is guaranteed to be able to convert something without needing more input + * (assuming the input is valid). + * + * Currently, the maximum case is the conversion UTF8 -> SJIS JIS X0201 half + * width kana, where a pair of UTF-8 characters is converted into a single + * SHIFT_JIS_2004 character (the reverse of the worst case for + * MAX_CONVERSION_GROWTH). It needs 6 bytes of input. In theory, a + * user-defined conversion function might have more complicated cases, although + * for the reverse mapping you would probably also need to bump up + * MAX_CONVERSION_GROWTH. But there is no need to be stingy here, so make it + * generous. + */ +#define MAX_CONVERSION_INPUT_LENGTH 16 + +/* + * Maximum byte length of the string equivalent to any one Unicode code point, + * in any backend encoding. The current value assumes that a 4-byte UTF-8 + * character might expand by MAX_CONVERSION_GROWTH, which is a huge + * overestimate. But in current usage we don't allocate large multiples of + * this, so there's little point in being stingy. + */ +#define MAX_UNICODE_EQUIVALENT_STRING 16 + +/* + * 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 PGDLLIMPORT const pg_enc2name pg_enc2name_tbl[]; + +/* + * Encoding names for gettext + */ +typedef struct pg_enc2gettext +{ + pg_enc encoding; + const char *name; +} pg_enc2gettext; + +extern PGDLLIMPORT 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 (*mbchar_verifier) (const unsigned char *mbstr, int len); + +typedef int (*mbstr_verifier) (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 */ + mbchar_verifier mbverifychar; /* verify multibyte character */ + mbstr_verifier mbverifystr; /* verify multibyte string */ + int maxmblen; /* max bytes for a char in this encoding */ +} pg_wchar_tbl; + +extern PGDLLIMPORT 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. + * + * There are three possible ways a character can be mapped: + * + * 1. Using a radix tree, from source to destination code. + * 2. Using a sorted array of source -> destination code pairs. This + * method is used for "combining" characters. There are so few of + * them that building a radix tree would be wasteful. + * 3. Using a conversion function. + */ + +/* + * Radix tree for character conversion. + * + * Logically, this is actually four different radix trees, for 1-byte, + * 2-byte, 3-byte and 4-byte inputs. The 1-byte tree is a simple lookup + * table from source to target code. The 2-byte tree consists of two levels: + * one lookup table for the first byte, where the value in the lookup table + * points to a lookup table for the second byte. And so on. + * + * Physically, all the trees are stored in one big array, in 'chars16' or + * 'chars32', depending on the maximum value that needs to be represented. For + * each level in each tree, we also store lower and upper bound of allowed + * values - values outside those bounds are considered invalid, and are left + * out of the tables. + * + * In the intermediate levels of the trees, the values stored are offsets + * into the chars[16|32] array. + * + * In the beginning of the chars[16|32] array, there is always a number of + * zeros, so that you safely follow an index from an intermediate table + * without explicitly checking for a zero. Following a zero any number of + * times will always bring you to the dummy, all-zeros table in the + * beginning. This helps to shave some cycles when looking up values. + */ +typedef struct +{ + /* + * Array containing all the values. Only one of chars16 or chars32 is + * used, depending on how wide the values we need to represent are. + */ + const uint16 *chars16; + const uint32 *chars32; + + /* Radix tree for 1-byte inputs */ + uint32 b1root; /* offset of table in the chars[16|32] array */ + uint8 b1_lower; /* min allowed value for a single byte input */ + uint8 b1_upper; /* max allowed value for a single byte input */ + + /* Radix tree for 2-byte inputs */ + uint32 b2root; /* offset of 1st byte's table */ + uint8 b2_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b2_1_upper; + uint8 b2_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b2_2_upper; + + /* Radix tree for 3-byte inputs */ + uint32 b3root; /* offset of 1st byte's table */ + uint8 b3_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b3_1_upper; + uint8 b3_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b3_2_upper; + uint8 b3_3_lower; /* min/max allowed value for 3rd input byte */ + uint8 b3_3_upper; + + /* Radix tree for 4-byte inputs */ + uint32 b4root; /* offset of 1st byte's table */ + uint8 b4_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b4_1_upper; + uint8 b4_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b4_2_upper; + uint8 b4_3_lower; /* min/max allowed value for 3rd input byte */ + uint8 b4_3_upper; + uint8 b4_4_lower; /* min/max allowed value for 4th input byte */ + uint8 b4_4_upper; + +} pg_mb_radix_tree; + +/* + * 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)) + + +/* + * Some handy functions for Unicode-specific tests. + */ +static inline bool +is_valid_unicode_codepoint(pg_wchar c) +{ + return (c > 0 && c <= 0x10FFFF); +} + +static inline bool +is_utf16_surrogate_first(pg_wchar c) +{ + return (c >= 0xD800 && c <= 0xDBFF); +} + +static inline bool +is_utf16_surrogate_second(pg_wchar c) +{ + return (c >= 0xDC00 && c <= 0xDFFF); +} + +static inline pg_wchar +surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second) +{ + return ((first & 0x3FF) << 10) + 0x10000 + (second & 0x3FF); +} + + +/* + * 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); + +/* + * These functions are available to frontend code that links with libpgcommon + * (in addition to the ones just above). The constant tables declared + * earlier in this file are also available from libpgcommon. + */ +extern int pg_encoding_mblen(int encoding, const char *mbstr); +extern int pg_encoding_mblen_bounded(int encoding, const char *mbstr); +extern int pg_encoding_dsplen(int encoding, const char *mbstr); +extern int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len); +extern int pg_encoding_max_length(int encoding); +extern int pg_valid_client_encoding(const char *name); +extern int pg_valid_server_encoding(const char *name); +extern bool is_encoding_supported_by_icu(int encoding); +extern const char *get_encoding_name_for_icu(int encoding); + +extern unsigned char *unicode_to_utf8(pg_wchar c, unsigned char *utf8string); +extern pg_wchar utf8_to_unicode(const unsigned char *c); +extern bool pg_utf8_islegal(const unsigned char *source, int length); +extern int pg_utf_mblen(const unsigned char *s); +extern int pg_mule_mblen(const unsigned char *s); + +/* + * The remaining functions are backend-only. + */ +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 *str); +extern int pg_mblen(const char *mbstr); +extern int pg_dsplen(const char *mbstr); +extern int pg_mbstrlen(const char *mbstr); +extern int pg_mbstrlen_with_len(const char *mbstr, int limit); +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 limit); +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 unsigned char *pg_do_encoding_conversion(unsigned char *src, int len, + int src_encoding, + int dest_encoding); +extern int pg_do_encoding_conversion_buf(Oid proc, + int src_encoding, + int dest_encoding, + unsigned char *src, int srclen, + unsigned char *dest, int destlen, + bool noError); + +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 void pg_unicode_to_server(pg_wchar c, unsigned char *s); +extern bool pg_unicode_to_server_noerror(pg_wchar c, unsigned char *s); + +extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc); +extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc); + +extern int UtfToLocal(const unsigned char *utf, int len, + unsigned char *iso, + const pg_mb_radix_tree *map, + const pg_utf_to_local_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding, bool noError); +extern int LocalToUtf(const unsigned char *iso, int len, + unsigned char *utf, + const pg_mb_radix_tree *map, + const pg_local_to_utf_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding, bool noError); + +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 int local2local(const unsigned char *l, unsigned char *p, int len, + int src_encoding, int dest_encoding, + const unsigned char *tab, bool noError); +extern int latin2mic(const unsigned char *l, unsigned char *p, int len, + int lc, int encoding, bool noError); +extern int mic2latin(const unsigned char *mic, unsigned char *p, int len, + int lc, int encoding, bool noError); +extern int latin2mic_with_table(const unsigned char *l, unsigned char *p, + int len, int lc, int encoding, + const unsigned char *tab, bool noError); +extern int mic2latin_with_table(const unsigned char *mic, unsigned char *p, + int len, int lc, int encoding, + const unsigned char *tab, bool noError); + +#ifdef WIN32 +extern WCHAR *pgwin32_message_to_UTF16(const char *str, int len, int *utf16len); +#endif + + +/* + * Verify a chunk of bytes for valid ASCII. + * + * Returns false if the input contains any zero bytes or bytes with the + * high-bit set. Input len must be a multiple of the chunk size (8 or 16). + */ +static inline bool +is_valid_ascii(const unsigned char *s, int len) +{ + const unsigned char *const s_end = s + len; + Vector8 chunk; + Vector8 highbit_cum = vector8_broadcast(0); +#ifdef USE_NO_SIMD + Vector8 zero_cum = vector8_broadcast(0x80); +#endif + + Assert(len % sizeof(chunk) == 0); + + while (s < s_end) + { + vector8_load(&chunk, s); + + /* Capture any zero bytes in this chunk. */ +#ifdef USE_NO_SIMD + + /* + * First, add 0x7f to each byte. This sets the high bit in each byte, + * unless it was a zero. If any resulting high bits are zero, the + * corresponding high bits in the zero accumulator will be cleared. + * + * If none of the bytes in the chunk had the high bit set, the max + * value each byte can have after the addition is 0x7f + 0x7f = 0xfe, + * and we don't need to worry about carrying over to the next byte. If + * any input bytes did have the high bit set, it doesn't matter + * because we check for those separately. + */ + zero_cum &= (chunk + vector8_broadcast(0x7F)); +#else + + /* + * Set all bits in each lane of the highbit accumulator where input + * bytes are zero. + */ + highbit_cum = vector8_or(highbit_cum, + vector8_eq(chunk, vector8_broadcast(0))); +#endif + + /* Capture all set bits in this chunk. */ + highbit_cum = vector8_or(highbit_cum, chunk); + + s += sizeof(chunk); + } + + /* Check if any high bits in the high bit accumulator got set. */ + if (vector8_is_highbit_set(highbit_cum)) + return false; + +#ifdef USE_NO_SIMD + /* Check if any high bits in the zero accumulator got cleared. */ + if (zero_cum != vector8_broadcast(0x80)) + return false; +#endif + + return true; +} + +#endif /* PG_WCHAR_H */ diff --git a/contrib/libs/libpq/src/include/parser/kwlist.h b/contrib/libs/libpq/src/include/parser/kwlist.h new file mode 100644 index 0000000000..f5b2e61ca5 --- /dev/null +++ b/contrib/libs/libpq/src/include/parser/kwlist.h @@ -0,0 +1,498 @@ +/*------------------------------------------------------------------------- + * + * kwlist.h + * + * The keyword lists are kept in their own source files for use by + * automatic tools. The exact representation of a keyword is determined + * by the PG_KEYWORD macro, which is not defined in this file; it can + * be defined by the caller for special purposes. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/parser/kwlist.h + * + *------------------------------------------------------------------------- + */ + +/* there is deliberately not an #ifndef KWLIST_H here */ + +/* + * List of keyword (name, token-value, category, bare-label-status) entries. + * + * Note: gen_keywordlist.pl requires the entries to appear in ASCII order. + */ + +/* name, value, category, is-bare-label */ +PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("absent", ABSENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, BARE_LABEL) /* British spelling */ +PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("and", AND, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("any", ANY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("as", AS, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("asensitive", ASENSITIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("atomic", ATOMIC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("breadth", BREADTH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("case", CASE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("compression", COMPRESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("depth", DEPTH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("finalize", FINALIZE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("for", FOR, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("format", FORMAT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("from", FROM, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("indent", INDENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("into", INTO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("json", JSON, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("json_array", JSON_ARRAY, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("json_arrayagg", JSON_ARRAYAGG, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("json_object", JSON_OBJECT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("json_objectagg", JSON_OBJECTAGG, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("keys", KEYS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("not", NOT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("on", ON, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("or", OR, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parameter", PARAMETER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ref", REF_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("return", RETURN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("scalar", SCALAR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("some", SOME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("start", START, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("system_user", SYSTEM_USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("then", THEN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("to", TO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("union", UNION, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("using", USING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("with", WITH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/contrib/libs/libpq/src/include/pg_config-linux-aarch64.h b/contrib/libs/libpq/src/include/pg_config-linux-aarch64.h new file mode 100644 index 0000000000..f27c40f1d7 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config-linux-aarch64.h @@ -0,0 +1,6 @@ +#pragma once + +#include "pg_config-linux.h" + +/* Define to 1 if you have __get_cpuid. */ +#undef HAVE__GET_CPUID diff --git a/contrib/libs/libpq/src/include/pg_config-linux.h b/contrib/libs/libpq/src/include/pg_config-linux.h new file mode 100644 index 0000000000..afcf2967c5 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config-linux.h @@ -0,0 +1,828 @@ +/* src/include/pg_config.h. Generated from pg_config.h.in by configure. */ +/* src/include/pg_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* The normal alignment of `double', in bytes. */ +#define ALIGNOF_DOUBLE 8 + +/* The normal alignment of `int', in bytes. */ +#define ALIGNOF_INT 4 + +/* The normal alignment of `long', in bytes. */ +#define ALIGNOF_LONG 8 + +/* The normal alignment of `long long int', in bytes. */ +/* #undef ALIGNOF_LONG_LONG_INT */ + +/* The normal alignment of `PG_INT128_TYPE', in bytes. */ +#define ALIGNOF_PG_INT128_TYPE 16 + +/* The normal alignment of `short', in bytes. */ +#define ALIGNOF_SHORT 2 + +/* 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. */ +#define BLCKSZ 8192 + +/* Saved arguments from configure */ +#define CONFIGURE_ARGS " '--prefix=/var/empty/postgresql-16.1' '--with-openssl' '--with-libxml' '--with-icu' '--sysconfdir=/etc' '--libdir=$(lib)/lib' '--with-system-tzdata=/var/empty/tzdata-2022f/share/zoneinfo' '--enable-debug' '--with-systemd' '--with-ossp-uuid' '--with-lz4' '--with-gssapi' '--without-gssapi' 'CC=cc' 'CXX=g++' 'PKG_CONFIG=pkg-config' 'PKG_CONFIG_PATH=/var/empty/libxcrypt-4.4.30/lib/pkgconfig:/var/empty/zlib-1.2.13-dev/lib/pkgconfig:/var/empty/ncurses-6.3-p20220507-dev/lib/pkgconfig:/var/empty/openssl-3.0.7-dev/lib/pkgconfig:/var/empty/libxml2-2.10.3-dev/lib/pkgconfig:/var/empty/icu4c-72.1-dev/lib/pkgconfig:/var/empty/lz4-1.9.4-dev/lib/pkgconfig:/var/empty/systemd-251.7-dev/lib/pkgconfig:/var/empty/systemd-251.7-dev/share/pkgconfig:/var/empty/libkrb5-1.20-dev/lib/pkgconfig:/var/empty/libossp-uuid-1.6.2/lib/pkgconfig'" + +/* 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 the file name extension of dynamically-loadable modules. */ +#define DLSUFFIX ".so" + +/* 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) */ +#define ENABLE_THREAD_SAFETY 1 + +/* Define to 1 if you have the `append_history' function. */ +#define HAVE_APPEND_HISTORY 1 + +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#define HAVE_ASN1_STRING_GET0_DATA 1 + +/* Define to 1 if you want to use atomics if available. */ +#define HAVE_ATOMICS 1 + +/* Define to 1 if you have the <atomic.h> header file. */ +/* #undef HAVE_ATOMIC_H */ + +/* Define to 1 if you have the `backtrace_symbols' function. */ +#define HAVE_BACKTRACE_SYMBOLS 1 + +/* Define to 1 if you have the `BIO_get_data' function. */ +#define HAVE_BIO_GET_DATA 1 + +/* Define to 1 if you have the `BIO_meth_new' function. */ +#define HAVE_BIO_METH_NEW 1 + +/* Define to 1 if your compiler handles computed gotos. */ +#define HAVE_COMPUTED_GOTO 1 + +/* Define to 1 if you have the `copyfile' function. */ +/* #undef HAVE_COPYFILE */ + +/* Define to 1 if you have the <copyfile.h> header file. */ +/* #undef HAVE_COPYFILE_H */ + +/* Define to 1 if you have the <crtdefs.h> header file. */ +/* #undef HAVE_CRTDEFS_H */ + +/* Define to 1 if you have the `CRYPTO_lock' function. */ +/* #undef HAVE_CRYPTO_LOCK */ + +/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you + don't. */ +#define HAVE_DECL_FDATASYNC 1 + +/* 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 + `LLVMCreateGDBRegistrationListener', and to 0 if you don't. */ +/* #undef HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER */ + +/* Define to 1 if you have the declaration of + `LLVMCreatePerfJITEventListener', and to 0 if you don't. */ +/* #undef HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER */ + +/* Define to 1 if you have the declaration of `LLVMGetHostCPUFeatures', and to + 0 if you don't. */ +/* #undef HAVE_DECL_LLVMGETHOSTCPUFEATURES */ + +/* Define to 1 if you have the declaration of `LLVMGetHostCPUName', and to 0 + if you don't. */ +/* #undef HAVE_DECL_LLVMGETHOSTCPUNAME */ + +/* Define to 1 if you have the declaration of `LLVMOrcGetSymbolAddressIn', and + to 0 if you don't. */ +/* #undef HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN */ + +/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you + don't. */ +#define HAVE_DECL_POSIX_FADVISE 1 + +/* Define to 1 if you have the declaration of `preadv', and to 0 if you don't. + */ +#define HAVE_DECL_PREADV 1 + +/* Define to 1 if you have the declaration of `pwritev', and to 0 if you + don't. */ +#define HAVE_DECL_PWRITEV 1 + +/* Define to 1 if you have the declaration of `strlcat', and to 0 if you + don't. */ +#define HAVE_DECL_STRLCAT 0 + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#define HAVE_DECL_STRLCPY 0 + +/* Define to 1 if you have the declaration of `strnlen', and to 0 if you + don't. */ +#define HAVE_DECL_STRNLEN 1 + +/* Define to 1 if you have the <editline/history.h> header file. */ +/* #undef HAVE_EDITLINE_HISTORY_H */ + +/* Define to 1 if you have the <editline/readline.h> header file. */ +/* #undef HAVE_EDITLINE_READLINE_H */ + +/* Define to 1 if you have the <execinfo.h> header file. */ +#define HAVE_EXECINFO_H 1 + +/* Define to 1 if you have the `explicit_bzero' function. */ +#define HAVE_EXPLICIT_BZERO 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int). */ +#define HAVE_GCC__ATOMIC_INT32_CAS 1 + +/* Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *, + int64). */ +#define HAVE_GCC__ATOMIC_INT64_CAS 1 + +/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */ +#define HAVE_GCC__SYNC_CHAR_TAS 1 + +/* Define to 1 if you have __sync_val_compare_and_swap(int *, int, int). */ +#define HAVE_GCC__SYNC_INT32_CAS 1 + +/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */ +#define HAVE_GCC__SYNC_INT32_TAS 1 + +/* Define to 1 if you have __sync_val_compare_and_swap(int64 *, int64, int64). + */ +#define HAVE_GCC__SYNC_INT64_CAS 1 + +/* Define to 1 if you have the `getifaddrs' function. */ +#define HAVE_GETIFADDRS 1 + +/* Define to 1 if you have the `getopt' function. */ +#define HAVE_GETOPT 1 + +/* Define to 1 if you have the <getopt.h> 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 `getpeerucred' function. */ +/* #undef HAVE_GETPEERUCRED */ + +/* Define to 1 if you have the <gssapi_ext.h> header file. */ +/* #undef HAVE_GSSAPI_EXT_H */ + +/* Define to 1 if you have the <gssapi/gssapi_ext.h> header file. */ +/* #undef HAVE_GSSAPI_GSSAPI_EXT_H */ + +/* Define to 1 if you have the <gssapi/gssapi.h> header file. */ +/* #undef HAVE_GSSAPI_GSSAPI_H */ + +/* Define to 1 if you have the <gssapi.h> header file. */ +/* #undef HAVE_GSSAPI_H */ + +/* Define to 1 if you have the <history.h> header file. */ +/* #undef HAVE_HISTORY_H */ + +/* Define to 1 if you have the `history_truncate_file' function. */ +#define HAVE_HISTORY_TRUNCATE_FILE 1 + +/* Define to 1 if you have the `HMAC_CTX_free' function. */ +#define HAVE_HMAC_CTX_FREE 1 + +/* Define to 1 if you have the `HMAC_CTX_new' function. */ +#define HAVE_HMAC_CTX_NEW 1 + +/* Define to 1 if you have the <ifaddrs.h> header file. */ +#define HAVE_IFADDRS_H 1 + +/* Define to 1 if you have the `inet_aton' function. */ +#define HAVE_INET_ATON 1 + +/* Define to 1 if you have the `inet_pton' function. */ +#define HAVE_INET_PTON 1 + +/* 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 <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the global variable 'int opterr'. */ +#define HAVE_INT_OPTERR 1 + +/* 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'. */ +#define HAVE_INT_TIMEZONE 1 + +/* Define to 1 if __builtin_constant_p(x) implies "i"(x) acceptance. */ +/* #undef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P */ + +/* Define to 1 if you have the `kqueue' function. */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the <langinfo.h> header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have the `ldap_initialize' function. */ +/* #undef HAVE_LDAP_INITIALIZE */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the `ldap' library (-lldap). */ +/* #undef HAVE_LIBLDAP */ + +/* Define to 1 if you have the `lz4' library (-llz4). */ +#define HAVE_LIBLZ4 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the `pam' library (-lpam). */ +/* #undef HAVE_LIBPAM */ + +/* Define if you have a function readline library */ +#define HAVE_LIBREADLINE 1 + +/* Define to 1 if you have the `selinux' library (-lselinux). */ +/* #undef HAVE_LIBSELINUX */ + +/* Define to 1 if you have the `ssl' library (-lssl). */ +#define HAVE_LIBSSL 1 + +/* Define to 1 if you have the `wldap32' library (-lwldap32). */ +/* #undef HAVE_LIBWLDAP32 */ + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +#define HAVE_LIBXML2 1 + +/* Define to 1 if you have the `xslt' library (-lxslt). */ +/* #undef HAVE_LIBXSLT */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the `zstd' library (-lzstd). */ +/* #undef HAVE_LIBZSTD */ + +/* 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. */ +#define HAVE_LONG_INT_64 1 + +/* 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 <mbarrier.h> 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 <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset_s' function. */ +/* #undef HAVE_MEMSET_S */ + +/* Define to 1 if you have the `mkdtemp' function. */ +#define HAVE_MKDTEMP 1 + +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ +#define HAVE_OPENSSL_INIT_SSL 1 + +/* Define to 1 if you have the <ossp/uuid.h> header file. */ +/* #undef HAVE_OSSP_UUID_H */ + +/* Define to 1 if you have the <pam/pam_appl.h> header file. */ +/* #undef HAVE_PAM_PAM_APPL_H */ + +/* Define to 1 if you have the `posix_fadvise' function. */ +#define HAVE_POSIX_FADVISE 1 + +/* Define to 1 if you have the `posix_fallocate' function. */ +#define HAVE_POSIX_FALLOCATE 1 + +/* Define to 1 if you have the `ppoll' function. */ +#define HAVE_PPOLL 1 + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Define to 1 if you have the `pthread_barrier_wait' function. */ +#define HAVE_PTHREAD_BARRIER_WAIT 1 + +/* Define to 1 if you have the `pthread_is_threaded_np' function. */ +/* #undef HAVE_PTHREAD_IS_THREADED_NP */ + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have the <readline.h> header file. */ +/* #undef HAVE_READLINE_H */ + +/* Define to 1 if you have the <readline/history.h> header file. */ +#define HAVE_READLINE_HISTORY_H 1 + +/* Define to 1 if you have the <readline/readline.h> header file. */ +#define HAVE_READLINE_READLINE_H 1 + +/* Define to 1 if you have the `rl_completion_matches' function. */ +#define HAVE_RL_COMPLETION_MATCHES 1 + +/* Define to 1 if you have the global variable 'rl_completion_suppress_quote'. + */ +#define HAVE_RL_COMPLETION_SUPPRESS_QUOTE 1 + +/* Define to 1 if you have the `rl_filename_completion_function' function. */ +#define HAVE_RL_FILENAME_COMPLETION_FUNCTION 1 + +/* Define to 1 if you have the global variable 'rl_filename_quote_characters'. + */ +#define HAVE_RL_FILENAME_QUOTE_CHARACTERS 1 + +/* Define to 1 if you have the global variable 'rl_filename_quoting_function'. + */ +#define HAVE_RL_FILENAME_QUOTING_FUNCTION 1 + +/* Define to 1 if you have the `rl_reset_screen_size' function. */ +#define HAVE_RL_RESET_SCREEN_SIZE 1 + +/* Define to 1 if you have the `rl_variable_bind' function. */ +#define HAVE_RL_VARIABLE_BIND 1 + +/* Define to 1 if you have the <security/pam_appl.h> 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 `setproctitle_fast' function. */ +/* #undef HAVE_SETPROCTITLE_FAST */ + +/* Define to 1 if the system has the type `socklen_t'. */ +#define HAVE_SOCKLEN_T 1 + +/* Define to 1 if you have spinlocks. */ +#define HAVE_SPINLOCKS 1 + +/* Define to 1 if you have the `SSL_CTX_set_cert_cb' function. */ +#define HAVE_SSL_CTX_SET_CERT_CB 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchrnul' function. */ +#define HAVE_STRCHRNUL 1 + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* 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 `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if the system has the type `struct option'. */ +#define HAVE_STRUCT_OPTION 1 + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ + +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_ZONE 1 + +/* Define to 1 if you have the `syncfs' function. */ +#define HAVE_SYNCFS 1 + +/* Define to 1 if you have the `sync_file_range' function. */ +#define HAVE_SYNC_FILE_RANGE 1 + +/* Define to 1 if you have the syslog interface. */ +#define HAVE_SYSLOG 1 + +/* Define to 1 if you have the <sys/epoll.h> header file. */ +#define HAVE_SYS_EPOLL_H 1 + +/* Define to 1 if you have the <sys/event.h> header file. */ +/* #undef HAVE_SYS_EVENT_H */ + +/* Define to 1 if you have the <sys/personality.h> header file. */ +#define HAVE_SYS_PERSONALITY_H 1 + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#define HAVE_SYS_PRCTL_H 1 + +/* Define to 1 if you have the <sys/procctl.h> header file. */ +/* #undef HAVE_SYS_PROCCTL_H */ + +/* Define to 1 if you have the <sys/signalfd.h> header file. */ +#define HAVE_SYS_SIGNALFD_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <sys/ucred.h> header file. */ +/* #undef HAVE_SYS_UCRED_H */ + +/* Define to 1 if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define to 1 if your compiler understands `typeof' or something similar. */ +#define HAVE_TYPEOF 1 + +/* Define to 1 if you have the <ucred.h> 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 `union semun'. */ +/* #undef HAVE_UNION_SEMUN */ + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `uselocale' function. */ +#define HAVE_USELOCALE 1 + +/* 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 <uuid.h> header file. */ +#define HAVE_UUID_H 1 + +/* Define to 1 if you have OSSP UUID support. */ +#define HAVE_UUID_OSSP 1 + +/* Define to 1 if you have the <uuid/uuid.h> header file. */ +/* #undef HAVE_UUID_UUID_H */ + +/* Define to 1 if your compiler knows the visibility("hidden") attribute. */ +#define HAVE_VISIBILITY_ATTRIBUTE 1 + +/* Define to 1 if you have the `wcstombs_l' function. */ +/* #undef HAVE_WCSTOMBS_L */ + +/* Define to 1 if you have the `X509_get_signature_info' function. */ +#define HAVE_X509_GET_SIGNATURE_INFO 1 + +/* Define to 1 if you have the `X509_get_signature_nid' function. */ +#define HAVE_X509_GET_SIGNATURE_NID 1 + +/* Define to 1 if the assembler supports X86_64's POPCNTQ instruction. */ +#define HAVE_X86_64_POPCNTQ 1 + +/* Define to 1 if the system has the type `_Bool'. */ +#define HAVE__BOOL 1 + +/* Define to 1 if your compiler understands __builtin_bswap16. */ +#define HAVE__BUILTIN_BSWAP16 1 + +/* Define to 1 if your compiler understands __builtin_bswap32. */ +#define HAVE__BUILTIN_BSWAP32 1 + +/* Define to 1 if your compiler understands __builtin_bswap64. */ +#define HAVE__BUILTIN_BSWAP64 1 + +/* Define to 1 if your compiler understands __builtin_clz. */ +#define HAVE__BUILTIN_CLZ 1 + +/* Define to 1 if your compiler understands __builtin_constant_p. */ +#define HAVE__BUILTIN_CONSTANT_P 1 + +/* Define to 1 if your compiler understands __builtin_ctz. */ +#define HAVE__BUILTIN_CTZ 1 + +/* Define to 1 if your compiler understands __builtin_frame_address. */ +#define HAVE__BUILTIN_FRAME_ADDRESS 1 + +/* Define to 1 if your compiler understands __builtin_$op_overflow. */ +#define HAVE__BUILTIN_OP_OVERFLOW 1 + +/* Define to 1 if your compiler understands __builtin_popcount. */ +#define HAVE__BUILTIN_POPCOUNT 1 + +/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ +#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1 + +/* Define to 1 if your compiler understands __builtin_unreachable. */ +#define HAVE__BUILTIN_UNREACHABLE 1 + +/* Define to 1 if you have the `_configthreadlocale' function. */ +/* #undef HAVE__CONFIGTHREADLOCALE */ + +/* Define to 1 if you have __cpuid. */ +/* #undef HAVE__CPUID */ + +/* Define to 1 if you have __get_cpuid. */ +#define HAVE__GET_CPUID 1 + +/* Define to 1 if your compiler understands _Static_assert. */ +#define HAVE__STATIC_ASSERT 1 + +/* Define to the appropriate printf length modifier for 64-bit ints. */ +#define INT64_MODIFIER "l" + +/* Define to 1 if `locale_t' requires <xlocale.h>. */ +/* #undef LOCALE_T_IN_XLOCALE */ + +/* 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 OpenSSL API version in use. This avoids deprecation warnings + from newer OpenSSL versions. */ +/* #define OPENSSL_API_COMPAT 0x10001000L */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "pgsql-bugs@lists.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 16.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "postgresql" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "https://www.postgresql.org/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "16.1" + +/* Define to the name of a signed 128-bit integer type. */ +#define PG_INT128_TYPE __int128 + +/* Define to the name of a signed 64-bit integer type. */ +#define PG_INT64_TYPE long int + +/* Define to the name of the default PostgreSQL service principal in Kerberos + (GSSAPI). (--with-krb-srvnam=NAME) */ +#define PG_KRB_SRVNAM "postgres" + +/* PostgreSQL major version as a string */ +#define PG_MAJORVERSION "16" + +/* PostgreSQL major version number */ +#define PG_MAJORVERSION_NUM 16 + +/* PostgreSQL minor version number */ +#define PG_MINORVERSION_NUM 1 + +/* Define to best printf format archetype, usually gnu_printf if available. */ +#define PG_PRINTF_ATTRIBUTE gnu_printf + +/* Define to 1 to use <stdbool.h> to define type bool. */ +#define PG_USE_STDBOOL 1 + +/* PostgreSQL version as a string */ +#define PG_VERSION "16.1" + +/* PostgreSQL version as a number */ +#define PG_VERSION_NUM 160001 + +/* A string containing the version number, platform, and C compiler */ +#define PG_VERSION_STR "PostgreSQL 16.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.3.0, 64-bit" + +/* 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. */ +#define RELSEG_SIZE 131072 + +/* The size of `bool', as computed by sizeof. */ +#define SIZEOF_BOOL 1 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `off_t', as computed by sizeof. */ +#define SIZEOF_OFF_T 8 + +/* The size of `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 8 + +/* The size of `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if strerror_r() returns int. */ +/* #undef STRERROR_R_INT */ + +/* Define to 1 to use ARMv8 CRC Extension. */ +/* #undef USE_ARMV8_CRC32C */ + +/* Define to 1 to use ARMv8 CRC Extension with a runtime check. */ +/* #undef USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK */ + +/* 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 build with ICU support. (--with-icu) */ +#define USE_ICU 1 + +/* Define to 1 to build with LDAP support. (--with-ldap) */ +/* #undef USE_LDAP */ + +/* Define to 1 to build with XML support. (--with-libxml) */ +#define USE_LIBXML 1 + +/* Define to 1 to use XSLT support when building contrib/xml2. + (--with-libxslt) */ +/* #undef USE_LIBXSLT */ + +/* Define to 1 to build with LLVM based JIT support. (--with-llvm) */ +/* #undef USE_LLVM */ + +/* Define to 1 to build with LZ4 support. (--with-lz4) */ +#define USE_LZ4 1 + +/* Define to select named POSIX semaphores. */ +/* #undef USE_NAMED_POSIX_SEMAPHORES */ + +/* Define to 1 to build with OpenSSL support. (--with-ssl=openssl) */ +#define USE_OPENSSL 1 + +/* Define to 1 to build with PAM support. (--with-pam) */ +/* #undef USE_PAM */ + +/* Define to 1 to use software CRC-32C implementation (slicing-by-8). */ +/* #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 SSE 4.2 CRC instructions with a runtime check. */ +#define USE_SSE42_CRC32C_WITH_RUNTIME_CHECK 1 + +/* Define to build with systemd support. (--with-systemd) */ +#define USE_SYSTEMD 1 + +/* 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. */ +#define USE_UNNAMED_POSIX_SEMAPHORES 1 + +/* 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 to build with ZSTD support. (--with-zstd) */ +/* #undef USE_ZSTD */ + +/* Define to 1 if `wcstombs_l' requires <xlocale.h>. */ +/* #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. + */ +#define XLOG_BLCKSZ 8192 + + + +/* 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 keyword to use for C99 restrict support, or to nothing if not + supported */ +#define pg_restrict __restrict + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#define restrict __restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to how the compiler spells `typeof'. */ +/* #undef typeof */ diff --git a/contrib/libs/libpq/src/include/pg_config-osx-arm64.h b/contrib/libs/libpq/src/include/pg_config-osx-arm64.h new file mode 100644 index 0000000000..dde70a44c9 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config-osx-arm64.h @@ -0,0 +1,159 @@ +#pragma once + +#include "pg_config-linux.h" + +/* Define to 1 if you have __get_cpuid. */ +#undef HAVE__GET_CPUID + +/* 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 have the `copyfile' function. */ +#define HAVE_COPYFILE 1 + +/* Define to 1 if you have the <copyfile.h> header file. */ +#define HAVE_COPYFILE_H 1 + +/* Define to 1 if you have the <crypt.h> 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 HAVE_DECL_FDATASYNC 0 + +/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you + don't. */ +#undef HAVE_DECL_F_FULLFSYNC +#define HAVE_DECL_F_FULLFSYNC 1 + +/* 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 `strlcat', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCAT +#define HAVE_DECL_STRLCAT 1 + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCPY +#define HAVE_DECL_STRLCPY 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 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 <dld.h> header file. */ +#undef HAVE_DLD_H + +/* Define to 1 if you have the `fls' function. */ +#define HAVE_FLS 1 + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `getpeereid' function. */ +#define HAVE_GETPEEREID 1 + +/* Define to 1 if you have the `mbstowcs_l' function. */ +#define HAVE_MBSTOWCS_L 1 + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_fallocate' function. */ +#undef HAVE_POSIX_FALLOCATE + +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pthread_is_threaded_np' function. */ +#define HAVE_PTHREAD_IS_THREADED_NP 1 + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* 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 `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `strchrnul' function. */ +#undef HAVE_STRCHRNUL + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strlcat' function. */ +#define HAVE_STRLCAT 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +#define HAVE_STRUCT_SOCKADDR_SA_LEN 1 + +/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 + +/* Define to 1 if you have the `sync_file_range' function. */ +#undef HAVE_SYNC_FILE_RANGE + +/* Define to 1 if you have the <sys/epoll.h> header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define to 1 if you have the <sys/sockio.h> header file. */ +#define HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the <sys/ucred.h> header file. */ +#define HAVE_SYS_UCRED_H 1 + +/* Define to 1 if you have the `towlower' function. */ +#define HAVE_TOWLOWER 1 + +/* Define to 1 if you have the <uuid.h> 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 `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `wcstombs_l' function. */ +#define HAVE_WCSTOMBS_L 1 + +/* Define to 1 if `locale_t' requires <xlocale.h>. */ +#define LOCALE_T_IN_XLOCALE 1 + +/* Define to gnu_printf if compiler supports it, else printf. */ +#undef PG_PRINTF_ATTRIBUTE +#define PG_PRINTF_ATTRIBUTE printf + +/* Define to 1 if strerror_r() returns int. */ +#define STRERROR_R_INT 1 + +/* Define to build with systemd support. (--with-systemd) */ +/* #undef USE_SYSTEMD */ + +/* Define to select SysV-style semaphores. */ +#define USE_SYSV_SEMAPHORES 1 + +/* Define to select unnamed POSIX semaphores. */ +/* #undef USE_UNNAMED_POSIX_SEMAPHORES */ + +/* Define to 1 if `wcstombs_l' requires <xlocale.h>. */ +#define WCSTOMBS_L_IN_XLOCALE 1 diff --git a/contrib/libs/libpq/src/include/pg_config-osx.h b/contrib/libs/libpq/src/include/pg_config-osx.h new file mode 100644 index 0000000000..4b1a8a294c --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config-osx.h @@ -0,0 +1,156 @@ +#pragma once + +#include "pg_config-linux.h" + +/* 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 have the `copyfile' function. */ +#define HAVE_COPYFILE 1 + +/* Define to 1 if you have the <copyfile.h> header file. */ +#define HAVE_COPYFILE_H 1 + +/* Define to 1 if you have the <crypt.h> 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 HAVE_DECL_FDATASYNC 0 + +/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you + don't. */ +#undef HAVE_DECL_F_FULLFSYNC +#define HAVE_DECL_F_FULLFSYNC 1 + +/* 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 `strlcat', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCAT +#define HAVE_DECL_STRLCAT 1 + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCPY +#define HAVE_DECL_STRLCPY 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 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 <dld.h> header file. */ +#undef HAVE_DLD_H + +/* Define to 1 if you have the `fls' function. */ +#define HAVE_FLS 1 + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `getpeereid' function. */ +#define HAVE_GETPEEREID 1 + +/* Define to 1 if you have the `mbstowcs_l' function. */ +#define HAVE_MBSTOWCS_L 1 + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_fallocate' function. */ +#undef HAVE_POSIX_FALLOCATE + +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pthread_is_threaded_np' function. */ +#define HAVE_PTHREAD_IS_THREADED_NP 1 + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* 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 `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `strchrnul' function. */ +#undef HAVE_STRCHRNUL + +/* Define to 1 if you have the `strerror_r' function. */ +#define HAVE_STRERROR_R 1 + +/* Define to 1 if you have the `strlcat' function. */ +#define HAVE_STRLCAT 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +#define HAVE_STRUCT_SOCKADDR_SA_LEN 1 + +/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 + +/* Define to 1 if you have the `sync_file_range' function. */ +#undef HAVE_SYNC_FILE_RANGE + +/* Define to 1 if you have the <sys/epoll.h> header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define to 1 if you have the <sys/sockio.h> header file. */ +#define HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the <sys/ucred.h> header file. */ +#define HAVE_SYS_UCRED_H 1 + +/* Define to 1 if you have the `towlower' function. */ +#define HAVE_TOWLOWER 1 + +/* Define to 1 if you have the <uuid.h> 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 `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `wcstombs_l' function. */ +#define HAVE_WCSTOMBS_L 1 + +/* Define to 1 if `locale_t' requires <xlocale.h>. */ +#define LOCALE_T_IN_XLOCALE 1 + +/* Define to gnu_printf if compiler supports it, else printf. */ +#undef PG_PRINTF_ATTRIBUTE +#define PG_PRINTF_ATTRIBUTE printf + +/* Define to 1 if strerror_r() returns int. */ +#define STRERROR_R_INT 1 + +/* Define to build with systemd support. (--with-systemd) */ +/* #undef USE_SYSTEMD */ + +/* Define to select SysV-style semaphores. */ +#define USE_SYSV_SEMAPHORES 1 + +/* Define to select unnamed POSIX semaphores. */ +/* #undef USE_UNNAMED_POSIX_SEMAPHORES */ + +/* Define to 1 if `wcstombs_l' requires <xlocale.h>. */ +#define WCSTOMBS_L_IN_XLOCALE 1 diff --git a/contrib/libs/libpq/src/include/pg_config-win.h b/contrib/libs/libpq/src/include/pg_config-win.h new file mode 100644 index 0000000000..9574513dc0 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config-win.h @@ -0,0 +1,318 @@ +#pragma once + +#include "pg_config-linux.h" + +/* Define to the type of arg 1 of 'accept' */ +#define ACCEPT_TYPE_ARG1 unsigned int + +/* 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 + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if your compiler handles computed gotos. */ +#undef HAVE_COMPUTED_GOTO + +/* Define to 1 if you have the `crypt' function. */ +#undef HAVE_CRYPT + +/* Define to 1 if you have the <crypt.h> header file. */ +#undef HAVE_CRYPT_H + +/* 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 `RTLD_GLOBAL', and to 0 if you + don't. */ +#undef HAVE_DECL_RTLD_GLOBAL + +/* Define to 1 if you have the declaration of `RTLD_NOW', and to 0 if you + don't. */ +#undef HAVE_DECL_RTLD_NOW + +/* Define to 1 if you have the declaration of `strlcat', and to 0 if you + don't. */ +#define HAVE_DECL_STRLCAT 0 + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#define HAVE_DECL_STRLCPY 0 + +/* Define to 1 if you have the `dlopen' function. */ +#undef HAVE_DLOPEN + +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + +/* 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 *, int64 *, + 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 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 `getopt' function. */ +#undef HAVE_GETOPT + +/* Define to 1 if you have the <getopt.h> 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 `getpwuid_r' function. */ +#undef HAVE_GETPWUID_R + +/* Define to 1 if you have the `getrlimit' function. */ +#undef HAVE_RLIMIT + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <langinfo.h> header file. */ +#undef HAVE_LANGINFO_H + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if `long int' works and is 64 bits. */ +#define HAVE_LONG_INT_64 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the `mbstowcs_l' function. */ +#define HAVE_MBSTOWCS_L 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 <netinet/tcp.h> header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define to 1 if you have the <poll.h> header file. */ +#undef HAVE_POLL_H + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_fallocate' function. */ +#undef HAVE_POSIX_FALLOCATE + +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Have PTHREAD_PRIO_INHERIT. */ +#define HAVE_PTHREAD_PRIO_INHERIT 1 + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* Define to 1 if you have the `readlink' function. */ +#undef HAVE_READLINK + +/* 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 `setsid' function. */ +#undef HAVE_SETSID + +/* Define to 1 if you have the `strchrnul' function. */ +#undef HAVE_STRCHRNUL + +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the `strsignal' function. */ +#undef HAVE_STRSIGNAL + +/* Define to 1 if the system has the type `struct option'. */ +#undef HAVE_STRUCT_OPTION + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + +/* 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 <sys/ipc.h> header file. */ +#undef HAVE_SYS_IPC_H + +/* Define to 1 if you have the <sys/personality.h> header file. */ +#undef HAVE_SYS_PERSONALITY_H + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#undef HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/sem.h> header file. */ +#undef HAVE_SYS_SEM_H + +/* Define to 1 if you have the <sys/shm.h> header file. */ +#undef HAVE_SYS_SHM_H + +/* Define to 1 if you have the <sys/un.h> header file. */ +#undef HAVE_SYS_UN_H + +/* Define to 1 if you have the <termios.h> 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 your compiler understands `typeof' or something similar. */ +#undef HAVE_TYPEOF + +/* Define to 1 if you have the external array `tzname'. */ +#undef HAVE_TZNAME + +/* 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 `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the `wcstombs_l' function. */ +#define HAVE_WCSTOMBS_L 1 + +/* Define to 1 if the assembler supports X86_64's POPCNTQ instruction. */ +#undef HAVE_X86_64_POPCNTQ + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to 1 if your compiler understands __builtin_bswap16. */ +#undef HAVE__BUILTIN_BSWAP16 + +/* 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_clz. */ +#undef HAVE__BUILTIN_CLZ + +/* Define to 1 if your compiler understands __builtin_constant_p. */ +#undef HAVE__BUILTIN_CONSTANT_P + +/* Define to 1 if your compiler understands __builtin_ctz. */ +#undef HAVE__BUILTIN_CTZ + +/* Define to 1 if your compiler understands __builtin_$op_overflow. */ +#undef HAVE__BUILTIN_OP_OVERFLOW + +/* Define to 1 if your compiler understands __builtin_popcount. */ +#undef HAVE__BUILTIN_POPCOUNT + +/* 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 the `_configthreadlocale' function. */ +#define HAVE__CONFIGTHREADLOCALE 1 + +/* 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 the appropriate printf length modifier for 64-bit ints. */ +#define INT64_MODIFIER "ll" + +/* Define to 1 if `locale_t' requires <xlocale.h>. */ +/* #undef LOCALE_T_IN_XLOCALE */ + +/* 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 + +/* The size of `size_t', as computed by sizeof. */ +#ifdef _WIN64 +#define SIZEOF_SIZE_T 8 +#else +#define SIZEOF_SIZE_T 4 +#endif + +/* The size of `void *', as computed by sizeof. */ +#ifndef _WIN64 +#define SIZEOF_VOID_P 8 +#else +#define SIZEOF_VOID_P 4 +#endif + +/* Define to select named POSIX semaphores. */ +#undef USE_NAMED_POSIX_SEMAPHORES + +/* Define to build with systemd support. (--with-systemd) */ +#undef USE_SYSTEMD + +/* Define to select unnamed POSIX semaphores. */ +#undef USE_UNNAMED_POSIX_SEMAPHORES + +/* Define to use native Windows API for random number generation */ +#define USE_WIN32_RANDOM 1 + +/* Define to select Win32-style semaphores. */ +#define USE_WIN32_SEMAPHORES 1 + +#define pg_restrict __restrict diff --git a/contrib/libs/libpq/src/include/pg_config.h b/contrib/libs/libpq/src/include/pg_config.h new file mode 100644 index 0000000000..b63bb45246 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config.h @@ -0,0 +1,13 @@ +#pragma once + +#if defined(__APPLE__) && (defined(__aarch64__) || defined(_M_ARM64)) +# include "pg_config-osx-arm64.h" +#elif defined(__APPLE__) +# include "pg_config-osx.h" +#elif defined(_MSC_VER) +# include "pg_config-win.h" +#elif defined(__linux__) && (defined(__aarch64__) || defined(_M_ARM64)) +# include "pg_config-linux-aarch64.h" +#else +# include "pg_config-linux.h" +#endif diff --git a/contrib/libs/libpq/src/include/pg_config_ext.h b/contrib/libs/libpq/src/include/pg_config_ext.h new file mode 100644 index 0000000000..b4c07dd857 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_ext.h @@ -0,0 +1,8 @@ +/* src/include/pg_config_ext.h. Generated from pg_config_ext.h.in by configure. */ +/* + * 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. */ +#define PG_INT64_TYPE long int diff --git a/contrib/libs/libpq/src/include/pg_config_manual.h b/contrib/libs/libpq/src/include/pg_config_manual.h new file mode 100644 index 0000000000..a1a93ad706 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_manual.h @@ -0,0 +1,372 @@ +/*------------------------------------------------------------------------ + * 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-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/pg_config_manual.h + *------------------------------------------------------------------------ + */ + +/* + * This is the default value for wal_segment_size to be used when initdb is run + * without the --wal-segsize option. It must be a valid segment size. + */ +#define DEFAULT_XLOG_SEG_SIZE (16*1024*1024) + +/* + * Maximum length for identifiers (e.g. table names, column names, + * function names). Names actually are limited to one fewer 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 + +/* + * When creating a product derived from PostgreSQL with changes that cause + * incompatibilities for loadable modules, it is recommended to change this + * string so that dfmgr.c can refuse to load incompatible modules with a clean + * error message. Typical examples that cause incompatibilities are any + * changes to node tags or node structures. (Note that dfmgr.c already + * detects common sources of incompatibilities due to major version + * differences and due to some changed compile-time constants. This setting + * is for catching anything that cannot be detected in a straightforward way.) + * + * There is no prescribed format for the string. The suggestion is to include + * product or company name, and optionally any internally-relevant ABI + * version. Example: "ACME Postgres/1.2". Note that the string will appear + * in a user-facing error message if an ABI mismatch is detected. + */ +#define FMGR_ABI_EXTRA "PostgreSQL" + +/* + * 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 + +/* + * Maximum number of columns in a partition key + */ +#define PARTITION_MAX_KEYS 32 + +/* + * Decide whether built-in 8-byte types, including float8, int8, and + * timestamp, are passed by value. This is on by default if sizeof(Datum) >= + * 8 (that is, on 64-bit platforms). If sizeof(Datum) < 8 (32-bit platforms), + * this must be off. We keep this here as an option so that it is easy to + * test the pass-by-reference code paths on 64-bit platforms. + * + * Changing this requires an initdb. + */ +#if SIZEOF_VOID_P >= 8 +#define USE_FLOAT8_BYVAL 1 +#endif + +/* + * 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 + +/* + * 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 + +/* + * 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 + +/* + * If EXEC_BACKEND is defined, the postmaster uses an alternative method for + * starting subprocesses: Instead of simply using fork(), as is standard on + * Unix platforms, it uses fork()+exec() or something equivalent on Windows, + * as well as lots of extra code to bring the required global state to those + * new processes. This must be enabled on Windows (because there is no + * fork()). On other platforms, it's only useful for verifying those + * otherwise Windows-specific code paths. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +#define EXEC_BACKEND +#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. + * If you change this, you probably need to adjust the error message in + * check_effective_io_concurrency.) + */ +#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. + */ +#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. + * + * If set to an empty string, then AF_UNIX sockets are not used by default: A + * server will not create an AF_UNIX socket unless the run-time configuration + * is changed, a client will connect via TCP/IP by default and will only use + * an AF_UNIX socket if one is explicitly specified. + * + * This is done by default on Windows because there is no good standard + * location for AF_UNIX sockets and many installations on Windows don't + * support them yet. + */ +#ifndef WIN32 +#define DEFAULT_PGSOCKET_DIR "/tmp" +#else +#define DEFAULT_PGSOCKET_DIR "" +#endif + +/* + * This is the default event source for Windows event log. + */ +#define DEFAULT_EVENT_SOURCE "PostgreSQL" + +/* + * 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 + +/* + * Assumed alignment requirement for direct I/O. 4K corresponds to common + * sector and memory page size. + */ +#define PG_IO_ALIGN_SIZE 4096 + +/* + *------------------------------------------------------------------------ + * 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. It also + * enables detection of buffer accesses that take place without holding a + * buffer pin (or without holding a buffer lock in the case of index access + * methods that superimpose their own custom client requests on top of the + * generic bufmgr.c requests). + * + * "make installcheck" is significantly slower under Valgrind. The client + * requests fall in hot code paths, so USE_VALGRIND slows execution by a few + * percentage points even when not run under Valgrind. + * + * Do not try to test the server under Valgrind without having built the + * server with USE_VALGRIND; else you will get false positives from sinval + * messaging (see comments in AddCatcacheInvalidationMessage). It's also + * important to use the suppression file src/tools/valgrind.supp to + * exclude other known false positives. + * + * 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 */ + +/* + * For cache-invalidation debugging, define DISCARD_CACHES_ENABLED to enable + * use of the debug_discard_caches GUC to aggressively flush syscache/relcache + * entries whenever it's possible to deliver invalidations. See + * AcceptInvalidationMessages() in src/backend/utils/cache/inval.c for + * details. + * + * USE_ASSERT_CHECKING builds default to enabling this. It's possible to use + * DISCARD_CACHES_ENABLED without a cassert build and the implied + * CLOBBER_FREED_MEMORY and MEMORY_CONTEXT_CHECKING options, but it's unlikely + * to be as effective at identifying problems. + */ +/* #define DISCARD_CACHES_ENABLED */ + +#if defined(USE_ASSERT_CHECKING) && !defined(DISCARD_CACHES_ENABLED) +#define DISCARD_CACHES_ENABLED +#endif + +/* + * Backwards compatibility for the older compile-time-only clobber-cache + * macros. + */ +#if !defined(DISCARD_CACHES_ENABLED) && (defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY)) +#define DISCARD_CACHES_ENABLED +#endif + +/* + * Recover memory used for relcache entries when invalidated. See + * RelationBuildDesc() in src/backend/utils/cache/relcache.c. + * + * This is active automatically for clobber-cache builds when clobbering is + * active, but can be overridden here by explicitly defining + * RECOVER_RELATION_BUILD_MEMORY. Define to 1 to always free relation cache + * memory even when clobber is off, or to 0 to never free relation cache + * memory even when clobbering is on. + */ + /* #define RECOVER_RELATION_BUILD_MEMORY 0 */ /* Force disable */ + /* #define RECOVER_RELATION_BUILD_MEMORY 1 */ /* Force enable */ + +/* + * 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 parse and plan trees to be passed through + * outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in + * those modules. + */ +/* #define WRITE_READ_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 */ diff --git a/contrib/libs/libpq/src/include/pg_config_os-linux.h b/contrib/libs/libpq/src/include/pg_config_os-linux.h new file mode 100644 index 0000000000..331e1b2cf1 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_os-linux.h @@ -0,0 +1 @@ +#include <contrib/libs/libpq/src/include/port/linux.h> diff --git a/contrib/libs/libpq/src/include/pg_config_os-osx.h b/contrib/libs/libpq/src/include/pg_config_os-osx.h new file mode 100644 index 0000000000..f77fb9d4da --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_os-osx.h @@ -0,0 +1 @@ +#include <contrib/libs/libpq/src/include/port/darwin.h> diff --git a/contrib/libs/libpq/src/include/pg_config_os-win.h b/contrib/libs/libpq/src/include/pg_config_os-win.h new file mode 100644 index 0000000000..e26ba92209 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_os-win.h @@ -0,0 +1 @@ +#include <contrib/libs/libpq/src/include/port/win32.h> diff --git a/contrib/libs/libpq/src/include/pg_config_os.h b/contrib/libs/libpq/src/include/pg_config_os.h new file mode 100644 index 0000000000..86db251be2 --- /dev/null +++ b/contrib/libs/libpq/src/include/pg_config_os.h @@ -0,0 +1,9 @@ +#pragma once + +#if defined(__APPLE__) +# include "pg_config_os-osx.h" +#elif defined(_MSC_VER) +# include "pg_config_os-win.h" +#else +# include "pg_config_os-linux.h" +#endif diff --git a/contrib/libs/libpq/src/include/pgtar.h b/contrib/libs/libpq/src/include/pgtar.h new file mode 100644 index 0000000000..661f9d7c59 --- /dev/null +++ b/contrib/libs/libpq/src/include/pgtar.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * pgtar.h + * Functions for manipulating tarfile datastructures (src/port/tar.c) + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/pgtar.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TAR_H +#define PG_TAR_H + +#define TAR_BLOCK_SIZE 512 + +enum tarError +{ + TAR_OK = 0, + TAR_NAME_TOO_LONG, + TAR_SYMLINK_TOO_LONG +}; + +extern enum tarError tarCreateHeader(char *h, const char *filename, + const char *linktarget, pgoff_t size, + mode_t mode, uid_t uid, gid_t gid, + time_t mtime); +extern uint64 read_tar_number(const char *s, int len); +extern void print_tar_number(char *s, int len, uint64 val); +extern int tarChecksum(char *header); + +/* + * Compute the number of padding bytes required for an entry in a tar + * archive. We must pad out to a multiple of TAR_BLOCK_SIZE. Since that's + * a power of 2, we can use TYPEALIGN(). + */ +static inline size_t +tarPaddingBytesRequired(size_t len) +{ + return TYPEALIGN(TAR_BLOCK_SIZE, len) - len; +} + +#endif diff --git a/contrib/libs/libpq/src/include/pgtime.h b/contrib/libs/libpq/src/include/pgtime.h new file mode 100644 index 0000000000..9d4b2efe94 --- /dev/null +++ b/contrib/libs/libpq/src/include/pgtime.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * pgtime.h + * PostgreSQL internal timezone library + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/pgtime.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PGTIME_H +#define _PGTIME_H + + +/* + * The API of this library is generally similar to the corresponding + * C library functions, except that we use pg_time_t which (we hope) is + * 64 bits wide, and which is most definitely signed not unsigned. + */ + +typedef int64 pg_time_t; + +/* + * Data structure representing a broken-down timestamp. + * + * CAUTION: the IANA timezone library (src/timezone/) follows the POSIX + * convention that tm_mon counts from 0 and tm_year is relative to 1900. + * However, Postgres' datetime functions generally treat tm_mon as counting + * from 1 and tm_year as relative to 1 BC. Be sure to make the appropriate + * adjustments when moving from one code domain to the other. + */ +struct pg_tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; /* see above */ + int tm_year; /* see above */ + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +/* These structs are opaque outside the timezone library */ +typedef struct pg_tz pg_tz; +typedef struct pg_tzenum pg_tzenum; + +/* Maximum length of a timezone name (not including trailing null) */ +#define TZ_STRLEN_MAX 255 + +/* these functions are in localtime.c */ + +extern struct pg_tm *pg_localtime(const pg_time_t *timep, const pg_tz *tz); +extern struct pg_tm *pg_gmtime(const pg_time_t *timep); +extern int pg_next_dst_boundary(const pg_time_t *timep, + long int *before_gmtoff, + int *before_isdst, + pg_time_t *boundary, + long int *after_gmtoff, + int *after_isdst, + const pg_tz *tz); +extern bool pg_interpret_timezone_abbrev(const char *abbrev, + const pg_time_t *timep, + long int *gmtoff, + int *isdst, + const pg_tz *tz); +extern bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff); +extern const char *pg_get_timezone_name(pg_tz *tz); +extern bool pg_tz_acceptable(pg_tz *tz); + +/* these functions are in strftime.c */ + +extern size_t pg_strftime(char *s, size_t maxsize, const char *format, + const struct pg_tm *t); + +/* these functions and variables are in pgtz.c */ + +extern PGDLLIMPORT pg_tz *session_timezone; +extern PGDLLIMPORT pg_tz *log_timezone; + +extern void pg_timezone_initialize(void); +extern pg_tz *pg_tzset(const char *tzname); +extern pg_tz *pg_tzset_offset(long gmtoffset); + +extern pg_tzenum *pg_tzenumerate_start(void); +extern pg_tz *pg_tzenumerate_next(pg_tzenum *dir); +extern void pg_tzenumerate_end(pg_tzenum *dir); + +#endif /* _PGTIME_H */ diff --git a/contrib/libs/libpq/src/include/port.h b/contrib/libs/libpq/src/include/port.h new file mode 100644 index 0000000000..a88d403483 --- /dev/null +++ b/contrib/libs/libpq/src/include/port.h @@ -0,0 +1,520 @@ +/*------------------------------------------------------------------------- + * + * port.h + * Header for src/port/ compatibility functions. + * + * Portions Copyright (c) 1996-2023, 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 <ctype.h> + +/* + * Windows has enough specialized port stuff that we push most of it off + * into another file. + * Note: Some CYGWIN includes might #define WIN32. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +#include "port/win32_port.h" +#endif + +/* 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 + +/* if platform lacks socklen_t, we assume this will work */ +#ifndef HAVE_SOCKLEN_T +typedef unsigned int socklen_t; +#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 *path); +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 *filename); +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); + +#define IS_NONWINDOWS_DIR_SEP(ch) ((ch) == '/') +#define is_nonwindows_absolute_path(filename) \ +( \ + IS_NONWINDOWS_DIR_SEP((filename)[0]) \ +) + +#define IS_WINDOWS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') +/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ +#define is_windows_absolute_path(filename) \ +( \ + IS_WINDOWS_DIR_SEP((filename)[0]) || \ + (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ + IS_WINDOWS_DIR_SEP((filename)[2])) \ +) + +/* + * is_absolute_path and IS_DIR_SEP + * + * By using macros here we avoid needing to include path.c in libpq. + */ +#ifndef WIN32 +#define IS_DIR_SEP(ch) IS_NONWINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_nonwindows_absolute_path(filename) +#else +#define IS_DIR_SEP(ch) IS_WINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_windows_absolute_path(filename) +#endif + +/* + * This macro provides a centralized list of all errnos that identify + * hard failure of a previously-established network connection. + * The macro is intended to be used in a switch statement, in the form + * "case ALL_CONNECTION_FAILURE_ERRNOS:". + * + * Note: this groups EPIPE and ECONNRESET, which we take to indicate a + * probable server crash, with other errors that indicate loss of network + * connectivity without proving much about the server's state. Places that + * are actually reporting errors typically single out EPIPE and ECONNRESET, + * while allowing the network failures to be reported generically. + */ +#define ALL_CONNECTION_FAILURE_ERRNOS \ + EPIPE: \ + case ECONNRESET: \ + case ECONNABORTED: \ + case EHOSTDOWN: \ + case EHOSTUNREACH: \ + case ENETDOWN: \ + case ENETRESET: \ + case ENETUNREACH: \ + case ETIMEDOUT + +/* Portable locale initialization (in exec.c) */ +extern void set_pglocale_pgservice(const char *argv0, const char *app); + +/* Portable way to find and execute binaries (in exec.c) */ +extern int validate_exec(const char *path); +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); +extern char *pipe_read_line(char *cmd, char *line, int maxsize); + +/* Doesn't belong here, but this is used with find_other_exec(), so... */ +#define PG_BACKEND_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n" + +#ifdef EXEC_BACKEND +/* Disable ASLR before exec, for developer builds only (in exec.c) */ +extern int pg_disable_aslr(void); +#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); + +/* + * Beginning in v12, we always replace snprintf() and friends with our own + * implementation. This symbol is no longer consulted by the core code, + * but keep it defined anyway in case any extensions are looking at it. + */ +#define USE_REPL_SNPRINTF 1 + +/* + * 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 vsprintf +#undef vsprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef printf +#undef printf +#endif + +extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) pg_attribute_printf(3, 0); +extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); +extern int pg_vsprintf(char *str, const char *fmt, va_list args) pg_attribute_printf(2, 0); +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) pg_attribute_printf(2, 0); +extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); +extern int pg_vprintf(const char *fmt, va_list args) pg_attribute_printf(1, 0); +extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); + +#ifndef WIN32 +/* + * We add a pg_ prefix as a warning that the Windows implementations have the + * non-standard side-effect of changing the current file position. + */ +#define pg_pread pread +#define pg_pwrite pwrite +#endif + +/* + * We use __VA_ARGS__ for printf to prevent replacing references to + * the "printf" format archetype in format() attribute declarations. + * That unfortunately means that taking a function pointer to printf + * will not do what we'd wish. (If you need to do that, you must name + * pg_printf explicitly.) For printf's sibling functions, use + * parameterless macros so that function pointers will work unsurprisingly. + */ +#define vsnprintf pg_vsnprintf +#define snprintf pg_snprintf +#define vsprintf pg_vsprintf +#define sprintf pg_sprintf +#define vfprintf pg_vfprintf +#define fprintf pg_fprintf +#define vprintf pg_vprintf +#define printf(...) pg_printf(__VA_ARGS__) + +/* This is also provided by snprintf.c */ +extern int pg_strfromd(char *str, size_t count, int precision, double value); + +/* Replace strerror() with our own, somewhat more robust wrapper */ +extern char *pg_strerror(int errnum); +#define strerror pg_strerror + +/* Likewise for strerror_r(); note we prefer the GNU API for that */ +extern char *pg_strerror_r(int errnum, char *buf, size_t buflen); +#define strerror_r pg_strerror_r +#define PG_STRERROR_R_BUFLEN 256 /* Recommended buffer size for strerror_r */ + +/* Wrap strsignal(), or provide our own version if necessary */ +extern const char *pg_strsignal(int signum); + +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 _MSC_VER +#include <io.h> +#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); + +#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); + +#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 HANDLE pgwin32_open_handle(const char *, int, bool); +extern int pgwin32_open(const char *, int,...); +extern FILE *pgwin32_fopen(const char *, const char *); +#define open(a,b,c) pgwin32_open(a,b,c) +#define fopen(a,b) pgwin32_fopen(a,b) + +/* + * 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) + +#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/. + */ + +/* Type to use with fseeko/ftello */ +#ifndef WIN32 /* WIN32 is handled in port/win32_port.h */ +#define pgoff_t off_t +#endif + +#ifndef HAVE_GETPEEREID +/* On Windows, Perl might have incompatible definitions of uid_t and gid_t. */ +#ifndef PLPERL_HAVE_UID_GID +extern int getpeereid(int sock, uid_t *uid, gid_t *gid); +#endif +#endif + +/* + * Glibc doesn't use the builtin for clang due to a *gcc* bug in a version + * newer than the gcc compatibility clang claims to have. This would cause a + * *lot* of superfluous function calls, therefore revert when using clang. In + * C++ there's issues with libc++ (not libstdc++), so disable as well. + */ +#if defined(__clang__) && !defined(__cplusplus) +/* needs to be separate to not confuse other compilers */ +#if __has_builtin(__builtin_isinf) +/* need to include before, to avoid getting overwritten */ +#include <math.h> +#undef isinf +#define isinf __builtin_isinf +#endif /* __has_builtin(isinf) */ +#endif /* __clang__ && !__cplusplus */ + +#ifndef HAVE_EXPLICIT_BZERO +extern void explicit_bzero(void *buf, size_t len); +#endif + +#ifdef HAVE_BUGGY_STRTOF +extern float pg_strtof(const char *nptr, char **endptr); +#define strtof(a,b) (pg_strtof((a),(b))) +#endif + +#ifdef WIN32 +/* src/port/win32link.c */ +extern int link(const char *src, const char *dst); +#endif + +#ifndef HAVE_MKDTEMP +extern char *mkdtemp(char *path); +#endif + +#ifndef HAVE_INET_ATON +#include <netinet/in.h> +#include <arpa/inet.h> +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 !HAVE_DECL_STRNLEN +extern size_t strnlen(const char *str, size_t maxlen); +#endif + +/* thread.c */ +#ifndef WIN32 +extern bool pg_get_user_name(uid_t user_id, char *buffer, size_t buflen); +extern bool pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen); +#endif + +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); + +extern void qsort_interruptible(void *base, size_t nel, size_t elsize, + qsort_arg_comparator cmp, void *arg); + +extern void *bsearch_arg(const void *key, const void *base0, + size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + 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 *pg_inet_net_ntop(int af, const void *src, int bits, + char *dst, size_t size); + +/* port/pg_strong_random.c */ +extern void pg_strong_random_init(void); +extern bool pg_strong_random(void *buf, size_t len); + +/* + * pg_backend_random used to be a wrapper for pg_strong_random before + * Postgres 12 for the backend code. + */ +#define pg_backend_random pg_strong_random + +/* 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) (SIGNAL_ARGS); +extern pqsigfunc pqsignal(int signo, pqsigfunc func); + +/* port/quotes.c */ +extern char *escape_single_quotes_ascii(const char *src); + +/* common/wait_error.c */ +extern char *wait_result_to_str(int exitstatus); +extern bool wait_result_is_signal(int exit_status, int signum); +extern bool wait_result_is_any_signal(int exit_status, bool include_command_not_found); +extern int wait_result_to_exit_code(int exit_status); + +/* + * Interfaces that we assume all Unix system have. We retain individual macros + * for better documentation. + * + * For symlink-related functions, there is often no need to test these macros, + * because we provided basic support on Windows that can work with absolute + * paths to directories. Code that wants to test for complete symlink support + * (including relative paths and non-directories) should be conditional on + * HAVE_READLINK or HAVE_SYMLINK. + */ +#ifndef WIN32 +#define HAVE_GETRLIMIT 1 +#define HAVE_POLL 1 +#define HAVE_POLL_H 1 +#define HAVE_READLINK 1 +#define HAVE_SETSID 1 +#define HAVE_SHM_OPEN 1 +#define HAVE_SYMLINK 1 +#endif + +#endif /* PG_PORT_H */ diff --git a/contrib/libs/libpq/src/include/port/darwin.h b/contrib/libs/libpq/src/include/port/darwin.h new file mode 100644 index 0000000000..15fb69d6db --- /dev/null +++ b/contrib/libs/libpq/src/include/port/darwin.h @@ -0,0 +1,8 @@ +/* src/include/port/darwin.h */ + +#define __darwin__ 1 + +#if HAVE_DECL_F_FULLFSYNC /* not present before macOS 10.3 */ +#define HAVE_FSYNC_WRITETHROUGH + +#endif diff --git a/contrib/libs/libpq/src/include/port/linux.h b/contrib/libs/libpq/src/include/port/linux.h new file mode 100644 index 0000000000..7a6e46cdbb --- /dev/null +++ b/contrib/libs/libpq/src/include/port/linux.h @@ -0,0 +1,22 @@ +/* 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/contrib/libs/libpq/src/include/port/pg_bitutils.h b/contrib/libs/libpq/src/include/port/pg_bitutils.h new file mode 100644 index 0000000000..21a4fa0341 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/pg_bitutils.h @@ -0,0 +1,339 @@ +/*------------------------------------------------------------------------- + * + * pg_bitutils.h + * Miscellaneous functions for bit-wise operations. + * + * + * Copyright (c) 2019-2023, PostgreSQL Global Development Group + * + * src/include/port/pg_bitutils.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_BITUTILS_H +#define PG_BITUTILS_H + +#ifdef _MSC_VER +#include <intrin.h> +#define HAVE_BITSCAN_FORWARD +#define HAVE_BITSCAN_REVERSE + +#else +#if defined(HAVE__BUILTIN_CTZ) +#define HAVE_BITSCAN_FORWARD +#endif + +#if defined(HAVE__BUILTIN_CLZ) +#define HAVE_BITSCAN_REVERSE +#endif +#endif /* _MSC_VER */ + +extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]; +extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256]; +extern PGDLLIMPORT const uint8 pg_number_of_ones[256]; + +/* + * pg_leftmost_one_pos32 + * Returns the position of the most significant set bit in "word", + * measured from the least significant bit. word must not be 0. + */ +static inline int +pg_leftmost_one_pos32(uint32 word) +{ +#ifdef HAVE__BUILTIN_CLZ + Assert(word != 0); + + return 31 - __builtin_clz(word); +#elif defined(_MSC_VER) + unsigned long result; + bool non_zero; + + non_zero = _BitScanReverse(&result, word); + Assert(non_zero); + return (int) result; +#else + int shift = 32 - 8; + + Assert(word != 0); + + while ((word >> shift) == 0) + shift -= 8; + + return shift + pg_leftmost_one_pos[(word >> shift) & 255]; +#endif /* HAVE__BUILTIN_CLZ */ +} + +/* + * pg_leftmost_one_pos64 + * As above, but for a 64-bit word. + */ +static inline int +pg_leftmost_one_pos64(uint64 word) +{ +#ifdef HAVE__BUILTIN_CLZ + Assert(word != 0); + +#if defined(HAVE_LONG_INT_64) + return 63 - __builtin_clzl(word); +#elif defined(HAVE_LONG_LONG_INT_64) + return 63 - __builtin_clzll(word); +#else +#error must have a working 64-bit integer datatype +#endif /* HAVE_LONG_INT_64 */ + +#elif defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_ARM64)) + unsigned long result; + bool non_zero; + + non_zero = _BitScanReverse64(&result, word); + Assert(non_zero); + return (int) result; +#else + int shift = 64 - 8; + + Assert(word != 0); + + while ((word >> shift) == 0) + shift -= 8; + + return shift + pg_leftmost_one_pos[(word >> shift) & 255]; +#endif /* HAVE__BUILTIN_CLZ */ +} + +/* + * pg_rightmost_one_pos32 + * Returns the position of the least significant set bit in "word", + * measured from the least significant bit. word must not be 0. + */ +static inline int +pg_rightmost_one_pos32(uint32 word) +{ +#ifdef HAVE__BUILTIN_CTZ + Assert(word != 0); + + return __builtin_ctz(word); +#elif defined(_MSC_VER) + unsigned long result; + bool non_zero; + + non_zero = _BitScanForward(&result, word); + Assert(non_zero); + return (int) result; +#else + int result = 0; + + Assert(word != 0); + + while ((word & 255) == 0) + { + word >>= 8; + result += 8; + } + result += pg_rightmost_one_pos[word & 255]; + return result; +#endif /* HAVE__BUILTIN_CTZ */ +} + +/* + * pg_rightmost_one_pos64 + * As above, but for a 64-bit word. + */ +static inline int +pg_rightmost_one_pos64(uint64 word) +{ +#ifdef HAVE__BUILTIN_CTZ + Assert(word != 0); + +#if defined(HAVE_LONG_INT_64) + return __builtin_ctzl(word); +#elif defined(HAVE_LONG_LONG_INT_64) + return __builtin_ctzll(word); +#else +#error must have a working 64-bit integer datatype +#endif /* HAVE_LONG_INT_64 */ + +#elif defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_ARM64)) + unsigned long result; + bool non_zero; + + non_zero = _BitScanForward64(&result, word); + Assert(non_zero); + return (int) result; +#else + int result = 0; + + Assert(word != 0); + + while ((word & 255) == 0) + { + word >>= 8; + result += 8; + } + result += pg_rightmost_one_pos[word & 255]; + return result; +#endif /* HAVE__BUILTIN_CTZ */ +} + +/* + * pg_nextpower2_32 + * Returns the next higher power of 2 above 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT32_MAX / 2 + 1. + */ +static inline uint32 +pg_nextpower2_32(uint32 num) +{ + Assert(num > 0 && num <= PG_UINT32_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint32) 1) << (pg_leftmost_one_pos32(num) + 1); +} + +/* + * pg_nextpower2_64 + * Returns the next higher power of 2 above 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT64_MAX / 2 + 1. + */ +static inline uint64 +pg_nextpower2_64(uint64 num) +{ + Assert(num > 0 && num <= PG_UINT64_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint64) 1) << (pg_leftmost_one_pos64(num) + 1); +} + +/* + * pg_prevpower2_32 + * Returns the next lower power of 2 below 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0. + */ +static inline uint32 +pg_prevpower2_32(uint32 num) +{ + return ((uint32) 1) << pg_leftmost_one_pos32(num); +} + +/* + * pg_prevpower2_64 + * Returns the next lower power of 2 below 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0. + */ +static inline uint64 +pg_prevpower2_64(uint64 num) +{ + return ((uint64) 1) << pg_leftmost_one_pos64(num); +} + +/* + * pg_ceil_log2_32 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint32 +pg_ceil_log2_32(uint32 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos32(num - 1) + 1; +} + +/* + * pg_ceil_log2_64 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint64 +pg_ceil_log2_64(uint64 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos64(num - 1) + 1; +} + +/* + * With MSVC on x86_64 builds, try using native popcnt instructions via the + * __popcnt and __popcnt64 intrinsics. These don't work the same as GCC's + * __builtin_popcount* intrinsic functions as they always emit popcnt + * instructions. + */ +#if defined(_MSC_VER) && defined(_M_AMD64) +#define HAVE_X86_64_POPCNTQ +#endif + +/* + * On x86_64, we can use the hardware popcount instruction, but only if + * we can verify that the CPU supports it via the cpuid instruction. + * + * Otherwise, we fall back to a hand-rolled implementation. + */ +#ifdef HAVE_X86_64_POPCNTQ +#if defined(HAVE__GET_CPUID) || defined(HAVE__CPUID) +#define TRY_POPCNT_FAST 1 +#endif +#endif + +#ifdef TRY_POPCNT_FAST +/* Attempt to use the POPCNT instruction, but perform a runtime check first */ +extern int (*pg_popcount32) (uint32 word); +extern int (*pg_popcount64) (uint64 word); + +#else +/* Use a portable implementation -- no need for a function pointer. */ +extern int pg_popcount32(uint32 word); +extern int pg_popcount64(uint64 word); + +#endif /* TRY_POPCNT_FAST */ + +/* Count the number of one-bits in a byte array */ +extern uint64 pg_popcount(const char *buf, int bytes); + +/* + * Rotate the bits of "word" to the right/left by n bits. + */ +static inline uint32 +pg_rotate_right32(uint32 word, int n) +{ + return (word >> n) | (word << (32 - n)); +} + +static inline uint32 +pg_rotate_left32(uint32 word, int n) +{ + return (word << n) | (word >> (32 - n)); +} + +/* size_t variants of the above, as required */ + +#if SIZEOF_SIZE_T == 4 +#define pg_leftmost_one_pos_size_t pg_leftmost_one_pos32 +#define pg_nextpower2_size_t pg_nextpower2_32 +#define pg_prevpower2_size_t pg_prevpower2_32 +#else +#define pg_leftmost_one_pos_size_t pg_leftmost_one_pos64 +#define pg_nextpower2_size_t pg_nextpower2_64 +#define pg_prevpower2_size_t pg_prevpower2_64 +#endif + +#endif /* PG_BITUTILS_H */ diff --git a/contrib/libs/libpq/src/include/port/pg_bswap.h b/contrib/libs/libpq/src/include/port/pg_bswap.h new file mode 100644 index 0000000000..80abd750d4 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/pg_bswap.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------- + * + * pg_bswap.h + * Byte swapping. + * + * Macros for reversing the byte order of 16, 32 and 64-bit unsigned integers. + * For example, 0xAABBCCDD becomes 0xDDCCBBAA. These are just wrappers for + * built-in functions provided by the compiler where support exists. + * + * Note that all of these functions accept unsigned integers as arguments and + * return the same. Use caution when using these wrapper macros with signed + * integers. + * + * Copyright (c) 2015-2023, PostgreSQL Global Development Group + * + * src/include/port/pg_bswap.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_BSWAP_H +#define PG_BSWAP_H + + +/* + * In all supported versions msvc provides _byteswap_* functions in stdlib.h, + * already included by c.h. + */ + + +/* implementation of uint16 pg_bswap16(uint16) */ +#if defined(HAVE__BUILTIN_BSWAP16) + +#define pg_bswap16(x) __builtin_bswap16(x) + +#elif defined(_MSC_VER) + +#define pg_bswap16(x) _byteswap_ushort(x) + +#else + +static inline uint16 +pg_bswap16(uint16 x) +{ + return + ((x << 8) & 0xff00) | + ((x >> 8) & 0x00ff); +} + +#endif /* HAVE__BUILTIN_BSWAP16 */ + + +/* implementation of uint32 pg_bswap32(uint32) */ +#if defined(HAVE__BUILTIN_BSWAP32) + +#define pg_bswap32(x) __builtin_bswap32(x) + +#elif defined(_MSC_VER) + +#define pg_bswap32(x) _byteswap_ulong(x) + +#else + +static inline uint32 +pg_bswap32(uint32 x) +{ + return + ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | + ((x >> 24) & 0x000000ff); +} + +#endif /* HAVE__BUILTIN_BSWAP32 */ + + +/* implementation of uint64 pg_bswap64(uint64) */ +#if defined(HAVE__BUILTIN_BSWAP64) + +#define pg_bswap64(x) __builtin_bswap64(x) + + +#elif defined(_MSC_VER) + +#define pg_bswap64(x) _byteswap_uint64(x) + +#else + +static inline uint64 +pg_bswap64(uint64 x) +{ + return + ((x << 56) & UINT64CONST(0xff00000000000000)) | + ((x << 40) & UINT64CONST(0x00ff000000000000)) | + ((x << 24) & UINT64CONST(0x0000ff0000000000)) | + ((x << 8) & UINT64CONST(0x000000ff00000000)) | + ((x >> 8) & UINT64CONST(0x00000000ff000000)) | + ((x >> 24) & UINT64CONST(0x0000000000ff0000)) | + ((x >> 40) & UINT64CONST(0x000000000000ff00)) | + ((x >> 56) & UINT64CONST(0x00000000000000ff)); +} +#endif /* HAVE__BUILTIN_BSWAP64 */ + + +/* + * Portable and fast equivalents for ntohs, ntohl, htons, htonl, + * additionally extended to 64 bits. + */ +#ifdef WORDS_BIGENDIAN + +#define pg_hton16(x) (x) +#define pg_hton32(x) (x) +#define pg_hton64(x) (x) + +#define pg_ntoh16(x) (x) +#define pg_ntoh32(x) (x) +#define pg_ntoh64(x) (x) + +#else + +#define pg_hton16(x) pg_bswap16(x) +#define pg_hton32(x) pg_bswap32(x) +#define pg_hton64(x) pg_bswap64(x) + +#define pg_ntoh16(x) pg_bswap16(x) +#define pg_ntoh32(x) pg_bswap32(x) +#define pg_ntoh64(x) pg_bswap64(x) + +#endif /* WORDS_BIGENDIAN */ + + +/* + * Rearrange the bytes of a Datum from big-endian order into the native byte + * order. On big-endian machines, this does nothing at all. Note that the C + * type Datum is an unsigned integer type on all platforms. + * + * One possible application of the DatumBigEndianToNative() macro is to make + * bitwise comparisons cheaper. A simple 3-way comparison of Datums + * transformed by the macro (based on native, unsigned comparisons) will return + * the same result as a memcmp() of the corresponding original Datums, but can + * be much cheaper. It's generally safe to do this on big-endian systems + * without any special transformation occurring first. + * + * If SIZEOF_DATUM is not defined, then postgres.h wasn't included and these + * macros probably shouldn't be used, so we define nothing. Note that + * SIZEOF_DATUM == 8 would evaluate as 0 == 8 in that case, potentially + * leading to the wrong implementation being selected and confusing errors, so + * defining nothing is safest. + */ +#ifdef SIZEOF_DATUM +#ifdef WORDS_BIGENDIAN +#define DatumBigEndianToNative(x) (x) +#else /* !WORDS_BIGENDIAN */ +#if SIZEOF_DATUM == 8 +#define DatumBigEndianToNative(x) pg_bswap64(x) +#else /* SIZEOF_DATUM != 8 */ +#define DatumBigEndianToNative(x) pg_bswap32(x) +#endif /* SIZEOF_DATUM == 8 */ +#endif /* WORDS_BIGENDIAN */ +#endif /* SIZEOF_DATUM */ + +#endif /* PG_BSWAP_H */ diff --git a/contrib/libs/libpq/src/include/port/pg_crc32c.h b/contrib/libs/libpq/src/include/port/pg_crc32c.h new file mode 100644 index 0000000000..7f8779261c --- /dev/null +++ b/contrib/libs/libpq/src/include/port/pg_crc32c.h @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c.h + * Routines for computing CRC-32C checksums. + * + * The speed of CRC-32C calculation has a big impact on performance, so we + * jump through some hoops to get the best implementation for each + * platform. Some CPU architectures have special instructions for speeding + * up CRC calculations (e.g. Intel SSE 4.2), on other platforms we use the + * Slicing-by-8 algorithm which uses lookup tables. + * + * The public interface consists of four macros: + * + * INIT_CRC32C(crc) + * Initialize a CRC accumulator + * + * COMP_CRC32C(crc, data, len) + * Accumulate some (more) bytes into a CRC + * + * FIN_CRC32C(crc) + * Finish a CRC calculation + * + * EQ_CRC32C(c1, c2) + * Check for equality of two CRCs. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/pg_crc32c.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CRC32C_H +#define PG_CRC32C_H + +#include "port/pg_bswap.h" + +typedef uint32 pg_crc32c; + +/* The INIT and EQ macros are the same for all implementations. */ +#define INIT_CRC32C(crc) ((crc) = 0xFFFFFFFF) +#define EQ_CRC32C(c1, c2) ((c1) == (c2)) + +#if defined(USE_SSE42_CRC32C) +/* Use Intel SSE4.2 instructions. */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_sse42((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len); + +#elif defined(USE_ARMV8_CRC32C) +/* Use ARMv8 CRC Extension instructions. */ + +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_armv8((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len); + +#elif defined(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK) || defined(USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK) + +/* + * Use Intel SSE 4.2 or ARMv8 instructions, but perform a runtime check first + * to check that they are available. + */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len); +extern pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len); + +#ifdef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK +extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len); +#endif +#ifdef USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK +extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len); +#endif + +#else +/* + * Use slicing-by-8 algorithm. + * + * On big-endian systems, the intermediate value is kept in reverse byte + * order, to avoid byte-swapping during the calculation. FIN_CRC32C reverses + * the bytes to the final order. + */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_sb8((crc), (data), (len))) +#ifdef WORDS_BIGENDIAN +#define FIN_CRC32C(crc) ((crc) = pg_bswap32(crc) ^ 0xFFFFFFFF) +#else +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) +#endif + +extern pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len); + +#endif + +#endif /* PG_CRC32C_H */ diff --git a/contrib/libs/libpq/src/include/port/pg_iovec.h b/contrib/libs/libpq/src/include/port/pg_iovec.h new file mode 100644 index 0000000000..689799c425 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/pg_iovec.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * pg_iovec.h + * Header for vectored I/O functions, to use in place of <sys/uio.h>. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/pg_iovec.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_IOVEC_H +#define PG_IOVEC_H + +#ifndef WIN32 + +#include <limits.h> +#include <sys/uio.h> + +#else + +/* POSIX requires at least 16 as a maximum iovcnt. */ +#define IOV_MAX 16 + +/* Define our own POSIX-compatible iovec struct. */ +struct iovec +{ + void *iov_base; + size_t iov_len; +}; + +#endif + +/* Define a reasonable maximum that is safe to use on the stack. */ +#define PG_IOV_MAX Min(IOV_MAX, 32) + +/* + * Note that pg_preadv and pg_pwritev have a pg_ prefix as a warning that the + * Windows implementations have the side-effect of changing the file position. + */ + +#if HAVE_DECL_PREADV +#define pg_preadv preadv +#else +extern ssize_t pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +#if HAVE_DECL_PWRITEV +#define pg_pwritev pwritev +#else +extern ssize_t pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +#endif /* PG_IOVEC_H */ diff --git a/contrib/libs/libpq/src/include/port/pg_lfind.h b/contrib/libs/libpq/src/include/port/pg_lfind.h new file mode 100644 index 0000000000..59aa8245ed --- /dev/null +++ b/contrib/libs/libpq/src/include/port/pg_lfind.h @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- + * + * pg_lfind.h + * Optimized linear search routines using SIMD intrinsics where + * available. + * + * Copyright (c) 2022-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/port/pg_lfind.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LFIND_H +#define PG_LFIND_H + +#include "port/simd.h" + +/* + * pg_lfind8 + * + * Return true if there is an element in 'base' that equals 'key', otherwise + * return false. + */ +static inline bool +pg_lfind8(uint8 key, uint8 *base, uint32 nelem) +{ + uint32 i; + + /* round down to multiple of vector length */ + uint32 tail_idx = nelem & ~(sizeof(Vector8) - 1); + Vector8 chunk; + + for (i = 0; i < tail_idx; i += sizeof(Vector8)) + { + vector8_load(&chunk, &base[i]); + if (vector8_has(chunk, key)) + return true; + } + + /* Process the remaining elements one at a time. */ + for (; i < nelem; i++) + { + if (key == base[i]) + return true; + } + + return false; +} + +/* + * pg_lfind8_le + * + * Return true if there is an element in 'base' that is less than or equal to + * 'key', otherwise return false. + */ +static inline bool +pg_lfind8_le(uint8 key, uint8 *base, uint32 nelem) +{ + uint32 i; + + /* round down to multiple of vector length */ + uint32 tail_idx = nelem & ~(sizeof(Vector8) - 1); + Vector8 chunk; + + for (i = 0; i < tail_idx; i += sizeof(Vector8)) + { + vector8_load(&chunk, &base[i]); + if (vector8_has_le(chunk, key)) + return true; + } + + /* Process the remaining elements one at a time. */ + for (; i < nelem; i++) + { + if (base[i] <= key) + return true; + } + + return false; +} + +/* + * pg_lfind32 + * + * Return true if there is an element in 'base' that equals 'key', otherwise + * return false. + */ +static inline bool +pg_lfind32(uint32 key, uint32 *base, uint32 nelem) +{ + uint32 i = 0; + +#ifndef USE_NO_SIMD + + /* + * For better instruction-level parallelism, each loop iteration operates + * on a block of four registers. Testing for SSE2 has showed this is ~40% + * faster than using a block of two registers. + */ + const Vector32 keys = vector32_broadcast(key); /* load copies of key */ + const uint32 nelem_per_vector = sizeof(Vector32) / sizeof(uint32); + const uint32 nelem_per_iteration = 4 * nelem_per_vector; + + /* round down to multiple of elements per iteration */ + const uint32 tail_idx = nelem & ~(nelem_per_iteration - 1); + +#if defined(USE_ASSERT_CHECKING) + bool assert_result = false; + + /* pre-compute the result for assert checking */ + for (i = 0; i < nelem; i++) + { + if (key == base[i]) + { + assert_result = true; + break; + } + } +#endif + + for (i = 0; i < tail_idx; i += nelem_per_iteration) + { + Vector32 vals1, + vals2, + vals3, + vals4, + result1, + result2, + result3, + result4, + tmp1, + tmp2, + result; + + /* load the next block into 4 registers */ + vector32_load(&vals1, &base[i]); + vector32_load(&vals2, &base[i + nelem_per_vector]); + vector32_load(&vals3, &base[i + nelem_per_vector * 2]); + vector32_load(&vals4, &base[i + nelem_per_vector * 3]); + + /* compare each value to the key */ + result1 = vector32_eq(keys, vals1); + result2 = vector32_eq(keys, vals2); + result3 = vector32_eq(keys, vals3); + result4 = vector32_eq(keys, vals4); + + /* combine the results into a single variable */ + tmp1 = vector32_or(result1, result2); + tmp2 = vector32_or(result3, result4); + result = vector32_or(tmp1, tmp2); + + /* see if there was a match */ + if (vector32_is_highbit_set(result)) + { + Assert(assert_result == true); + return true; + } + } +#endif /* ! USE_NO_SIMD */ + + /* Process the remaining elements one at a time. */ + for (; i < nelem; i++) + { + if (key == base[i]) + { +#ifndef USE_NO_SIMD + Assert(assert_result == true); +#endif + return true; + } + } + +#ifndef USE_NO_SIMD + Assert(assert_result == false); +#endif + return false; +} + +#endif /* PG_LFIND_H */ diff --git a/contrib/libs/libpq/src/include/port/simd.h b/contrib/libs/libpq/src/include/port/simd.h new file mode 100644 index 0000000000..1fa6c3bc6c --- /dev/null +++ b/contrib/libs/libpq/src/include/port/simd.h @@ -0,0 +1,375 @@ +/*------------------------------------------------------------------------- + * + * simd.h + * Support for platform-specific vector operations. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/simd.h + * + * NOTES + * - VectorN in this file refers to a register where the element operands + * are N bits wide. The vector width is platform-specific, so users that care + * about that will need to inspect "sizeof(VectorN)". + * + *------------------------------------------------------------------------- + */ +#ifndef SIMD_H +#define SIMD_H + +#if (defined(__x86_64__) || defined(_M_AMD64)) +/* + * SSE2 instructions are part of the spec for the 64-bit x86 ISA. We assume + * that compilers targeting this architecture understand SSE2 intrinsics. + * + * We use emmintrin.h rather than the comprehensive header immintrin.h in + * order to exclude extensions beyond SSE2. This is because MSVC, at least, + * will allow the use of intrinsics that haven't been enabled at compile + * time. + */ +#include <emmintrin.h> +#define USE_SSE2 +typedef __m128i Vector8; +typedef __m128i Vector32; + +#elif defined(__aarch64__) && defined(__ARM_NEON) +/* + * We use the Neon instructions if the compiler provides access to them (as + * indicated by __ARM_NEON) and we are on aarch64. While Neon support is + * technically optional for aarch64, it appears that all available 64-bit + * hardware does have it. Neon exists in some 32-bit hardware too, but we + * could not realistically use it there without a run-time check, which seems + * not worth the trouble for now. + */ +#include <arm_neon.h> +#define USE_NEON +typedef uint8x16_t Vector8; +typedef uint32x4_t Vector32; + +#else +/* + * If no SIMD instructions are available, we can in some cases emulate vector + * operations using bitwise operations on unsigned integers. Note that many + * of the functions in this file presently do not have non-SIMD + * implementations. In particular, none of the functions involving Vector32 + * are implemented without SIMD since it's likely not worthwhile to represent + * two 32-bit integers using a uint64. + */ +#define USE_NO_SIMD +typedef uint64 Vector8; +#endif + +/* load/store operations */ +static inline void vector8_load(Vector8 *v, const uint8 *s); +#ifndef USE_NO_SIMD +static inline void vector32_load(Vector32 *v, const uint32 *s); +#endif + +/* assignment operations */ +static inline Vector8 vector8_broadcast(const uint8 c); +#ifndef USE_NO_SIMD +static inline Vector32 vector32_broadcast(const uint32 c); +#endif + +/* element-wise comparisons to a scalar */ +static inline bool vector8_has(const Vector8 v, const uint8 c); +static inline bool vector8_has_zero(const Vector8 v); +static inline bool vector8_has_le(const Vector8 v, const uint8 c); +static inline bool vector8_is_highbit_set(const Vector8 v); +#ifndef USE_NO_SIMD +static inline bool vector32_is_highbit_set(const Vector32 v); +#endif + +/* arithmetic operations */ +static inline Vector8 vector8_or(const Vector8 v1, const Vector8 v2); +#ifndef USE_NO_SIMD +static inline Vector32 vector32_or(const Vector32 v1, const Vector32 v2); +static inline Vector8 vector8_ssub(const Vector8 v1, const Vector8 v2); +#endif + +/* + * comparisons between vectors + * + * Note: These return a vector rather than boolean, which is why we don't + * have non-SIMD implementations. + */ +#ifndef USE_NO_SIMD +static inline Vector8 vector8_eq(const Vector8 v1, const Vector8 v2); +static inline Vector32 vector32_eq(const Vector32 v1, const Vector32 v2); +#endif + +/* + * Load a chunk of memory into the given vector. + */ +static inline void +vector8_load(Vector8 *v, const uint8 *s) +{ +#if defined(USE_SSE2) + *v = _mm_loadu_si128((const __m128i *) s); +#elif defined(USE_NEON) + *v = vld1q_u8(s); +#else + memcpy(v, s, sizeof(Vector8)); +#endif +} + +#ifndef USE_NO_SIMD +static inline void +vector32_load(Vector32 *v, const uint32 *s) +{ +#ifdef USE_SSE2 + *v = _mm_loadu_si128((const __m128i *) s); +#elif defined(USE_NEON) + *v = vld1q_u32(s); +#endif +} +#endif /* ! USE_NO_SIMD */ + +/* + * Create a vector with all elements set to the same value. + */ +static inline Vector8 +vector8_broadcast(const uint8 c) +{ +#if defined(USE_SSE2) + return _mm_set1_epi8(c); +#elif defined(USE_NEON) + return vdupq_n_u8(c); +#else + return ~UINT64CONST(0) / 0xFF * c; +#endif +} + +#ifndef USE_NO_SIMD +static inline Vector32 +vector32_broadcast(const uint32 c) +{ +#ifdef USE_SSE2 + return _mm_set1_epi32(c); +#elif defined(USE_NEON) + return vdupq_n_u32(c); +#endif +} +#endif /* ! USE_NO_SIMD */ + +/* + * Return true if any elements in the vector are equal to the given scalar. + */ +static inline bool +vector8_has(const Vector8 v, const uint8 c) +{ + bool result; + + /* pre-compute the result for assert checking */ +#ifdef USE_ASSERT_CHECKING + bool assert_result = false; + + for (Size i = 0; i < sizeof(Vector8); i++) + { + if (((const uint8 *) &v)[i] == c) + { + assert_result = true; + break; + } + } +#endif /* USE_ASSERT_CHECKING */ + +#if defined(USE_NO_SIMD) + /* any bytes in v equal to c will evaluate to zero via XOR */ + result = vector8_has_zero(v ^ vector8_broadcast(c)); +#else + result = vector8_is_highbit_set(vector8_eq(v, vector8_broadcast(c))); +#endif + + Assert(assert_result == result); + return result; +} + +/* + * Convenience function equivalent to vector8_has(v, 0) + */ +static inline bool +vector8_has_zero(const Vector8 v) +{ +#if defined(USE_NO_SIMD) + /* + * We cannot call vector8_has() here, because that would lead to a + * circular definition. + */ + return vector8_has_le(v, 0); +#else + return vector8_has(v, 0); +#endif +} + +/* + * Return true if any elements in the vector are less than or equal to the + * given scalar. + */ +static inline bool +vector8_has_le(const Vector8 v, const uint8 c) +{ + bool result = false; + + /* pre-compute the result for assert checking */ +#ifdef USE_ASSERT_CHECKING + bool assert_result = false; + + for (Size i = 0; i < sizeof(Vector8); i++) + { + if (((const uint8 *) &v)[i] <= c) + { + assert_result = true; + break; + } + } +#endif /* USE_ASSERT_CHECKING */ + +#if defined(USE_NO_SIMD) + + /* + * To find bytes <= c, we can use bitwise operations to find bytes < c+1, + * but it only works if c+1 <= 128 and if the highest bit in v is not set. + * Adapted from + * https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + */ + if ((int64) v >= 0 && c < 0x80) + result = (v - vector8_broadcast(c + 1)) & ~v & vector8_broadcast(0x80); + else + { + /* one byte at a time */ + for (Size i = 0; i < sizeof(Vector8); i++) + { + if (((const uint8 *) &v)[i] <= c) + { + result = true; + break; + } + } + } +#else + + /* + * Use saturating subtraction to find bytes <= c, which will present as + * NUL bytes. This approach is a workaround for the lack of unsigned + * comparison instructions on some architectures. + */ + result = vector8_has_zero(vector8_ssub(v, vector8_broadcast(c))); +#endif + + Assert(assert_result == result); + return result; +} + +/* + * Return true if the high bit of any element is set + */ +static inline bool +vector8_is_highbit_set(const Vector8 v) +{ +#ifdef USE_SSE2 + return _mm_movemask_epi8(v) != 0; +#elif defined(USE_NEON) + return vmaxvq_u8(v) > 0x7F; +#else + return v & vector8_broadcast(0x80); +#endif +} + +/* + * Exactly like vector8_is_highbit_set except for the input type, so it + * looks at each byte separately. + * + * XXX x86 uses the same underlying type for 8-bit, 16-bit, and 32-bit + * integer elements, but Arm does not, hence the need for a separate + * function. We could instead adopt the behavior of Arm's vmaxvq_u32(), i.e. + * check each 32-bit element, but that would require an additional mask + * operation on x86. + */ +#ifndef USE_NO_SIMD +static inline bool +vector32_is_highbit_set(const Vector32 v) +{ +#if defined(USE_NEON) + return vector8_is_highbit_set((Vector8) v); +#else + return vector8_is_highbit_set(v); +#endif +} +#endif /* ! USE_NO_SIMD */ + +/* + * Return the bitwise OR of the inputs + */ +static inline Vector8 +vector8_or(const Vector8 v1, const Vector8 v2) +{ +#ifdef USE_SSE2 + return _mm_or_si128(v1, v2); +#elif defined(USE_NEON) + return vorrq_u8(v1, v2); +#else + return v1 | v2; +#endif +} + +#ifndef USE_NO_SIMD +static inline Vector32 +vector32_or(const Vector32 v1, const Vector32 v2) +{ +#ifdef USE_SSE2 + return _mm_or_si128(v1, v2); +#elif defined(USE_NEON) + return vorrq_u32(v1, v2); +#endif +} +#endif /* ! USE_NO_SIMD */ + +/* + * Return the result of subtracting the respective elements of the input + * vectors using saturation (i.e., if the operation would yield a value less + * than zero, zero is returned instead). For more information on saturation + * arithmetic, see https://en.wikipedia.org/wiki/Saturation_arithmetic + */ +#ifndef USE_NO_SIMD +static inline Vector8 +vector8_ssub(const Vector8 v1, const Vector8 v2) +{ +#ifdef USE_SSE2 + return _mm_subs_epu8(v1, v2); +#elif defined(USE_NEON) + return vqsubq_u8(v1, v2); +#endif +} +#endif /* ! USE_NO_SIMD */ + +/* + * Return a vector with all bits set in each lane where the corresponding + * lanes in the inputs are equal. + */ +#ifndef USE_NO_SIMD +static inline Vector8 +vector8_eq(const Vector8 v1, const Vector8 v2) +{ +#ifdef USE_SSE2 + return _mm_cmpeq_epi8(v1, v2); +#elif defined(USE_NEON) + return vceqq_u8(v1, v2); +#endif +} +#endif /* ! USE_NO_SIMD */ + +#ifndef USE_NO_SIMD +static inline Vector32 +vector32_eq(const Vector32 v1, const Vector32 v2) +{ +#ifdef USE_SSE2 + return _mm_cmpeq_epi32(v1, v2); +#elif defined(USE_NEON) + return vceqq_u32(v1, v2); +#endif +} +#endif /* ! USE_NO_SIMD */ + +#endif /* SIMD_H */ diff --git a/contrib/libs/libpq/src/include/port/win32.h b/contrib/libs/libpq/src/include/port/win32.h new file mode 100644 index 0000000000..5867e5622f --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32.h @@ -0,0 +1,60 @@ +/* src/include/port/win32.h */ +#pragma once + +/* + * 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 + +/* + * Make sure _WIN32_WINNT has the minimum required value. + * Leave a higher value in place. The minimum requirement is Windows 10. + */ +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif + +#define _WIN32_WINNT 0x0A00 + +/* + * We need to prevent <crtdefs.h> from defining a symbol conflicting with + * our errcode() function. Since it's likely to get included by standard + * system headers, pre-emptively include it now. + */ +#if defined(_MSC_VER) || defined(HAVE_CRTDEFS_H) +#define errcode __msvc_errcode +#include <crtdefs.h> +#undef errcode +#endif + +/* + * defines for dynamic linking on Win32 platform + */ + +/* + * Variables declared in the core backend and referenced by loadable + * modules need to be marked "dllimport" in the core build, but + * "dllexport" when the declaration is read in a loadable module. + * No special markings should be used when compiling frontend code. + */ +#ifndef FRONTEND +#ifdef BUILDING_DLL +#define PGDLLIMPORT __declspec (dllexport) +#else +#define PGDLLIMPORT __declspec (dllimport) +#endif +#endif + +/* + * Functions exported by a loadable module must be marked "dllexport". + * + * While mingw would otherwise fall back to + * __attribute__((visibility("default"))), that appears to only work as long + * as no symbols are declared with __declspec(dllexport). But we can end up + * with some, e.g. plpython's Py_Init. + */ +#define PGDLLEXPORT __declspec (dllexport) diff --git a/contrib/libs/libpq/src/include/port/win32/arpa/inet.h b/contrib/libs/libpq/src/include/port/win32/arpa/inet.h new file mode 100644 index 0000000000..ad1803179c --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/arpa/inet.h @@ -0,0 +1,3 @@ +/* src/include/port/win32/arpa/inet.h */ + +#include <sys/socket.h> diff --git a/contrib/libs/libpq/src/include/port/win32/netdb.h b/contrib/libs/libpq/src/include/port/win32/netdb.h new file mode 100644 index 0000000000..9ed13e457b --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/netdb.h @@ -0,0 +1,7 @@ +/* src/include/port/win32/netdb.h */ +#ifndef WIN32_NETDB_H +#define WIN32_NETDB_H + +#include <ws2tcpip.h> + +#endif diff --git a/contrib/libs/libpq/src/include/port/win32/netinet/in.h b/contrib/libs/libpq/src/include/port/win32/netinet/in.h new file mode 100644 index 0000000000..a4e22f89f4 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/netinet/in.h @@ -0,0 +1,3 @@ +/* src/include/port/win32/netinet/in.h */ + +#include <sys/socket.h> diff --git a/contrib/libs/libpq/src/include/port/win32/netinet/tcp.h b/contrib/libs/libpq/src/include/port/win32/netinet/tcp.h new file mode 100644 index 0000000000..1d377b6adc --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/netinet/tcp.h @@ -0,0 +1,7 @@ +/* src/include/port/win32/netinet/tcp.h */ +#ifndef WIN32_NETINET_TCP_H +#define WIN32_NETINET_TCP_H + +#include <sys/socket.h> + +#endif diff --git a/contrib/libs/libpq/src/include/port/win32/pwd.h b/contrib/libs/libpq/src/include/port/win32/pwd.h new file mode 100644 index 0000000000..b8c7178fc0 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/pwd.h @@ -0,0 +1,3 @@ +/* + * src/include/port/win32/pwd.h + */ diff --git a/contrib/libs/libpq/src/include/port/win32/sys/select.h b/contrib/libs/libpq/src/include/port/win32/sys/select.h new file mode 100644 index 0000000000..f8a877accd --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/sys/select.h @@ -0,0 +1,3 @@ +/* + * src/include/port/win32/sys/select.h + */ diff --git a/contrib/libs/libpq/src/include/port/win32/sys/socket.h b/contrib/libs/libpq/src/include/port/win32/sys/socket.h new file mode 100644 index 0000000000..0c32c0f7b2 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/sys/socket.h @@ -0,0 +1,26 @@ +/* + * src/include/port/win32/sys/socket.h + */ +#ifndef WIN32_SYS_SOCKET_H +#define WIN32_SYS_SOCKET_H + +/* + * Unfortunately, <wingdi.h> of VC++ also defines ERROR. + * To avoid the conflict, we include <windows.h> here and undefine ERROR + * immediately. + * + * Note: Don't include <wingdi.h> directly. It causes compile errors. + */ +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> + +#undef ERROR +#undef small + +/* Restore old ERROR value */ +#ifdef PGERROR +#define ERROR PGERROR +#endif + +#endif /* WIN32_SYS_SOCKET_H */ diff --git a/contrib/libs/libpq/src/include/port/win32/sys/un.h b/contrib/libs/libpq/src/include/port/win32/sys/un.h new file mode 100644 index 0000000000..4fc13a23fd --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/sys/un.h @@ -0,0 +1,17 @@ +/* + * src/include/port/win32/sys/un.h + */ +#ifndef WIN32_SYS_UN_H +#define WIN32_SYS_UN_H + +/* + * Windows defines this structure in <afunix.h>, but not all tool chains have + * the header yet, so we define it here for now. + */ +struct sockaddr_un +{ + unsigned short sun_family; + char sun_path[108]; +}; + +#endif diff --git a/contrib/libs/libpq/src/include/port/win32/sys/wait.h b/contrib/libs/libpq/src/include/port/win32/sys/wait.h new file mode 100644 index 0000000000..eaeb5661c9 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32/sys/wait.h @@ -0,0 +1,3 @@ +/* + * src/include/port/win32/sys/wait.h + */ diff --git a/contrib/libs/libpq/src/include/port/win32_msvc/dirent.h b/contrib/libs/libpq/src/include/port/win32_msvc/dirent.h new file mode 100644 index 0000000000..62799db001 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_msvc/dirent.h @@ -0,0 +1,34 @@ +/* + * Headers for port/dirent.c, win32 native implementation of dirent functions + * + * src/include/port/win32_msvc/dirent.h + */ + +#ifndef _WIN32VC_DIRENT_H +#define _WIN32VC_DIRENT_H +struct dirent +{ + long d_ino; + unsigned short d_reclen; + unsigned char d_type; + unsigned short d_namlen; + char d_name[MAX_PATH]; +}; + +typedef struct DIR DIR; + +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int closedir(DIR *); + +/* File types for 'd_type'. */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +#endif diff --git a/contrib/libs/libpq/src/include/port/win32_msvc/sys/file.h b/contrib/libs/libpq/src/include/port/win32_msvc/sys/file.h new file mode 100644 index 0000000000..76be3e7774 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_msvc/sys/file.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/file.h */ diff --git a/contrib/libs/libpq/src/include/port/win32_msvc/sys/param.h b/contrib/libs/libpq/src/include/port/win32_msvc/sys/param.h new file mode 100644 index 0000000000..160df3b25e --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_msvc/sys/param.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/param.h */ diff --git a/contrib/libs/libpq/src/include/port/win32_msvc/sys/time.h b/contrib/libs/libpq/src/include/port/win32_msvc/sys/time.h new file mode 100644 index 0000000000..9d943ecc6f --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_msvc/sys/time.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/time.h */ diff --git a/contrib/libs/libpq/src/include/port/win32_msvc/unistd.h b/contrib/libs/libpq/src/include/port/win32_msvc/unistd.h new file mode 100644 index 0000000000..b7795ba03c --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_msvc/unistd.h @@ -0,0 +1,9 @@ +/* src/include/port/win32_msvc/unistd.h */ + +/* + * MSVC does not define these, nor does _fileno(stdin) etc reliably work + * (returns -1 if stdin/out/err are closed). + */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 diff --git a/contrib/libs/libpq/src/include/port/win32_port.h b/contrib/libs/libpq/src/include/port/win32_port.h new file mode 100644 index 0000000000..b957d5c598 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32_port.h @@ -0,0 +1,594 @@ +/*------------------------------------------------------------------------- + * + * win32_port.h + * Windows-specific compatibility stuff. + * + * Note this is read in MinGW as well as native Windows builds, + * but not in Cygwin builds. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/win32_port.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_WIN32_PORT_H +#define PG_WIN32_PORT_H + +/* + * Always build with SSPI support. Keep it as a #define in case + * we want a switch to disable it sometime in the future. + */ +#define ENABLE_SSPI 1 + +/* undefine and redefine after #include */ +#undef mkdir + +#undef ERROR + +/* + * VS2013 and later issue warnings about using the old Winsock API, + * which we don't really want to hear about. + */ +#ifdef _MSC_VER +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +/* + * The MinGW64 headers choke if this is already defined - they + * define it themselves. + */ +#if !defined(__MINGW64_VERSION_MAJOR) || defined(_MSC_VER) +#define _WINSOCKAPI_ +#endif + +/* + * windows.h includes a lot of other headers, slowing down compilation + * significantly. WIN32_LEAN_AND_MEAN reduces that a bit. It'd be better to + * remove the include of windows.h (as well as indirect inclusions of it) from + * such a central place, but until then... + * + * To be able to include ntstatus.h tell windows.h to not declare NTSTATUS by + * temporarily defining UMDF_USING_NTSTATUS, otherwise we'll get warning about + * macro redefinitions, as windows.h also defines NTSTATUS (yuck). That in + * turn requires including ntstatus.h, winternl.h to get common symbols. + */ +#define WIN32_LEAN_AND_MEAN +#define UMDF_USING_NTSTATUS + +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#include <ntstatus.h> +#include <winternl.h> + +#undef small +#include <process.h> +#include <signal.h> +#include <direct.h> +#undef near + +/* needed before sys/stat hacking below: */ +#define fstat microsoft_native_fstat +#define stat microsoft_native_stat +#include <sys/stat.h> +#undef fstat +#undef stat + +/* 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 + +/* + * 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 indicate non-exit() termination, which is + * similar to a unix-style signal exit (think SIGSEGV == + * STATUS_ACCESS_VIOLATION). Return values are broken up into groups: + * + * https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values + * + * 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 - + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 + * + * The comprehensive exception list is included in ntstatus.h from the + * Windows Driver Kit (WDK). A subset of the list is also included in + * winnt.h from the Windows SDK. Defining WIN32_NO_STATUS before including + * windows.h helps to avoid any conflicts. + * + * 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 SIGWINCH 28 +#define SIGUSR1 30 +#define SIGUSR2 31 + +/* MinGW has gettimeofday(), but MSVC doesn't */ +#ifdef _MSC_VER +/* Last parameter not used */ +extern int gettimeofday(struct timeval *tp, void *tzp); +#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); + +/* Convenience wrapper for GetFileType() */ +extern DWORD pgwin32_get_file_type(HANDLE hFile); + +/* + * WIN32 does not provide 64-bit off_t, but does provide the functions operating + * with 64-bit offsets. Also, fseek() might not give an error for unseekable + * streams, so harden that function with our version. + */ +#define pgoff_t __int64 + +#ifdef _MSC_VER +extern int _pgfseeko64(FILE *stream, pgoff_t offset, int origin); +extern pgoff_t _pgftello64(FILE *stream); +#define fseeko(stream, offset, origin) _pgfseeko64(stream, offset, origin) +#define ftello(stream) _pgftello64(stream) +#else +#ifndef fseeko +#define fseeko(stream, offset, origin) fseeko64(stream, offset, origin) +#endif +#ifndef ftello +#define ftello(stream) ftello64(stream) +#endif +#endif + +/* + * 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. + */ +extern int pgsymlink(const char *oldpath, const char *newpath); +extern int pgreadlink(const char *path, char *buf, size_t size); + +#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) +#define readlink(path, buf, size) pgreadlink(path, buf, size) + +/* + * Supplement to <sys/types.h>. + * + * 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 _MSC_VER +typedef int pid_t; +#endif + +/* + * Supplement to <sys/stat.h>. + * + * We must pull in sys/stat.h before this part, else our overrides lose. + * + * stat() is not guaranteed to set the st_size field on win32, so we + * redefine it to our own implementation. See src/port/win32stat.c. + * + * The struct stat is 32 bit in MSVC, so we redefine it as a copy of + * struct __stat64. This also fixes the struct size for MINGW builds. + */ +struct stat /* This should match struct __stat64 */ +{ + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; +}; + +extern int _pgfstat64(int fileno, struct stat *buf); +extern int _pgstat64(const char *name, struct stat *buf); +extern int _pglstat64(const char *name, struct stat *buf); + +#define fstat(fileno, sb) _pgfstat64(fileno, sb) +#define stat(path, sb) _pgstat64(path, sb) +#define lstat(path, sb) _pglstat64(path, sb) + +/* These macros are not provided by older MinGW, nor by MSVC */ +#ifndef S_IRUSR +#define S_IRUSR _S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR _S_IWRITE +#endif +#ifndef S_IXUSR +#define S_IXUSR _S_IEXEC +#endif +#ifndef S_IRWXU +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif +#ifndef S_IRGRP +#define S_IRGRP 0 +#endif +#ifndef S_IWGRP +#define S_IWGRP 0 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0 +#endif +#ifndef S_IRWXG +#define S_IRWXG 0 +#endif +#ifndef S_IROTH +#define S_IROTH 0 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0 +#endif +#ifndef S_IRWXO +#define S_IRWXO 0 +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* + * In order for lstat() to be able to report junction points as symlinks, we + * need to hijack a bit in st_mode, since neither MSVC nor MinGW provides + * S_ISLNK and there aren't any spare bits. We'll steal the one for character + * devices, because we don't otherwise make use of those. + */ +#ifdef S_ISLNK +#error "S_ISLNK is already defined" +#endif +#ifdef S_IFLNK +#error "S_IFLNK is already defined" +#endif +#define S_IFLNK S_IFCHR +#define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK) + +/* + * Supplement to <fcntl.h>. + * 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 + +/* + * Our open() replacement does not create inheritable handles, so it is safe to + * ignore O_CLOEXEC. (If we were using Windows' own open(), it might be + * necessary to convert this to _O_NOINHERIT.) + */ +#define O_CLOEXEC 0 + +/* + * Supplement to <errno.h>. + * + * We redefine network-related Berkeley error symbols as the corresponding WSA + * constants. This allows strerror.c to recognize them as being in the Winsock + * error code range and pass them off to win32_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 EHOSTDOWN +#define EHOSTDOWN WSAEHOSTDOWN +#undef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#undef ENETDOWN +#define ENETDOWN WSAENETDOWN +#undef ENETRESET +#define ENETRESET WSAENETRESET +#undef ENETUNREACH +#define ENETUNREACH WSAENETUNREACH +#undef ENOTCONN +#define ENOTCONN WSAENOTCONN +#undef ETIMEDOUT +#define ETIMEDOUT WSAETIMEDOUT + +/* + * Locale stuff. + * + * 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 + +/* + * 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) + + +/* In backend/port/win32/signal.c */ +extern PGDLLIMPORT volatile int pg_signal_queue; +extern PGDLLIMPORT int pg_signal_mask; +extern PGDLLIMPORT HANDLE pgwin32_signal_event; +extern PGDLLIMPORT HANDLE pgwin32_initial_signal_pipe; + +#define UNBLOCKED_SIGNAL_QUEUE() (pg_signal_queue & ~pg_signal_mask) +#define PG_SIGNAL_COUNT 32 + +extern void pgwin32_signal_initialize(void); +extern HANDLE pgwin32_create_signal_listener(pid_t pid); +extern void pgwin32_dispatch_queued_signals(void); +extern void pg_queue_signal(int signum); + +/* In src/port/kill.c */ +#define kill(pid,sig) pgkill(pid,sig) +extern int pgkill(int pid, int sig); + +/* 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) + +extern SOCKET pgwin32_socket(int af, int type, int protocol); +extern int pgwin32_bind(SOCKET s, struct sockaddr *addr, int addrlen); +extern int pgwin32_listen(SOCKET s, int backlog); +extern SOCKET pgwin32_accept(SOCKET s, struct sockaddr *addr, int *addrlen); +extern int pgwin32_connect(SOCKET s, const struct sockaddr *name, int namelen); +extern int pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout); +extern int pgwin32_recv(SOCKET s, char *buf, int len, int flags); +extern int pgwin32_send(SOCKET s, const void *buf, int len, int flags); +extern int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); + +extern PGDLLIMPORT int pgwin32_noblock; + +#endif /* FRONTEND */ + +/* 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/win32dlopen.c */ +extern void *dlopen(const char *file, int mode); +extern void *dlsym(void *handle, const char *symbol); +extern int dlclose(void *handle); +extern char *dlerror(void); + +#define RTLD_NOW 1 +#define RTLD_GLOBAL 0 + +/* in port/win32error.c */ +extern void _dosmaperr(unsigned long); + +/* in port/win32env.c */ +extern int pgwin32_putenv(const char *); +extern int pgwin32_setenv(const char *name, const char *value, int overwrite); +extern int pgwin32_unsetenv(const char *name); + +#define putenv(x) pgwin32_putenv(x) +#define setenv(x,y,z) pgwin32_setenv(x,y,z) +#define unsetenv(x) pgwin32_unsetenv(x) + +/* in port/win32security.c */ +extern int pgwin32_is_service(void); +extern int pgwin32_is_admin(void); + +/* Windows security token manipulation (in src/common/exec.c) */ +extern BOOL AddUserToTokenDacl(HANDLE hToken); + +/* Things that exist in MinGW headers, but need to be added to MSVC */ +#ifdef _MSC_VER + +#ifndef _WIN64 +typedef long ssize_t; +#else +typedef __int64 ssize_t; +#endif + +typedef unsigned short mode_t; + +#define F_OK 0 +#define W_OK 2 +#define R_OK 4 + +#endif /* _MSC_VER */ + +#if defined(__MINGW32__) || defined(__MINGW64__) +/* + * Mingw claims to have a strtof, and my reading of its source code suggests + * that it ought to work (and not need this hack), but the regression test + * results disagree with me; whether this is a version issue or not is not + * clear. However, using our wrapper (and the misrounded-input variant file, + * already required for supporting ancient systems) can't make things any + * worse, except for a tiny performance loss when reading zeros. + * + * See also cygwin.h for another instance of this. + */ +#define HAVE_BUGGY_STRTOF 1 +#endif + +/* in port/win32pread.c */ +extern ssize_t pg_pread(int fd, void *buf, size_t nbyte, off_t offset); + +/* in port/win32pwrite.c */ +extern ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset); + +#endif /* PG_WIN32_PORT_H */ diff --git a/contrib/libs/libpq/src/include/port/win32ntdll.h b/contrib/libs/libpq/src/include/port/win32ntdll.h new file mode 100644 index 0000000000..1ce9360ec1 --- /dev/null +++ b/contrib/libs/libpq/src/include/port/win32ntdll.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * win32ntdll.h + * Dynamically loaded Windows NT functions. + * + * Portions Copyright (c) 2021-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/win32ntdll.h + * + *------------------------------------------------------------------------- + */ + +#ifndef WIN32NTDLL_H +#define WIN32NTDLL_H + +#include <ntstatus.h> +#include <winternl.h> + +#ifndef FLUSH_FLAGS_FILE_DATA_SYNC_ONLY +#define FLUSH_FLAGS_FILE_DATA_SYNC_ONLY 0x4 +#endif + +typedef NTSTATUS (__stdcall * RtlGetLastNtStatus_t) (void); +typedef ULONG (__stdcall * RtlNtStatusToDosError_t) (NTSTATUS); +typedef NTSTATUS (__stdcall * NtFlushBuffersFileEx_t) (HANDLE, ULONG, PVOID, ULONG, PIO_STATUS_BLOCK); + +extern PGDLLIMPORT RtlGetLastNtStatus_t pg_RtlGetLastNtStatus; +extern PGDLLIMPORT RtlNtStatusToDosError_t pg_RtlNtStatusToDosError; +extern PGDLLIMPORT NtFlushBuffersFileEx_t pg_NtFlushBuffersFileEx; + +extern int initialize_ntdll(void); + +#endif /* WIN32NTDLL_H */ diff --git a/contrib/libs/libpq/src/include/postgres.h b/contrib/libs/libpq/src/include/postgres.h new file mode 100644 index 0000000000..8a028ff789 --- /dev/null +++ b/contrib/libs/libpq/src/include/postgres.h @@ -0,0 +1,579 @@ +/*------------------------------------------------------------------------- + * + * postgres.h + * Primary include file for PostgreSQL server .c files + * + * This should be the first file included by PostgreSQL backend modules. + * Client-side code should include postgres_fe.h instead. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1995, Regents of the University of California + * + * src/include/postgres.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 + * ------- ------------------------------------------------ + * 1) Datum type + support functions + * 2) miscellaneous + * + * NOTES + * + * In general, this file should contain declarations that are widely needed + * in the backend environment, but are of no interest outside the backend. + * + * Simple type definitions live in c.h, where they are shared with + * postgres_fe.h. We do that since those type definitions are needed by + * frontend modules that want to deal with binary data transmission to or + * from the backend. Type definitions in this file should be for + * representations that never escape the backend, such as Datum. + * + *---------------------------------------------------------------- + */ +#ifndef POSTGRES_H +#define POSTGRES_H + +#include "c.h" +#include "utils/elog.h" +#include "utils/palloc.h" + +/* ---------------------------------------------------------------- + * Section 1: Datum type + support functions + * ---------------------------------------------------------------- + */ + +/* + * A Datum contains either a value of a pass-by-value type or a pointer to a + * value of a pass-by-reference type. Therefore, we require: + * + * sizeof(Datum) == sizeof(void *) == 4 or 8 + * + * The functions below and the analogous functions for other types should be used to + * convert between a Datum and the appropriate C type. + */ + +typedef uintptr_t Datum; + +/* + * A NullableDatum is used in places where both a Datum and its nullness needs + * to be stored. This can be more efficient than storing datums and nullness + * in separate arrays, due to better spatial locality, even if more space may + * be wasted due to padding. + */ +typedef struct NullableDatum +{ +#define FIELDNO_NULLABLE_DATUM_DATUM 0 + Datum value; +#define FIELDNO_NULLABLE_DATUM_ISNULL 1 + bool isnull; + /* due to alignment padding this could be used for flags for free */ +} NullableDatum; + +#define SIZEOF_DATUM SIZEOF_VOID_P + +/* + * DatumGetBool + * Returns boolean value of a datum. + * + * Note: any nonzero value will be considered true. + */ +static inline bool +DatumGetBool(Datum X) +{ + return (X != 0); +} + +/* + * BoolGetDatum + * Returns datum representation for a boolean. + * + * Note: any nonzero value will be considered true. + */ +static inline Datum +BoolGetDatum(bool X) +{ + return (Datum) (X ? 1 : 0); +} + +/* + * DatumGetChar + * Returns character value of a datum. + */ +static inline char +DatumGetChar(Datum X) +{ + return (char) X; +} + +/* + * CharGetDatum + * Returns datum representation for a character. + */ +static inline Datum +CharGetDatum(char X) +{ + return (Datum) X; +} + +/* + * Int8GetDatum + * Returns datum representation for an 8-bit integer. + */ +static inline Datum +Int8GetDatum(int8 X) +{ + return (Datum) X; +} + +/* + * DatumGetUInt8 + * Returns 8-bit unsigned integer value of a datum. + */ +static inline uint8 +DatumGetUInt8(Datum X) +{ + return (uint8) X; +} + +/* + * UInt8GetDatum + * Returns datum representation for an 8-bit unsigned integer. + */ +static inline Datum +UInt8GetDatum(uint8 X) +{ + return (Datum) X; +} + +/* + * DatumGetInt16 + * Returns 16-bit integer value of a datum. + */ +static inline int16 +DatumGetInt16(Datum X) +{ + return (int16) X; +} + +/* + * Int16GetDatum + * Returns datum representation for a 16-bit integer. + */ +static inline Datum +Int16GetDatum(int16 X) +{ + return (Datum) X; +} + +/* + * DatumGetUInt16 + * Returns 16-bit unsigned integer value of a datum. + */ +static inline uint16 +DatumGetUInt16(Datum X) +{ + return (uint16) X; +} + +/* + * UInt16GetDatum + * Returns datum representation for a 16-bit unsigned integer. + */ +static inline Datum +UInt16GetDatum(uint16 X) +{ + return (Datum) X; +} + +/* + * DatumGetInt32 + * Returns 32-bit integer value of a datum. + */ +static inline int32 +DatumGetInt32(Datum X) +{ + return (int32) X; +} + +/* + * Int32GetDatum + * Returns datum representation for a 32-bit integer. + */ +static inline Datum +Int32GetDatum(int32 X) +{ + return (Datum) X; +} + +/* + * DatumGetUInt32 + * Returns 32-bit unsigned integer value of a datum. + */ +static inline uint32 +DatumGetUInt32(Datum X) +{ + return (uint32) X; +} + +/* + * UInt32GetDatum + * Returns datum representation for a 32-bit unsigned integer. + */ +static inline Datum +UInt32GetDatum(uint32 X) +{ + return (Datum) X; +} + +/* + * DatumGetObjectId + * Returns object identifier value of a datum. + */ +static inline Oid +DatumGetObjectId(Datum X) +{ + return (Oid) X; +} + +/* + * ObjectIdGetDatum + * Returns datum representation for an object identifier. + */ +static inline Datum +ObjectIdGetDatum(Oid X) +{ + return (Datum) X; +} + +/* + * DatumGetTransactionId + * Returns transaction identifier value of a datum. + */ +static inline TransactionId +DatumGetTransactionId(Datum X) +{ + return (TransactionId) X; +} + +/* + * TransactionIdGetDatum + * Returns datum representation for a transaction identifier. + */ +static inline Datum +TransactionIdGetDatum(TransactionId X) +{ + return (Datum) X; +} + +/* + * MultiXactIdGetDatum + * Returns datum representation for a multixact identifier. + */ +static inline Datum +MultiXactIdGetDatum(MultiXactId X) +{ + return (Datum) X; +} + +/* + * DatumGetCommandId + * Returns command identifier value of a datum. + */ +static inline CommandId +DatumGetCommandId(Datum X) +{ + return (CommandId) X; +} + +/* + * CommandIdGetDatum + * Returns datum representation for a command identifier. + */ +static inline Datum +CommandIdGetDatum(CommandId X) +{ + return (Datum) X; +} + +/* + * DatumGetPointer + * Returns pointer value of a datum. + */ +static inline Pointer +DatumGetPointer(Datum X) +{ + return (Pointer) X; +} + +/* + * PointerGetDatum + * Returns datum representation for a pointer. + */ +static inline Datum +PointerGetDatum(const void *X) +{ + return (Datum) X; +} + +/* + * DatumGetCString + * Returns C string (null-terminated string) value of a datum. + * + * Note: C string is not a full-fledged Postgres type at present, + * but type input functions use this conversion for their inputs. + */ +static inline char * +DatumGetCString(Datum X) +{ + return (char *) DatumGetPointer(X); +} + +/* + * CStringGetDatum + * Returns datum representation for a C string (null-terminated string). + * + * Note: C string is not a full-fledged Postgres type at present, + * but type output functions use this conversion for their outputs. + * Note: CString is pass-by-reference; caller must ensure the pointed-to + * value has adequate lifetime. + */ +static inline Datum +CStringGetDatum(const char *X) +{ + return PointerGetDatum(X); +} + +/* + * DatumGetName + * Returns name value of a datum. + */ +static inline Name +DatumGetName(Datum X) +{ + return (Name) DatumGetPointer(X); +} + +/* + * NameGetDatum + * Returns datum representation for a name. + * + * Note: Name is pass-by-reference; caller must ensure the pointed-to + * value has adequate lifetime. + */ +static inline Datum +NameGetDatum(const NameData *X) +{ + return CStringGetDatum(NameStr(*X)); +} + +/* + * DatumGetInt64 + * Returns 64-bit integer value of a datum. + * + * Note: this function hides whether int64 is pass by value or by reference. + */ +static inline int64 +DatumGetInt64(Datum X) +{ +#ifdef USE_FLOAT8_BYVAL + return (int64) X; +#else + return *((int64 *) DatumGetPointer(X)); +#endif +} + +/* + * Int64GetDatum + * Returns datum representation for a 64-bit integer. + * + * Note: if int64 is pass by reference, this function returns a reference + * to palloc'd space. + */ +#ifdef USE_FLOAT8_BYVAL +static inline Datum +Int64GetDatum(int64 X) +{ + return (Datum) X; +} +#else +extern Datum Int64GetDatum(int64 X); +#endif + + +/* + * DatumGetUInt64 + * Returns 64-bit unsigned integer value of a datum. + * + * Note: this function hides whether int64 is pass by value or by reference. + */ +static inline uint64 +DatumGetUInt64(Datum X) +{ +#ifdef USE_FLOAT8_BYVAL + return (uint64) X; +#else + return *((uint64 *) DatumGetPointer(X)); +#endif +} + +/* + * UInt64GetDatum + * Returns datum representation for a 64-bit unsigned integer. + * + * Note: if int64 is pass by reference, this function returns a reference + * to palloc'd space. + */ +static inline Datum +UInt64GetDatum(uint64 X) +{ +#ifdef USE_FLOAT8_BYVAL + return (Datum) X; +#else + return Int64GetDatum((int64) X); +#endif +} + +/* + * Float <-> Datum conversions + * + * These have to be implemented as inline functions rather than macros, when + * passing by value, because many machines pass int and float function + * parameters/results differently; so we need to play weird games with unions. + */ + +/* + * DatumGetFloat4 + * Returns 4-byte floating point value of a datum. + */ +static inline float4 +DatumGetFloat4(Datum X) +{ + union + { + int32 value; + float4 retval; + } myunion; + + myunion.value = DatumGetInt32(X); + return myunion.retval; +} + +/* + * Float4GetDatum + * Returns datum representation for a 4-byte floating point number. + */ +static inline Datum +Float4GetDatum(float4 X) +{ + union + { + float4 value; + int32 retval; + } myunion; + + myunion.value = X; + return Int32GetDatum(myunion.retval); +} + +/* + * DatumGetFloat8 + * Returns 8-byte floating point value of a datum. + * + * Note: this function hides whether float8 is pass by value or by reference. + */ +static inline float8 +DatumGetFloat8(Datum X) +{ +#ifdef USE_FLOAT8_BYVAL + union + { + int64 value; + float8 retval; + } myunion; + + myunion.value = DatumGetInt64(X); + return myunion.retval; +#else + return *((float8 *) DatumGetPointer(X)); +#endif +} + +/* + * Float8GetDatum + * Returns datum representation for an 8-byte floating point number. + * + * Note: if float8 is pass by reference, this function returns a reference + * to palloc'd space. + */ +#ifdef USE_FLOAT8_BYVAL +static inline Datum +Float8GetDatum(float8 X) +{ + union + { + float8 value; + int64 retval; + } myunion; + + myunion.value = X; + return Int64GetDatum(myunion.retval); +} +#else +extern Datum Float8GetDatum(float8 X); +#endif + + +/* + * Int64GetDatumFast + * Float8GetDatumFast + * + * These macros are intended to allow writing code that does not depend on + * whether int64 and float8 are pass-by-reference types, while not + * sacrificing performance when they are. The argument must be a variable + * that will exist and have the same value for as long as the Datum is needed. + * In the pass-by-ref case, the address of the variable is taken to use as + * the Datum. In the pass-by-val case, these are the same as the non-Fast + * functions, except for asserting that the variable is of the correct type. + */ + +#ifdef USE_FLOAT8_BYVAL +#define Int64GetDatumFast(X) \ + (AssertVariableIsOfTypeMacro(X, int64), Int64GetDatum(X)) +#define Float8GetDatumFast(X) \ + (AssertVariableIsOfTypeMacro(X, double), Float8GetDatum(X)) +#else +#define Int64GetDatumFast(X) \ + (AssertVariableIsOfTypeMacro(X, int64), PointerGetDatum(&(X))) +#define Float8GetDatumFast(X) \ + (AssertVariableIsOfTypeMacro(X, double), PointerGetDatum(&(X))) +#endif + + +/* ---------------------------------------------------------------- + * Section 2: miscellaneous + * ---------------------------------------------------------------- + */ + +/* + * NON_EXEC_STATIC: It's sometimes useful to define a variable or function + * that is normally static but extern when using EXEC_BACKEND (see + * pg_config_manual.h). There would then typically be some code in + * postmaster.c that uses those extern symbols to transfer state between + * processes or do whatever other things it needs to do in EXEC_BACKEND mode. + */ +#ifdef EXEC_BACKEND +#define NON_EXEC_STATIC +#else +#define NON_EXEC_STATIC static +#endif + +#endif /* POSTGRES_H */ diff --git a/contrib/libs/libpq/src/include/postgres_ext.h b/contrib/libs/libpq/src/include/postgres_ext.h new file mode 100644 index 0000000000..240ad4e93b --- /dev/null +++ b/contrib/libs/libpq/src/include/postgres_ext.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * 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 <limits.h> to use the above #define */ + +#define atooid(x) ((Oid) strtoul((x), NULL, 10)) +/* the above needs <stdlib.h> */ + + +/* 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/contrib/libs/libpq/src/include/postgres_fe.h b/contrib/libs/libpq/src/include/postgres_fe.h new file mode 100644 index 0000000000..5bc71dd0b3 --- /dev/null +++ b/contrib/libs/libpq/src/include/postgres_fe.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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/contrib/libs/libpq/src/include/storage/backendid.h b/contrib/libs/libpq/src/include/storage/backendid.h new file mode 100644 index 0000000000..1e90b602f0 --- /dev/null +++ b/contrib/libs/libpq/src/include/storage/backendid.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * backendid.h + * POSTGRES backend id communication definitions + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/backendid.h + * + *------------------------------------------------------------------------- + */ +#ifndef BACKENDID_H +#define BACKENDID_H + +/* ---------------- + * -cim 8/17/90 + * ---------------- + */ +typedef int BackendId; /* unique currently active backend identifier */ + +#define InvalidBackendId (-1) + +extern PGDLLIMPORT BackendId MyBackendId; /* backend id of this backend */ + +/* backend id of our parallel session leader, or InvalidBackendId if none */ +extern PGDLLIMPORT BackendId ParallelLeaderBackendId; + +/* + * The BackendId to use for our session's temp relations is normally our own, + * but parallel workers should use their leader's ID. + */ +#define BackendIdForTempRelations() \ + (ParallelLeaderBackendId == InvalidBackendId ? MyBackendId : ParallelLeaderBackendId) + +#endif /* BACKENDID_H */ diff --git a/contrib/libs/libpq/src/include/storage/block.h b/contrib/libs/libpq/src/include/storage/block.h new file mode 100644 index 0000000000..31a036df0d --- /dev/null +++ b/contrib/libs/libpq/src/include/storage/block.h @@ -0,0 +1,108 @@ +/*------------------------------------------------------------------------- + * + * block.h + * POSTGRES disk block definitions. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/block.h + * + *------------------------------------------------------------------------- + */ +#ifndef BLOCK_H +#define BLOCK_H + +/* + * BlockNumber: + * + * each data file (heap or index) is divided into postgres disk blocks + * (which may be thought of as the unit of i/o -- a postgres buffer + * contains exactly one disk block). the blocks are numbered + * sequentially, 0 to 0xFFFFFFFE. + * + * InvalidBlockNumber is the same thing as P_NEW in bufmgr.h. + * + * the access methods, the buffer manager and the storage manager are + * more or less the only pieces of code that should be accessing disk + * blocks directly. + */ +typedef uint32 BlockNumber; + +#define InvalidBlockNumber ((BlockNumber) 0xFFFFFFFF) + +#define MaxBlockNumber ((BlockNumber) 0xFFFFFFFE) + +/* + * BlockId: + * + * this is a storage type for BlockNumber. in other words, this type + * is used for on-disk structures (e.g., in HeapTupleData) whereas + * BlockNumber is the type on which calculations are performed (e.g., + * in access method code). + * + * there doesn't appear to be any reason to have separate types except + * for the fact that BlockIds can be SHORTALIGN'd (and therefore any + * structures that contains them, such as ItemPointerData, can also be + * SHORTALIGN'd). this is an important consideration for reducing the + * space requirements of the line pointer (ItemIdData) array on each + * page and the header of each heap or index tuple, so it doesn't seem + * wise to change this without good reason. + */ +typedef struct BlockIdData +{ + uint16 bi_hi; + uint16 bi_lo; +} BlockIdData; + +typedef BlockIdData *BlockId; /* block identifier */ + +/* ---------------- + * support functions + * ---------------- + */ + +/* + * BlockNumberIsValid + * True iff blockNumber is valid. + */ +static inline bool +BlockNumberIsValid(BlockNumber blockNumber) +{ + return blockNumber != InvalidBlockNumber; +} + +/* + * BlockIdSet + * Sets a block identifier to the specified value. + */ +static inline void +BlockIdSet(BlockIdData *blockId, BlockNumber blockNumber) +{ + blockId->bi_hi = blockNumber >> 16; + blockId->bi_lo = blockNumber & 0xffff; +} + +/* + * BlockIdEquals + * Check for block number equality. + */ +static inline bool +BlockIdEquals(const BlockIdData *blockId1, const BlockIdData *blockId2) +{ + return (blockId1->bi_hi == blockId2->bi_hi && + blockId1->bi_lo == blockId2->bi_lo); +} + +/* + * BlockIdGetBlockNumber + * Retrieve the block number from a block identifier. + */ +static inline BlockNumber +BlockIdGetBlockNumber(const BlockIdData *blockId) +{ + return (((BlockNumber) blockId->bi_hi) << 16) | ((BlockNumber) blockId->bi_lo); +} + +#endif /* BLOCK_H */ diff --git a/contrib/libs/libpq/src/include/storage/buf.h b/contrib/libs/libpq/src/include/storage/buf.h new file mode 100644 index 0000000000..6520d9ae1e --- /dev/null +++ b/contrib/libs/libpq/src/include/storage/buf.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- + * + * buf.h + * Basic buffer manager data types. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/buf.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUF_H +#define BUF_H + +/* + * Buffer identifiers. + * + * Zero is invalid, positive is the index of a shared buffer (1..NBuffers), + * negative is the index of a local buffer (-1 .. -NLocBuffer). + */ +typedef int Buffer; + +#define InvalidBuffer 0 + +/* + * BufferIsInvalid + * True iff the buffer is invalid. + */ +#define BufferIsInvalid(buffer) ((buffer) == InvalidBuffer) + +/* + * BufferIsLocal + * True iff the buffer is local (not visible to other backends). + */ +#define BufferIsLocal(buffer) ((buffer) < 0) + +/* + * Buffer access strategy objects. + * + * BufferAccessStrategyData is private to freelist.c + */ +typedef struct BufferAccessStrategyData *BufferAccessStrategy; + +#endif /* BUF_H */ diff --git a/contrib/libs/libpq/src/include/storage/relfilelocator.h b/contrib/libs/libpq/src/include/storage/relfilelocator.h new file mode 100644 index 0000000000..61cf0169bd --- /dev/null +++ b/contrib/libs/libpq/src/include/storage/relfilelocator.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * relfilelocator.h + * Physical access information for relations. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/relfilelocator.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELFILELOCATOR_H +#define RELFILELOCATOR_H + +#include "common/relpath.h" +#include "storage/backendid.h" + +/* + * RelFileLocator must provide all that we need to know to physically access + * a relation, with the exception of the backend ID, which can be provided + * separately. Note, however, that a "physical" relation is comprised of + * multiple files on the filesystem, as each fork is stored as a separate + * file, and each fork can be divided into multiple segments. See md.c. + * + * spcOid identifies the tablespace of the relation. It corresponds to + * pg_tablespace.oid. + * + * dbOid identifies the database of the relation. It is zero for + * "shared" relations (those common to all databases of a cluster). + * Nonzero dbOid values correspond to pg_database.oid. + * + * relNumber identifies the specific relation. relNumber corresponds to + * pg_class.relfilenode (NOT pg_class.oid, because we need to be able + * to assign new physical files to relations in some situations). + * Notice that relNumber is only unique within a database in a particular + * tablespace. + * + * Note: spcOid must be GLOBALTABLESPACE_OID if and only if dbOid is + * zero. We support shared relations only in the "global" tablespace. + * + * Note: in pg_class we allow reltablespace == 0 to denote that the + * relation is stored in its database's "default" tablespace (as + * identified by pg_database.dattablespace). However this shorthand + * is NOT allowed in RelFileLocator structs --- the real tablespace ID + * must be supplied when setting spcOid. + * + * Note: in pg_class, relfilenode can be zero to denote that the relation + * is a "mapped" relation, whose current true filenode number is available + * from relmapper.c. Again, this case is NOT allowed in RelFileLocators. + * + * Note: various places use RelFileLocator in hashtable keys. Therefore, + * there *must not* be any unused padding bytes in this struct. That + * should be safe as long as all the fields are of type Oid. + */ +typedef struct RelFileLocator +{ + Oid spcOid; /* tablespace */ + Oid dbOid; /* database */ + RelFileNumber relNumber; /* relation */ +} RelFileLocator; + +/* + * Augmenting a relfilelocator with the backend ID provides all the information + * we need to locate the physical storage. The backend ID is InvalidBackendId + * for regular relations (those accessible to more than one backend), or the + * owning backend's ID for backend-local relations. Backend-local relations + * are always transient and removed in case of a database crash; they are + * never WAL-logged or fsync'd. + */ +typedef struct RelFileLocatorBackend +{ + RelFileLocator locator; + BackendId backend; +} RelFileLocatorBackend; + +#define RelFileLocatorBackendIsTemp(rlocator) \ + ((rlocator).backend != InvalidBackendId) + +/* + * Note: RelFileLocatorEquals and RelFileLocatorBackendEquals compare relNumber + * first since that is most likely to be different in two unequal + * RelFileLocators. It is probably redundant to compare spcOid if the other + * fields are found equal, but do it anyway to be sure. Likewise for checking + * the backend ID in RelFileLocatorBackendEquals. + */ +#define RelFileLocatorEquals(locator1, locator2) \ + ((locator1).relNumber == (locator2).relNumber && \ + (locator1).dbOid == (locator2).dbOid && \ + (locator1).spcOid == (locator2).spcOid) + +#define RelFileLocatorBackendEquals(locator1, locator2) \ + ((locator1).locator.relNumber == (locator2).locator.relNumber && \ + (locator1).locator.dbOid == (locator2).locator.dbOid && \ + (locator1).backend == (locator2).backend && \ + (locator1).locator.spcOid == (locator2).locator.spcOid) + +#endif /* RELFILELOCATOR_H */ diff --git a/contrib/libs/libpq/src/include/utils/elog.h b/contrib/libs/libpq/src/include/utils/elog.h new file mode 100644 index 0000000000..0292e88b4f --- /dev/null +++ b/contrib/libs/libpq/src/include/utils/elog.h @@ -0,0 +1,545 @@ +/*------------------------------------------------------------------------- + * + * elog.h + * POSTGRES error reporting/logging definitions. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/elog.h + * + *------------------------------------------------------------------------- + */ +#ifndef ELOG_H +#define ELOG_H + +#include <setjmp.h> + +#include "lib/stringinfo.h" + +/* We cannot include nodes.h yet, so forward-declare struct Node */ +struct Node; + + +/* Error level codes */ +#define DEBUG5 10 /* Debugging messages, in categories of + * decreasing detail. */ +#define DEBUG4 11 +#define DEBUG3 12 +#define DEBUG2 13 +#define DEBUG1 14 /* used by GUC debug_* variables */ +#define LOG 15 /* Server operational messages; sent only to + * server log by default. */ +#define LOG_SERVER_ONLY 16 /* Same as LOG for server reporting, but never + * sent to client. */ +#define COMMERROR LOG_SERVER_ONLY /* Client communication problems; same as + * LOG for server reporting, but never + * sent to client. */ +#define INFO 17 /* Messages specifically requested by user (eg + * VACUUM VERBOSE output); always sent to + * client regardless of client_min_messages, + * but by default not sent to server log. */ +#define NOTICE 18 /* Helpful messages to users about query + * operation; sent to client and not to server + * log by default. */ +#define WARNING 19 /* Warnings. NOTICE is for expected messages + * like implicit sequence creation by SERIAL. + * WARNING is for unexpected messages. */ +#define PGWARNING 19 /* Must equal WARNING; see NOTE below. */ +#define WARNING_CLIENT_ONLY 20 /* Warnings to be sent to client as usual, but + * never to the server log. */ +#define ERROR 21 /* user error - abort transaction; return to + * known state */ +#define PGERROR 21 /* Must equal ERROR; see NOTE below. */ +#define FATAL 22 /* fatal error - abort process */ +#define PANIC 23 /* take down the other backends with me */ + +/* + * NOTE: the alternate names PGWARNING and PGERROR are useful for dealing + * with third-party headers that make other definitions of WARNING and/or + * ERROR. One can, for example, re-define ERROR as PGERROR after including + * such a header. + */ + + +/* macros for representing SQLSTATE strings compactly */ +#define PGSIXBIT(ch) (((ch) - '0') & 0x3F) +#define PGUNSIXBIT(val) (((val) & 0x3F) + '0') + +#define MAKE_SQLSTATE(ch1,ch2,ch3,ch4,ch5) \ + (PGSIXBIT(ch1) + (PGSIXBIT(ch2) << 6) + (PGSIXBIT(ch3) << 12) + \ + (PGSIXBIT(ch4) << 18) + (PGSIXBIT(ch5) << 24)) + +/* These macros depend on the fact that '0' becomes a zero in PGSIXBIT */ +#define ERRCODE_TO_CATEGORY(ec) ((ec) & ((1 << 12) - 1)) +#define ERRCODE_IS_CATEGORY(ec) (((ec) & ~((1 << 12) - 1)) == 0) + +/* SQLSTATE codes for errors are defined in a separate file */ +#include "utils/errcodes.h" + +/* + * Provide a way to prevent "errno" from being accidentally used inside an + * elog() or ereport() invocation. Since we know that some operating systems + * define errno as something involving a function call, we'll put a local + * variable of the same name as that function in the local scope to force a + * compile error. On platforms that don't define errno in that way, nothing + * happens, so we get no warning ... but we can live with that as long as it + * happens on some popular platforms. + */ +#if defined(errno) && defined(__linux__) +#define pg_prevent_errno_in_scope() int __errno_location pg_attribute_unused() +#elif defined(errno) && (defined(__darwin__) || defined(__FreeBSD__)) +#define pg_prevent_errno_in_scope() int __error pg_attribute_unused() +#else +#define pg_prevent_errno_in_scope() +#endif + + +/*---------- + * New-style error reporting API: to be used in this way: + * ereport(ERROR, + * errcode(ERRCODE_UNDEFINED_CURSOR), + * errmsg("portal \"%s\" not found", stmt->portalname), + * ... other errxxx() fields as needed ...); + * + * The error level is required, and so is a primary error message (errmsg + * or errmsg_internal). All else is optional. errcode() defaults to + * ERRCODE_INTERNAL_ERROR if elevel is ERROR or more, ERRCODE_WARNING + * if elevel is WARNING, or ERRCODE_SUCCESSFUL_COMPLETION if elevel is + * NOTICE or below. + * + * Before Postgres v12, extra parentheses were required around the + * list of auxiliary function calls; that's now optional. + * + * ereport_domain() allows a message domain to be specified, for modules that + * wish to use a different message catalog from the backend's. To avoid having + * one copy of the default text domain per .o file, we define it as NULL here + * and have errstart insert the default text domain. Modules can either use + * ereport_domain() directly, or preferably they can override the TEXTDOMAIN + * macro. + * + * When __builtin_constant_p is available and elevel >= ERROR we make a call + * to errstart_cold() instead of errstart(). This version of the function is + * marked with pg_attribute_cold which will coax supporting compilers into + * generating code which is more optimized towards non-ERROR cases. Because + * we use __builtin_constant_p() in the condition, when elevel is not a + * compile-time constant, or if it is, but it's < ERROR, the compiler has no + * need to generate any code for this branch. It can simply call errstart() + * unconditionally. + * + * If elevel >= ERROR, the call will not return; we try to inform the compiler + * of that via pg_unreachable(). However, no useful optimization effect is + * obtained unless the compiler sees elevel as a compile-time constant, else + * we're just adding code bloat. So, if __builtin_constant_p is available, + * use that to cause the second if() to vanish completely for non-constant + * cases. We avoid using a local variable because it's not necessary and + * prevents gcc from making the unreachability deduction at optlevel -O0. + *---------- + */ +#ifdef HAVE__BUILTIN_CONSTANT_P +#define ereport_domain(elevel, domain, ...) \ + do { \ + pg_prevent_errno_in_scope(); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \ + errstart_cold(elevel, domain) : \ + errstart(elevel, domain)) \ + __VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ + pg_unreachable(); \ + } while(0) +#else /* !HAVE__BUILTIN_CONSTANT_P */ +#define ereport_domain(elevel, domain, ...) \ + do { \ + const int elevel_ = (elevel); \ + pg_prevent_errno_in_scope(); \ + if (errstart(elevel_, domain)) \ + __VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \ + if (elevel_ >= ERROR) \ + pg_unreachable(); \ + } while(0) +#endif /* HAVE__BUILTIN_CONSTANT_P */ + +#define ereport(elevel, ...) \ + ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__) + +#define TEXTDOMAIN NULL + +extern bool message_level_is_interesting(int elevel); + +extern bool errstart(int elevel, const char *domain); +extern pg_attribute_cold bool errstart_cold(int elevel, const char *domain); +extern void errfinish(const char *filename, int lineno, const char *funcname); + +extern int errcode(int sqlerrcode); + +extern int errcode_for_file_access(void); +extern int errcode_for_socket_access(void); + +extern int errmsg(const char *fmt,...) pg_attribute_printf(1, 2); +extern int errmsg_internal(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errmsg_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errdetail(const char *fmt,...) pg_attribute_printf(1, 2); +extern int errdetail_internal(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errdetail_log(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errdetail_log_plural(const char *fmt_singular, + const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errdetail_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errhint_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +/* + * errcontext() is typically called in error context callback functions, not + * within an ereport() invocation. The callback function can be in a different + * module than the ereport() call, so the message domain passed in errstart() + * is not usually the correct domain for translating the context message. + * set_errcontext_domain() first sets the domain to be used, and + * errcontext_msg() passes the actual message. + */ +#define errcontext set_errcontext_domain(TEXTDOMAIN), errcontext_msg + +extern int set_errcontext_domain(const char *domain); + +extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errhidestmt(bool hide_stmt); +extern int errhidecontext(bool hide_ctx); + +extern int errbacktrace(void); + +extern int errposition(int cursorpos); + +extern int internalerrposition(int cursorpos); +extern int internalerrquery(const char *query); + +extern int err_generic_string(int field, const char *str); + +extern int geterrcode(void); +extern int geterrposition(void); +extern int getinternalerrposition(void); + + +/*---------- + * Old-style error reporting API: to be used in this way: + * elog(ERROR, "portal \"%s\" not found", stmt->portalname); + *---------- + */ +#define elog(elevel, ...) \ + ereport(elevel, errmsg_internal(__VA_ARGS__)) + + +/*---------- + * Support for reporting "soft" errors that don't require a full transaction + * abort to clean up. This is to be used in this way: + * errsave(context, + * errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + * errmsg("invalid input syntax for type %s: \"%s\"", + * "boolean", in_str), + * ... other errxxx() fields as needed ...); + * + * "context" is a node pointer or NULL, and the remaining auxiliary calls + * provide the same error details as in ereport(). If context is not a + * pointer to an ErrorSaveContext node, then errsave(context, ...) + * behaves identically to ereport(ERROR, ...). If context is a pointer + * to an ErrorSaveContext node, then the information provided by the + * auxiliary calls is stored in the context node and control returns + * normally. The caller of errsave() must then do any required cleanup + * and return control back to its caller. That caller must check the + * ErrorSaveContext node to see whether an error occurred before + * it can trust the function's result to be meaningful. + * + * errsave_domain() allows a message domain to be specified; it is + * precisely analogous to ereport_domain(). + *---------- + */ +#define errsave_domain(context, domain, ...) \ + do { \ + struct Node *context_ = (context); \ + pg_prevent_errno_in_scope(); \ + if (errsave_start(context_, domain)) \ + __VA_ARGS__, errsave_finish(context_, __FILE__, __LINE__, __func__); \ + } while(0) + +#define errsave(context, ...) \ + errsave_domain(context, TEXTDOMAIN, __VA_ARGS__) + +/* + * "ereturn(context, dummy_value, ...);" is exactly the same as + * "errsave(context, ...); return dummy_value;". This saves a bit + * of typing in the common case where a function has no cleanup + * actions to take after reporting a soft error. "dummy_value" + * can be empty if the function returns void. + */ +#define ereturn_domain(context, dummy_value, domain, ...) \ + do { \ + errsave_domain(context, domain, __VA_ARGS__); \ + return dummy_value; \ + } while(0) + +#define ereturn(context, dummy_value, ...) \ + ereturn_domain(context, dummy_value, TEXTDOMAIN, __VA_ARGS__) + +extern bool errsave_start(struct Node *context, const char *domain); +extern void errsave_finish(struct Node *context, + const char *filename, int lineno, + const char *funcname); + + +/* Support for constructing error strings separately from ereport() calls */ + +extern void pre_format_elog_string(int errnumber, const char *domain); +extern char *format_elog_string(const char *fmt,...) pg_attribute_printf(1, 2); + + +/* Support for attaching context information to error reports */ + +typedef struct ErrorContextCallback +{ + struct ErrorContextCallback *previous; + void (*callback) (void *arg); + void *arg; +} ErrorContextCallback; + +extern PGDLLIMPORT ErrorContextCallback *error_context_stack; + + +/*---------- + * API for catching ereport(ERROR) exits. Use these macros like so: + * + * PG_TRY(); + * { + * ... code that might throw ereport(ERROR) ... + * } + * PG_CATCH(); + * { + * ... error recovery code ... + * } + * PG_END_TRY(); + * + * (The braces are not actually necessary, but are recommended so that + * pgindent will indent the construct nicely.) The error recovery code + * can either do PG_RE_THROW to propagate the error outwards, or do a + * (sub)transaction abort. Failure to do so may leave the system in an + * inconsistent state for further processing. + * + * For the common case that the error recovery code and the cleanup in the + * normal code path are identical, the following can be used instead: + * + * PG_TRY(); + * { + * ... code that might throw ereport(ERROR) ... + * } + * PG_FINALLY(); + * { + * ... cleanup code ... + * } + * PG_END_TRY(); + * + * The cleanup code will be run in either case, and any error will be rethrown + * afterwards. + * + * You cannot use both PG_CATCH() and PG_FINALLY() in the same + * PG_TRY()/PG_END_TRY() block. + * + * Note: while the system will correctly propagate any new ereport(ERROR) + * occurring in the recovery section, there is a small limit on the number + * of levels this will work for. It's best to keep the error recovery + * section simple enough that it can't generate any new errors, at least + * not before popping the error stack. + * + * Note: an ereport(FATAL) will not be caught by this construct; control will + * exit straight through proc_exit(). Therefore, do NOT put any cleanup + * of non-process-local resources into the error recovery section, at least + * not without taking thought for what will happen during ereport(FATAL). + * The PG_ENSURE_ERROR_CLEANUP macros provided by storage/ipc.h may be + * helpful in such cases. + * + * Note: if a local variable of the function containing PG_TRY is modified + * in the PG_TRY section and used in the PG_CATCH section, that variable + * must be declared "volatile" for POSIX compliance. This is not mere + * pedantry; we have seen bugs from compilers improperly optimizing code + * away when such a variable was not marked. Beware that gcc's -Wclobbered + * warnings are just about entirely useless for catching such oversights. + * + * Each of these macros accepts an optional argument which can be specified + * to apply a suffix to the variables declared within the macros. This suffix + * can be used to avoid the compiler emitting warnings about shadowed + * variables when compiling with -Wshadow in situations where nested PG_TRY() + * statements are required. The optional suffix may contain any character + * that's allowed in a variable name. The suffix, if specified, must be the + * same within each component macro of the given PG_TRY() statement. + *---------- + */ +#define PG_TRY(...) \ + do { \ + sigjmp_buf *_save_exception_stack##__VA_ARGS__ = PG_exception_stack; \ + ErrorContextCallback *_save_context_stack##__VA_ARGS__ = error_context_stack; \ + sigjmp_buf _local_sigjmp_buf##__VA_ARGS__; \ + bool _do_rethrow##__VA_ARGS__ = false; \ + if (sigsetjmp(_local_sigjmp_buf##__VA_ARGS__, 0) == 0) \ + { \ + PG_exception_stack = &_local_sigjmp_buf##__VA_ARGS__ + +#define PG_CATCH(...) \ + } \ + else \ + { \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__ + +#define PG_FINALLY(...) \ + } \ + else \ + _do_rethrow##__VA_ARGS__ = true; \ + { \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__ + +#define PG_END_TRY(...) \ + } \ + if (_do_rethrow##__VA_ARGS__) \ + PG_RE_THROW(); \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__; \ + } while (0) + +/* + * Some compilers understand pg_attribute_noreturn(); for other compilers, + * insert pg_unreachable() so that the compiler gets the point. + */ +#ifdef HAVE_PG_ATTRIBUTE_NORETURN +#define PG_RE_THROW() \ + pg_re_throw() +#else +#define PG_RE_THROW() \ + (pg_re_throw(), pg_unreachable()) +#endif + +extern PGDLLIMPORT sigjmp_buf *PG_exception_stack; + + +/* Stuff that error handlers might want to use */ + +/* + * ErrorData holds the data accumulated during any one ereport() cycle. + * Any non-NULL pointers must point to palloc'd data. + * (The const pointers are an exception; we assume they point at non-freeable + * constant strings.) + */ +typedef struct ErrorData +{ + int elevel; /* error level */ + bool output_to_server; /* will report to server log? */ + bool output_to_client; /* will report to client? */ + bool hide_stmt; /* true to prevent STATEMENT: inclusion */ + bool hide_ctx; /* true to prevent CONTEXT: inclusion */ + const char *filename; /* __FILE__ of ereport() call */ + int lineno; /* __LINE__ of ereport() call */ + const char *funcname; /* __func__ of ereport() call */ + const char *domain; /* message domain */ + const char *context_domain; /* message domain for context message */ + int sqlerrcode; /* encoded ERRSTATE */ + char *message; /* primary error message (translated) */ + char *detail; /* detail error message */ + char *detail_log; /* detail error message for server log only */ + char *hint; /* hint message */ + char *context; /* context message */ + char *backtrace; /* backtrace */ + const char *message_id; /* primary message's id (original string) */ + char *schema_name; /* name of schema */ + char *table_name; /* name of table */ + char *column_name; /* name of column */ + char *datatype_name; /* name of datatype */ + char *constraint_name; /* name of constraint */ + int cursorpos; /* cursor index into query string */ + int internalpos; /* cursor index into internalquery */ + char *internalquery; /* text of internally-generated query */ + int saved_errno; /* errno at entry */ + + /* context containing associated non-constant strings */ + struct MemoryContextData *assoc_context; +} ErrorData; + +extern void EmitErrorReport(void); +extern ErrorData *CopyErrorData(void); +extern void FreeErrorData(ErrorData *edata); +extern void FlushErrorState(void); +extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn(); +extern void ThrowErrorData(ErrorData *edata); +extern void pg_re_throw(void) pg_attribute_noreturn(); + +extern char *GetErrorContextStack(void); + +/* Hook for intercepting messages before they are sent to the server log */ +typedef void (*emit_log_hook_type) (ErrorData *edata); +extern PGDLLIMPORT emit_log_hook_type emit_log_hook; + + +/* GUC-configurable parameters */ + +typedef enum +{ + PGERROR_TERSE, /* single-line error messages */ + PGERROR_DEFAULT, /* recommended style */ + PGERROR_VERBOSE /* all the facts, ma'am */ +} PGErrorVerbosity; + +extern PGDLLIMPORT int Log_error_verbosity; +extern PGDLLIMPORT char *Log_line_prefix; +extern PGDLLIMPORT int Log_destination; +extern PGDLLIMPORT char *Log_destination_string; +extern PGDLLIMPORT bool syslog_sequence_numbers; +extern PGDLLIMPORT bool syslog_split_messages; + +/* Log destination bitmap */ +#define LOG_DESTINATION_STDERR 1 +#define LOG_DESTINATION_SYSLOG 2 +#define LOG_DESTINATION_EVENTLOG 4 +#define LOG_DESTINATION_CSVLOG 8 +#define LOG_DESTINATION_JSONLOG 16 + +/* Other exported functions */ +extern void log_status_format(StringInfo buf, const char *format, + ErrorData *edata); +extern void DebugFileOpen(void); +extern char *unpack_sql_state(int sql_state); +extern bool in_error_recursion_trouble(void); + +/* Common functions shared across destinations */ +extern void reset_formatted_start_time(void); +extern char *get_formatted_start_time(void); +extern char *get_formatted_log_time(void); +extern const char *get_backend_type_for_log(void); +extern bool check_log_of_query(ErrorData *edata); +extern const char *error_severity(int elevel); +extern void write_pipe_chunks(char *data, int len, int dest); + +/* Destination-specific functions */ +extern void write_csvlog(ErrorData *edata); +extern void write_jsonlog(ErrorData *edata); + +/* + * Write errors to stderr (or by equal means when stderr is + * not available). Used before ereport/elog can be used + * safely (memory context, GUC load etc) + */ +extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2); + +/* + * Write a message to STDERR using only async-signal-safe functions. This can + * be used to safely emit a message from a signal handler. + */ +extern void write_stderr_signal_safe(const char *fmt); + +#endif /* ELOG_H */ diff --git a/contrib/libs/libpq/src/include/utils/palloc.h b/contrib/libs/libpq/src/include/utils/palloc.h new file mode 100644 index 0000000000..d1146c1235 --- /dev/null +++ b/contrib/libs/libpq/src/include/utils/palloc.h @@ -0,0 +1,165 @@ +/*------------------------------------------------------------------------- + * + * palloc.h + * POSTGRES memory allocator definitions. + * + * This file contains the basic memory allocation interface that is + * needed by almost every backend module. It is included directly by + * postgres.h, so the definitions here are automatically available + * everywhere. Keep it lean! + * + * Memory allocation occurs within "contexts". Every chunk obtained from + * palloc()/MemoryContextAlloc() is allocated within a specific context. + * The entire contents of a context can be freed easily and quickly by + * resetting or deleting the context --- this is both faster and less + * prone to memory-leakage bugs than releasing chunks individually. + * We organize contexts into context trees to allow fine-grain control + * over chunk lifetime while preserving the certainty that we will free + * everything that should be freed. See utils/mmgr/README for more info. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/palloc.h + * + *------------------------------------------------------------------------- + */ +#ifndef PALLOC_H +#define PALLOC_H + +/* + * Type MemoryContextData is declared in nodes/memnodes.h. Most users + * of memory allocation should just treat it as an abstract type, so we + * do not provide the struct contents here. + */ +typedef struct MemoryContextData *MemoryContext; + +/* + * A memory context can have callback functions registered on it. Any such + * function will be called once just before the context is next reset or + * deleted. The MemoryContextCallback struct describing such a callback + * typically would be allocated within the context itself, thereby avoiding + * any need to manage it explicitly (the reset/delete action will free it). + */ +typedef void (*MemoryContextCallbackFunction) (void *arg); + +typedef struct MemoryContextCallback +{ + MemoryContextCallbackFunction func; /* function to call */ + void *arg; /* argument to pass it */ + struct MemoryContextCallback *next; /* next in list of callbacks */ +} MemoryContextCallback; + +/* + * CurrentMemoryContext is the default allocation context for palloc(). + * Avoid accessing it directly! Instead, use MemoryContextSwitchTo() + * to change the setting. + */ +extern PGDLLIMPORT MemoryContext CurrentMemoryContext; + +/* + * Flags for MemoryContextAllocExtended. + */ +#define MCXT_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */ +#define MCXT_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ +#define MCXT_ALLOC_ZERO 0x04 /* zero allocated memory */ + +/* + * Fundamental memory-allocation operations (more are in utils/memutils.h) + */ +extern void *MemoryContextAlloc(MemoryContext context, Size size); +extern void *MemoryContextAllocZero(MemoryContext context, Size size); +extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size); +extern void *MemoryContextAllocExtended(MemoryContext context, + Size size, int flags); +extern void *MemoryContextAllocAligned(MemoryContext context, + Size size, Size alignto, int flags); + +extern void *palloc(Size size); +extern void *palloc0(Size size); +extern void *palloc_extended(Size size, int flags); +extern void *palloc_aligned(Size size, Size alignto, int flags); +extern pg_nodiscard void *repalloc(void *pointer, Size size); +extern pg_nodiscard void *repalloc_extended(void *pointer, + Size size, int flags); +extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, Size size); +extern void pfree(void *pointer); + +/* + * Variants with easier notation and more type safety + */ + +/* + * Allocate space for one object of type "type" + */ +#define palloc_object(type) ((type *) palloc(sizeof(type))) +#define palloc0_object(type) ((type *) palloc0(sizeof(type))) + +/* + * Allocate space for "count" objects of type "type" + */ +#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) +#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) + +/* + * Change size of allocation pointed to by "pointer" to have space for "count" + * objects of type "type" + */ +#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) +#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, sizeof(type) * (oldcount), sizeof(type) * (count))) + +/* + * The result of palloc() is always word-aligned, so we can skip testing + * alignment of the pointer when deciding which MemSet variant to use. + * Note that this variant does not offer any advantage, and should not be + * used, unless its "sz" argument is a compile-time constant; therefore, the + * issue that it evaluates the argument multiple times isn't a problem in + * practice. + */ +#define palloc0fast(sz) \ + ( MemSetTest(0, sz) ? \ + MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \ + MemoryContextAllocZero(CurrentMemoryContext, sz) ) + +/* Higher-limit allocators. */ +extern void *MemoryContextAllocHuge(MemoryContext context, Size size); +extern pg_nodiscard void *repalloc_huge(void *pointer, Size size); + +/* + * Although this header file is nominally backend-only, certain frontend + * programs like pg_controldata include it via postgres.h. For some compilers + * it's necessary to hide the inline definition of MemoryContextSwitchTo in + * this scenario; hence the #ifndef FRONTEND. + */ + +#ifndef FRONTEND +static inline MemoryContext +MemoryContextSwitchTo(MemoryContext context) +{ + MemoryContext old = CurrentMemoryContext; + + CurrentMemoryContext = context; + return old; +} +#endif /* FRONTEND */ + +/* Registration of memory context reset/delete callbacks */ +extern void MemoryContextRegisterResetCallback(MemoryContext context, + MemoryContextCallback *cb); + +/* + * These are like standard strdup() except the copied string is + * allocated in a context, not with malloc(). + */ +extern char *MemoryContextStrdup(MemoryContext context, const char *string); +extern char *pstrdup(const char *in); +extern char *pnstrdup(const char *in, Size len); + +extern char *pchomp(const char *in); + +/* 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 /* PALLOC_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/README b/contrib/libs/libpq/src/interfaces/libpq/README new file mode 100644 index 0000000000..0dcef75a83 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/README @@ -0,0 +1,3 @@ +src/interfaces/libpq/README + +This directory contains the C version of Libpq, the POSTGRES frontend library. diff --git a/contrib/libs/libpq/src/interfaces/libpq/exports.txt b/contrib/libs/libpq/src/interfaces/libpq/exports.txt new file mode 100644 index 0000000000..7ded77aff3 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/exports.txt @@ -0,0 +1,189 @@ +# src/interfaces/libpq/exports.txt +# Functions to be exported by libpq DLLs +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 +PQsetSSLKeyPassHook_OpenSSL 177 +PQgetSSLKeyPassHook_OpenSSL 178 +PQdefaultSSLKeyPassHook_OpenSSL 179 +PQenterPipelineMode 180 +PQexitPipelineMode 181 +PQpipelineSync 182 +PQpipelineStatus 183 +PQsetTraceFlags 184 +PQmblenBounded 185 +PQsendFlushRequest 186 +PQconnectionUsedGSSAPI 187 diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-auth-sasl.h b/contrib/libs/libpq/src/interfaces/libpq/fe-auth-sasl.h new file mode 100644 index 0000000000..ddf6ea3f3f --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-auth-sasl.h @@ -0,0 +1,131 @@ +/*------------------------------------------------------------------------- + * + * fe-auth-sasl.h + * Defines the SASL mechanism interface for libpq. + * + * Each SASL mechanism defines a frontend and a backend callback structure. + * This is not part of the public API for applications. + * + * See src/include/libpq/sasl.h for the backend counterpart. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/interfaces/libpq/fe-auth-sasl.h + * + *------------------------------------------------------------------------- + */ + +#ifndef FE_AUTH_SASL_H +#define FE_AUTH_SASL_H + +#include "libpq-fe.h" + +/* + * Frontend SASL mechanism callbacks. + * + * To implement a frontend mechanism, declare a pg_be_sasl_mech struct with + * appropriate callback implementations, then hook it into conn->sasl during + * pg_SASL_init()'s mechanism negotiation. + */ +typedef struct pg_fe_sasl_mech +{ + /*------- + * init() + * + * Initializes mechanism-specific state for a connection. This + * callback must return a pointer to its allocated state, which will + * be passed as-is as the first argument to the other callbacks. + * the free() callback is called to release any state resources. + * + * If state allocation fails, the implementation should return NULL to + * fail the authentication exchange. + * + * Input parameters: + * + * conn: The connection to the server + * + * password: The user's supplied password for the current connection + * + * mech: The mechanism name in use, for implementations that may + * advertise more than one name (such as *-PLUS variants). + *------- + */ + void *(*init) (PGconn *conn, const char *password, const char *mech); + + /*-------- + * exchange() + * + * Produces a client response to a server challenge. As a special case + * for client-first SASL mechanisms, exchange() is called with a NULL + * server response once at the start of the authentication exchange to + * generate an initial response. + * + * Input parameters: + * + * state: The opaque mechanism state returned by init() + * + * input: The challenge data sent by the server, or NULL when + * generating a client-first initial response (that is, when + * the server expects the client to send a message to start + * the exchange). This is guaranteed to be null-terminated + * for safety, but SASL allows embedded nulls in challenges, + * so mechanisms must be careful to check inputlen. + * + * inputlen: The length of the challenge data sent by the server, or -1 + * during client-first initial response generation. + * + * Output parameters, to be set by the callback function: + * + * output: A malloc'd buffer containing the client's response to + * the server (can be empty), or NULL if the exchange should + * be aborted. (*success should be set to false in the + * latter case.) + * + * outputlen: The length (0 or higher) of the client response buffer, + * ignored if output is NULL. + * + * done: Set to true if the SASL exchange should not continue, + * because the exchange is either complete or failed + * + * success: Set to true if the SASL exchange completed successfully. + * Ignored if *done is false. + *-------- + */ + void (*exchange) (void *state, char *input, int inputlen, + char **output, int *outputlen, + bool *done, bool *success); + + /*-------- + * channel_bound() + * + * Returns true if the connection has an established channel binding. A + * mechanism implementation must ensure that a SASL exchange has actually + * been completed, in addition to checking that channel binding is in use. + * + * Mechanisms that do not implement channel binding may simply return + * false. + * + * Input parameters: + * + * state: The opaque mechanism state returned by init() + *-------- + */ + bool (*channel_bound) (void *state); + + /*-------- + * free() + * + * Frees the state allocated by init(). This is called when the connection + * is dropped, not when the exchange is completed. + * + * Input parameters: + * + * state: The opaque mechanism state returned by init() + *-------- + */ + void (*free) (void *state); + +} pg_fe_sasl_mech; + +#endif /* FE_AUTH_SASL_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c b/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c new file mode 100644 index 0000000000..6b779ec7ff --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-auth-scram.c @@ -0,0 +1,936 @@ +/*------------------------------------------------------------------------- + * + * fe-auth-scram.c + * The front-end (client) implementation of SCRAM authentication. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/interfaces/libpq/fe-auth-scram.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include "common/base64.h" +#include "common/hmac.h" +#include "common/saslprep.h" +#include "common/scram-common.h" +#include "fe-auth.h" + + +/* The exported SCRAM callback mechanism. */ +static void *scram_init(PGconn *conn, const char *password, + const char *sasl_mechanism); +static void scram_exchange(void *opaq, char *input, int inputlen, + char **output, int *outputlen, + bool *done, bool *success); +static bool scram_channel_bound(void *opaq); +static void scram_free(void *opaq); + +const pg_fe_sasl_mech pg_scram_mech = { + scram_init, + scram_exchange, + scram_channel_bound, + scram_free +}; + +/* + * Status of exchange messages used for SCRAM authentication via the + * SASL protocol. + */ +typedef enum +{ + FE_SCRAM_INIT, + FE_SCRAM_NONCE_SENT, + FE_SCRAM_PROOF_SENT, + FE_SCRAM_FINISHED +} fe_scram_state_enum; + +typedef struct +{ + fe_scram_state_enum state; + + /* These are supplied by the user */ + PGconn *conn; + char *password; + char *sasl_mechanism; + + /* State data depending on the hash type */ + pg_cryptohash_type hash_type; + int key_length; + + /* We construct these */ + uint8 SaltedPassword[SCRAM_MAX_KEY_LEN]; + char *client_nonce; + char *client_first_message_bare; + char *client_final_message_without_proof; + + /* These come from the server-first message */ + char *server_first_message; + char *salt; + int saltlen; + int iterations; + char *nonce; + + /* These come from the server-final message */ + char *server_final_message; + char ServerSignature[SCRAM_MAX_KEY_LEN]; +} fe_scram_state; + +static bool read_server_first_message(fe_scram_state *state, char *input); +static bool read_server_final_message(fe_scram_state *state, char *input); +static char *build_client_first_message(fe_scram_state *state); +static char *build_client_final_message(fe_scram_state *state); +static bool verify_server_signature(fe_scram_state *state, bool *match, + const char **errstr); +static bool calculate_client_proof(fe_scram_state *state, + const char *client_final_message_without_proof, + uint8 *result, const char **errstr); + +/* + * Initialize SCRAM exchange status. + */ +static void * +scram_init(PGconn *conn, + const char *password, + const char *sasl_mechanism) +{ + fe_scram_state *state; + char *prep_password; + pg_saslprep_rc rc; + + Assert(sasl_mechanism != NULL); + + state = (fe_scram_state *) malloc(sizeof(fe_scram_state)); + if (!state) + return NULL; + memset(state, 0, sizeof(fe_scram_state)); + state->conn = conn; + state->state = FE_SCRAM_INIT; + state->key_length = SCRAM_SHA_256_KEY_LEN; + state->hash_type = PG_SHA256; + + state->sasl_mechanism = strdup(sasl_mechanism); + if (!state->sasl_mechanism) + { + free(state); + return NULL; + } + + /* Normalize the password with SASLprep, if possible */ + rc = pg_saslprep(password, &prep_password); + if (rc == SASLPREP_OOM) + { + free(state->sasl_mechanism); + free(state); + return NULL; + } + if (rc != SASLPREP_SUCCESS) + { + prep_password = strdup(password); + if (!prep_password) + { + free(state->sasl_mechanism); + free(state); + return NULL; + } + } + state->password = prep_password; + + return state; +} + +/* + * Return true if channel binding was employed and the SCRAM exchange + * completed. This should be used after a successful exchange to determine + * whether the server authenticated itself to the client. + * + * Note that the caller must also ensure that the exchange was actually + * successful. + */ +static bool +scram_channel_bound(void *opaq) +{ + fe_scram_state *state = (fe_scram_state *) opaq; + + /* no SCRAM exchange done */ + if (state == NULL) + return false; + + /* SCRAM exchange not completed */ + if (state->state != FE_SCRAM_FINISHED) + return false; + + /* channel binding mechanism not used */ + if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0) + return false; + + /* all clear! */ + return true; +} + +/* + * Free SCRAM exchange status + */ +static void +scram_free(void *opaq) +{ + fe_scram_state *state = (fe_scram_state *) opaq; + + free(state->password); + free(state->sasl_mechanism); + + /* client messages */ + free(state->client_nonce); + free(state->client_first_message_bare); + free(state->client_final_message_without_proof); + + /* first message from server */ + free(state->server_first_message); + free(state->salt); + free(state->nonce); + + /* final message from server */ + free(state->server_final_message); + + free(state); +} + +/* + * Exchange a SCRAM message with backend. + */ +static void +scram_exchange(void *opaq, char *input, int inputlen, + char **output, int *outputlen, + bool *done, bool *success) +{ + fe_scram_state *state = (fe_scram_state *) opaq; + PGconn *conn = state->conn; + const char *errstr = NULL; + + *done = false; + *success = false; + *output = NULL; + *outputlen = 0; + + /* + * Check that the input length agrees with the string length of the input. + * We can ignore inputlen after this. + */ + if (state->state != FE_SCRAM_INIT) + { + if (inputlen == 0) + { + libpq_append_conn_error(conn, "malformed SCRAM message (empty message)"); + goto error; + } + if (inputlen != strlen(input)) + { + libpq_append_conn_error(conn, "malformed SCRAM message (length mismatch)"); + goto error; + } + } + + switch (state->state) + { + case FE_SCRAM_INIT: + /* Begin the SCRAM handshake, by sending client nonce */ + *output = build_client_first_message(state); + if (*output == NULL) + goto error; + + *outputlen = strlen(*output); + *done = false; + state->state = FE_SCRAM_NONCE_SENT; + break; + + case FE_SCRAM_NONCE_SENT: + /* Receive salt and server nonce, send response. */ + if (!read_server_first_message(state, input)) + goto error; + + *output = build_client_final_message(state); + if (*output == NULL) + goto error; + + *outputlen = strlen(*output); + *done = false; + state->state = FE_SCRAM_PROOF_SENT; + break; + + case FE_SCRAM_PROOF_SENT: + /* Receive server signature */ + if (!read_server_final_message(state, input)) + goto error; + + /* + * Verify server signature, to make sure we're talking to the + * genuine server. + */ + if (!verify_server_signature(state, success, &errstr)) + { + libpq_append_conn_error(conn, "could not verify server signature: %s", errstr); + goto error; + } + + if (!*success) + { + libpq_append_conn_error(conn, "incorrect server signature"); + } + *done = true; + state->state = FE_SCRAM_FINISHED; + state->conn->client_finished_auth = true; + break; + + default: + /* shouldn't happen */ + libpq_append_conn_error(conn, "invalid SCRAM exchange state"); + goto error; + } + return; + +error: + *done = true; + *success = false; +} + +/* + * Read value for an attribute part of a SCRAM message. + * + * The buffer at **input is destructively modified, and *input is + * advanced over the "attr=value" string and any following comma. + * + * On failure, append an error message to *errorMessage and return NULL. + */ +static char * +read_attr_value(char **input, char attr, PQExpBuffer errorMessage) +{ + char *begin = *input; + char *end; + + if (*begin != attr) + { + libpq_append_error(errorMessage, + "malformed SCRAM message (attribute \"%c\" expected)", + attr); + return NULL; + } + begin++; + + if (*begin != '=') + { + libpq_append_error(errorMessage, + "malformed SCRAM message (expected character \"=\" for attribute \"%c\")", + attr); + return NULL; + } + begin++; + + end = begin; + while (*end && *end != ',') + end++; + + if (*end) + { + *end = '\0'; + *input = end + 1; + } + else + *input = end; + + return begin; +} + +/* + * Build the first exchange message sent by the client. + */ +static char * +build_client_first_message(fe_scram_state *state) +{ + PGconn *conn = state->conn; + char raw_nonce[SCRAM_RAW_NONCE_LEN + 1]; + char *result; + int channel_info_len; + int encoded_len; + PQExpBufferData buf; + + /* + * Generate a "raw" nonce. This is converted to ASCII-printable form by + * base64-encoding it. + */ + if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN)) + { + libpq_append_conn_error(conn, "could not generate nonce"); + return NULL; + } + + encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN); + /* don't forget the zero-terminator */ + state->client_nonce = malloc(encoded_len + 1); + if (state->client_nonce == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return NULL; + } + encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, + state->client_nonce, encoded_len); + if (encoded_len < 0) + { + libpq_append_conn_error(conn, "could not encode nonce"); + return NULL; + } + state->client_nonce[encoded_len] = '\0'; + + /* + * Generate message. The username is left empty as the backend uses the + * value provided by the startup packet. Also, as this username is not + * prepared with SASLprep, the message parsing would fail if it includes + * '=' or ',' characters. + */ + + initPQExpBuffer(&buf); + + /* + * First build the gs2-header with channel binding information. + */ + if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0) + { + Assert(conn->ssl_in_use); + appendPQExpBufferStr(&buf, "p=tls-server-end-point"); + } +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH + else if (conn->channel_binding[0] != 'd' && /* disable */ + conn->ssl_in_use) + { + /* + * Client supports channel binding, but thinks the server does not. + */ + appendPQExpBufferChar(&buf, 'y'); + } +#endif + else + { + /* + * Client does not support channel binding, or has disabled it. + */ + appendPQExpBufferChar(&buf, 'n'); + } + + if (PQExpBufferDataBroken(buf)) + goto oom_error; + + channel_info_len = buf.len; + + appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce); + if (PQExpBufferDataBroken(buf)) + goto oom_error; + + /* + * The first message content needs to be saved without channel binding + * information. + */ + state->client_first_message_bare = strdup(buf.data + channel_info_len + 2); + if (!state->client_first_message_bare) + goto oom_error; + + result = strdup(buf.data); + if (result == NULL) + goto oom_error; + + termPQExpBuffer(&buf); + return result; + +oom_error: + termPQExpBuffer(&buf); + libpq_append_conn_error(conn, "out of memory"); + return NULL; +} + +/* + * Build the final exchange message sent from the client. + */ +static char * +build_client_final_message(fe_scram_state *state) +{ + PQExpBufferData buf; + PGconn *conn = state->conn; + uint8 client_proof[SCRAM_MAX_KEY_LEN]; + char *result; + int encoded_len; + const char *errstr = NULL; + + initPQExpBuffer(&buf); + + /* + * Construct client-final-message-without-proof. We need to remember it + * for verifying the server proof in the final step of authentication. + * + * The channel binding flag handling (p/y/n) must be consistent with + * build_client_first_message(), because the server will check that it's + * the same flag both times. + */ + if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0) + { +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH + char *cbind_data = NULL; + size_t cbind_data_len = 0; + size_t cbind_header_len; + char *cbind_input; + size_t cbind_input_len; + int encoded_cbind_len; + + /* Fetch hash data of server's SSL certificate */ + cbind_data = + pgtls_get_peer_certificate_hash(state->conn, + &cbind_data_len); + if (cbind_data == NULL) + { + /* error message is already set on error */ + termPQExpBuffer(&buf); + return NULL; + } + + appendPQExpBufferStr(&buf, "c="); + + /* p=type,, */ + cbind_header_len = strlen("p=tls-server-end-point,,"); + cbind_input_len = cbind_header_len + cbind_data_len; + cbind_input = malloc(cbind_input_len); + if (!cbind_input) + { + free(cbind_data); + goto oom_error; + } + memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len); + memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len); + + encoded_cbind_len = pg_b64_enc_len(cbind_input_len); + if (!enlargePQExpBuffer(&buf, encoded_cbind_len)) + { + free(cbind_data); + free(cbind_input); + goto oom_error; + } + encoded_cbind_len = pg_b64_encode(cbind_input, cbind_input_len, + buf.data + buf.len, + encoded_cbind_len); + if (encoded_cbind_len < 0) + { + free(cbind_data); + free(cbind_input); + termPQExpBuffer(&buf); + appendPQExpBufferStr(&conn->errorMessage, + "could not encode cbind data for channel binding\n"); + return NULL; + } + buf.len += encoded_cbind_len; + buf.data[buf.len] = '\0'; + + free(cbind_data); + free(cbind_input); +#else + /* + * Chose channel binding, but the SSL library doesn't support it. + * Shouldn't happen. + */ + termPQExpBuffer(&buf); + appendPQExpBufferStr(&conn->errorMessage, + "channel binding not supported by this build\n"); + return NULL; +#endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */ + } +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH + else if (conn->channel_binding[0] != 'd' && /* disable */ + conn->ssl_in_use) + appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */ +#endif + else + appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */ + + if (PQExpBufferDataBroken(buf)) + goto oom_error; + + appendPQExpBuffer(&buf, ",r=%s", state->nonce); + if (PQExpBufferDataBroken(buf)) + goto oom_error; + + state->client_final_message_without_proof = strdup(buf.data); + if (state->client_final_message_without_proof == NULL) + goto oom_error; + + /* Append proof to it, to form client-final-message. */ + if (!calculate_client_proof(state, + state->client_final_message_without_proof, + client_proof, &errstr)) + { + termPQExpBuffer(&buf); + libpq_append_conn_error(conn, "could not calculate client proof: %s", errstr); + return NULL; + } + + appendPQExpBufferStr(&buf, ",p="); + encoded_len = pg_b64_enc_len(state->key_length); + if (!enlargePQExpBuffer(&buf, encoded_len)) + goto oom_error; + encoded_len = pg_b64_encode((char *) client_proof, + state->key_length, + buf.data + buf.len, + encoded_len); + if (encoded_len < 0) + { + termPQExpBuffer(&buf); + libpq_append_conn_error(conn, "could not encode client proof"); + return NULL; + } + buf.len += encoded_len; + buf.data[buf.len] = '\0'; + + result = strdup(buf.data); + if (result == NULL) + goto oom_error; + + termPQExpBuffer(&buf); + return result; + +oom_error: + termPQExpBuffer(&buf); + libpq_append_conn_error(conn, "out of memory"); + return NULL; +} + +/* + * Read the first exchange message coming from the server. + */ +static bool +read_server_first_message(fe_scram_state *state, char *input) +{ + PGconn *conn = state->conn; + char *iterations_str; + char *endptr; + char *encoded_salt; + char *nonce; + int decoded_salt_len; + + state->server_first_message = strdup(input); + if (state->server_first_message == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return false; + } + + /* parse the message */ + nonce = read_attr_value(&input, 'r', + &conn->errorMessage); + if (nonce == NULL) + { + /* read_attr_value() has appended an error string */ + return false; + } + + /* Verify immediately that the server used our part of the nonce */ + if (strlen(nonce) < strlen(state->client_nonce) || + memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0) + { + libpq_append_conn_error(conn, "invalid SCRAM response (nonce mismatch)"); + return false; + } + + state->nonce = strdup(nonce); + if (state->nonce == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return false; + } + + encoded_salt = read_attr_value(&input, 's', &conn->errorMessage); + if (encoded_salt == NULL) + { + /* read_attr_value() has appended an error string */ + return false; + } + decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt)); + state->salt = malloc(decoded_salt_len); + if (state->salt == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return false; + } + state->saltlen = pg_b64_decode(encoded_salt, + strlen(encoded_salt), + state->salt, + decoded_salt_len); + if (state->saltlen < 0) + { + libpq_append_conn_error(conn, "malformed SCRAM message (invalid salt)"); + return false; + } + + iterations_str = read_attr_value(&input, 'i', &conn->errorMessage); + if (iterations_str == NULL) + { + /* read_attr_value() has appended an error string */ + return false; + } + state->iterations = strtol(iterations_str, &endptr, 10); + if (*endptr != '\0' || state->iterations < 1) + { + libpq_append_conn_error(conn, "malformed SCRAM message (invalid iteration count)"); + return false; + } + + if (*input != '\0') + libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-first-message)"); + + return true; +} + +/* + * Read the final exchange message coming from the server. + */ +static bool +read_server_final_message(fe_scram_state *state, char *input) +{ + PGconn *conn = state->conn; + char *encoded_server_signature; + char *decoded_server_signature; + int server_signature_len; + + state->server_final_message = strdup(input); + if (!state->server_final_message) + { + libpq_append_conn_error(conn, "out of memory"); + return false; + } + + /* Check for error result. */ + if (*input == 'e') + { + char *errmsg = read_attr_value(&input, 'e', + &conn->errorMessage); + + if (errmsg == NULL) + { + /* read_attr_value() has appended an error message */ + return false; + } + libpq_append_conn_error(conn, "error received from server in SCRAM exchange: %s", + errmsg); + return false; + } + + /* Parse the message. */ + encoded_server_signature = read_attr_value(&input, 'v', + &conn->errorMessage); + if (encoded_server_signature == NULL) + { + /* read_attr_value() has appended an error message */ + return false; + } + + if (*input != '\0') + libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-final-message)"); + + server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature)); + decoded_server_signature = malloc(server_signature_len); + if (!decoded_server_signature) + { + libpq_append_conn_error(conn, "out of memory"); + return false; + } + + server_signature_len = pg_b64_decode(encoded_server_signature, + strlen(encoded_server_signature), + decoded_server_signature, + server_signature_len); + if (server_signature_len != state->key_length) + { + free(decoded_server_signature); + libpq_append_conn_error(conn, "malformed SCRAM message (invalid server signature)"); + return false; + } + memcpy(state->ServerSignature, decoded_server_signature, + state->key_length); + free(decoded_server_signature); + + return true; +} + +/* + * Calculate the client proof, part of the final exchange message sent + * by the client. Returns true on success, false on failure with *errstr + * pointing to a message about the error details. + */ +static bool +calculate_client_proof(fe_scram_state *state, + const char *client_final_message_without_proof, + uint8 *result, const char **errstr) +{ + uint8 StoredKey[SCRAM_MAX_KEY_LEN]; + uint8 ClientKey[SCRAM_MAX_KEY_LEN]; + uint8 ClientSignature[SCRAM_MAX_KEY_LEN]; + int i; + pg_hmac_ctx *ctx; + + ctx = pg_hmac_create(state->hash_type); + if (ctx == NULL) + { + *errstr = pg_hmac_error(NULL); /* returns OOM */ + return false; + } + + /* + * Calculate SaltedPassword, and store it in 'state' so that we can reuse + * it later in verify_server_signature. + */ + if (scram_SaltedPassword(state->password, state->hash_type, + state->key_length, state->salt, state->saltlen, + state->iterations, state->SaltedPassword, + errstr) < 0 || + scram_ClientKey(state->SaltedPassword, state->hash_type, + state->key_length, ClientKey, errstr) < 0 || + scram_H(ClientKey, state->hash_type, state->key_length, + StoredKey, errstr) < 0) + { + /* errstr is already filled here */ + pg_hmac_free(ctx); + return false; + } + + if (pg_hmac_init(ctx, StoredKey, state->key_length) < 0 || + pg_hmac_update(ctx, + (uint8 *) state->client_first_message_bare, + strlen(state->client_first_message_bare)) < 0 || + pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 || + pg_hmac_update(ctx, + (uint8 *) state->server_first_message, + strlen(state->server_first_message)) < 0 || + pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 || + pg_hmac_update(ctx, + (uint8 *) client_final_message_without_proof, + strlen(client_final_message_without_proof)) < 0 || + pg_hmac_final(ctx, ClientSignature, state->key_length) < 0) + { + *errstr = pg_hmac_error(ctx); + pg_hmac_free(ctx); + return false; + } + + for (i = 0; i < state->key_length; i++) + result[i] = ClientKey[i] ^ ClientSignature[i]; + + pg_hmac_free(ctx); + return true; +} + +/* + * Validate the server signature, received as part of the final exchange + * message received from the server. *match tracks if the server signature + * matched or not. Returns true if the server signature got verified, and + * false for a processing error with *errstr pointing to a message about the + * error details. + */ +static bool +verify_server_signature(fe_scram_state *state, bool *match, + const char **errstr) +{ + uint8 expected_ServerSignature[SCRAM_MAX_KEY_LEN]; + uint8 ServerKey[SCRAM_MAX_KEY_LEN]; + pg_hmac_ctx *ctx; + + ctx = pg_hmac_create(state->hash_type); + if (ctx == NULL) + { + *errstr = pg_hmac_error(NULL); /* returns OOM */ + return false; + } + + if (scram_ServerKey(state->SaltedPassword, state->hash_type, + state->key_length, ServerKey, errstr) < 0) + { + /* errstr is filled already */ + pg_hmac_free(ctx); + return false; + } + + /* calculate ServerSignature */ + if (pg_hmac_init(ctx, ServerKey, state->key_length) < 0 || + pg_hmac_update(ctx, + (uint8 *) state->client_first_message_bare, + strlen(state->client_first_message_bare)) < 0 || + pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 || + pg_hmac_update(ctx, + (uint8 *) state->server_first_message, + strlen(state->server_first_message)) < 0 || + pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 || + pg_hmac_update(ctx, + (uint8 *) state->client_final_message_without_proof, + strlen(state->client_final_message_without_proof)) < 0 || + pg_hmac_final(ctx, expected_ServerSignature, + state->key_length) < 0) + { + *errstr = pg_hmac_error(ctx); + pg_hmac_free(ctx); + return false; + } + + pg_hmac_free(ctx); + + /* signature processed, so now check after it */ + if (memcmp(expected_ServerSignature, state->ServerSignature, + state->key_length) != 0) + *match = false; + else + *match = true; + + return true; +} + +/* + * Build a new SCRAM secret. + * + * On error, returns NULL and sets *errstr to point to a message about the + * error details. + */ +char * +pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr) +{ + char *prep_password; + pg_saslprep_rc rc; + char saltbuf[SCRAM_DEFAULT_SALT_LEN]; + char *result; + + /* + * Normalize the password with SASLprep. If that doesn't work, because + * the password isn't valid UTF-8 or contains prohibited characters, just + * proceed with the original password. (See comments at the top of + * auth-scram.c.) + */ + rc = pg_saslprep(password, &prep_password); + if (rc == SASLPREP_OOM) + { + *errstr = libpq_gettext("out of memory"); + return NULL; + } + if (rc == SASLPREP_SUCCESS) + password = (const char *) prep_password; + + /* Generate a random salt */ + if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN)) + { + *errstr = libpq_gettext("could not generate random salt"); + free(prep_password); + return NULL; + } + + result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN, saltbuf, + SCRAM_DEFAULT_SALT_LEN, + iterations, password, + errstr); + + free(prep_password); + + return result; +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c b/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c new file mode 100644 index 0000000000..fce7f3da38 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-auth.c @@ -0,0 +1,1385 @@ +/*------------------------------------------------------------------------- + * + * fe-auth.c + * The front-end (client) authorization routines + * + * Portions Copyright (c) 1996-2023, 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 <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/param.h> /* for MAXHOSTNAMELEN on most */ +#include <sys/socket.h> +#ifdef HAVE_SYS_UCRED_H +#include <sys/ucred.h> +#endif +#ifndef MAXHOSTNAMELEN +#include <netdb.h> /* for MAXHOSTNAMELEN on some */ +#endif +#endif + +#include "common/md5.h" +#include "common/scram-common.h" +#include "fe-auth.h" +#include "fe-auth-sasl.h" +#include "libpq-fe.h" + +#ifdef ENABLE_GSS +/* + * GSSAPI authentication system. + */ + +#error #include "fe-gssapi-common.h" + +/* + * Continue GSS authentication with next token as needed. + */ +static int +pg_GSS_continue(PGconn *conn, int payloadlen) +{ + OM_uint32 maj_stat, + min_stat, + lmin_s, + gss_flags = GSS_C_MUTUAL_FLAG; + gss_buffer_desc ginbuf; + gss_buffer_desc goutbuf; + + /* + * On first call, there's no input token. On subsequent calls, read the + * input token into a GSS buffer. + */ + if (conn->gctx != GSS_C_NO_CONTEXT) + { + ginbuf.length = payloadlen; + ginbuf.value = malloc(payloadlen); + if (!ginbuf.value) + { + libpq_append_conn_error(conn, "out of memory allocating GSSAPI buffer (%d)", + payloadlen); + return STATUS_ERROR; + } + if (pqGetnchar(ginbuf.value, payloadlen, conn)) + { + /* + * Shouldn't happen, because the caller should've ensured that the + * whole message is already in the input buffer. + */ + free(ginbuf.value); + return STATUS_ERROR; + } + } + else + { + ginbuf.length = 0; + ginbuf.value = NULL; + } + + /* Only try to acquire credentials if GSS delegation isn't disabled. */ + if (!pg_GSS_have_cred_cache(&conn->gcred)) + conn->gcred = GSS_C_NO_CREDENTIAL; + + if (conn->gssdelegation && conn->gssdelegation[0] == '1') + gss_flags |= GSS_C_DELEG_FLAG; + + maj_stat = gss_init_sec_context(&min_stat, + conn->gcred, + &conn->gctx, + conn->gtarg_nam, + GSS_C_NO_OID, + gss_flags, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf, + NULL, + &goutbuf, + NULL, + NULL); + + free(ginbuf.value); + + if (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', + goutbuf.value, goutbuf.length) != STATUS_OK) + { + gss_release_buffer(&lmin_s, &goutbuf); + return STATUS_ERROR; + } + } + gss_release_buffer(&lmin_s, &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) + { + conn->client_finished_auth = true; + gss_release_name(&lmin_s, &conn->gtarg_nam); + conn->gssapi_used = true; + } + + return STATUS_OK; +} + +/* + * Send initial GSS authentication token + */ +static int +pg_GSS_startup(PGconn *conn, int payloadlen) +{ + int ret; + char *host = conn->connhost[conn->whichhost].host; + + if (!(host && host[0] != '\0')) + { + libpq_append_conn_error(conn, "host name must be specified"); + return STATUS_ERROR; + } + + if (conn->gctx) + { + libpq_append_conn_error(conn, "duplicate GSS authentication request"); + return STATUS_ERROR; + } + + ret = pg_GSS_load_servicename(conn); + if (ret != STATUS_OK) + return ret; + + /* + * Initial packet is the same as a continuation packet with no initial + * context. + */ + conn->gctx = GSS_C_NO_CONTEXT; + + return pg_GSS_continue(conn, payloadlen); +} +#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) + appendPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n", + mprefix, (unsigned int) r); + else + appendPQExpBuffer(&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, int payloadlen) +{ + SECURITY_STATUS r; + CtxtHandle newContext; + ULONG contextAttr; + SecBufferDesc inbuf; + SecBufferDesc outbuf; + SecBuffer OutBuffers[1]; + SecBuffer InBuffers[1]; + char *inputbuf = NULL; + + if (conn->sspictx != NULL) + { + /* + * On runs other than the first we have some data to send. Put this + * data in a SecBuffer type structure. + */ + inputbuf = malloc(payloadlen); + if (!inputbuf) + { + libpq_append_conn_error(conn, "out of memory allocating SSPI buffer (%d)", + payloadlen); + return STATUS_ERROR; + } + if (pqGetnchar(inputbuf, payloadlen, conn)) + { + /* + * Shouldn't happen, because the caller should've ensured that the + * whole message is already in the input buffer. + */ + free(inputbuf); + return STATUS_ERROR; + } + + inbuf.ulVersion = SECBUFFER_VERSION; + inbuf.cBuffers = 1; + inbuf.pBuffers = InBuffers; + InBuffers[0].pvBuffer = inputbuf; + InBuffers[0].cbBuffer = payloadlen; + 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); + + /* we don't need the input anymore */ + free(inputbuf); + + 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) + { + libpq_append_conn_error(conn, "out of memory"); + return STATUS_ERROR; + } + memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); + } + + /* + * 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. + */ + appendPQExpBufferStr(&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); + } + + if (r == SEC_E_OK) + conn->client_finished_auth = true; + + /* 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, int payloadlen) +{ + SECURITY_STATUS r; + TimeStamp expire; + char *host = conn->connhost[conn->whichhost].host; + + if (conn->sspictx) + { + libpq_append_conn_error(conn, "duplicate SSPI authentication request"); + return STATUS_ERROR; + } + + /* + * Retrieve credentials handle + */ + conn->sspicred = malloc(sizeof(CredHandle)); + if (conn->sspicred == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + 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 (!(host && host[0] != '\0')) + { + libpq_append_conn_error(conn, "host name must be specified"); + return STATUS_ERROR; + } + conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2); + if (!conn->sspitarget) + { + libpq_append_conn_error(conn, "out of memory"); + return STATUS_ERROR; + } + sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host); + + /* + * 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, payloadlen); +} +#endif /* ENABLE_SSPI */ + +/* + * Initialize SASL authentication exchange. + */ +static int +pg_SASL_init(PGconn *conn, int payloadlen) +{ + char *initialresponse = NULL; + int initialresponselen; + bool done; + bool success; + const char *selected_mechanism; + PQExpBufferData mechanism_buf; + char *password; + + initPQExpBuffer(&mechanism_buf); + + if (conn->channel_binding[0] == 'r' && /* require */ + !conn->ssl_in_use) + { + libpq_append_conn_error(conn, "channel binding required, but SSL not in use"); + goto error; + } + + if (conn->sasl_state) + { + libpq_append_conn_error(conn, "duplicate SASL authentication request"); + goto error; + } + + /* + * Parse the list of SASL authentication mechanisms in the + * AuthenticationSASL message, and select the best mechanism that we + * support. SCRAM-SHA-256-PLUS and SCRAM-SHA-256 are the only ones + * supported at the moment, listed by order of decreasing importance. + */ + selected_mechanism = NULL; + for (;;) + { + if (pqGets(&mechanism_buf, conn)) + { + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n"); + goto error; + } + if (PQExpBufferDataBroken(mechanism_buf)) + goto oom_error; + + /* An empty string indicates end of list */ + if (mechanism_buf.data[0] == '\0') + break; + + /* + * Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything + * else if a channel binding type is set and if the client supports it + * (and did not set channel_binding=disable). Pick SCRAM-SHA-256 if + * nothing else has already been picked. If we add more mechanisms, a + * more refined priority mechanism might become necessary. + */ + if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0) + { + if (conn->ssl_in_use) + { + /* The server has offered SCRAM-SHA-256-PLUS. */ + +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH + /* + * The client supports channel binding, which is chosen if + * channel_binding is not disabled. + */ + if (conn->channel_binding[0] != 'd') /* disable */ + { + selected_mechanism = SCRAM_SHA_256_PLUS_NAME; + conn->sasl = &pg_scram_mech; + } +#else + /* + * The client does not support channel binding. If it is + * required, complain immediately instead of the error below + * which would be confusing as the server is publishing + * SCRAM-SHA-256-PLUS. + */ + if (conn->channel_binding[0] == 'r') /* require */ + { + libpq_append_conn_error(conn, "channel binding is required, but client does not support it"); + goto error; + } +#endif + } + else + { + /* + * The server offered SCRAM-SHA-256-PLUS, but the connection + * is not SSL-encrypted. That's not sane. Perhaps SSL was + * stripped by a proxy? There's no point in continuing, + * because the server will reject the connection anyway if we + * try authenticate without channel binding even though both + * the client and server supported it. The SCRAM exchange + * checks for that, to prevent downgrade attacks. + */ + libpq_append_conn_error(conn, "server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection"); + goto error; + } + } + else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 && + !selected_mechanism) + { + selected_mechanism = SCRAM_SHA_256_NAME; + conn->sasl = &pg_scram_mech; + } + } + + if (!selected_mechanism) + { + libpq_append_conn_error(conn, "none of the server's SASL authentication mechanisms are supported"); + goto error; + } + + if (conn->channel_binding[0] == 'r' && /* require */ + strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0) + { + libpq_append_conn_error(conn, "channel binding is required, but server did not offer an authentication method that supports channel binding"); + goto error; + } + + /* + * Now that the SASL mechanism has been chosen for the exchange, + * initialize its state information. + */ + + /* + * First, select the password to use for the exchange, complaining if + * there isn't one. Currently, all supported SASL mechanisms require a + * password, so we can just go ahead here without further distinction. + */ + conn->password_needed = true; + password = conn->connhost[conn->whichhost].password; + if (password == NULL) + password = conn->pgpass; + if (password == NULL || password[0] == '\0') + { + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); + goto error; + } + + Assert(conn->sasl); + + /* + * Initialize the SASL state information with all the information gathered + * during the initial exchange. + * + * Note: Only tls-unique is supported for the moment. + */ + conn->sasl_state = conn->sasl->init(conn, + password, + selected_mechanism); + if (!conn->sasl_state) + goto oom_error; + + /* Get the mechanism-specific Initial Client Response, if any */ + conn->sasl->exchange(conn->sasl_state, + NULL, -1, + &initialresponse, &initialresponselen, + &done, &success); + + if (done && !success) + goto error; + + /* + * Build a SASLInitialResponse message, and send it. + */ + if (pqPutMsgStart('p', conn)) + goto error; + if (pqPuts(selected_mechanism, conn)) + goto error; + if (initialresponse) + { + if (pqPutInt(initialresponselen, 4, conn)) + goto error; + if (pqPutnchar(initialresponse, initialresponselen, conn)) + goto error; + } + if (pqPutMsgEnd(conn)) + goto error; + if (pqFlush(conn)) + goto error; + + termPQExpBuffer(&mechanism_buf); + free(initialresponse); + + return STATUS_OK; + +error: + termPQExpBuffer(&mechanism_buf); + free(initialresponse); + return STATUS_ERROR; + +oom_error: + termPQExpBuffer(&mechanism_buf); + free(initialresponse); + libpq_append_conn_error(conn, "out of memory"); + return STATUS_ERROR; +} + +/* + * Exchange a message for SASL communication protocol with the backend. + * This should be used after calling pg_SASL_init to set up the status of + * the protocol. + */ +static int +pg_SASL_continue(PGconn *conn, int payloadlen, bool final) +{ + char *output; + int outputlen; + bool done; + bool success; + int res; + char *challenge; + + /* Read the SASL challenge from the AuthenticationSASLContinue message. */ + challenge = malloc(payloadlen + 1); + if (!challenge) + { + libpq_append_conn_error(conn, "out of memory allocating SASL buffer (%d)", + payloadlen); + return STATUS_ERROR; + } + + if (pqGetnchar(challenge, payloadlen, conn)) + { + free(challenge); + return STATUS_ERROR; + } + /* For safety and convenience, ensure the buffer is NULL-terminated. */ + challenge[payloadlen] = '\0'; + + conn->sasl->exchange(conn->sasl_state, + challenge, payloadlen, + &output, &outputlen, + &done, &success); + free(challenge); /* don't need the input anymore */ + + if (final && !done) + { + if (outputlen != 0) + free(output); + + libpq_append_conn_error(conn, "AuthenticationSASLFinal received from server, but SASL authentication was not completed"); + return STATUS_ERROR; + } + + /* + * If the exchange is not completed yet, we need to make sure that the + * SASL mechanism has generated a message to send back. + */ + if (output == NULL && !done) + { + libpq_append_conn_error(conn, "no client response found after SASL exchange success"); + return STATUS_ERROR; + } + + /* + * SASL allows zero-length responses, so this check uses "output" and not + * "outputlen" to allow the case of an empty message. + */ + if (output) + { + /* + * Send the SASL response to the server. + */ + res = pqPacketSend(conn, 'p', output, outputlen); + free(output); + + if (res != STATUS_OK) + return STATUS_ERROR; + } + + if (done && !success) + return STATUS_ERROR; + + return STATUS_OK; +} + +static int +pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) +{ + int ret; + char *crypt_pwd = NULL; + const char *pwd_to_send; + char md5Salt[4]; + + /* Read the salt from the AuthenticationMD5Password message. */ + if (areq == AUTH_REQ_MD5) + { + if (pqGetnchar(md5Salt, 4, conn)) + return STATUS_ERROR; /* shouldn't happen */ + } + + /* Encrypt the password if needed. */ + + switch (areq) + { + case AUTH_REQ_MD5: + { + char *crypt_pwd2; + const char *errstr = NULL; + + /* Allocate enough space for two MD5 hashes */ + crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1)); + if (!crypt_pwd) + { + libpq_append_conn_error(conn, "out of memory"); + return STATUS_ERROR; + } + + crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1; + if (!pg_md5_encrypt(password, conn->pguser, + strlen(conn->pguser), crypt_pwd2, + &errstr)) + { + libpq_append_conn_error(conn, "could not encrypt password: %s", errstr); + free(crypt_pwd); + return STATUS_ERROR; + } + if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt, + 4, crypt_pwd, &errstr)) + { + libpq_append_conn_error(conn, "could not encrypt password: %s", errstr); + 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; + } + ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1); + free(crypt_pwd); + return ret; +} + +/* + * Translate a disallowed AuthRequest code into an error message. + */ +static const char * +auth_method_description(AuthRequest areq) +{ + switch (areq) + { + case AUTH_REQ_PASSWORD: + return libpq_gettext("server requested a cleartext password"); + case AUTH_REQ_MD5: + return libpq_gettext("server requested a hashed password"); + case AUTH_REQ_GSS: + case AUTH_REQ_GSS_CONT: + return libpq_gettext("server requested GSSAPI authentication"); + case AUTH_REQ_SSPI: + return libpq_gettext("server requested SSPI authentication"); + case AUTH_REQ_SASL: + case AUTH_REQ_SASL_CONT: + case AUTH_REQ_SASL_FIN: + return libpq_gettext("server requested SASL authentication"); + } + + return libpq_gettext("server requested an unknown authentication type"); +} + +/* + * Convenience macro for checking the allowed_auth_methods bitmask. Caller + * must ensure that type is not greater than 31 (high bit of the bitmask). + */ +#define auth_method_allowed(conn, type) \ + (((conn)->allowed_auth_methods & (1 << (type))) != 0) + +/* + * Verify that the authentication request is expected, given the connection + * parameters. This is especially important when the client wishes to + * authenticate the server before any sensitive information is exchanged. + */ +static bool +check_expected_areq(AuthRequest areq, PGconn *conn) +{ + bool result = true; + const char *reason = NULL; + + StaticAssertDecl((sizeof(conn->allowed_auth_methods) * CHAR_BIT) > AUTH_REQ_MAX, + "AUTH_REQ_MAX overflows the allowed_auth_methods bitmask"); + + if (conn->sslcertmode[0] == 'r' /* require */ + && areq == AUTH_REQ_OK) + { + /* + * Trade off a little bit of complexity to try to get these error + * messages as precise as possible. + */ + if (!conn->ssl_cert_requested) + { + libpq_append_conn_error(conn, "server did not request an SSL certificate"); + return false; + } + else if (!conn->ssl_cert_sent) + { + libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate"); + return false; + } + } + + /* + * If the user required a specific auth method, or specified an allowed + * set, then reject all others here, and make sure the server actually + * completes an authentication exchange. + */ + if (conn->require_auth) + { + switch (areq) + { + case AUTH_REQ_OK: + + /* + * Check to make sure we've actually finished our exchange (or + * else that the user has allowed an authentication-less + * connection). + * + * If the user has allowed both SCRAM and unauthenticated + * (trust) connections, then this check will silently accept + * partial SCRAM exchanges, where a misbehaving server does + * not provide its verifier before sending an OK. This is + * consistent with historical behavior, but it may be a point + * to revisit in the future, since it could allow a server + * that doesn't know the user's password to silently harvest + * material for a brute force attack. + */ + if (!conn->auth_required || conn->client_finished_auth) + break; + + /* + * No explicit authentication request was made by the server + * -- or perhaps it was made and not completed, in the case of + * SCRAM -- but there is one special case to check. If the + * user allowed "gss", then a GSS-encrypted channel also + * satisfies the check. + */ +#ifdef ENABLE_GSS + if (auth_method_allowed(conn, AUTH_REQ_GSS) && conn->gssenc) + { + /* + * If implicit GSS auth has already been performed via GSS + * encryption, we don't need to have performed an + * AUTH_REQ_GSS exchange. This allows require_auth=gss to + * be combined with gssencmode, since there won't be an + * explicit authentication request in that case. + */ + } + else +#endif + { + reason = libpq_gettext("server did not complete authentication"); + result = false; + } + + break; + + case AUTH_REQ_PASSWORD: + case AUTH_REQ_MD5: + case AUTH_REQ_GSS: + case AUTH_REQ_GSS_CONT: + case AUTH_REQ_SSPI: + case AUTH_REQ_SASL: + case AUTH_REQ_SASL_CONT: + case AUTH_REQ_SASL_FIN: + + /* + * We don't handle these with the default case, to avoid + * bit-shifting past the end of the allowed_auth_methods mask + * if the server sends an unexpected AuthRequest. + */ + result = auth_method_allowed(conn, areq); + break; + + default: + result = false; + break; + } + } + + if (!result) + { + if (!reason) + reason = auth_method_description(areq); + + libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: %s", + conn->require_auth, reason); + return result; + } + + /* + * When channel_binding=require, we must protect against two cases: (1) we + * must not respond to non-SASL authentication requests, which might leak + * information such as the client's password; and (2) even if we receive + * AUTH_REQ_OK, we still must ensure that channel binding has happened in + * order to authenticate the server. + */ + if (conn->channel_binding[0] == 'r' /* require */ ) + { + switch (areq) + { + case AUTH_REQ_SASL: + case AUTH_REQ_SASL_CONT: + case AUTH_REQ_SASL_FIN: + break; + case AUTH_REQ_OK: + if (!conn->sasl || !conn->sasl->channel_bound(conn->sasl_state)) + { + libpq_append_conn_error(conn, "channel binding required, but server authenticated client without channel binding"); + result = false; + } + break; + default: + libpq_append_conn_error(conn, "channel binding required but not supported by server's authentication request"); + result = false; + break; + } + } + + return result; +} + +/* + * pg_fe_sendauth + * client demux routine for processing an authentication request + * + * The server has sent us an authentication challenge (or OK). Send an + * appropriate response. The caller has ensured that the whole message is + * now in the input buffer, and has already read the type and length of + * it. We are responsible for reading any remaining extra data, specific + * to the authentication method. 'payloadlen' is the remaining length in + * the message. + */ +int +pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) +{ + int oldmsglen; + + if (!check_expected_areq(areq, conn)) + return STATUS_ERROR; + + switch (areq) + { + case AUTH_REQ_OK: + break; + + case AUTH_REQ_KRB4: + libpq_append_conn_error(conn, "Kerberos 4 authentication not supported"); + return STATUS_ERROR; + + case AUTH_REQ_KRB5: + libpq_append_conn_error(conn, "Kerberos 5 authentication not supported"); + 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, payloadlen); + else + r = pg_SSPI_startup(conn, 0, payloadlen); +#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) + r = pg_GSS_startup(conn, payloadlen); +#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) + r = pg_SSPI_startup(conn, 0, payloadlen); +#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, payloadlen); + else + r = pg_GSS_continue(conn, payloadlen); +#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI) + r = pg_GSS_continue(conn, payloadlen); +#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI) + r = pg_SSPI_continue(conn, payloadlen); +#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: + libpq_append_conn_error(conn, "GSSAPI authentication not supported"); + return STATUS_ERROR; +#endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */ + +#ifdef ENABLE_SSPI + case AUTH_REQ_SSPI: + + /* + * SSPI has its 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, payloadlen) != 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_GSS above, so don't duplicate the case label in + * that case. + */ +#if !defined(ENABLE_GSS) + case AUTH_REQ_SSPI: + libpq_append_conn_error(conn, "SSPI authentication not supported"); + return STATUS_ERROR; +#endif /* !define(ENABLE_GSS) */ +#endif /* ENABLE_SSPI */ + + + case AUTH_REQ_CRYPT: + libpq_append_conn_error(conn, "Crypt authentication not supported"); + return STATUS_ERROR; + + case AUTH_REQ_MD5: + case AUTH_REQ_PASSWORD: + { + char *password; + + conn->password_needed = true; + password = conn->connhost[conn->whichhost].password; + if (password == NULL) + password = conn->pgpass; + if (password == NULL || password[0] == '\0') + { + appendPQExpBufferStr(&conn->errorMessage, + PQnoPasswordSupplied); + return STATUS_ERROR; + } + if (pg_password_sendauth(conn, password, areq) != STATUS_OK) + { + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error sending password authentication\n"); + return STATUS_ERROR; + } + + /* We expect no further authentication requests. */ + conn->client_finished_auth = true; + break; + } + + case AUTH_REQ_SASL: + + /* + * The request contains the name (as assigned by IANA) of the + * authentication mechanism. + */ + if (pg_SASL_init(conn, payloadlen) != STATUS_OK) + { + /* pg_SASL_init already set the error message */ + return STATUS_ERROR; + } + break; + + case AUTH_REQ_SASL_CONT: + case AUTH_REQ_SASL_FIN: + if (conn->sasl_state == NULL) + { + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n"); + return STATUS_ERROR; + } + oldmsglen = conn->errorMessage.len; + if (pg_SASL_continue(conn, payloadlen, + (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK) + { + /* Use this message if pg_SASL_continue didn't supply one */ + if (conn->errorMessage.len == oldmsglen) + appendPQExpBufferStr(&conn->errorMessage, + "fe_sendauth: error in SASL authentication\n"); + return STATUS_ERROR; + } + break; + + default: + libpq_append_conn_error(conn, "authentication method %u not supported", areq); + return STATUS_ERROR; + } + + return STATUS_OK; +} + + +/* + * pg_fe_getusername + * + * Returns a pointer to malloc'd space containing the name of the + * specified user_id. If there is an error, return NULL, and append + * a suitable error message to *errorMessage if that's not NULL. + * + * Caution: on Windows, the user_id argument is ignored, and we always + * fetch the current user's name. + */ +char * +pg_fe_getusername(uid_t user_id, 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 + char pwdbuf[BUFSIZ]; +#endif + + /* + * Some users are using configure --enable-thread-safety-force, so we + * might as well do the locking within our library to protect getpwuid(). + * 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) + libpq_append_error(errorMessage, + "user name lookup failure: error code %lu", + GetLastError()); +#else + if (pg_get_user_name(user_id, pwdbuf, sizeof(pwdbuf))) + name = pwdbuf; + else if (errorMessage) + appendPQExpBuffer(errorMessage, "%s\n", pwdbuf); +#endif + + if (name) + { + result = strdup(name); + if (result == NULL && errorMessage) + libpq_append_error(errorMessage, "out of memory"); + } + + pgunlock_thread(); + + return result; +} + +/* + * 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 append a suitable error message to *errorMessage if that's not NULL. + */ +char * +pg_fe_getauthname(PQExpBuffer errorMessage) +{ +#ifdef WIN32 + return pg_fe_getusername(0, errorMessage); +#else + return pg_fe_getusername(geteuid(), errorMessage); +#endif +} + + +/* + * PQencryptPassword -- exported routine to encrypt a password with MD5 + * + * This function is equivalent to calling PQencryptPasswordConn with + * "md5" as the encryption method, except that this doesn't require + * a connection object. This function is deprecated, use + * PQencryptPasswordConn instead. + */ +char * +PQencryptPassword(const char *passwd, const char *user) +{ + char *crypt_pwd; + const char *errstr = NULL; + + crypt_pwd = malloc(MD5_PASSWD_LEN + 1); + if (!crypt_pwd) + return NULL; + + if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd, &errstr)) + { + free(crypt_pwd); + return NULL; + } + + return crypt_pwd; +} + +/* + * PQencryptPasswordConn -- 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 a connection object, the cleartext password, the SQL + * name of the user it is for, and a string indicating the algorithm to + * use for encrypting the password. If algorithm is NULL, this queries + * the server for the current 'password_encryption' value. If you wish + * to avoid that, e.g. to avoid blocking, you can execute + * 'show password_encryption' yourself before calling this function, and + * pass it as the algorithm. + * + * Return value is a malloc'd string. The client may assume the string + * doesn't contain any special characters that would require escaping. + * On error, an error message is stored in the connection object, and + * returns NULL. + */ +char * +PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, + const char *algorithm) +{ +#define MAX_ALGORITHM_NAME_LEN 50 + char algobuf[MAX_ALGORITHM_NAME_LEN + 1]; + char *crypt_pwd = NULL; + + if (!conn) + return NULL; + + pqClearConnErrorState(conn); + + /* If no algorithm was given, ask the server. */ + if (algorithm == NULL) + { + PGresult *res; + char *val; + + res = PQexec(conn, "show password_encryption"); + if (res == NULL) + { + /* PQexec() should've set conn->errorMessage already */ + return NULL; + } + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + /* PQexec() should've set conn->errorMessage already */ + PQclear(res); + return NULL; + } + if (PQntuples(res) != 1 || PQnfields(res) != 1) + { + PQclear(res); + libpq_append_conn_error(conn, "unexpected shape of result set returned for SHOW"); + return NULL; + } + val = PQgetvalue(res, 0, 0); + + if (strlen(val) > MAX_ALGORITHM_NAME_LEN) + { + PQclear(res); + libpq_append_conn_error(conn, "password_encryption value too long"); + return NULL; + } + strcpy(algobuf, val); + PQclear(res); + + algorithm = algobuf; + } + + /* + * Also accept "on" and "off" as aliases for "md5", because + * password_encryption was a boolean before PostgreSQL 10. We refuse to + * send the password in plaintext even if it was "off". + */ + if (strcmp(algorithm, "on") == 0 || + strcmp(algorithm, "off") == 0) + algorithm = "md5"; + + /* + * Ok, now we know what algorithm to use + */ + if (strcmp(algorithm, "scram-sha-256") == 0) + { + const char *errstr = NULL; + + crypt_pwd = pg_fe_scram_build_secret(passwd, + conn->scram_sha_256_iterations, + &errstr); + if (!crypt_pwd) + libpq_append_conn_error(conn, "could not encrypt password: %s", errstr); + } + else if (strcmp(algorithm, "md5") == 0) + { + crypt_pwd = malloc(MD5_PASSWD_LEN + 1); + if (crypt_pwd) + { + const char *errstr = NULL; + + if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd, &errstr)) + { + libpq_append_conn_error(conn, "could not encrypt password: %s", errstr); + free(crypt_pwd); + crypt_pwd = NULL; + } + } + else + libpq_append_conn_error(conn, "out of memory"); + } + else + { + libpq_append_conn_error(conn, "unrecognized password encryption algorithm \"%s\"", + algorithm); + return NULL; + } + + return crypt_pwd; +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-auth.h b/contrib/libs/libpq/src/interfaces/libpq/fe-auth.h new file mode 100644 index 0000000000..124dd5d031 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-auth.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * fe-auth.h + * + * Definitions for network authentication routines + * + * Portions Copyright (c) 1996-2023, 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" + + +/* Prototypes for functions in fe-auth.c */ +extern int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn); +extern char *pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage); +extern char *pg_fe_getauthname(PQExpBuffer errorMessage); + +/* Mechanisms in fe-auth-scram.c */ +extern const pg_fe_sasl_mech pg_scram_mech; +extern char *pg_fe_scram_build_secret(const char *password, + int iterations, + const char **errstr); + +#endif /* FE_AUTH_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c b/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c new file mode 100644 index 0000000000..a61eec7282 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-connect.c @@ -0,0 +1,7831 @@ +/*------------------------------------------------------------------------- + * + * fe-connect.c + * functions related to setting up a connection to the backend + * + * Portions Copyright (c) 1996-2023, 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 <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <netdb.h> +#include <time.h> +#include <unistd.h> + +#include "common/ip.h" +#include "common/link-canary.h" +#include "common/scram-common.h" +#include "common/string.h" +#include "fe-auth.h" +#include "libpq-fe.h" +#include "libpq-int.h" +#include "mb/pg_wchar.h" +#include "pg_config_paths.h" +#include "port/pg_bswap.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 <shlobj.h> +#include <mstcpip.h> +#else +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#endif + +#ifdef ENABLE_THREAD_SAFETY +#ifdef WIN32 +#include "pthread-win32.h" +#else +#include <pthread.h> +#endif +#endif + +#ifdef USE_LDAP +#ifdef WIN32 +#include <winldap.h> +#else +/* OpenLDAP deprecates RFC 1823, but we want standard conformance */ +#define LDAP_DEPRECATED 1 +#error #include <ldap.h> +typedef struct timeval LDAP_TIMEVAL; +#endif +static int ldapServiceLookup(const char *purl, PQconninfoOption *options, + PQExpBuffer errorMessage); +#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 DefaultOption "" +#ifdef USE_SSL +#define DefaultChannelBinding "prefer" +#else +#define DefaultChannelBinding "disable" +#endif +#define DefaultTargetSessionAttrs "any" +#define DefaultLoadBalanceHosts "disable" +#ifdef USE_SSL +#define DefaultSSLMode "prefer" +#define DefaultSSLCertMode "allow" +#else +#define DefaultSSLMode "disable" +#define DefaultSSLCertMode "disable" +#endif +#ifdef ENABLE_GSS +#error #include "fe-gssapi-common.h" +#define DefaultGSSMode "prefer" +#else +#define DefaultGSSMode "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[] = { + {"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)}, + + {"passfile", "PGPASSFILE", NULL, NULL, + "Database-Password-File", "", 64, + offsetof(struct pg_conn, pgpassfile)}, + + {"channel_binding", "PGCHANNELBINDING", DefaultChannelBinding, NULL, + "Channel-Binding", "", 8, /* sizeof("require") == 8 */ + offsetof(struct pg_conn, channel_binding)}, + + {"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)}, + + {"options", "PGOPTIONS", DefaultOption, NULL, + "Backend-Options", "", 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)}, + + {"tcp_user_timeout", NULL, NULL, NULL, + "TCP-User-Timeout", "", 10, /* strlen(INT32_MAX) == 10 */ + offsetof(struct pg_conn, pgtcp_user_timeout)}, + + /* + * 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", "0", 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)}, + + {"sslcertmode", "PGSSLCERTMODE", NULL, NULL, + "SSL-Client-Cert-Mode", "", 8, /* sizeof("disable") == 8 */ + offsetof(struct pg_conn, sslcertmode)}, + + {"sslpassword", NULL, NULL, NULL, + "SSL-Client-Key-Password", "*", 20, + offsetof(struct pg_conn, sslpassword)}, + + {"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)}, + + {"sslcrldir", "PGSSLCRLDIR", NULL, NULL, + "SSL-Revocation-List-Dir", "", 64, + offsetof(struct pg_conn, sslcrldir)}, + + {"sslsni", "PGSSLSNI", "1", NULL, + "SSL-SNI", "", 1, + offsetof(struct pg_conn, sslsni)}, + + {"requirepeer", "PGREQUIREPEER", NULL, NULL, + "Require-Peer", "", 10, + offsetof(struct pg_conn, requirepeer)}, + + {"require_auth", "PGREQUIREAUTH", NULL, NULL, + "Require-Auth", "", 14, /* sizeof("scram-sha-256") == 14 */ + offsetof(struct pg_conn, require_auth)}, + + {"ssl_min_protocol_version", "PGSSLMINPROTOCOLVERSION", "TLSv1.2", NULL, + "SSL-Minimum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */ + offsetof(struct pg_conn, ssl_min_protocol_version)}, + + {"ssl_max_protocol_version", "PGSSLMAXPROTOCOLVERSION", NULL, NULL, + "SSL-Maximum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */ + offsetof(struct pg_conn, ssl_max_protocol_version)}, + + /* + * As with SSL, all GSS options are exposed even in builds that don't have + * support. + */ + {"gssencmode", "PGGSSENCMODE", DefaultGSSMode, NULL, + "GSSENC-Mode", "", 8, /* sizeof("disable") == 8 */ + offsetof(struct pg_conn, gssencmode)}, + + /* Kerberos and GSSAPI authentication support specifying the service name */ + {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL, + "Kerberos-service-name", "", 20, + offsetof(struct pg_conn, krbsrvname)}, + + {"gsslib", "PGGSSLIB", NULL, NULL, + "GSS-library", "", 7, /* sizeof("gssapi") == 7 */ + offsetof(struct pg_conn, gsslib)}, + + {"gssdelegation", "PGGSSDELEGATION", "0", NULL, + "GSS-delegation", "", 1, + offsetof(struct pg_conn, gssdelegation)}, + + {"replication", NULL, NULL, NULL, + "Replication", "D", 5, + offsetof(struct pg_conn, replication)}, + + {"target_session_attrs", "PGTARGETSESSIONATTRS", + DefaultTargetSessionAttrs, NULL, + "Target-Session-Attrs", "", 15, /* sizeof("prefer-standby") = 15 */ + offsetof(struct pg_conn, target_session_attrs)}, + + {"load_balance_hosts", "PGLOADBALANCEHOSTS", + DefaultLoadBalanceHosts, NULL, + "Load-Balance-Hosts", "", 8, /* sizeof("disable") = 8 */ + offsetof(struct pg_conn, load_balance_hosts)}, + + /* 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 void pqFreeCommandQueue(PGcmdQueueEntry *queue); +static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions); +static void freePGconn(PGconn *conn); +static void closePGconn(PGconn *conn); +static void release_conn_addrinfo(PGconn *conn); +static int store_conn_addrinfo(PGconn *conn, struct addrinfo *addrlist); +static void sendTerminateConn(PGconn *conn); +static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage); +static PQconninfoOption *parse_connection_string(const char *connstr, + 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, const char *token); +static char *passwordFromFile(const char *hostname, const char *port, const char *dbname, + const char *username, const char *pgpassfile); +static void pgpassfileWarning(PGconn *conn); +static void default_threadlock(int acquire); +static bool sslVerifyProtocolVersion(const char *version); +static bool sslVerifyProtocolRange(const char *min, const char *max); +static bool parse_int_param(const char *value, int *result, PGconn *conn, + const char *context); + + +/* 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, nor local state that might still + * be useful later. + * + * 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; + + /* Likewise, discard any pending pipelined commands */ + pqFreeCommandQueue(conn->cmd_queue_head); + conn->cmd_queue_head = conn->cmd_queue_tail = NULL; + pqFreeCommandQueue(conn->cmd_queue_recycle); + conn->cmd_queue_recycle = NULL; + + /* Free authentication/encryption state */ +#ifdef ENABLE_GSS + { + OM_uint32 min_s; + + if (conn->gcred != GSS_C_NO_CREDENTIAL) + { + gss_release_cred(&min_s, &conn->gcred); + conn->gcred = GSS_C_NO_CREDENTIAL; + } + 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->gss_SendBuffer) + { + free(conn->gss_SendBuffer); + conn->gss_SendBuffer = NULL; + } + if (conn->gss_RecvBuffer) + { + free(conn->gss_RecvBuffer); + conn->gss_RecvBuffer = NULL; + } + if (conn->gss_ResultBuffer) + { + free(conn->gss_ResultBuffer); + conn->gss_ResultBuffer = NULL; + } + conn->gssenc = false; + } +#endif +#ifdef ENABLE_SSPI + 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 + if (conn->sasl_state) + { + conn->sasl->free(conn->sasl_state); + conn->sasl_state = NULL; + } +} + +/* + * pqFreeCommandQueue + * Free all the entries of PGcmdQueueEntry queue passed. + */ +static void +pqFreeCommandQueue(PGcmdQueueEntry *queue) +{ + while (queue != NULL) + { + PGcmdQueueEntry *cur = queue; + + queue = cur->next; + free(cur->query); + free(cur); + } +} + +/* + * pqDropServerData + * + * Clear all connection state data that was received from (or deduced about) + * the server. This is essential to do between connection attempts to + * different servers, else we may incorrectly hold over some data from the + * old server. + * + * It would be better to merge this into pqDropConnection, perhaps, but + * right now we cannot because that function is called immediately on + * detection of connection loss (cf. pqReadData, for instance). This data + * should be kept until we are actually starting a new connection. + */ +static void +pqDropServerData(PGconn *conn) +{ + PGnotify *notify; + pgParameterStatus *pstatus; + + /* Forget pending notifies */ + notify = conn->notifyHead; + while (notify != NULL) + { + PGnotify *prev = notify; + + notify = notify->next; + free(prev); + } + conn->notifyHead = conn->notifyTail = NULL; + + /* Reset ParameterStatus data, as well as variables deduced from it */ + pstatus = conn->pstatus; + while (pstatus != NULL) + { + pgParameterStatus *prev = pstatus; + + pstatus = pstatus->next; + free(prev); + } + conn->pstatus = NULL; + conn->client_encoding = PG_SQL_ASCII; + conn->std_strings = false; + conn->default_transaction_read_only = PG_BOOL_UNKNOWN; + conn->in_hot_standby = PG_BOOL_UNKNOWN; + conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS; + conn->sversion = 0; + + /* Drop large-object lookup data */ + free(conn->lobjfuncs); + conn->lobjfuncs = NULL; + + /* Reset assorted other per-connection state */ + conn->last_sqlstate[0] = '\0'; + conn->auth_req_received = false; + conn->client_finished_auth = false; + conn->password_needed = false; + conn->gssapi_used = false; + conn->write_failed = false; + free(conn->write_err_msg); + conn->write_err_msg = NULL; + conn->be_pid = 0; + conn->be_key = 0; +} + + +/* + * 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. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. + */ + 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. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. + */ + 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); + + free(*connmember); + *connmember = strdup(tmp); + if (*connmember == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + 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; +} + +/* + * Count the number of elements in a simple comma-separated list. + */ +static int +count_comma_separated_elems(const char *input) +{ + int n; + + n = 1; + for (; *input != '\0'; input++) + { + if (*input == ',') + n++; + } + + return n; +} + +/* + * Parse a simple comma-separated list. + * + * On each call, returns a malloc'd copy of the next element, and sets *more + * to indicate whether there are any more elements in the list after this, + * and updates *startptr to point to the next element, if any. + * + * On out of memory, returns NULL. + */ +static char * +parse_comma_separated_list(char **startptr, bool *more) +{ + char *p; + char *s = *startptr; + char *e; + int len; + + /* + * Search for the end of the current element; a comma or end-of-string + * acts as a terminator. + */ + e = s; + while (*e != '\0' && *e != ',') + ++e; + *more = (*e == ','); + + len = e - s; + p = (char *) malloc(sizeof(char) * (len + 1)); + if (p) + { + memcpy(p, s, len); + p[len] = '\0'; + } + *startptr = e + 1; + + return p; +} + +/* + * Initializes the prng_state field of the connection. We want something + * unpredictable, so if possible, use high-quality random bits for the + * seed. Otherwise, fall back to a seed based on the connection address, + * timestamp and PID. + */ +static void +libpq_prng_init(PGconn *conn) +{ + uint64 rseed; + struct timeval tval = {0}; + + if (pg_prng_strong_seed(&conn->prng_state)) + return; + + gettimeofday(&tval, NULL); + + rseed = ((uintptr_t) conn) ^ + ((uint64) getpid()) ^ + ((uint64) tval.tv_usec) ^ + ((uint64) tval.tv_sec); + + pg_prng_seed(&conn->prng_state, rseed); +} + +/* + * 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) +{ + int i; + + /* + * Allocate memory for details about each host to which we might possibly + * try to connect. For that, count the number of elements in the hostaddr + * or host options. If neither is given, assume one host. + */ + conn->whichhost = 0; + if (conn->pghostaddr && conn->pghostaddr[0] != '\0') + conn->nconnhost = count_comma_separated_elems(conn->pghostaddr); + else if (conn->pghost && conn->pghost[0] != '\0') + conn->nconnhost = count_comma_separated_elems(conn->pghost); + else + conn->nconnhost = 1; + conn->connhost = (pg_conn_host *) + calloc(conn->nconnhost, sizeof(pg_conn_host)); + if (conn->connhost == NULL) + goto oom_error; + + /* + * We now have one pg_conn_host structure per possible host. Fill in the + * host and hostaddr fields for each, by splitting the parameter strings. + */ + if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0') + { + char *s = conn->pghostaddr; + bool more = true; + + for (i = 0; i < conn->nconnhost && more; i++) + { + conn->connhost[i].hostaddr = parse_comma_separated_list(&s, &more); + if (conn->connhost[i].hostaddr == NULL) + goto oom_error; + } + + /* + * If hostaddr was given, the array was allocated according to the + * number of elements in the hostaddr list, so it really should be the + * right size. + */ + Assert(!more); + Assert(i == conn->nconnhost); + } + + if (conn->pghost != NULL && conn->pghost[0] != '\0') + { + char *s = conn->pghost; + bool more = true; + + for (i = 0; i < conn->nconnhost && more; i++) + { + conn->connhost[i].host = parse_comma_separated_list(&s, &more); + if (conn->connhost[i].host == NULL) + goto oom_error; + } + + /* Check for wrong number of host items. */ + if (more || i != conn->nconnhost) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "could not match %d host names to %d hostaddr values", + count_comma_separated_elems(conn->pghost), conn->nconnhost); + return false; + } + } + + /* + * Now, for each host slot, identify the type of address spec, and fill in + * the default address if nothing was given. + */ + for (i = 0; i < conn->nconnhost; i++) + { + pg_conn_host *ch = &conn->connhost[i]; + + if (ch->hostaddr != NULL && ch->hostaddr[0] != '\0') + ch->type = CHT_HOST_ADDRESS; + else if (ch->host != NULL && ch->host[0] != '\0') + { + ch->type = CHT_HOST_NAME; + if (is_unixsock_path(ch->host)) + ch->type = CHT_UNIX_SOCKET; + } + else + { + free(ch->host); + + /* + * This bit selects the default host location. If you change + * this, see also pg_regress. + */ + if (DEFAULT_PGSOCKET_DIR[0]) + { + ch->host = strdup(DEFAULT_PGSOCKET_DIR); + ch->type = CHT_UNIX_SOCKET; + } + else + { + ch->host = strdup(DefaultHost); + ch->type = CHT_HOST_NAME; + } + if (ch->host == NULL) + goto oom_error; + } + } + + /* + * Next, work out the port number corresponding to each host name. + * + * Note: unlike the above for host names, this could leave the port fields + * as null or empty strings. We will substitute DEF_PGPORT whenever we + * read such a port field. + */ + if (conn->pgport != NULL && conn->pgport[0] != '\0') + { + char *s = conn->pgport; + bool more = true; + + for (i = 0; i < conn->nconnhost && more; i++) + { + conn->connhost[i].port = parse_comma_separated_list(&s, &more); + if (conn->connhost[i].port == NULL) + goto oom_error; + } + + /* + * If exactly one port was given, use it for every host. Otherwise, + * there must be exactly as many ports as there were hosts. + */ + if (i == 1 && !more) + { + for (i = 1; i < conn->nconnhost; i++) + { + conn->connhost[i].port = strdup(conn->connhost[0].port); + if (conn->connhost[i].port == NULL) + goto oom_error; + } + } + else if (more || i != conn->nconnhost) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "could not match %d port numbers to %d hosts", + count_comma_separated_elems(conn->pgport), conn->nconnhost); + return false; + } + } + + /* + * 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') + { + 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') + { + free(conn->dbName); + conn->dbName = strdup(conn->pguser); + if (!conn->dbName) + goto oom_error; + } + + /* + * If password was not given, try to look it up in password file. Note + * that the result might be different for each host/port pair. + */ + if (conn->pgpass == NULL || conn->pgpass[0] == '\0') + { + /* If password file wasn't specified, use ~/PGPASSFILE */ + if (conn->pgpassfile == NULL || conn->pgpassfile[0] == '\0') + { + char homedir[MAXPGPATH]; + + if (pqGetHomeDirectory(homedir, sizeof(homedir))) + { + free(conn->pgpassfile); + conn->pgpassfile = malloc(MAXPGPATH); + if (!conn->pgpassfile) + goto oom_error; + snprintf(conn->pgpassfile, MAXPGPATH, "%s/%s", + homedir, PGPASSFILE); + } + } + + if (conn->pgpassfile != NULL && conn->pgpassfile[0] != '\0') + { + for (i = 0; i < conn->nconnhost; i++) + { + /* + * Try to get a password for this host from file. We use host + * for the hostname search key if given, else hostaddr (at + * least one of them is guaranteed nonempty by now). + */ + const char *pwhost = conn->connhost[i].host; + + if (pwhost == NULL || pwhost[0] == '\0') + pwhost = conn->connhost[i].hostaddr; + + conn->connhost[i].password = + passwordFromFile(pwhost, + conn->connhost[i].port, + conn->dbName, + conn->pguser, + conn->pgpassfile); + } + } + } + + /* + * parse and validate require_auth option + */ + if (conn->require_auth && conn->require_auth[0]) + { + char *s = conn->require_auth; + bool first, + more; + bool negated = false; + + /* + * By default, start from an empty set of allowed options and add to + * it. + */ + conn->auth_required = true; + conn->allowed_auth_methods = 0; + + for (first = true, more = true; more; first = false) + { + char *method, + *part; + uint32 bits; + + part = parse_comma_separated_list(&s, &more); + if (part == NULL) + goto oom_error; + + /* + * Check for negation, e.g. '!password'. If one element is + * negated, they all have to be. + */ + method = part; + if (*method == '!') + { + if (first) + { + /* + * Switch to a permissive set of allowed options, and + * subtract from it. + */ + conn->auth_required = false; + conn->allowed_auth_methods = -1; + } + else if (!negated) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "negative require_auth method \"%s\" cannot be mixed with non-negative methods", + method); + + free(part); + return false; + } + + negated = true; + method++; + } + else if (negated) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "require_auth method \"%s\" cannot be mixed with negative methods", + method); + + free(part); + return false; + } + + if (strcmp(method, "password") == 0) + { + bits = (1 << AUTH_REQ_PASSWORD); + } + else if (strcmp(method, "md5") == 0) + { + bits = (1 << AUTH_REQ_MD5); + } + else if (strcmp(method, "gss") == 0) + { + bits = (1 << AUTH_REQ_GSS); + bits |= (1 << AUTH_REQ_GSS_CONT); + } + else if (strcmp(method, "sspi") == 0) + { + bits = (1 << AUTH_REQ_SSPI); + bits |= (1 << AUTH_REQ_GSS_CONT); + } + else if (strcmp(method, "scram-sha-256") == 0) + { + /* This currently assumes that SCRAM is the only SASL method. */ + bits = (1 << AUTH_REQ_SASL); + bits |= (1 << AUTH_REQ_SASL_CONT); + bits |= (1 << AUTH_REQ_SASL_FIN); + } + else if (strcmp(method, "none") == 0) + { + /* + * Special case: let the user explicitly allow (or disallow) + * connections where the server does not send an explicit + * authentication challenge, such as "trust" and "cert" auth. + */ + if (negated) /* "!none" */ + { + if (conn->auth_required) + goto duplicate; + + conn->auth_required = true; + } + else /* "none" */ + { + if (!conn->auth_required) + goto duplicate; + + conn->auth_required = false; + } + + free(part); + continue; /* avoid the bitmask manipulation below */ + } + else + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "require_auth", method); + + free(part); + return false; + } + + /* Update the bitmask. */ + if (negated) + { + if ((conn->allowed_auth_methods & bits) == 0) + goto duplicate; + + conn->allowed_auth_methods &= ~bits; + } + else + { + if ((conn->allowed_auth_methods & bits) == bits) + goto duplicate; + + conn->allowed_auth_methods |= bits; + } + + free(part); + continue; + + duplicate: + + /* + * A duplicated method probably indicates a typo in a setting + * where typos are extremely risky. + */ + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "require_auth method \"%s\" is specified more than once", + part); + + free(part); + return false; + } + } + + /* + * validate channel_binding option + */ + if (conn->channel_binding) + { + if (strcmp(conn->channel_binding, "disable") != 0 + && strcmp(conn->channel_binding, "prefer") != 0 + && strcmp(conn->channel_binding, "require") != 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "channel_binding", conn->channel_binding); + return false; + } + } + else + { + conn->channel_binding = strdup(DefaultChannelBinding); + if (!conn->channel_binding) + goto oom_error; + } + +#ifndef USE_SSL + + /* + * sslrootcert=system is not supported. Since setting this changes the + * default sslmode, check this _before_ we validate sslmode, to avoid + * confusing the user with errors for an option they may not have set. + */ + if (conn->sslrootcert + && strcmp(conn->sslrootcert, "system") == 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in", + "sslrootcert", conn->sslrootcert); + return false; + } +#endif + + /* + * 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; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "sslmode", 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; + libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in", + "sslmode", conn->sslmode); + return false; + } +#endif + } + else + { + conn->sslmode = strdup(DefaultSSLMode); + if (!conn->sslmode) + goto oom_error; + } + +#ifdef USE_SSL + + /* + * If sslrootcert=system, make sure our chosen sslmode is compatible. + */ + if (conn->sslrootcert + && strcmp(conn->sslrootcert, "system") == 0 + && strcmp(conn->sslmode, "verify-full") != 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "weak sslmode \"%s\" may not be used with sslrootcert=system (use \"verify-full\")", + conn->sslmode); + return false; + } +#endif + + /* + * Validate TLS protocol versions for ssl_min_protocol_version and + * ssl_max_protocol_version. + */ + if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version)) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "ssl_min_protocol_version", + conn->ssl_min_protocol_version); + return false; + } + if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version)) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "ssl_max_protocol_version", + conn->ssl_max_protocol_version); + return false; + } + + /* + * Check if the range of SSL protocols defined is correct. This is done + * at this early step because this is independent of the SSL + * implementation used, and this avoids unnecessary cycles with an + * already-built SSL context when the connection is being established, as + * it would be doomed anyway. + */ + if (!sslVerifyProtocolRange(conn->ssl_min_protocol_version, + conn->ssl_max_protocol_version)) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid SSL protocol version range"); + return false; + } + + /* + * validate sslcertmode option + */ + if (conn->sslcertmode) + { + if (strcmp(conn->sslcertmode, "disable") != 0 && + strcmp(conn->sslcertmode, "allow") != 0 && + strcmp(conn->sslcertmode, "require") != 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "sslcertmode", conn->sslcertmode); + return false; + } +#ifndef USE_SSL + if (strcmp(conn->sslcertmode, "require") == 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in", + "sslcertmode", conn->sslcertmode); + return false; + } +#endif +#ifndef HAVE_SSL_CTX_SET_CERT_CB + + /* + * Without a certificate callback, the current implementation can't + * figure out if a certificate was actually requested, so "require" is + * useless. + */ + if (strcmp(conn->sslcertmode, "require") == 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "%s value \"%s\" is not supported (check OpenSSL version)", + "sslcertmode", conn->sslcertmode); + return false; + } +#endif + } + else + { + conn->sslcertmode = strdup(DefaultSSLCertMode); + if (!conn->sslcertmode) + goto oom_error; + } + + /* + * validate gssencmode option + */ + if (conn->gssencmode) + { + if (strcmp(conn->gssencmode, "disable") != 0 && + strcmp(conn->gssencmode, "prefer") != 0 && + strcmp(conn->gssencmode, "require") != 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", "gssencmode", conn->gssencmode); + return false; + } +#ifndef ENABLE_GSS + if (strcmp(conn->gssencmode, "require") == 0) + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "gssencmode value \"%s\" invalid when GSSAPI support is not compiled in", + conn->gssencmode); + return false; + } +#endif + } + else + { + conn->gssencmode = strdup(DefaultGSSMode); + if (!conn->gssencmode) + goto oom_error; + } + + /* + * validate target_session_attrs option, and set target_server_type + */ + if (conn->target_session_attrs) + { + if (strcmp(conn->target_session_attrs, "any") == 0) + conn->target_server_type = SERVER_TYPE_ANY; + else if (strcmp(conn->target_session_attrs, "read-write") == 0) + conn->target_server_type = SERVER_TYPE_READ_WRITE; + else if (strcmp(conn->target_session_attrs, "read-only") == 0) + conn->target_server_type = SERVER_TYPE_READ_ONLY; + else if (strcmp(conn->target_session_attrs, "primary") == 0) + conn->target_server_type = SERVER_TYPE_PRIMARY; + else if (strcmp(conn->target_session_attrs, "standby") == 0) + conn->target_server_type = SERVER_TYPE_STANDBY; + else if (strcmp(conn->target_session_attrs, "prefer-standby") == 0) + conn->target_server_type = SERVER_TYPE_PREFER_STANDBY; + else + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "target_session_attrs", + conn->target_session_attrs); + return false; + } + } + else + conn->target_server_type = SERVER_TYPE_ANY; + + /* + * validate load_balance_hosts option, and set load_balance_type + */ + if (conn->load_balance_hosts) + { + if (strcmp(conn->load_balance_hosts, "disable") == 0) + conn->load_balance_type = LOAD_BALANCE_DISABLE; + else if (strcmp(conn->load_balance_hosts, "random") == 0) + conn->load_balance_type = LOAD_BALANCE_RANDOM; + else + { + conn->status = CONNECTION_BAD; + libpq_append_conn_error(conn, "invalid %s value: \"%s\"", + "load_balance_hosts", + conn->load_balance_hosts); + return false; + } + } + else + conn->load_balance_type = LOAD_BALANCE_DISABLE; + + if (conn->load_balance_type == LOAD_BALANCE_RANDOM) + { + libpq_prng_init(conn); + + /* + * This is the "inside-out" variant of the Fisher-Yates shuffle + * algorithm. Notionally, we append each new value to the array and + * then swap it with a randomly-chosen array element (possibly + * including itself, else we fail to generate permutations with the + * last integer last). The swap step can be optimized by combining it + * with the insertion. + */ + for (i = 1; i < conn->nconnhost; i++) + { + int j = pg_prng_uint64_range(&conn->prng_state, 0, i); + pg_conn_host temp = conn->connhost[j]; + + conn->connhost[j] = conn->connhost[i]; + conn->connhost[i] = temp; + } + } + + /* + * 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; + libpq_append_conn_error(conn, "out of memory"); + 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. Note that we also expect this + * to initialize conn->errorMessage to empty. All subsequent steps during + * connection initialization will only append to that buffer. + */ + 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') + { + 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') + { + free(conn->pghost); + conn->pghost = strdup(pghost); + if (!conn->pghost) + goto oom_error; + } + + if (pgport && pgport[0] != '\0') + { + free(conn->pgport); + conn->pgport = strdup(pgport); + if (!conn->pgport) + goto oom_error; + } + + if (pgoptions && pgoptions[0] != '\0') + { + free(conn->pgoptions); + conn->pgoptions = strdup(pgoptions); + if (!conn->pgoptions) + goto oom_error; + } + + if (login && login[0] != '\0') + { + free(conn->pguser); + conn->pguser = strdup(login); + if (!conn->pguser) + goto oom_error; + } + + if (pwd && pwd[0] != '\0') + { + 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; + libpq_append_conn_error(conn, "out of memory"); + 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[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "could not set socket to TCP no delay mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + +/* ---------- + * Write currently connected IP address into host_addr (of len host_addr_len). + * If unable to, set it to the empty string. + * ---------- + */ +static void +getHostaddr(PGconn *conn, char *host_addr, int host_addr_len) +{ + struct sockaddr_storage *addr = &conn->raddr.addr; + + if (addr->ss_family == AF_INET) + { + if (pg_inet_net_ntop(AF_INET, + &((struct sockaddr_in *) addr)->sin_addr.s_addr, + 32, + host_addr, host_addr_len) == NULL) + host_addr[0] = '\0'; + } + else if (addr->ss_family == AF_INET6) + { + if (pg_inet_net_ntop(AF_INET6, + &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, + 128, + host_addr, host_addr_len) == NULL) + host_addr[0] = '\0'; + } + else + host_addr[0] = '\0'; +} + +/* + * emitHostIdentityInfo - + * Speculatively append "connection to server so-and-so failed: " to + * conn->errorMessage once we've identified the current connection target + * address. This ensures that any subsequent error message will be properly + * attributed to the server we couldn't connect to. conn->raddr must be + * valid, and the result of getHostaddr() must be supplied. + */ +static void +emitHostIdentityInfo(PGconn *conn, const char *host_addr) +{ + if (conn->raddr.addr.ss_family == AF_UNIX) + { + 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("connection to server on socket \"%s\" failed: "), + service); + } + else + { + const char *displayed_host; + const char *displayed_port; + + /* To which host and port were we actually connecting? */ + if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS) + displayed_host = conn->connhost[conn->whichhost].hostaddr; + else + displayed_host = conn->connhost[conn->whichhost].host; + displayed_port = conn->connhost[conn->whichhost].port; + if (displayed_port == NULL || displayed_port[0] == '\0') + displayed_port = DEF_PGPORT_STR; + + /* + * 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->connhost[conn->whichhost].type != CHT_HOST_ADDRESS && + host_addr[0] && + strcmp(displayed_host, host_addr) != 0) + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("connection to server at \"%s\" (%s), port %s failed: "), + displayed_host, host_addr, + displayed_port); + else + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("connection to server at \"%s\", port %s failed: "), + displayed_host, + displayed_port); + } +} + +/* ---------- + * connectFailureMessage - + * create a friendly error message on connection failure, + * using the given errno value. Use this for error cases that + * imply that there's no server there. + * ---------- + */ +static void +connectFailureMessage(PGconn *conn, int errorno) +{ + char sebuf[PG_STRERROR_R_BUFLEN]; + + appendPQExpBuffer(&conn->errorMessage, + "%s\n", + SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); + + if (conn->raddr.addr.ss_family == AF_UNIX) + libpq_append_conn_error(conn, "\tIs the server running locally and accepting connections on that socket?"); + else + libpq_append_conn_error(conn, "\tIs the server running on that host and accepting TCP/IP connections?"); +} + +/* + * 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; +} + +/* + * Parse and try to interpret "value" as an integer value, and if successful, + * store it in *result, complaining if there is any trailing garbage or an + * overflow. This allows any number of leading and trailing whitespaces. + */ +static bool +parse_int_param(const char *value, int *result, PGconn *conn, + const char *context) +{ + char *end; + long numval; + + Assert(value != NULL); + + *result = 0; + + /* strtol(3) skips leading whitespaces */ + errno = 0; + numval = strtol(value, &end, 10); + + /* + * If no progress was done during the parsing or an error happened, fail. + * This tests properly for overflows of the result. + */ + if (value == end || errno != 0 || numval != (int) numval) + goto error; + + /* + * Skip any trailing whitespace; if anything but whitespace remains before + * the terminating character, fail + */ + while (*end != '\0' && isspace((unsigned char) *end)) + end++; + + if (*end != '\0') + goto error; + + *result = numval; + return true; + +error: + libpq_append_conn_error(conn, "invalid integer value \"%s\" for connection option \"%s\"", + value, context); + return false; +} + +#ifndef WIN32 +/* + * Set the keepalive idle timer. + */ +static int +setKeepalivesIdle(PGconn *conn) +{ + int idle; + + if (conn->keepalives_idle == NULL) + return 1; + + if (!parse_int_param(conn->keepalives_idle, &idle, conn, + "keepalives_idle")) + return 0; + 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[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + 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; + + if (!parse_int_param(conn->keepalives_interval, &interval, conn, + "keepalives_interval")) + return 0; + if (interval < 0) + interval = 0; + +#ifdef TCP_KEEPINTVL + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL, + (char *) &interval, sizeof(interval)) < 0) + { + char sebuf[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + "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; + + if (!parse_int_param(conn->keepalives_count, &count, conn, + "keepalives_count")) + return 0; + if (count < 0) + count = 0; + +#ifdef TCP_KEEPCNT + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT, + (char *) &count, sizeof(count)) < 0) + { + char sebuf[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + "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. + * + * CAUTION: This needs to be signal safe, since it's used by PQcancel. + */ +static int +setKeepalivesWin32(pgsocket sock, int idle, int interval) +{ + struct tcp_keepalive ka; + DWORD retsize; + + if (idle <= 0) + idle = 2 * 60 * 60; /* 2 hours = default */ + if (interval <= 0) + interval = 1; /* 1 second = default */ + + ka.onoff = 1; + ka.keepalivetime = idle * 1000; + ka.keepaliveinterval = interval * 1000; + + if (WSAIoctl(sock, + SIO_KEEPALIVE_VALS, + (LPVOID) &ka, + sizeof(ka), + NULL, + 0, + &retsize, + NULL, + NULL) + != 0) + return 0; + return 1; +} + +static int +prepKeepalivesWin32(PGconn *conn) +{ + int idle = -1; + int interval = -1; + + if (conn->keepalives_idle && + !parse_int_param(conn->keepalives_idle, &idle, conn, + "keepalives_idle")) + return 0; + if (conn->keepalives_interval && + !parse_int_param(conn->keepalives_interval, &interval, conn, + "keepalives_interval")) + return 0; + + if (!setKeepalivesWin32(conn->sock, idle, interval)) + { + libpq_append_conn_error(conn, "%s(%s) failed: error code %d", + "WSAIoctl", "SIO_KEEPALIVE_VALS", + WSAGetLastError()); + return 0; + } + return 1; +} +#endif /* SIO_KEEPALIVE_VALS */ +#endif /* WIN32 */ + +/* + * Set the TCP user timeout. + */ +static int +setTCPUserTimeout(PGconn *conn) +{ + int timeout; + + if (conn->pgtcp_user_timeout == NULL) + return 1; + + if (!parse_int_param(conn->pgtcp_user_timeout, &timeout, conn, + "tcp_user_timeout")) + return 0; + + if (timeout < 0) + timeout = 0; + +// Compilation must fail on linux if TCP_USER_TIMEOUT is not defined +#ifdef __linux__ + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_USER_TIMEOUT, + (char *) &timeout, sizeof(timeout)) < 0) + { + char sebuf[256]; + + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + "TCP_USER_TIMEOUT", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + +/* ---------- + * connectDBStart - + * Begin the process of making a connection to the backend. + * + * Returns 1 if successful, 0 if not. + * ---------- + */ +static int +connectDBStart(PGconn *conn) +{ + if (!conn) + return 0; + + if (!conn->options_valid) + goto connect_errReturn; + + /* + * Check for bad linking to backend-internal versions of src/common + * functions (see comments in link-canary.c for the reason we need this). + * Nobody but developers should see this message, so we don't bother + * translating it. + */ + if (!pg_link_canary_is_frontend()) + { + appendPQExpBufferStr(&conn->errorMessage, + "libpq is incorrectly linked to backend functions\n"); + goto connect_errReturn; + } + + /* Ensure our buffers are empty */ + conn->inStart = conn->inCursor = conn->inEnd = 0; + conn->outCount = 0; + + /* + * Set up to try to connect to the first host. (Setting whichhost = -1 is + * a bit of a cheat, but PQconnectPoll will advance it to 0 before + * anything else looks at it.) + */ + conn->whichhost = -1; + conn->try_next_addr = false; + conn->try_next_host = true; + conn->status = CONNECTION_NEEDED; + + /* Also reset the target_server_type state if needed */ + if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY_PASS2) + conn->target_server_type = SERVER_TYPE_PREFER_STANDBY; + + /* + * 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: + + /* + * If we managed to open a socket, close it immediately rather than + * waiting till PQfinish. (The application cannot have gotten the socket + * from PQsocket yet, so this doesn't risk breaking anything.) + */ + 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); + int timeout = 0; + int last_whichhost = -2; /* certainly different from whichhost */ + int last_whichaddr = -2; /* certainly different from whichaddr */ + + 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) + { + if (!parse_int_param(conn->connect_timeout, &timeout, conn, + "connect_timeout")) + { + /* mark the connection as bad to report the parsing failure */ + conn->status = CONNECTION_BAD; + return 0; + } + + if (timeout > 0) + { + /* + * Rounding could cause connection to fail unexpectedly quickly; + * to prevent possibly waiting hardly-at-all, insist on at least + * two seconds. + */ + if (timeout < 2) + timeout = 2; + } + else /* negative means 0 */ + timeout = 0; + } + + for (;;) + { + int ret = 0; + + /* + * (Re)start the connect_timeout timer if it's active and we are + * considering a different host than we were last time through. If + * we've already succeeded, though, needn't recalculate. + */ + if (flag != PGRES_POLLING_OK && + timeout > 0 && + (conn->whichhost != last_whichhost || + conn->whichaddr != last_whichaddr)) + { + finish_time = time(NULL) + timeout; + last_whichhost = conn->whichhost; + last_whichaddr = conn->whichaddr; + } + + /* + * 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: + return 1; /* success! */ + + case PGRES_POLLING_READING: + ret = pqWaitTimed(1, 0, conn, finish_time); + if (ret == -1) + { + /* hard failure, eg select() problem, aborts everything */ + conn->status = CONNECTION_BAD; + return 0; + } + break; + + case PGRES_POLLING_WRITING: + ret = pqWaitTimed(0, 1, conn, finish_time); + if (ret == -1) + { + /* hard failure, eg select() problem, aborts everything */ + conn->status = CONNECTION_BAD; + return 0; + } + break; + + default: + /* Just in case we failed to set it in PQconnectPoll */ + conn->status = CONNECTION_BAD; + return 0; + } + + if (ret == 1) /* connect_timeout elapsed */ + { + /* + * Give up on current server/address, try the next one. + */ + conn->try_next_addr = true; + conn->status = CONNECTION_NEEDED; + } + + /* + * 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 + * getaddrinfo. 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) +{ + bool reset_connection_state_machine = false; + bool need_new_connection = false; + PGresult *res; + char sebuf[PG_STRERROR_R_BUFLEN]; + 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: + case CONNECTION_CHECK_WRITABLE: + case CONNECTION_CONSUME: + case CONNECTION_CHECK_STANDBY: + { + /* 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; + + /* Special cases: proceed without waiting. */ + case CONNECTION_SSL_STARTUP: + case CONNECTION_NEEDED: + case CONNECTION_GSS_STARTUP: + case CONNECTION_CHECK_TARGET: + break; + + default: + libpq_append_conn_error(conn, "invalid connection state, probably indicative of memory corruption"); + goto error_return; + } + + +keep_going: /* We will come back to here until there is + * nothing left to do. */ + + /* Time to advance to next address, or next host if no more addresses? */ + if (conn->try_next_addr) + { + if (conn->whichaddr < conn->naddr) + { + conn->whichaddr++; + reset_connection_state_machine = true; + } + else + conn->try_next_host = true; + conn->try_next_addr = false; + } + + /* Time to advance to next connhost[] entry? */ + if (conn->try_next_host) + { + pg_conn_host *ch; + struct addrinfo hint; + struct addrinfo *addrlist; + int thisport; + int ret; + char portstr[MAXPGPATH]; + + if (conn->whichhost + 1 < conn->nconnhost) + conn->whichhost++; + else + { + /* + * Oops, no more hosts. + * + * If we are trying to connect in "prefer-standby" mode, then drop + * the standby requirement and start over. + * + * Otherwise, an appropriate error message is already set up, so + * we just need to set the right status. + */ + if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY && + conn->nconnhost > 0) + { + conn->target_server_type = SERVER_TYPE_PREFER_STANDBY_PASS2; + conn->whichhost = 0; + } + else + goto error_return; + } + + /* Drop any address info for previous host */ + release_conn_addrinfo(conn); + + /* + * Look up info for the new host. On failure, log the problem in + * conn->errorMessage, then loop around to try the next host. (Note + * we don't clear try_next_host until we've succeeded.) + */ + ch = &conn->connhost[conn->whichhost]; + + /* Initialize hint structure */ + MemSet(&hint, 0, sizeof(hint)); + hint.ai_socktype = SOCK_STREAM; + hint.ai_family = AF_UNSPEC; + + /* Figure out the port number we're going to use. */ + if (ch->port == NULL || ch->port[0] == '\0') + thisport = DEF_PGPORT; + else + { + if (!parse_int_param(ch->port, &thisport, conn, "port")) + goto error_return; + + if (thisport < 1 || thisport > 65535) + { + libpq_append_conn_error(conn, "invalid port number: \"%s\"", ch->port); + goto keep_going; + } + } + snprintf(portstr, sizeof(portstr), "%d", thisport); + + /* Use pg_getaddrinfo_all() to resolve the address */ + switch (ch->type) + { + case CHT_HOST_NAME: + ret = pg_getaddrinfo_all(ch->host, portstr, &hint, + &addrlist); + if (ret || !addrlist) + { + libpq_append_conn_error(conn, "could not translate host name \"%s\" to address: %s", + ch->host, gai_strerror(ret)); + goto keep_going; + } + break; + + case CHT_HOST_ADDRESS: + hint.ai_flags = AI_NUMERICHOST; + ret = pg_getaddrinfo_all(ch->hostaddr, portstr, &hint, + &addrlist); + if (ret || !addrlist) + { + libpq_append_conn_error(conn, "could not parse network address \"%s\": %s", + ch->hostaddr, gai_strerror(ret)); + goto keep_going; + } + break; + + case CHT_UNIX_SOCKET: + hint.ai_family = AF_UNIX; + UNIXSOCK_PATH(portstr, thisport, ch->host); + if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN) + { + libpq_append_conn_error(conn, "Unix-domain socket path \"%s\" is too long (maximum %d bytes)", + portstr, + (int) (UNIXSOCK_PATH_BUFLEN - 1)); + goto keep_going; + } + + /* + * NULL hostname tells pg_getaddrinfo_all to parse the service + * name as a Unix-domain socket path. + */ + ret = pg_getaddrinfo_all(NULL, portstr, &hint, + &addrlist); + if (ret || !addrlist) + { + libpq_append_conn_error(conn, "could not translate Unix-domain socket path \"%s\" to address: %s", + portstr, gai_strerror(ret)); + goto keep_going; + } + break; + } + + /* + * Store a copy of the addrlist in private memory so we can perform + * randomization for load balancing. + */ + ret = store_conn_addrinfo(conn, addrlist); + pg_freeaddrinfo_all(hint.ai_family, addrlist); + if (ret) + goto error_return; /* message already logged */ + + /* + * If random load balancing is enabled we shuffle the addresses. + */ + if (conn->load_balance_type == LOAD_BALANCE_RANDOM) + { + /* + * This is the "inside-out" variant of the Fisher-Yates shuffle + * algorithm. Notionally, we append each new value to the array + * and then swap it with a randomly-chosen array element (possibly + * including itself, else we fail to generate permutations with + * the last integer last). The swap step can be optimized by + * combining it with the insertion. + * + * We don't need to initialize conn->prng_state here, because that + * already happened in connectOptions2. + */ + for (int i = 1; i < conn->naddr; i++) + { + int j = pg_prng_uint64_range(&conn->prng_state, 0, i); + AddrInfo temp = conn->addr[j]; + + conn->addr[j] = conn->addr[i]; + conn->addr[i] = temp; + } + } + + reset_connection_state_machine = true; + conn->try_next_host = false; + } + + /* Reset connection state machine? */ + if (reset_connection_state_machine) + { + /* + * (Re) initialize our connection control variables for a set of + * connection attempts to a single server address. These variables + * must persist across individual connection attempts, but we must + * reset them when we start to consider a new server. + */ + conn->pversion = PG_PROTOCOL(3, 0); + conn->send_appname = true; +#ifdef USE_SSL + /* initialize these values based on SSL mode */ + conn->allow_ssl_try = (conn->sslmode[0] != 'd'); /* "disable" */ + conn->wait_ssl_try = (conn->sslmode[0] == 'a'); /* "allow" */ +#endif +#ifdef ENABLE_GSS + conn->try_gss = (conn->gssencmode[0] != 'd'); /* "disable" */ +#endif + + reset_connection_state_machine = false; + need_new_connection = true; + } + + /* Force a new connection (perhaps to the same server as before)? */ + if (need_new_connection) + { + /* Drop any existing connection */ + pqDropConnection(conn, true); + + /* Reset all state obtained from old server */ + pqDropServerData(conn); + + /* Drop any PGresult we might have, too */ + conn->asyncStatus = PGASYNC_IDLE; + conn->xactStatus = PQTRANS_IDLE; + conn->pipelineStatus = PQ_PIPELINE_OFF; + pqClearAsyncResult(conn); + + /* Reset conn->status to put the state machine in the right state */ + conn->status = CONNECTION_NEEDED; + + need_new_connection = false; + } + + /* Now try to advance the state machine for this connection */ + switch (conn->status) + { + case CONNECTION_NEEDED: + { + /* + * Try to initiate a connection to one of the addresses + * returned by pg_getaddrinfo_all(). conn->whichaddr is the + * next one to try. + * + * The extra level of braces here is historical. It's not + * worth reindenting this whole switch case to remove 'em. + */ + { + char host_addr[NI_MAXHOST]; + int sock_type; + AddrInfo *addr_cur; + + /* + * Advance to next possible host, if we've tried all of + * the addresses for the current host. + */ + if (conn->whichaddr == conn->naddr) + { + conn->try_next_host = true; + goto keep_going; + } + addr_cur = &conn->addr[conn->whichaddr]; + + /* Remember current address for possible use later */ + memcpy(&conn->raddr, &addr_cur->addr, sizeof(SockAddr)); + + /* + * Set connip, too. Note we purposely ignore strdup + * failure; not a big problem if it fails. + */ + if (conn->connip != NULL) + { + free(conn->connip); + conn->connip = NULL; + } + getHostaddr(conn, host_addr, NI_MAXHOST); + if (host_addr[0]) + conn->connip = strdup(host_addr); + + /* Try to create the socket */ + sock_type = SOCK_STREAM; +#ifdef SOCK_CLOEXEC + + /* + * Atomically mark close-on-exec, if possible on this + * platform, so that there isn't a window where a + * subprogram executed by another thread inherits the + * socket. See fallback code below. + */ + sock_type |= SOCK_CLOEXEC; +#endif +#ifdef SOCK_NONBLOCK + + /* + * We might as well skip a system call for nonblocking + * mode too, if we can. + */ + sock_type |= SOCK_NONBLOCK; +#endif + conn->sock = socket(addr_cur->family, sock_type, 0); + if (conn->sock == PGINVALID_SOCKET) + { + int errorno = SOCK_ERRNO; + + /* + * Silently ignore socket() failure if we have more + * addresses to try; this reduces useless chatter in + * cases where the address list includes both IPv4 and + * IPv6 but kernel only accepts one family. + */ + if (conn->whichaddr < conn->naddr || + conn->whichhost + 1 < conn->nconnhost) + { + conn->try_next_addr = true; + goto keep_going; + } + emitHostIdentityInfo(conn, host_addr); + libpq_append_conn_error(conn, "could not create socket: %s", + SOCK_STRERROR(errorno, sebuf, sizeof(sebuf))); + goto error_return; + } + + /* + * Once we've identified a target address, all errors + * except the preceding socket()-failure case should be + * prefixed with host-identity information. (If the + * connection succeeds, the contents of conn->errorMessage + * won't matter, so this is harmless.) + */ + emitHostIdentityInfo(conn, host_addr); + + /* + * Select socket options: no delay of outgoing data for + * TCP sockets, nonblock mode, close-on-exec. Try the + * next address if any of this fails. + */ + if (addr_cur->family != AF_UNIX) + { + if (!connectNoDelay(conn)) + { + /* error message already created */ + conn->try_next_addr = true; + goto keep_going; + } + } +#ifndef SOCK_NONBLOCK + if (!pg_set_noblock(conn->sock)) + { + libpq_append_conn_error(conn, "could not set socket to nonblocking mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + conn->try_next_addr = true; + goto keep_going; + } +#endif + +#ifndef SOCK_CLOEXEC +#ifdef F_SETFD + if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1) + { + libpq_append_conn_error(conn, "could not set socket to close-on-exec mode: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + conn->try_next_addr = true; + goto keep_going; + } +#endif /* F_SETFD */ +#endif + + if (addr_cur->family != AF_UNIX) + { +#ifndef WIN32 + int on = 1; +#endif + int usekeepalives = useKeepalives(conn); + int err = 0; + + if (usekeepalives < 0) + { + libpq_append_conn_error(conn, "keepalives parameter must be an integer"); + err = 1; + } + else if (usekeepalives == 0) + { + /* Do nothing */ + } +#ifndef WIN32 + else if (setsockopt(conn->sock, + SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)) < 0) + { + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + "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 (!prepKeepalivesWin32(conn)) + err = 1; +#endif /* SIO_KEEPALIVE_VALS */ +#endif /* WIN32 */ + else if (!setTCPUserTimeout(conn)) + err = 1; + + if (err) + { + conn->try_next_addr = true; + goto keep_going; + } + } + + /*---------- + * 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, (struct sockaddr *) &addr_cur->addr.addr, + addr_cur->addr.salen) < 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. Add the error report to + * conn->errorMessage, then try the next address if any. + */ + connectFailureMessage(conn, SOCK_ERRNO); + conn->try_next_addr = true; + goto keep_going; + } + } + + case CONNECTION_STARTED: + { + socklen_t 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) + { + libpq_append_conn_error(conn, "could not get socket error status: %s", + 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); + + /* + * Try the next address if any, just as in the case where + * connect() returned failure immediately. + */ + conn->try_next_addr = true; + goto keep_going; + } + + /* 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) + { + libpq_append_conn_error(conn, "could not get client address from socket: %s", + 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; + + /* + * Implement requirepeer check, if requested and it's a + * Unix-domain socket. + */ + if (conn->requirepeer && conn->requirepeer[0] && + conn->raddr.addr.ss_family == AF_UNIX) + { +#ifndef WIN32 + char *remote_username; +#endif + 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) + libpq_append_conn_error(conn, "requirepeer parameter is not supported on this platform"); + else + libpq_append_conn_error(conn, "could not get peer credentials: %s", + strerror_r(errno, sebuf, sizeof(sebuf))); + goto error_return; + } + +#ifndef WIN32 + remote_username = pg_fe_getusername(uid, + &conn->errorMessage); + if (remote_username == NULL) + goto error_return; /* message already logged */ + + if (strcmp(remote_username, conn->requirepeer) != 0) + { + libpq_append_conn_error(conn, "requirepeer specifies \"%s\", but actual peer user name is \"%s\"", + conn->requirepeer, remote_username); + free(remote_username); + goto error_return; + } + free(remote_username); +#else /* WIN32 */ + /* should have failed with ENOSYS above */ + Assert(false); +#endif /* WIN32 */ + } + + if (conn->raddr.addr.ss_family == AF_UNIX) + { + /* Don't request SSL or GSSAPI over Unix sockets */ +#ifdef USE_SSL + conn->allow_ssl_try = false; +#endif +#ifdef ENABLE_GSS + conn->try_gss = false; +#endif + } + +#ifdef ENABLE_GSS + + /* + * If GSSAPI encryption is enabled, then call + * pg_GSS_have_cred_cache() which will return true if we can + * acquire credentials (and give us a handle to use in + * conn->gcred), and then send a packet to the server asking + * for GSSAPI Encryption (and skip past SSL negotiation and + * regular startup below). + */ + if (conn->try_gss && !conn->gctx) + conn->try_gss = pg_GSS_have_cred_cache(&conn->gcred); + if (conn->try_gss && !conn->gctx) + { + ProtocolVersion pv = pg_hton32(NEGOTIATE_GSS_CODE); + + if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) + { + libpq_append_conn_error(conn, "could not send GSSAPI negotiation packet: %s", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + goto error_return; + } + + /* Ok, wait for response */ + conn->status = CONNECTION_GSS_STARTUP; + return PGRES_POLLING_READING; + } + else if (!conn->gctx && conn->gssencmode[0] == 'r') + { + libpq_append_conn_error(conn, + "GSSAPI encryption required but was impossible (possibly no credential cache, no server support, or using a local socket)"); + goto error_return; + } +#endif + +#ifdef USE_SSL + + /* + * Enable the libcrypto callbacks before checking if SSL needs + * to be done. This is done before sending the startup packet + * as depending on the type of authentication done, like MD5 + * or SCRAM that use cryptohashes, the callbacks would be + * required even without a SSL connection + */ + if (pqsecure_initialize(conn, false, true) < 0) + goto error_return; + + /* + * If SSL is enabled and we haven't already got encryption of + * some sort running, request SSL instead of sending the + * startup message. + */ + if (conn->allow_ssl_try && !conn->wait_ssl_try && + !conn->ssl_in_use +#ifdef ENABLE_GSS + && !conn->gssenc +#endif + ) + { + 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 = pg_hton32(NEGOTIATE_SSL_CODE); + if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK) + { + libpq_append_conn_error(conn, "could not send SSL negotiation packet: %s", + 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. + */ + startpacket = pqBuildStartupPacket3(conn, &packetlen, + EnvironmentOptions); + if (!startpacket) + { + libpq_append_conn_error(conn, "out of memory"); + 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) + { + libpq_append_conn_error(conn, "could not send startup packet: %s", + 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. The crypto + * state has already been set if libpq took care of + * doing that, so there is no need to make that happen + * again. + */ + if (pqsecure_initialize(conn, true, false) != 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 */ + libpq_append_conn_error(conn, "server does not support SSL, but SSL was required"); + goto error_return; + } + /* Otherwise, proceed with normal startup */ + conn->allow_ssl_try = false; + /* We can proceed using this connection */ + 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 + { + libpq_append_conn_error(conn, "received invalid response to SSL negotiation: %c", + SSLok); + goto error_return; + } + } + + /* + * Begin or continue the SSL negotiation process. + */ + pollres = pqsecure_open_client(conn); + if (pollres == PGRES_POLLING_OK) + { + /* + * At this point we should have no data already buffered. + * If we do, it was received before we performed the SSL + * handshake, so it wasn't encrypted and indeed may have + * been injected by a man-in-the-middle. + */ + if (conn->inCursor != conn->inEnd) + { + libpq_append_conn_error(conn, "received unencrypted data after SSL response"); + goto error_return; + } + + /* 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; + need_new_connection = true; + goto keep_going; + } + /* Else it's a hard failure */ + goto error_return; + } + /* Else, return POLLING_READING or POLLING_WRITING status */ + return pollres; +#else /* !USE_SSL */ + /* can't get here */ + goto error_return; +#endif /* USE_SSL */ + } + + case CONNECTION_GSS_STARTUP: + { +#ifdef ENABLE_GSS + PostgresPollingStatusType pollres; + + /* + * If we haven't yet, get the postmaster's response to our + * negotiation packet + */ + if (conn->try_gss && !conn->gctx) + { + char gss_ok; + int rdresult = pqReadData(conn); + + if (rdresult < 0) + /* pqReadData fills in error message */ + goto error_return; + else if (rdresult == 0) + /* caller failed to wait for data */ + return PGRES_POLLING_READING; + if (pqGetc(&gss_ok, conn) < 0) + /* shouldn't happen... */ + return PGRES_POLLING_READING; + + if (gss_ok == 'E') + { + /* + * Server failure of some sort. Assume it's a + * protocol version support failure, and let's see if + * we can't recover (if it's not, we'll get a better + * error message on retry). Server gets fussy if we + * don't hang up the socket, though. + */ + conn->try_gss = false; + need_new_connection = true; + goto keep_going; + } + + /* mark byte consumed */ + conn->inStart = conn->inCursor; + + if (gss_ok == 'N') + { + /* Server doesn't want GSSAPI; fall back if we can */ + if (conn->gssencmode[0] == 'r') + { + libpq_append_conn_error(conn, "server doesn't support GSSAPI encryption, but it was required"); + goto error_return; + } + + conn->try_gss = false; + /* We can proceed using this connection */ + conn->status = CONNECTION_MADE; + return PGRES_POLLING_WRITING; + } + else if (gss_ok != 'G') + { + libpq_append_conn_error(conn, "received invalid response to GSSAPI negotiation: %c", + gss_ok); + goto error_return; + } + } + + /* Begin or continue GSSAPI negotiation */ + pollres = pqsecure_open_gss(conn); + if (pollres == PGRES_POLLING_OK) + { + /* + * At this point we should have no data already buffered. + * If we do, it was received before we performed the GSS + * handshake, so it wasn't encrypted and indeed may have + * been injected by a man-in-the-middle. + */ + if (conn->inCursor != conn->inEnd) + { + libpq_append_conn_error(conn, "received unencrypted data after GSSAPI encryption response"); + goto error_return; + } + + /* All set for startup packet */ + conn->status = CONNECTION_MADE; + return PGRES_POLLING_WRITING; + } + else if (pollres == PGRES_POLLING_FAILED) + { + if (conn->gssencmode[0] == 'p') + { + /* + * We failed, but we can retry on "prefer". Have to + * drop the current connection to do so, though. + */ + conn->try_gss = false; + need_new_connection = true; + goto keep_going; + } + /* Else it's a hard failure */ + goto error_return; + } + /* Else, return POLLING_READING or POLLING_WRITING status */ + return pollres; +#else /* !ENABLE_GSS */ + /* unreachable */ + goto error_return; +#endif /* ENABLE_GSS */ + } + + /* + * Handle authentication exchange: wait for postmaster messages + * and respond as necessary. + */ + case CONNECTION_AWAITING_RESPONSE: + { + char beresp; + int msgLength; + int avail; + AuthRequest areq; + int res; + + /* + * 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, NegotiateProtocolVersion, or an error here. + * Anything else probably means it's not Postgres on the other + * end at all. + */ + if (!(beresp == 'R' || beresp == 'v' || beresp == 'E')) + { + libpq_append_conn_error(conn, "expected authentication request from server, but received %c", + beresp); + goto error_return; + } + + /* Read message length word */ + if (pqGetInt(&msgLength, 4, conn)) + { + /* We'll come back when there is more data */ + return PGRES_POLLING_READING; + } + + /* + * Try to validate message length before using it. + * + * Authentication requests can't be very large, although GSS + * auth requests may not be that small. Same for + * NegotiateProtocolVersion. + * + * 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. (Before + * version 14, the server also used the old protocol for + * errors that happened before processing the startup packet.) + */ + if (beresp == 'R' && (msgLength < 8 || msgLength > 2000)) + { + libpq_append_conn_error(conn, "received invalid authentication request"); + goto error_return; + } + if (beresp == 'v' && (msgLength < 8 || msgLength > 2000)) + { + libpq_append_conn_error(conn, "received invalid protocol negotiation message"); + goto error_return; + } + +#define MAX_ERRLEN 30000 + if (beresp == 'E' && (msgLength < 8 || msgLength > MAX_ERRLEN)) + { + /* Handle error from a pre-3.0 server */ + conn->inCursor = conn->inStart + 1; /* reread data */ + if (pqGets_append(&conn->errorMessage, conn)) + { + /* + * We may not have authenticated the server yet, so + * don't let the buffer grow forever. + */ + avail = conn->inEnd - conn->inCursor; + if (avail > MAX_ERRLEN) + { + libpq_append_conn_error(conn, "received invalid error message"); + goto error_return; + } + + /* 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; + + /* + * Before 7.2, the postmaster didn't always end its + * messages with a newline, so add one if needed to + * conform to libpq conventions. + */ + if (conn->errorMessage.len == 0 || + conn->errorMessage.data[conn->errorMessage.len - 1] != '\n') + { + appendPQExpBufferChar(&conn->errorMessage, '\n'); + } + + goto error_return; + } +#undef MAX_ERRLEN + + /* + * Can't process if message body isn't all here yet. + * + * After this check passes, any further EOF during parsing + * implies that the server sent a bad/truncated message. + * Reading more bytes won't help in that case, so don't return + * PGRES_POLLING_READING after this point. + */ + 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 (pqGetErrorNotice3(conn, true)) + { + libpq_append_conn_error(conn, "received invalid error message"); + goto error_return; + } + /* OK, we read the message; mark data consumed */ + conn->inStart = conn->inCursor; + + /* + * If error is "cannot connect now", try the next host if + * any (but we don't want to consider additional addresses + * for this host, nor is there much point in changing SSL + * or GSS mode). This is helpful when dealing with + * standby servers that might not be in hot-standby state. + */ + if (strcmp(conn->last_sqlstate, + ERRCODE_CANNOT_CONNECT_NOW) == 0) + { + conn->try_next_host = true; + goto keep_going; + } + + /* Check to see if we should mention pgpassfile */ + pgpassfileWarning(conn); + +#ifdef ENABLE_GSS + + /* + * If gssencmode is "prefer" and we're using GSSAPI, retry + * without it. + */ + if (conn->gssenc && conn->gssencmode[0] == 'p') + { + /* only retry once */ + conn->try_gss = false; + need_new_connection = true; + goto keep_going; + } +#endif + +#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; + need_new_connection = true; + 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->ssl_in_use + && conn->allow_ssl_try /* redundant? */ + && !conn->wait_ssl_try) /* redundant? */ + { + /* only retry once */ + conn->allow_ssl_try = false; + need_new_connection = true; + goto keep_going; + } +#endif + + goto error_return; + } + else if (beresp == 'v') + { + if (pqGetNegotiateProtocolVersion3(conn)) + { + libpq_append_conn_error(conn, "received invalid protocol negotiation message"); + goto error_return; + } + /* OK, we read the message; mark data consumed */ + conn->inStart = conn->inCursor; + goto error_return; + } + + /* It is an authentication request. */ + conn->auth_req_received = true; + + /* Get the type of request. */ + if (pqGetInt((int *) &areq, 4, conn)) + { + /* can't happen because we checked the length already */ + libpq_append_conn_error(conn, "received invalid authentication request"); + goto error_return; + } + msgLength -= 4; + + /* + * Process the rest of the authentication request message, and + * respond to it if necessary. + * + * Note that conn->pghost must be non-NULL if we are going to + * avoid the Kerberos code doing a hostname look-up. + */ + res = pg_fe_sendauth(areq, msgLength, conn); + + /* OK, we have processed the message; mark data consumed */ + conn->inStart = conn->inCursor; + + if (res != STATUS_OK) + goto error_return; + + /* + * 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) + libpq_append_conn_error(conn, "unexpected message from server during startup"); + 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; + need_new_connection = true; + 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; + } + + /* Almost there now ... */ + conn->status = CONNECTION_CHECK_TARGET; + goto keep_going; + } + + case CONNECTION_CHECK_TARGET: + { + /* + * If a read-write, read-only, primary, or standby connection + * is required, see if we have one. + */ + if (conn->target_server_type == SERVER_TYPE_READ_WRITE || + conn->target_server_type == SERVER_TYPE_READ_ONLY) + { + bool read_only_server; + + /* + * If the server didn't report + * "default_transaction_read_only" or "in_hot_standby" at + * startup, we must determine its state by sending the + * query "SHOW transaction_read_only". This GUC exists in + * all server versions that support 3.0 protocol. + */ + if (conn->default_transaction_read_only == PG_BOOL_UNKNOWN || + conn->in_hot_standby == PG_BOOL_UNKNOWN) + { + /* + * We use PQsendQueryContinue so that + * conn->errorMessage does not get cleared. We need + * to preserve any error messages related to previous + * hosts we have tried and failed to connect to. + */ + conn->status = CONNECTION_OK; + if (!PQsendQueryContinue(conn, + "SHOW transaction_read_only")) + goto error_return; + /* We'll return to this state when we have the answer */ + conn->status = CONNECTION_CHECK_WRITABLE; + return PGRES_POLLING_READING; + } + + /* OK, we can make the test */ + read_only_server = + (conn->default_transaction_read_only == PG_BOOL_YES || + conn->in_hot_standby == PG_BOOL_YES); + + if ((conn->target_server_type == SERVER_TYPE_READ_WRITE) ? + read_only_server : !read_only_server) + { + /* Wrong server state, reject and try the next host */ + if (conn->target_server_type == SERVER_TYPE_READ_WRITE) + libpq_append_conn_error(conn, "session is read-only"); + else + libpq_append_conn_error(conn, "session is not read-only"); + + /* Close connection politely. */ + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + + /* + * Try next host if any, but we don't want to consider + * additional addresses for this host. + */ + conn->try_next_host = true; + goto keep_going; + } + } + else if (conn->target_server_type == SERVER_TYPE_PRIMARY || + conn->target_server_type == SERVER_TYPE_STANDBY || + conn->target_server_type == SERVER_TYPE_PREFER_STANDBY) + { + /* + * If the server didn't report "in_hot_standby" at + * startup, we must determine its state by sending the + * query "SELECT pg_catalog.pg_is_in_recovery()". Servers + * before 9.0 don't have that function, but by the same + * token they don't have any standby mode, so we may just + * assume the result. + */ + if (conn->sversion < 90000) + conn->in_hot_standby = PG_BOOL_NO; + + if (conn->in_hot_standby == PG_BOOL_UNKNOWN) + { + /* + * We use PQsendQueryContinue so that + * conn->errorMessage does not get cleared. We need + * to preserve any error messages related to previous + * hosts we have tried and failed to connect to. + */ + conn->status = CONNECTION_OK; + if (!PQsendQueryContinue(conn, + "SELECT pg_catalog.pg_is_in_recovery()")) + goto error_return; + /* We'll return to this state when we have the answer */ + conn->status = CONNECTION_CHECK_STANDBY; + return PGRES_POLLING_READING; + } + + /* OK, we can make the test */ + if ((conn->target_server_type == SERVER_TYPE_PRIMARY) ? + (conn->in_hot_standby == PG_BOOL_YES) : + (conn->in_hot_standby == PG_BOOL_NO)) + { + /* Wrong server state, reject and try the next host */ + if (conn->target_server_type == SERVER_TYPE_PRIMARY) + libpq_append_conn_error(conn, "server is in hot standby mode"); + else + libpq_append_conn_error(conn, "server is not in hot standby mode"); + + /* Close connection politely. */ + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + + /* + * Try next host if any, but we don't want to consider + * additional addresses for this host. + */ + conn->try_next_host = true; + goto keep_going; + } + } + + /* We can release the address list now. */ + release_conn_addrinfo(conn); + + /* + * Contents of conn->errorMessage are no longer interesting + * (and it seems some clients expect it to be empty after a + * successful connection). + */ + pqClearConnErrorState(conn); + + /* We are open for business! */ + conn->status = CONNECTION_OK; + return PGRES_POLLING_OK; + } + + case CONNECTION_CONSUME: + { + /* + * This state just makes sure the connection is idle after + * we've obtained the result of a SHOW or SELECT query. Once + * we're clear, return to CONNECTION_CHECK_TARGET state to + * decide what to do next. We must transiently set status = + * CONNECTION_OK in order to use the result-consuming + * subroutines. + */ + conn->status = CONNECTION_OK; + if (!PQconsumeInput(conn)) + goto error_return; + + if (PQisBusy(conn)) + { + conn->status = CONNECTION_CONSUME; + return PGRES_POLLING_READING; + } + + /* Call PQgetResult() again until we get a NULL result */ + res = PQgetResult(conn); + if (res != NULL) + { + PQclear(res); + conn->status = CONNECTION_CONSUME; + return PGRES_POLLING_READING; + } + + conn->status = CONNECTION_CHECK_TARGET; + goto keep_going; + } + + case CONNECTION_CHECK_WRITABLE: + { + /* + * Waiting for result of "SHOW transaction_read_only". We + * must transiently set status = CONNECTION_OK in order to use + * the result-consuming subroutines. + */ + conn->status = CONNECTION_OK; + if (!PQconsumeInput(conn)) + goto error_return; + + if (PQisBusy(conn)) + { + conn->status = CONNECTION_CHECK_WRITABLE; + return PGRES_POLLING_READING; + } + + res = PQgetResult(conn); + if (res && PQresultStatus(res) == PGRES_TUPLES_OK && + PQntuples(res) == 1) + { + char *val = PQgetvalue(res, 0, 0); + + /* + * "transaction_read_only = on" proves that at least one + * of default_transaction_read_only and in_hot_standby is + * on, but we don't actually know which. We don't care + * though for the purpose of identifying a read-only + * session, so satisfy the CONNECTION_CHECK_TARGET code by + * claiming they are both on. On the other hand, if it's + * a read-write session, they are certainly both off. + */ + if (strncmp(val, "on", 2) == 0) + { + conn->default_transaction_read_only = PG_BOOL_YES; + conn->in_hot_standby = PG_BOOL_YES; + } + else + { + conn->default_transaction_read_only = PG_BOOL_NO; + conn->in_hot_standby = PG_BOOL_NO; + } + PQclear(res); + + /* Finish reading messages before continuing */ + conn->status = CONNECTION_CONSUME; + goto keep_going; + } + + /* Something went wrong with "SHOW transaction_read_only". */ + PQclear(res); + + /* Append error report to conn->errorMessage. */ + libpq_append_conn_error(conn, "\"%s\" failed", + "SHOW transaction_read_only"); + + /* Close connection politely. */ + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + + /* Try next host. */ + conn->try_next_host = true; + goto keep_going; + } + + case CONNECTION_CHECK_STANDBY: + { + /* + * Waiting for result of "SELECT pg_is_in_recovery()". We + * must transiently set status = CONNECTION_OK in order to use + * the result-consuming subroutines. + */ + conn->status = CONNECTION_OK; + if (!PQconsumeInput(conn)) + goto error_return; + + if (PQisBusy(conn)) + { + conn->status = CONNECTION_CHECK_STANDBY; + return PGRES_POLLING_READING; + } + + res = PQgetResult(conn); + if (res && PQresultStatus(res) == PGRES_TUPLES_OK && + PQntuples(res) == 1) + { + char *val = PQgetvalue(res, 0, 0); + + if (strncmp(val, "t", 1) == 0) + conn->in_hot_standby = PG_BOOL_YES; + else + conn->in_hot_standby = PG_BOOL_NO; + PQclear(res); + + /* Finish reading messages before continuing */ + conn->status = CONNECTION_CONSUME; + goto keep_going; + } + + /* Something went wrong with "SELECT pg_is_in_recovery()". */ + PQclear(res); + + /* Append error report to conn->errorMessage. */ + libpq_append_conn_error(conn, "\"%s\" failed", + "SELECT pg_is_in_recovery()"); + + /* Close connection politely. */ + conn->status = CONNECTION_OK; + sendTerminateConn(conn); + + /* Try next host. */ + conn->try_next_host = true; + goto keep_going; + } + + default: + libpq_append_conn_error(conn, + "invalid connection state %d, probably indicative of memory corruption", + conn->status); + goto error_return; + } + + /* Unreachable */ + +error_return: + + /* + * 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 PQPING_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. + */ + 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 in this process. + * + * Note: the Windows documentation says that we should eventually do a + * matching WSACleanup() call, but experience suggests that that is at + * least as likely to cause problems as fix them. So we don't. + */ + static bool wsastartup_done = false; + + if (!wsastartup_done) + { + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + return NULL; + wsastartup_done = true; + } + + /* Forget any earlier error */ + WSASetLastError(0); +#endif /* WIN32 */ + + conn = (PGconn *) malloc(sizeof(PGconn)); + if (conn == NULL) + 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->pipelineStatus = PQ_PIPELINE_OFF; + conn->xactStatus = PQTRANS_IDLE; + conn->options_valid = false; + conn->nonblocking = false; + conn->client_encoding = PG_SQL_ASCII; + conn->std_strings = false; /* unless server says differently */ + conn->default_transaction_read_only = PG_BOOL_UNKNOWN; + conn->in_hot_standby = PG_BOOL_UNKNOWN; + conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS; + conn->verbosity = PQERRORS_DEFAULT; + conn->show_context = PQSHOW_CONTEXT_ERRORS; + conn->sock = PGINVALID_SOCKET; + conn->Pfdebug = NULL; + + /* + * 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) +{ + /* let any event procs clean up their state data */ + for (int 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); + } + + /* clean up pg_conn_host structures */ + for (int i = 0; i < conn->nconnhost; ++i) + { + free(conn->connhost[i].host); + free(conn->connhost[i].hostaddr); + free(conn->connhost[i].port); + if (conn->connhost[i].password != NULL) + { + explicit_bzero(conn->connhost[i].password, strlen(conn->connhost[i].password)); + free(conn->connhost[i].password); + } + } + free(conn->connhost); + + free(conn->client_encoding_initial); + free(conn->events); + free(conn->pghost); + free(conn->pghostaddr); + free(conn->pgport); + free(conn->connect_timeout); + free(conn->pgtcp_user_timeout); + free(conn->pgoptions); + free(conn->appname); + free(conn->fbappname); + free(conn->dbName); + free(conn->replication); + free(conn->pguser); + if (conn->pgpass) + { + explicit_bzero(conn->pgpass, strlen(conn->pgpass)); + free(conn->pgpass); + } + free(conn->pgpassfile); + free(conn->channel_binding); + free(conn->keepalives); + free(conn->keepalives_idle); + free(conn->keepalives_interval); + free(conn->keepalives_count); + free(conn->sslmode); + free(conn->sslcert); + free(conn->sslkey); + if (conn->sslpassword) + { + explicit_bzero(conn->sslpassword, strlen(conn->sslpassword)); + free(conn->sslpassword); + } + free(conn->sslcertmode); + free(conn->sslrootcert); + free(conn->sslcrl); + free(conn->sslcrldir); + free(conn->sslcompression); + free(conn->sslsni); + free(conn->requirepeer); + free(conn->require_auth); + free(conn->ssl_min_protocol_version); + free(conn->ssl_max_protocol_version); + free(conn->gssencmode); + free(conn->krbsrvname); + free(conn->gsslib); + free(conn->gssdelegation); + free(conn->connip); + /* Note that conn->Pfdebug is not ours to close or free */ + free(conn->write_err_msg); + free(conn->inBuffer); + free(conn->outBuffer); + free(conn->rowBuf); + free(conn->target_session_attrs); + free(conn->load_balance_hosts); + termPQExpBuffer(&conn->errorMessage); + termPQExpBuffer(&conn->workBuffer); + + free(conn); +} + +/* + * store_conn_addrinfo + * - copy addrinfo to PGconn object + * + * Copies the addrinfos from addrlist to the PGconn object such that the + * addrinfos can be manipulated by libpq. Returns a positive integer on + * failure, otherwise zero. + */ +static int +store_conn_addrinfo(PGconn *conn, struct addrinfo *addrlist) +{ + struct addrinfo *ai = addrlist; + + conn->whichaddr = 0; + + conn->naddr = 0; + while (ai) + { + ai = ai->ai_next; + conn->naddr++; + } + + conn->addr = calloc(conn->naddr, sizeof(AddrInfo)); + if (conn->addr == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return 1; + } + + ai = addrlist; + for (int i = 0; i < conn->naddr; i++) + { + conn->addr[i].family = ai->ai_family; + + memcpy(&conn->addr[i].addr.addr, ai->ai_addr, + ai->ai_addrlen); + conn->addr[i].addr.salen = ai->ai_addrlen; + ai = ai->ai_next; + } + + return 0; +} + +/* + * release_conn_addrinfo + * - Free any addrinfo list in the PGconn. + */ +static void +release_conn_addrinfo(PGconn *conn) +{ + if (conn->addr) + { + free(conn->addr); + conn->addr = NULL; + } +} + +/* + * sendTerminateConn + * - Send a terminate message to backend. + */ +static void +sendTerminateConn(PGconn *conn) +{ + /* + * 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', conn); + pqPutMsgEnd(conn); + (void) pqFlush(conn); + } +} + +/* + * 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) +{ + /* + * If possible, send Terminate message to close the connection politely. + */ + sendTerminateConn(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. + * Note that this includes clearing conn's error state; we're no longer + * interested in any failures associated with the old connection, and we + * want a clean slate for any new connection attempt. + */ + pqDropConnection(conn, true); + conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */ + conn->asyncStatus = PGASYNC_IDLE; + conn->xactStatus = PQTRANS_IDLE; + conn->pipelineStatus = PQ_PIPELINE_OFF; + pqClearAsyncResult(conn); /* deallocate result */ + pqClearConnErrorState(conn); + release_conn_addrinfo(conn); + + /* Reset all state obtained from server, too */ + pqDropServerData(conn); +} + +/* + * 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. + */ + int i; + + for (i = 0; i < conn->nEvents; i++) + { + PGEventConnReset evt; + + evt.conn = conn; + (void) conn->events[i].proc(PGEVT_CONNRESET, &evt, + conn->events[i].passThrough); + } + } + } +} + + +/* + * 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. + */ + int i; + + for (i = 0; i < conn->nEvents; i++) + { + PGEventConnReset evt; + + evt.conn = conn; + (void) conn->events[i].proc(PGEVT_CONNRESET, &evt, + conn->events[i].passThrough); + } + } + + 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; + /* We use -1 to indicate an unset connection option */ + cancel->pgtcp_user_timeout = -1; + cancel->keepalives = -1; + cancel->keepalives_idle = -1; + cancel->keepalives_interval = -1; + cancel->keepalives_count = -1; + if (conn->pgtcp_user_timeout != NULL) + { + if (!parse_int_param(conn->pgtcp_user_timeout, + &cancel->pgtcp_user_timeout, + conn, "tcp_user_timeout")) + goto fail; + } + if (conn->keepalives != NULL) + { + if (!parse_int_param(conn->keepalives, + &cancel->keepalives, + conn, "keepalives")) + goto fail; + } + if (conn->keepalives_idle != NULL) + { + if (!parse_int_param(conn->keepalives_idle, + &cancel->keepalives_idle, + conn, "keepalives_idle")) + goto fail; + } + if (conn->keepalives_interval != NULL) + { + if (!parse_int_param(conn->keepalives_interval, + &cancel->keepalives_interval, + conn, "keepalives_interval")) + goto fail; + } + if (conn->keepalives_count != NULL) + { + if (!parse_int_param(conn->keepalives_count, + &cancel->keepalives_count, + conn, "keepalives_count")) + goto fail; + } + + return cancel; + +fail: + free(cancel); + return NULL; +} + +/* PQfreeCancel: free a cancel structure */ +void +PQfreeCancel(PGcancel *cancel) +{ + free(cancel); +} + + +/* + * Sets an integer socket option on a TCP socket, if the provided value is + * not negative. Returns false if setsockopt fails for some reason. + * + * CAUTION: This needs to be signal safe, since it's used by PQcancel. + */ +#if defined(TCP_USER_TIMEOUT) || !defined(WIN32) +static bool +optional_setsockopt(int fd, int protoid, int optid, int value) +{ + if (value < 0) + return true; + if (setsockopt(fd, protoid, optid, (char *) &value, sizeof(value)) < 0) + return false; + return true; +} +#endif + + +/* + * PQcancel: request query cancel + * + * 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. + * + * 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. + * + * 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. + */ +int +PQcancel(PGcancel *cancel, char *errbuf, int errbufsize) +{ + int save_errno = SOCK_ERRNO; + pgsocket tmpsock = PGINVALID_SOCKET; + int maxlen; + struct + { + uint32 packetlen; + CancelRequestPacket cp; + } crp; + + if (!cancel) + { + strlcpy(errbuf, "PQcancel() -- no cancel object supplied", errbufsize); + /* strlcpy probably doesn't change errno, but be paranoid */ + SOCK_ERRNO_SET(save_errno); + return false; + } + + /* + * We need to open a temporary connection to the postmaster. Do this with + * only kernel calls. + */ + if ((tmpsock = socket(cancel->raddr.addr.ss_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET) + { + strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize); + goto cancel_errReturn; + } + + /* + * Since this connection will only be used to send a single packet of + * data, we don't need NODELAY. We also don't set the socket to + * nonblocking mode, because the API definition of PQcancel requires the + * cancel to be sent in a blocking way. + * + * We do set socket options related to keepalives and other TCP timeouts. + * This ensures that this function does not block indefinitely when + * reasonable keepalive and timeout settings have been provided. + */ + if (cancel->raddr.addr.ss_family != AF_UNIX && + cancel->keepalives != 0) + { +#ifndef WIN32 + if (!optional_setsockopt(tmpsock, SOL_SOCKET, SO_KEEPALIVE, 1)) + { + strlcpy(errbuf, "PQcancel() -- setsockopt(SO_KEEPALIVE) failed: ", errbufsize); + goto cancel_errReturn; + } + +#ifdef PG_TCP_KEEPALIVE_IDLE + if (!optional_setsockopt(tmpsock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE, + cancel->keepalives_idle)) + { + strlcpy(errbuf, "PQcancel() -- setsockopt(" PG_TCP_KEEPALIVE_IDLE_STR ") failed: ", errbufsize); + goto cancel_errReturn; + } +#endif + +#ifdef TCP_KEEPINTVL + if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPINTVL, + cancel->keepalives_interval)) + { + strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPINTVL) failed: ", errbufsize); + goto cancel_errReturn; + } +#endif + +#ifdef TCP_KEEPCNT + if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_KEEPCNT, + cancel->keepalives_count)) + { + strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_KEEPCNT) failed: ", errbufsize); + goto cancel_errReturn; + } +#endif + +#else /* WIN32 */ + +#ifdef SIO_KEEPALIVE_VALS + if (!setKeepalivesWin32(tmpsock, + cancel->keepalives_idle, + cancel->keepalives_interval)) + { + strlcpy(errbuf, "PQcancel() -- WSAIoctl(SIO_KEEPALIVE_VALS) failed: ", errbufsize); + goto cancel_errReturn; + } +#endif /* SIO_KEEPALIVE_VALS */ +#endif /* WIN32 */ + + /* TCP_USER_TIMEOUT works the same way on Unix and Windows */ +#ifdef TCP_USER_TIMEOUT + if (!optional_setsockopt(tmpsock, IPPROTO_TCP, TCP_USER_TIMEOUT, + cancel->pgtcp_user_timeout)) + { + strlcpy(errbuf, "PQcancel() -- setsockopt(TCP_USER_TIMEOUT) failed: ", errbufsize); + goto cancel_errReturn; + } +#endif + } + +retry3: + if (connect(tmpsock, (struct sockaddr *) &cancel->raddr.addr, + cancel->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; + } + + /* Create and send the cancel request packet. */ + + crp.packetlen = pg_hton32((uint32) sizeof(crp)); + crp.cp.cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE); + crp.cp.backendPID = pg_hton32(cancel->be_pid); + crp.cp.cancelAuthCode = pg_hton32(cancel->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) + { + /* + * We can't invoke strerror here, since it's not signal-safe. Settle + * for printing the decimal value of errno. Even that has to be done + * the hard way. + */ + int val = SOCK_ERRNO; + char buf[32]; + char *bufp; + + bufp = buf + sizeof(buf) - 1; + *bufp = '\0'; + do + { + *(--bufp) = (val % 10) + '0'; + val /= 10; + } while (val > 0); + bufp -= 6; + memcpy(bufp, "error ", 6); + strncat(errbuf, bufp, maxlen); + strcat(errbuf, "\n"); + } + if (tmpsock != PGINVALID_SOCKET) + closesocket(tmpsock); + SOCK_ERRNO_SET(save_errno); + return false; +} + + +/* + * 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; + PGcancel *cancel; + + /* 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); + conn->errorReported = 0; + + return false; + } + + cancel = PQgetCancel(conn); + if (cancel) + { + r = PQcancel(cancel, conn->errorMessage.data, + conn->errorMessage.maxlen); + PQfreeCancel(cancel); + } + else + { + strlcpy(conn->errorMessage.data, "out of memory", + conn->errorMessage.maxlen); + r = false; + } + + if (!r) + { + conn->errorMessage.len = strlen(conn->errorMessage.data); + conn->errorReported = 0; + } + + 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. + */ +int +pqPacketSend(PGconn *conn, char pack_type, + const void *buf, size_t buf_len) +{ + /* Start the message. */ + if (pqPutMsgStart(pack_type, 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 appended to *errorMessage 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) + { + libpq_append_error(errorMessage, "out of memory"); + 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) + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": scheme must be ldap://", 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) == '?') + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": missing distinguished name", + purl); + free(url); + return 3; + } + *p = '\0'; /* terminate hostname */ + dn = p + 1; + + /* attribute */ + if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": must have exactly one attribute", + purl); + free(url); + return 3; + } + *p = '\0'; + attrs[0] = p + 1; + + /* scope */ + if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": must have search scope (base/one/sub)", + purl); + free(url); + return 3; + } + *p = '\0'; + scopestr = p + 1; + + /* filter */ + if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?') + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": no filter", + 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) + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": invalid port number", + purl); + free(url); + return 3; + } + port = (int) lport; + } + + /* Allow only one attribute */ + if (strchr(attrs[0], ',') != NULL) + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": must have exactly one attribute", + 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 + { + libpq_append_error(errorMessage, + "invalid LDAP URL \"%s\": must have search scope (base/one/sub)", + purl); + free(url); + return 3; + } + + /* initialize LDAP structure */ + if ((ld = ldap_init(hostname, port)) == NULL) + { + libpq_append_error(errorMessage, "could not create LDAP structure"); + 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); + libpq_append_error(errorMessage, "lookup on LDAP server failed: %s", 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) + { + if (rc > 1) + libpq_append_error(errorMessage, "more than one entry found on LDAP lookup"); + else + libpq_append_error(errorMessage, "no entry found on LDAP lookup"); + ldap_msgfree(res); + ldap_unbind(ld); + free(url); + return 1; + } + + /* get entry */ + if ((entry = ldap_first_entry(ld, res)) == NULL) + { + /* should never happen */ + libpq_append_error(errorMessage, "no entry found on LDAP lookup"); + ldap_msgfree(res); + ldap_unbind(ld); + free(url); + return 1; + } + + /* get values */ + if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL) + { + libpq_append_error(errorMessage, "attribute has no values on LDAP lookup"); + ldap_msgfree(res); + ldap_unbind(ld); + free(url); + return 1; + } + + ldap_msgfree(res); + free(url); + + if (values[0] == NULL) + { + libpq_append_error(errorMessage, "attribute has no values on LDAP lookup"); + 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) + { + libpq_append_error(errorMessage, "out of memory"); + 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)) + { + libpq_append_error(errorMessage, + "missing \"=\" after \"%s\" in connection info string", + 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)) + { + libpq_append_error(errorMessage, + "missing \"=\" after \"%s\" in connection info string", + 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) + { + libpq_append_error(errorMessage, "out of memory"); + free(result); + return 3; + } + } + found_keyword = true; + break; + } + } + if (!found_keyword) + { + libpq_append_error(errorMessage, "invalid connection option \"%s\"", optname); + free(result); + return 1; + } + optname = NULL; + optval = NULL; + } + oldstate = state; + } + + free(result); + + if (state == 5 || state == 6) + { + libpq_append_error(errorMessage, + "unterminated quoted string in connection info string"); + return 3; + } + + return 0; +} + +#endif /* USE_LDAP */ + +/* + * parseServiceInfo: if a service name has been given, look it up and absorb + * connection options from it into *options. + * + * Returns 0 on success, nonzero on failure. On failure, if errorMessage + * isn't null, also store an error message there. (Note: the only reason + * this function and related ones don't dump core on errorMessage == NULL + * is the undocumented fact that appendPQExpBuffer does nothing when passed + * a null PQExpBuffer pointer.) + */ +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 no service name given, nothing to do */ + if (service == NULL) + return 0; + + /* + * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that + * exists). + */ + if ((env = getenv("PGSERVICEFILE")) != NULL) + strlcpy(serviceFile, env, sizeof(serviceFile)); + else + { + char homedir[MAXPGPATH]; + + if (!pqGetHomeDirectory(homedir, sizeof(homedir))) + goto next_file; + snprintf(serviceFile, MAXPGPATH, "%s/%s", homedir, ".pg_service.conf"); + if (stat(serviceFile, &stat_buf) != 0) + 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); + if (stat(serviceFile, &stat_buf) != 0) + goto last_file; + + status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); + if (status != 0) + return status; + +last_file: + if (!group_found) + { + libpq_append_error(errorMessage, "definition of service \"%s\" not found", service); + return 3; + } + + return 0; +} + +static int +parseServiceFile(const char *serviceFile, + const char *service, + PQconninfoOption *options, + PQExpBuffer errorMessage, + bool *group_found) +{ + int result = 0, + linenr = 0, + i; + FILE *f; + char *line; + char buf[1024]; + + *group_found = false; + + f = fopen(serviceFile, "r"); + if (f == NULL) + { + libpq_append_error(errorMessage, "service file \"%s\" not found", serviceFile); + return 1; + } + + while ((line = fgets(buf, sizeof(buf), f)) != NULL) + { + int len; + + linenr++; + + if (strlen(line) >= sizeof(buf) - 1) + { + libpq_append_error(errorMessage, + "line %d too long in service file \"%s\"", + linenr, + serviceFile); + result = 2; + goto exit; + } + + /* ignore whitespace at end of line, especially the newline */ + len = strlen(line); + while (len > 0 && isspace((unsigned char) line[len - 1])) + line[--len] = '\0'; + + /* ignore leading whitespace too */ + while (*line && isspace((unsigned char) line[0])) + line++; + + /* ignore comments and empty lines */ + if (line[0] == '\0' || line[0] == '#') + continue; + + /* Check for right groupname */ + if (line[0] == '[') + { + if (*group_found) + { + /* end of desired group reached; return success */ + goto exit; + } + + 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: + goto exit; + case 1: + case 3: + result = 3; + goto exit; + case 2: + continue; + } + } +#endif + + key = line; + val = strchr(line, '='); + if (val == NULL) + { + libpq_append_error(errorMessage, + "syntax error in service file \"%s\", line %d", + serviceFile, + linenr); + result = 3; + goto exit; + } + *val++ = '\0'; + + if (strcmp(key, "service") == 0) + { + libpq_append_error(errorMessage, + "nested service specifications not supported in service file \"%s\", line %d", + serviceFile, + linenr); + result = 3; + goto exit; + } + + /* + * 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) + { + libpq_append_error(errorMessage, "out of memory"); + result = 3; + goto exit; + } + found_keyword = true; + break; + } + } + + if (!found_keyword) + { + libpq_append_error(errorMessage, + "syntax error in service file \"%s\", line %d", + serviceFile, + linenr); + result = 3; + goto exit; + } + } + } + } + +exit: + fclose(f); + + return result; +} + + +/* + * 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) + { + libpq_append_error(errorMessage, "out of memory"); + 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 added to 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) + { + libpq_append_error(errorMessage, "out of memory"); + 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 != '=') + { + libpq_append_error(errorMessage, + "missing \"=\" after \"%s\" in connection info string", + 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') + { + libpq_append_error(errorMessage, "unterminated quoted string in connection info string"); + 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 + * appended to 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) + { + libpq_append_error(errorMessage, "invalid connection option \"%s\"", 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) + { + free(options[k].val); + options[k].val = strdup(str_option->val); + if (!options[k].val) + { + libpq_append_error(errorMessage, "out of memory"); + 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 + */ + free(option->val); + option->val = strdup(pvalue); + if (!option->val) + { + libpq_append_error(errorMessage, "out of memory"); + 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; + PQconninfoOption *sslmode_default = NULL, + *sslrootcert = NULL; + 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 (strcmp(option->keyword, "sslrootcert") == 0) + sslrootcert = option; /* save for later */ + + 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) + libpq_append_error(errorMessage, "out of memory"); + 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) + libpq_append_error(errorMessage, "out of memory"); + return false; + } + continue; + } + + /* + * sslmode is not specified. Let it be filled in with the compiled + * default for now, but if sslrootcert=system, we'll override the + * default later before returning. + */ + sslmode_default = option; + } + + /* + * 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) + libpq_append_error(errorMessage, "out of memory"); + 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; + } + } + + /* + * Special handling for sslrootcert=system with no sslmode explicitly + * defined. In this case we want to strengthen the default sslmode to + * verify-full. + */ + if (sslmode_default && sslrootcert) + { + if (sslrootcert->val && strcmp(sslrootcert->val, "system") == 0) + { + free(sslmode_default->val); + + sslmode_default->val = strdup("verify-full"); + if (!sslmode_default->val) + { + if (errorMessage) + libpq_append_error(errorMessage, "out of memory"); + return false; + } + } + } + + 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. As an extension, we also allow multiple + * netloc[:port] specifications, separated by commas: + * + * postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...] + * + * 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 = NULL; + char *start; + char prevchar = '\0'; + char *user = NULL; + char *host = NULL; + bool retval = false; + PQExpBufferData hostbuf; + PQExpBufferData portbuf; + + initPQExpBuffer(&hostbuf); + initPQExpBuffer(&portbuf); + if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) + { + libpq_append_error(errorMessage, "out of memory"); + goto cleanup; + } + + /* need a modifiable copy of the input URI */ + buf = strdup(uri); + if (buf == NULL) + { + libpq_append_error(errorMessage, "out of memory"); + goto cleanup; + } + start = buf; + + /* Skip the URI prefix */ + prefix_len = uri_prefix_length(uri); + if (prefix_len == 0) + { + /* Should never happen */ + libpq_append_error(errorMessage, + "invalid URI propagated to internal parser routine: \"%s\"", + 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; + } + + /* + * There may be multiple netloc[:port] pairs, each separated from the next + * by a comma. When we initially enter this loop, "p" has been + * incremented past optional URI credential information at this point and + * now points at the "netloc" part of the URI. On subsequent loop + * iterations, "p" has been incremented past the comma separator and now + * points at the start of the next "netloc". + */ + for (;;) + { + /* + * Look for IPv6 address. + */ + if (*p == '[') + { + host = ++p; + while (*p && *p != ']') + ++p; + if (!*p) + { + libpq_append_error(errorMessage, + "end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"", + uri); + goto cleanup; + } + if (p == host) + { + libpq_append_error(errorMessage, + "IPv6 host address may not be empty in URI: \"%s\"", + 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 or a separator comma. + */ + if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') + { + libpq_append_error(errorMessage, + "unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"", + *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) or host separator (comma). + */ + while (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',') + ++p; + } + + /* Save the hostname terminator before we null it */ + prevchar = *p; + *p = '\0'; + + appendPQExpBufferStr(&hostbuf, host); + + if (prevchar == ':') + { + const char *port = ++p; /* advance past host terminator */ + + while (*p && *p != '/' && *p != '?' && *p != ',') + ++p; + + prevchar = *p; + *p = '\0'; + + appendPQExpBufferStr(&portbuf, port); + } + + if (prevchar != ',') + break; + ++p; /* advance past comma separator */ + appendPQExpBufferChar(&hostbuf, ','); + appendPQExpBufferChar(&portbuf, ','); + } + + /* Save final values for host and port. */ + if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf)) + goto cleanup; + if (hostbuf.data[0] && + !conninfo_storeval(options, "host", hostbuf.data, + errorMessage, false, true)) + goto cleanup; + if (portbuf.data[0] && + !conninfo_storeval(options, "port", portbuf.data, + 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: + termPQExpBuffer(&hostbuf); + termPQExpBuffer(&portbuf); + 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; + int oldmsglen; + + /* + * Scan the params string for '=' and '&', marking the end of keyword + * and value respectively. + */ + for (;;) + { + if (*p == '=') + { + /* Was there '=' already? */ + if (value != NULL) + { + libpq_append_error(errorMessage, + "extra key/value separator \"=\" in URI query parameter: \"%s\"", + 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) + { + libpq_append_error(errorMessage, + "missing key/value separator \"=\" in URI query parameter: \"%s\"", + 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. + */ + oldmsglen = errorMessage->len; + if (!conninfo_storeval(connOptions, keyword, value, + errorMessage, true, false)) + { + /* Insert generic message if conninfo_storeval didn't give one. */ + if (errorMessage->len == oldmsglen) + libpq_append_error(errorMessage, + "invalid URI query parameter: \"%s\"", + 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) + { + libpq_append_error(errorMessage, "out of memory"); + 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))) + { + libpq_append_error(errorMessage, + "invalid percent-encoded token: \"%s\"", + str); + free(buf); + return NULL; + } + + c = (hi << 4) | lo; + if (c == 0) + { + libpq_append_error(errorMessage, + "forbidden value %%00 in percent-encoded value: \"%s\"", + 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) + libpq_append_error(errorMessage, + "invalid connection option \"%s\"", + 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) + { + libpq_append_error(errorMessage, "out of memory"); + return NULL; + } + } + + 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, + * and we prefer not to trash the conn's errorMessage. + */ + 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) +{ + if (connOptions == NULL) + return; + + for (PQconninfoOption *option = connOptions; option->keyword != NULL; option++) + 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) +{ + char *password = NULL; + + if (!conn) + return NULL; + if (conn->connhost != NULL) + password = conn->connhost[conn->whichhost].password; + if (password == NULL) + password = conn->pgpass; + /* Historically we've returned "" not NULL for no password specified */ + if (password == NULL) + password = ""; + return password; +} + +char * +PQhost(const PGconn *conn) +{ + if (!conn) + return NULL; + + if (conn->connhost != NULL) + { + /* + * Return the verbatim host value provided by user, or hostaddr in its + * lack. + */ + if (conn->connhost[conn->whichhost].host != NULL && + conn->connhost[conn->whichhost].host[0] != '\0') + return conn->connhost[conn->whichhost].host; + else if (conn->connhost[conn->whichhost].hostaddr != NULL && + conn->connhost[conn->whichhost].hostaddr[0] != '\0') + return conn->connhost[conn->whichhost].hostaddr; + } + + return ""; +} + +char * +PQhostaddr(const PGconn *conn) +{ + if (!conn) + return NULL; + + /* Return the parsed IP address */ + if (conn->connhost != NULL && conn->connip != NULL) + return conn->connip; + + return ""; +} + +char * +PQport(const PGconn *conn) +{ + if (!conn) + return NULL; + + if (conn->connhost != NULL) + return conn->connhost[conn->whichhost].port; + + return ""; +} + +/* + * No longer does anything, but the function remains for API backwards + * compatibility. + */ +char * +PQtty(const PGconn *conn) +{ + if (!conn) + return NULL; + return ""; +} + +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"); + + /* + * The errorMessage buffer might be marked "broken" due to having + * previously failed to allocate enough memory for the message. In that + * case, tell the application we ran out of memory. + */ + if (PQExpBufferBroken(&conn->errorMessage)) + return libpq_gettext("out of memory\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; +} + +PGpipelineStatus +PQpipelineStatus(const PGconn *conn) +{ + if (!conn) + return PQ_PIPELINE_OFF; + + return conn->pipelineStatus; +} + +int +PQconnectionNeedsPassword(const PGconn *conn) +{ + char *password; + + if (!conn) + return false; + password = PQpass(conn); + if (conn->password_needed && + (password == NULL || password[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 +PQconnectionUsedGSSAPI(const PGconn *conn) +{ + if (!conn) + return false; + if (conn->gssapi_used) + 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 + { + /* + * We rely on the backend to report the parameter value, and we'll + * change state at that time. + */ + 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; +} + +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, const char *token) +{ + char *tbuf; + const char *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(const char *hostname, const char *port, const char *dbname, + const char *username, const char *pgpassfile) +{ + FILE *fp; + struct stat stat_buf; + PQExpBufferData buf; + + if (dbname == NULL || dbname[0] == '\0') + return NULL; + + if (username == NULL || username[0] == '\0') + return NULL; + + /* 'localhost' matches pghost of '' or the default socket directory */ + if (hostname == NULL || hostname[0] == '\0') + hostname = DefaultHost; + else if (is_unixsock_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[0] == '\0') + port = DEF_PGPORT_STR; + + /* 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; + + /* Use an expansible buffer to accommodate any reasonable line length */ + initPQExpBuffer(&buf); + + while (!feof(fp) && !ferror(fp)) + { + /* Make sure there's a reasonable amount of room in the buffer */ + if (!enlargePQExpBuffer(&buf, 128)) + break; + + /* Read some data, appending it to what we already have */ + if (fgets(buf.data + buf.len, buf.maxlen - buf.len, fp) == NULL) + break; + buf.len += strlen(buf.data + buf.len); + + /* If we don't yet have a whole line, loop around to read more */ + if (!(buf.len > 0 && buf.data[buf.len - 1] == '\n') && !feof(fp)) + continue; + + /* ignore comments */ + if (buf.data[0] != '#') + { + char *t = buf.data; + int len; + + /* strip trailing newline and carriage return */ + len = pg_strip_crlf(t); + + if (len > 0 && + (t = pwdfMatchesString(t, hostname)) != NULL && + (t = pwdfMatchesString(t, port)) != NULL && + (t = pwdfMatchesString(t, dbname)) != NULL && + (t = pwdfMatchesString(t, username)) != NULL) + { + /* Found a match. */ + char *ret, + *p1, + *p2; + + ret = strdup(t); + + fclose(fp); + explicit_bzero(buf.data, buf.maxlen); + termPQExpBuffer(&buf); + + 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; + } + } + + /* No match, reset buffer to prepare for next line. */ + buf.len = 0; + } + + fclose(fp); + explicit_bzero(buf.data, buf.maxlen); + termPQExpBuffer(&buf); + return NULL; +} + + +/* + * If the connection failed due to bad password, we should mention + * if we got the password from the pgpassfile. + */ +static void +pgpassfileWarning(PGconn *conn) +{ + /* If it was 'invalid authorization', add pgpassfile mention */ + /* only works with >= 9.0 servers */ + if (conn->password_needed && + conn->connhost[conn->whichhost].password != NULL && + conn->result) + { + const char *sqlstate = PQresultErrorField(conn->result, + PG_DIAG_SQLSTATE); + + if (sqlstate && strcmp(sqlstate, ERRCODE_INVALID_PASSWORD) == 0) + libpq_append_conn_error(conn, "password retrieved from file \"%s\"", + conn->pgpassfile); + } +} + +/* + * Check if the SSL protocol value given in input is valid or not. + * This is used as a sanity check routine for the connection parameters + * ssl_min_protocol_version and ssl_max_protocol_version. + */ +static bool +sslVerifyProtocolVersion(const char *version) +{ + /* + * An empty string and a NULL value are considered valid as it is + * equivalent to ignoring the parameter. + */ + if (!version || strlen(version) == 0) + return true; + + if (pg_strcasecmp(version, "TLSv1") == 0 || + pg_strcasecmp(version, "TLSv1.1") == 0 || + pg_strcasecmp(version, "TLSv1.2") == 0 || + pg_strcasecmp(version, "TLSv1.3") == 0) + return true; + + /* anything else is wrong */ + return false; +} + + +/* + * Ensure that the SSL protocol range given in input is correct. The check + * is performed on the input string to keep it TLS backend agnostic. Input + * to this function is expected verified with sslVerifyProtocolVersion(). + */ +static bool +sslVerifyProtocolRange(const char *min, const char *max) +{ + Assert(sslVerifyProtocolVersion(min) && + sslVerifyProtocolVersion(max)); + + /* If at least one of the bounds is not set, the range is valid */ + if (min == NULL || max == NULL || strlen(min) == 0 || strlen(max) == 0) + return true; + + /* + * If the minimum version is the lowest one we accept, then all options + * for the maximum are valid. + */ + if (pg_strcasecmp(min, "TLSv1") == 0) + return true; + + /* + * The minimum bound is valid, and cannot be TLSv1, so using TLSv1 for the + * maximum is incorrect. + */ + if (pg_strcasecmp(max, "TLSv1") == 0) + return false; + + /* + * At this point we know that we have a mix of TLSv1.1 through 1.3 + * versions. + */ + if (pg_strcasecmp(min, max) > 0) + return false; + + return true; +} + + +/* + * 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). + * + * Returns true on success, false on failure to obtain the directory name. + * + * CAUTION: although in most situations failure is unexpected, there are users + * who like to run applications in a home-directory-less environment. On + * failure, you almost certainly DO NOT want to report an error. Just act as + * though whatever file you were hoping to find in the home directory isn't + * there (which it isn't). + */ +bool +pqGetHomeDirectory(char *buf, int bufsize) +{ +#ifndef WIN32 + const char *home; + + home = getenv("HOME"); + if (home == NULL || home[0] == '\0') + return pg_get_user_home_dir(geteuid(), buf, bufsize); + strlcpy(buf, home, 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. + * + * Since we neglected to provide any error-return convention in the + * pgthreadlock_t API, we can't do much except Assert upon failure of any + * mutex primitive. Fortunately, such failures appear to be nonexistent in + * the field. + */ + +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)) + Assert(false); + } + InterlockedExchange(&mutex_initlock, 0); + } +#endif + if (acquire) + { + if (pthread_mutex_lock(&singlethread_lock)) + Assert(false); + } + else + { + if (pthread_mutex_unlock(&singlethread_lock)) + Assert(false); + } +#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/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c b/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c new file mode 100644 index 0000000000..26564955d0 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-exec.c @@ -0,0 +1,4445 @@ +/*------------------------------------------------------------------------- + * + * fe-exec.c + * functions related to sending a query down to the backend + * + * Portions Copyright (c) 1996-2023, 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 <ctype.h> +#include <fcntl.h> +#include <limits.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "mb/pg_wchar.h" + +/* 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", + "PGRES_PIPELINE_SYNC", + "PGRES_PIPELINE_ABORTED" +}; + +/* We return this if we're unable to make a PGresult at all */ +static const PGresult OOM_result = { + .resultStatus = PGRES_FATAL_ERROR, + .client_encoding = PG_SQL_ASCII, + .errMsg = "out of memory\n", +}; + +/* + * 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, size_t *memSize); +static bool pqAddTuple(PGresult *res, PGresAttValue *tup, + const char **errmsgp); +static int PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery); +static bool PQsendQueryStart(PGconn *conn, bool newQuery); +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); +static void pqPipelineProcessQueue(PGconn *conn); +static int pqPipelineFlush(PGconn *conn); + + +/* ---------------- + * 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. + * + * Note: the logic to copy the conn's errorMessage is now vestigial; + * no internal caller uses it. However, that behavior is documented for + * outside callers, so we'd better keep it. + */ +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; + result->memorySize = sizeof(PGresult); + + 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: + /* we intentionally do not use or modify errorReported here */ + pqSetResultError(result, &conn->errorMessage, 0); + break; + } + + /* copy events last; result must be valid if we need to PQclear */ + if (conn->nEvents > 0) + { + result->events = dupEvents(conn->events, conn->nEvents, + &result->memorySize); + 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; + + /* Fail if argument is NULL or OOM_result */ + if (!res || (const PGresult *) res == &OOM_result) + return false; + + /* If attrs already exist, they cannot be overwritten. */ + if (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, + &dest->memorySize); + if (!dest->events) + { + PQclear(dest); + return NULL; + } + dest->nEvents = src->nEvents; + } + + /* Okay, trigger PGEVT_RESULTCOPY event */ + for (i = 0; i < dest->nEvents; i++) + { + /* We don't fire events that had some previous failure */ + 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)) + 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. + * The total space allocated is added to *memSize. + */ +static PGEvent * +dupEvents(PGEvent *events, int count, size_t *memSize) +{ + PGEvent *newEvents; + size_t msize; + int i; + + if (!events || count <= 0) + return NULL; + + msize = count * sizeof(PGEvent); + newEvents = (PGEvent *) malloc(msize); + 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; + } + msize += strlen(events[i].name) + 1; + } + + *memSize += msize; + 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. + * (On failure, we report the specific problem via pqInternalNotice.) + */ +int +PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len) +{ + PGresAttValue *attval; + const char *errmsg = NULL; + + /* Fail if argument is NULL or OOM_result */ + if (!res || (const PGresult *) res == &OOM_result) + return false; + + /* Invalid field_num? */ + if (!check_field_number(res, field_num)) + return false; + + /* Invalid tup_num, must be <= ntups */ + if (tup_num < 0 || tup_num > res->ntups) + { + pqInternalNotice(&res->noticeHooks, + "row number %d is out of range 0..%d", + 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) + goto fail; + + /* 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, &errmsg)) + goto fail; + } + + 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) + goto fail; + attval->len = len; + memcpy(attval->value, value, len); + attval->value[len] = '\0'; + } + + return true; + + /* + * Report failure via pqInternalNotice. If preceding code didn't provide + * an error message, assume "out of memory" was meant. + */ +fail: + if (!errmsg) + errmsg = libpq_gettext("out of memory"); + pqInternalNotice(&res->noticeHooks, "%s", errmsg); + + return false; +} + +/* + * 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) +{ + /* Fail if argument is NULL or OOM_result */ + if (!res || (const PGresult *) res == &OOM_result) + return NULL; + + 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) + { + size_t alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD; + + block = (PGresult_data *) malloc(alloc_size); + if (!block) + return NULL; + res->memorySize += alloc_size; + 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; + res->memorySize += PGRESULT_DATA_BLOCKSIZE; + 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; +} + +/* + * PQresultMemorySize - + * Returns total space allocated for the PGresult. + */ +size_t +PQresultMemorySize(const PGresult *res) +{ + if (!res) + return 0; + return res->memorySize; +} + +/* + * 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 + * + * Copy text from errorMessage buffer beginning at given offset + * (it's caller's responsibility that offset is valid) + */ +void +pqSetResultError(PGresult *res, PQExpBuffer errorMessage, int offset) +{ + char *msg; + + if (!res) + return; + + /* + * We handle two OOM scenarios here. The errorMessage buffer might be + * marked "broken" due to having previously failed to allocate enough + * memory for the message, or it might be fine but pqResultStrdup fails + * and returns NULL. In either case, just make res->errMsg point directly + * at a constant "out of memory" string. + */ + if (!PQExpBufferBroken(errorMessage)) + msg = pqResultStrdup(res, errorMessage->data + offset); + else + msg = NULL; + if (msg) + res->errMsg = msg; + else + res->errMsg = libpq_gettext("out of memory\n"); +} + +/* + * PQclear - + * free's the memory associated with a PGresult + */ +void +PQclear(PGresult *res) +{ + PGresult_data *block; + int i; + + /* As a convenience, do nothing for a NULL pointer */ + if (!res) + return; + /* Also, do nothing if the argument is OOM_result */ + if ((const PGresult *) res == &OOM_result) + return; + + /* Close down any events we may have */ + 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); + } + + 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 */ + 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) +{ + PQclear(conn->result); + conn->result = NULL; + conn->error_result = false; + PQclear(conn->next_result); + conn->next_result = NULL; +} + +/* + * pqSaveErrorResult - + * remember that we have an error condition + * + * In much of libpq, reporting an error just requires appending text to + * conn->errorMessage and returning a failure code to one's caller. + * Where returning a failure code is impractical, instead call this + * function to remember that an error needs to be reported. + * + * (It might seem that appending text to conn->errorMessage should be + * sufficient, but we can't rely on that working under out-of-memory + * conditions. The OOM hazard is also why we don't try to make a new + * PGresult right here.) + */ +void +pqSaveErrorResult(PGconn *conn) +{ + /* Drop any pending result ... */ + pqClearAsyncResult(conn); + /* ... and set flag to remember to make an error result later */ + conn->error_result = true; +} + +/* + * pqSaveWriteError - + * report a write failure + * + * As above, after appending conn->write_err_msg to whatever other error we + * have. This is used when we've detected a write failure and have exhausted + * our chances of reporting something else instead. + */ +static void +pqSaveWriteError(PGconn *conn) +{ + /* + * If write_err_msg is null because of previous strdup failure, do what we + * can. (It's likely our machinations here will get OOM failures as well, + * but might as well try.) + */ + if (conn->write_err_msg) + { + appendPQExpBufferStr(&conn->errorMessage, conn->write_err_msg); + /* Avoid possibly appending the same message twice */ + conn->write_err_msg[0] = '\0'; + } + else + libpq_append_conn_error(conn, "write to server failed"); + + pqSaveErrorResult(conn); +} + +/* + * pqPrepareAsyncResult - + * prepare the current 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 update our notion of how much error text has been + * returned to the application. + */ +PGresult * +pqPrepareAsyncResult(PGconn *conn) +{ + PGresult *res; + + res = conn->result; + if (res) + { + /* + * If the pre-existing result is an ERROR (presumably something + * received from the server), assume that it represents whatever is in + * conn->errorMessage, and advance errorReported. + */ + if (res->resultStatus == PGRES_FATAL_ERROR) + conn->errorReported = conn->errorMessage.len; + } + else + { + /* + * We get here after internal-to-libpq errors. We should probably + * always have error_result = true, but if we don't, gin up some error + * text. + */ + if (!conn->error_result) + libpq_append_conn_error(conn, "no error text available"); + + /* Paranoia: be sure errorReported offset is sane */ + if (conn->errorReported < 0 || + conn->errorReported >= conn->errorMessage.len) + conn->errorReported = 0; + + /* + * Make a PGresult struct for the error. We temporarily lie about the + * result status, so that PQmakeEmptyPGresult doesn't uselessly copy + * all of conn->errorMessage. + */ + res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY); + if (res) + { + /* + * Report whatever new error text we have, and advance + * errorReported. + */ + res->resultStatus = PGRES_FATAL_ERROR; + pqSetResultError(res, &conn->errorMessage, conn->errorReported); + conn->errorReported = conn->errorMessage.len; + } + else + { + /* + * Ouch, not enough memory for a PGresult. Fortunately, we have a + * card up our sleeve: we can use the static OOM_result. Casting + * away const here is a bit ugly, but it seems best to declare + * OOM_result as const, in hopes it will be allocated in read-only + * storage. + */ + res = unconstify(PGresult *, &OOM_result); + + /* + * Don't advance errorReported. Perhaps we'll be able to report + * the text later. + */ + } + } + + /* + * 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->error_result = false; /* next_result is never an error */ + 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, substitute "out of memory", as in pqSetResultError. + */ + res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, false); + if (res->errMsg) + sprintf(res->errMsg, "%s\n", msgBuf); + else + res->errMsg = libpq_gettext("out of memory\n"); + + /* + * 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 an error prevented adding the row + * + * 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". + */ +static bool +pqAddTuple(PGresult *res, PGresAttValue *tup, const char **errmsgp) +{ + 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; + PGresAttValue **newTuples; + + /* + * Since we use integers for row numbers, we can't support more than + * INT_MAX rows. Make sure we allow that many, though. + */ + if (res->tupArrSize <= INT_MAX / 2) + newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128; + else if (res->tupArrSize < INT_MAX) + newSize = INT_MAX; + else + { + *errmsgp = libpq_gettext("PGresult cannot support more than INT_MAX tuples"); + return false; + } + + /* + * Also, on 32-bit platforms we could, in theory, overflow size_t even + * before newSize gets to INT_MAX. (In practice we'd doubtless hit + * OOM long before that, but let's check.) + */ +#if INT_MAX >= (SIZE_MAX / 2) + if (newSize > SIZE_MAX / sizeof(PGresAttValue *)) + { + *errmsgp = libpq_gettext("size_t overflow"); + return false; + } +#endif + + 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->memorySize += + (newSize - res->tupArrSize) * sizeof(PGresAttValue *); + 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; + + /* + * 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; + } + + /* + * Save values of settings that are of interest to libpq in fields of the + * PGconn object. We keep client_encoding and standard_conforming_strings + * 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) + { + /* We convert the server version to numeric form. */ + 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 */ + } + else if (strcmp(name, "default_transaction_read_only") == 0) + { + conn->default_transaction_read_only = + (strcmp(value, "on") == 0) ? PG_BOOL_YES : PG_BOOL_NO; + } + else if (strcmp(name, "in_hot_standby") == 0) + { + conn->in_hot_standby = + (strcmp(value, "on") == 0) ? PG_BOOL_YES : PG_BOOL_NO; + } + else if (strcmp(name, "scram_iterations") == 0) + { + conn->scram_sha_256_iterations = atoi(value); + } +} + + +/* + * 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. + * (Such a string should already be translated via libpq_gettext().) + * 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, errmsgp)) + 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_MORE; + } + + return 1; + +fail: + /* release locally allocated PGresult, if we made one */ + if (res != conn->result) + PQclear(res); + return 0; +} + + +/* + * pqAllocCmdQueueEntry + * Get a command queue entry for caller to fill. + * + * If the recycle queue has a free element, that is returned; if not, a + * fresh one is allocated. Caller is responsible for adding it to the + * command queue (pqAppendCmdQueueEntry) once the struct is filled in, or + * releasing the memory (pqRecycleCmdQueueEntry) if an error occurs. + * + * If allocation fails, sets the error message and returns NULL. + */ +static PGcmdQueueEntry * +pqAllocCmdQueueEntry(PGconn *conn) +{ + PGcmdQueueEntry *entry; + + if (conn->cmd_queue_recycle == NULL) + { + entry = (PGcmdQueueEntry *) malloc(sizeof(PGcmdQueueEntry)); + if (entry == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return NULL; + } + } + else + { + entry = conn->cmd_queue_recycle; + conn->cmd_queue_recycle = entry->next; + } + entry->next = NULL; + entry->query = NULL; + + return entry; +} + +/* + * pqAppendCmdQueueEntry + * Append a caller-allocated entry to the command queue, and update + * conn->asyncStatus to account for it. + * + * The query itself must already have been put in the output buffer by the + * caller. + */ +static void +pqAppendCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry) +{ + Assert(entry->next == NULL); + + if (conn->cmd_queue_head == NULL) + conn->cmd_queue_head = entry; + else + conn->cmd_queue_tail->next = entry; + + conn->cmd_queue_tail = entry; + + switch (conn->pipelineStatus) + { + case PQ_PIPELINE_OFF: + case PQ_PIPELINE_ON: + + /* + * When not in pipeline aborted state, if there's a result ready + * to be consumed, let it be so (that is, don't change away from + * READY or READY_MORE); otherwise set us busy to wait for + * something to arrive from the server. + */ + if (conn->asyncStatus == PGASYNC_IDLE) + conn->asyncStatus = PGASYNC_BUSY; + break; + + case PQ_PIPELINE_ABORTED: + + /* + * In aborted pipeline state, we don't expect anything from the + * server (since we don't send any queries that are queued). + * Therefore, if IDLE then do what PQgetResult would do to let + * itself consume commands from the queue; if we're in any other + * state, we don't have to do anything. + */ + if (conn->asyncStatus == PGASYNC_IDLE || + conn->asyncStatus == PGASYNC_PIPELINE_IDLE) + pqPipelineProcessQueue(conn); + break; + } +} + +/* + * pqRecycleCmdQueueEntry + * Push a command queue entry onto the freelist. + */ +static void +pqRecycleCmdQueueEntry(PGconn *conn, PGcmdQueueEntry *entry) +{ + if (entry == NULL) + return; + + /* recyclable entries should not have a follow-on command */ + Assert(entry->next == NULL); + + if (entry->query) + { + free(entry->query); + entry->query = NULL; + } + + entry->next = conn->cmd_queue_recycle; + conn->cmd_queue_recycle = entry; +} + + +/* + * PQsendQuery + * Submit a query, but don't wait for it to finish + * + * Returns: 1 if successfully submitted + * 0 if error (conn->errorMessage is set) + * + * PQsendQueryContinue is a non-exported version that behaves identically + * except that it doesn't reset conn->errorMessage. + */ +int +PQsendQuery(PGconn *conn, const char *query) +{ + return PQsendQueryInternal(conn, query, true); +} + +int +PQsendQueryContinue(PGconn *conn, const char *query) +{ + return PQsendQueryInternal(conn, query, false); +} + +static int +PQsendQueryInternal(PGconn *conn, const char *query, bool newQuery) +{ + PGcmdQueueEntry *entry = NULL; + + if (!PQsendQueryStart(conn, newQuery)) + return 0; + + /* check the argument */ + if (!query) + { + libpq_append_conn_error(conn, "command string is a null pointer"); + return 0; + } + + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "%s not allowed in pipeline mode", + "PQsendQuery"); + return 0; + } + + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + + /* Send the query message(s) */ + /* construct the outgoing Query message */ + if (pqPutMsgStart('Q', conn) < 0 || + pqPuts(query, conn) < 0 || + pqPutMsgEnd(conn) < 0) + { + /* error message should be set up already */ + pqRecycleCmdQueueEntry(conn, entry); + return 0; + } + + /* remember we are using simple query protocol */ + entry->queryclass = PGQUERY_SIMPLE; + /* and remember the query text too, if possible */ + entry->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! */ + pqAppendCmdQueueEntry(conn, entry); + + return 1; + +sendFailed: + pqRecycleCmdQueueEntry(conn, entry); + /* error message should be set up already */ + return 0; +} + +/* + * PQsendQueryParams + * Like PQsendQuery, but use extended query protocol 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, true)) + return 0; + + /* check the arguments */ + if (!command) + { + libpq_append_conn_error(conn, "command string is a null pointer"); + return 0; + } + if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) + { + libpq_append_conn_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); + 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) +{ + PGcmdQueueEntry *entry = NULL; + + if (!PQsendQueryStart(conn, true)) + return 0; + + /* check the arguments */ + if (!stmtName) + { + libpq_append_conn_error(conn, "statement name is a null pointer"); + return 0; + } + if (!query) + { + libpq_append_conn_error(conn, "command string is a null pointer"); + return 0; + } + if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) + { + libpq_append_conn_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); + return 0; + } + + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + + /* construct the Parse message */ + if (pqPutMsgStart('P', 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; + + /* Add a Sync, unless in pipeline mode. */ + if (conn->pipelineStatus == PQ_PIPELINE_OFF) + { + if (pqPutMsgStart('S', conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + } + + /* remember we are doing just a Parse */ + entry->queryclass = PGQUERY_PREPARE; + + /* and remember the query text too, if possible */ + /* if insufficient memory, query just winds up NULL */ + entry->query = strdup(query); + + /* + * Give the data a push (in pipeline mode, only if we're past the size + * threshold). In nonblock mode, don't complain if we're unable to send + * it all; PQgetResult() will do any additional flushing needed. + */ + if (pqPipelineFlush(conn) < 0) + goto sendFailed; + + /* OK, it's launched! */ + pqAppendCmdQueueEntry(conn, entry); + + return 1; + +sendFailed: + pqRecycleCmdQueueEntry(conn, entry); + /* error message should be set up already */ + return 0; +} + +/* + * PQsendQueryPrepared + * Like PQsendQuery, but execute a previously prepared statement, + * using extended query protocol 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, true)) + return 0; + + /* check the arguments */ + if (!stmtName) + { + libpq_append_conn_error(conn, "statement name is a null pointer"); + return 0; + } + if (nParams < 0 || nParams > PQ_QUERY_PARAM_MAX_LIMIT) + { + libpq_append_conn_error(conn, "number of parameters must be between 0 and %d", + PQ_QUERY_PARAM_MAX_LIMIT); + return 0; + } + + return PQsendQueryGuts(conn, + NULL, /* no command to parse */ + stmtName, + nParams, + NULL, /* no param types */ + paramValues, + paramLengths, + paramFormats, + resultFormat); +} + +/* + * PQsendQueryStart + * Common startup code for PQsendQuery and sibling routines + */ +static bool +PQsendQueryStart(PGconn *conn, bool newQuery) +{ + if (!conn) + return false; + + /* + * If this is the beginning of a query cycle, reset the error state. + * However, in pipeline mode with something already queued, the error + * buffer belongs to that command and we shouldn't clear it. + */ + if (newQuery && conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + /* Don't try to send if we know there's no live connection. */ + if (conn->status != CONNECTION_OK) + { + libpq_append_conn_error(conn, "no connection to the server"); + return false; + } + + /* Can't send while already busy, either, unless enqueuing for later */ + if (conn->asyncStatus != PGASYNC_IDLE && + conn->pipelineStatus == PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "another command is already in progress"); + return false; + } + + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + /* + * When enqueuing commands we don't change much of the connection + * state since it's already in use for the current command. The + * connection state will get updated when pqPipelineProcessQueue() + * advances to start processing the queued message. + * + * Just make sure we can safely enqueue given the current connection + * state. We can enqueue behind another queue item, or behind a + * non-queue command (one that sends its own sync), but we can't + * enqueue if the connection is in a copy state. + */ + switch (conn->asyncStatus) + { + case PGASYNC_IDLE: + case PGASYNC_PIPELINE_IDLE: + case PGASYNC_READY: + case PGASYNC_READY_MORE: + case PGASYNC_BUSY: + /* ok to queue */ + break; + + case PGASYNC_COPY_IN: + case PGASYNC_COPY_OUT: + case PGASYNC_COPY_BOTH: + libpq_append_conn_error(conn, "cannot queue commands during COPY"); + return false; + } + } + else + { + /* + * This command's results will come in immediately. 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 sending a query with extended query protocol + * 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; + PGcmdQueueEntry *entry; + + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + + /* + * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync + * (if not in pipeline mode), using specified statement name and the + * unnamed portal. + */ + + if (command) + { + /* construct the Parse message */ + if (pqPutMsgStart('P', 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', 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 + { + libpq_append_conn_error(conn, "length must be given for binary parameter"); + 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', conn) < 0 || + pqPutc('P', conn) < 0 || + pqPuts("", conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + + /* construct the Execute message */ + if (pqPutMsgStart('E', conn) < 0 || + pqPuts("", conn) < 0 || + pqPutInt(0, 4, conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + + /* construct the Sync message if not in pipeline mode */ + if (conn->pipelineStatus == PQ_PIPELINE_OFF) + { + if (pqPutMsgStart('S', conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + } + + /* remember we are using extended query protocol */ + entry->queryclass = PGQUERY_EXTENDED; + + /* and remember the query text too, if possible */ + /* if insufficient memory, query just winds up NULL */ + if (command) + entry->query = strdup(command); + + /* + * Give the data a push (in pipeline mode, only if we're past the size + * threshold). In nonblock mode, don't complain if we're unable to send + * it all; PQgetResult() will do any additional flushing needed. + */ + if (pqPipelineFlush(conn) < 0) + goto sendFailed; + + /* OK, it's launched! */ + pqAppendCmdQueueEntry(conn, entry); + + return 1; + +sendFailed: + pqRecycleCmdQueueEntry(conn, entry); + /* error message should be set up already */ + return 0; +} + +/* + * 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->cmd_queue_head || + (conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE && + conn->cmd_queue_head->queryclass != PGQUERY_EXTENDED)) + return 0; + if (pgHavePendingResult(conn)) + 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) +{ + pqParseInput3(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. Also, + * if we've detected read EOF and dropped the connection, we can expect + * that PQgetResult will fail immediately. Note that we do *not* check + * conn->write_failed here --- once that's become set, we know we have + * trouble, but we need to keep trying to read until we have a complete + * server message or detect read EOF. + */ + return conn->asyncStatus == PGASYNC_BUSY && conn->status != CONNECTION_BAD; +} + +/* + * 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). + * + * In pipeline mode, once all the result of a query have been returned, + * PQgetResult returns NULL to let the user know that the next + * query is being processed. At the end of the pipeline, returns a + * result with PQresultStatus(result) == PGRES_PIPELINE_SYNC. + */ +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. (Note: if the connection has + * been lost, pqWait should return immediately because the socket + * should be read-ready, either with the last server data or with an + * EOF indication. We expect therefore that this won't result in any + * undue delay in reporting a previous write failure.) + */ + if (flushResult || + pqWait(true, false, conn) || + pqReadData(conn) < 0) + { + /* Report the error saved by pqWait or pqReadData */ + pqSaveErrorResult(conn); + conn->asyncStatus = PGASYNC_IDLE; + return pqPrepareAsyncResult(conn); + } + + /* Parse it. */ + parseInput(conn); + + /* + * If we had a write error, but nothing above obtained a query result + * or detected a read error, report the write error. + */ + if (conn->write_failed && conn->asyncStatus == PGASYNC_BUSY) + { + pqSaveWriteError(conn); + conn->asyncStatus = PGASYNC_IDLE; + return pqPrepareAsyncResult(conn); + } + } + + /* Return the appropriate thing. */ + switch (conn->asyncStatus) + { + case PGASYNC_IDLE: + res = NULL; /* query is complete */ + break; + case PGASYNC_PIPELINE_IDLE: + Assert(conn->pipelineStatus != PQ_PIPELINE_OFF); + + /* + * We're about to return the NULL that terminates the round of + * results from the current query; prepare to send the results of + * the next query, if any, when we're called next. If there's no + * next element in the command queue, this gets us in IDLE state. + */ + pqPipelineProcessQueue(conn); + res = NULL; /* query is complete */ + break; + + case PGASYNC_READY: + + /* + * For any query type other than simple query protocol, we advance + * the command queue here. This is because for simple query + * protocol we can get the READY state multiple times before the + * command is actually complete, since the command string can + * contain many queries. In simple query protocol, the queue + * advance is done by fe-protocol3 when it receives ReadyForQuery. + */ + if (conn->cmd_queue_head && + conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE) + pqCommandQueueAdvance(conn); + res = pqPrepareAsyncResult(conn); + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + /* + * We're about to send the results of the current query. Set + * us idle now, and ... + */ + conn->asyncStatus = PGASYNC_PIPELINE_IDLE; + + /* + * ... in cases when we're sending a pipeline-sync result, + * move queue processing forwards immediately, so that next + * time we're called, we're prepared to return the next result + * received from the server. In all other cases, leave the + * queue state change for next time, so that a terminating + * NULL result is sent. + * + * (In other words: we don't return a NULL after a pipeline + * sync.) + */ + if (res && res->resultStatus == PGRES_PIPELINE_SYNC) + pqPipelineProcessQueue(conn); + } + else + { + /* Set the state back to BUSY, allowing parsing to proceed. */ + conn->asyncStatus = PGASYNC_BUSY; + } + break; + case PGASYNC_READY_MORE: + 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: + libpq_append_conn_error(conn, "unexpected asyncStatus: %d", (int) conn->asyncStatus); + pqSaveErrorResult(conn); + conn->asyncStatus = PGASYNC_IDLE; /* try to restore valid state */ + res = pqPrepareAsyncResult(conn); + break; + } + + /* Time to fire PGEVT_RESULTCREATE events, if there are any */ + if (res && res->nEvents > 0) + (void) PQfireResultCreateEvents(conn, res); + + 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 extended query protocol 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 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 extended query protocol 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; + + /* + * Since this is the beginning of a query cycle, reset the error state. + * However, in pipeline mode with something already queued, the error + * buffer belongs to that command and we shouldn't clear it. + */ + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "synchronous command execution functions are not allowed in pipeline mode"); + 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) + { + /* 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 if (resultStatus == PGRES_COPY_OUT) + { + /* + * 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 if (resultStatus == PGRES_COPY_BOTH) + { + /* We don't allow PQexec during COPY BOTH */ + libpq_append_conn_error(conn, "PQexec not allowed during COPY BOTH"); + 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. (We used to have logic here to concatenate successive error + * messages, but now that happens automatically, since conn->errorMessage + * will continue to accumulate errors throughout this loop.) + * + * 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) + { + /* The CONNECTION_BAD status could have been triggered by a previous query error */ + if (conn->status == CONNECTION_BAD && lastResult && lastResult->resultStatus == PGRES_FATAL_ERROR) { + PQclear(result); + break; + } + 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) +{ + PGcmdQueueEntry *entry = NULL; + + /* Treat null desc_target as empty string */ + if (!desc_target) + desc_target = ""; + + if (!PQsendQueryStart(conn, true)) + return 0; + + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + + /* construct the Describe message */ + if (pqPutMsgStart('D', conn) < 0 || + pqPutc(desc_type, conn) < 0 || + pqPuts(desc_target, conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + + /* construct the Sync message */ + if (conn->pipelineStatus == PQ_PIPELINE_OFF) + { + if (pqPutMsgStart('S', conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + } + + /* remember we are doing a Describe */ + entry->queryclass = PGQUERY_DESCRIBE; + + /* + * Give the data a push (in pipeline mode, only if we're past the size + * threshold). In nonblock mode, don't complain if we're unable to send + * it all; PQgetResult() will do any additional flushing needed. + */ + if (pqPipelineFlush(conn) < 0) + goto sendFailed; + + /* OK, it's launched! */ + pqAppendCmdQueueEntry(conn, entry); + + return 1; + +sendFailed: + pqRecycleCmdQueueEntry(conn, entry); + /* error message should be set up already */ + 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 + * + * Note that this function does not read any new data from the socket; + * so usually, caller should call PQconsumeInput() first. + */ +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) + { + libpq_append_conn_error(conn, "no COPY in progress"); + 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.) + */ + 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 (pqPutMsgStart('d', 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) + { + libpq_append_conn_error(conn, "no COPY in progress"); + return -1; + } + + /* + * Send the COPY END indicator. This is simple enough that we don't + * bother delegating it to the fe-protocol files. + */ + if (errormsg) + { + /* Send COPY FAIL */ + if (pqPutMsgStart('f', conn) < 0 || + pqPuts(errormsg, conn) < 0 || + pqPutMsgEnd(conn) < 0) + return -1; + } + else + { + /* Send COPY DONE */ + if (pqPutMsgStart('c', 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->cmd_queue_head && + conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE) + { + if (pqPutMsgStart('S', 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; + + /* 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) + { + libpq_append_conn_error(conn, "no COPY in progress"); + return -2; + } + return pqGetCopyData3(conn, buffer, async); +} + +/* + * PQgetline - gets a newline-terminated string from the backend. + * + * Chiefly here so that applications can use "COPY <rel> to stdout" + * and read the output string. Returns a null-terminated string in `buffer`. + * + * 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 `length`-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 `length` bytes.) + * 1 in other cases (i.e., the buffer was filled before \n is reached) + */ +int +PQgetline(PGconn *conn, char *buffer, int length) +{ + if (!buffer || length <= 0) + return EOF; + *buffer = '\0'; + /* length must be at least 3 to hold the \. terminator! */ + if (length < 3) + return EOF; + + if (!conn) + return EOF; + + return pqGetline3(conn, buffer, length); +} + +/* + * PQgetlineAsync - gets a COPY data row without blocking. + * + * This routine is for applications that want to do "COPY <rel> 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; + + return pqGetlineAsync3(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 *string) +{ + return PQputnbytes(conn, string, strlen(string)); +} + +/* + * 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. + * + * This is deprecated; it's cleaner to use PQgetResult to get the transfer + * status. + * + * RETURNS: + * 0 on success + * 1 on failure + */ +int +PQendcopy(PGconn *conn) +{ + if (!conn) + return 0; + + return pqEndcopy3(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; + + /* + * Since this is the beginning of a query cycle, reset the error state. + * However, in pipeline mode with something already queued, the error + * buffer belongs to that command and we shouldn't clear it. + */ + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn"); + return NULL; + } + + if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE || + pgHavePendingResult(conn)) + { + libpq_append_conn_error(conn, "connection in wrong state"); + return NULL; + } + + return pqFunctionCall3(conn, fnid, + result_buf, result_len, + result_is_int, + args, nargs); +} + +/* ====== Pipeline mode support ======== */ + +/* + * PQenterPipelineMode + * Put an idle connection in pipeline mode. + * + * Returns 1 on success. On failure, errorMessage is set and 0 is returned. + * + * Commands submitted after this can be pipelined on the connection; + * there's no requirement to wait for one to finish before the next is + * dispatched. + * + * Queuing of a new query or syncing during COPY is not allowed. + * + * A set of commands is terminated by a PQpipelineSync. Multiple sync + * points can be established while in pipeline mode. Pipeline mode can + * be exited by calling PQexitPipelineMode() once all results are processed. + * + * This doesn't actually send anything on the wire, it just puts libpq + * into a state where it can pipeline work. + */ +int +PQenterPipelineMode(PGconn *conn) +{ + if (!conn) + return 0; + + /* succeed with no action if already in pipeline mode */ + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + return 1; + + if (conn->asyncStatus != PGASYNC_IDLE) + { + libpq_append_conn_error(conn, "cannot enter pipeline mode, connection not idle"); + return 0; + } + + conn->pipelineStatus = PQ_PIPELINE_ON; + + return 1; +} + +/* + * PQexitPipelineMode + * End pipeline mode and return to normal command mode. + * + * Returns 1 in success (pipeline mode successfully ended, or not in pipeline + * mode). + * + * Returns 0 if in pipeline mode and cannot be ended yet. Error message will + * be set. + */ +int +PQexitPipelineMode(PGconn *conn) +{ + if (!conn) + return 0; + + if (conn->pipelineStatus == PQ_PIPELINE_OFF && + (conn->asyncStatus == PGASYNC_IDLE || + conn->asyncStatus == PGASYNC_PIPELINE_IDLE) && + conn->cmd_queue_head == NULL) + return 1; + + switch (conn->asyncStatus) + { + case PGASYNC_READY: + case PGASYNC_READY_MORE: + /* there are some uncollected results */ + libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results"); + return 0; + + case PGASYNC_BUSY: + libpq_append_conn_error(conn, "cannot exit pipeline mode while busy"); + return 0; + + case PGASYNC_IDLE: + case PGASYNC_PIPELINE_IDLE: + /* OK */ + break; + + case PGASYNC_COPY_IN: + case PGASYNC_COPY_OUT: + case PGASYNC_COPY_BOTH: + libpq_append_conn_error(conn, "cannot exit pipeline mode while in COPY"); + } + + /* still work to process */ + if (conn->cmd_queue_head != NULL) + { + libpq_append_conn_error(conn, "cannot exit pipeline mode with uncollected results"); + return 0; + } + + conn->pipelineStatus = PQ_PIPELINE_OFF; + conn->asyncStatus = PGASYNC_IDLE; + + /* Flush any pending data in out buffer */ + if (pqFlush(conn) < 0) + return 0; /* error message is setup already */ + return 1; +} + +/* + * pqCommandQueueAdvance + * Remove one query from the command queue, when we receive + * all results from the server that pertain to it. + */ +void +pqCommandQueueAdvance(PGconn *conn) +{ + PGcmdQueueEntry *prevquery; + + if (conn->cmd_queue_head == NULL) + return; + + /* delink from queue */ + prevquery = conn->cmd_queue_head; + conn->cmd_queue_head = conn->cmd_queue_head->next; + + /* If the queue is now empty, reset the tail too */ + if (conn->cmd_queue_head == NULL) + conn->cmd_queue_tail = NULL; + + /* and make it recyclable */ + prevquery->next = NULL; + pqRecycleCmdQueueEntry(conn, prevquery); +} + +/* + * pqPipelineProcessQueue: subroutine for PQgetResult + * In pipeline mode, start processing the results of the next query in the queue. + */ +static void +pqPipelineProcessQueue(PGconn *conn) +{ + switch (conn->asyncStatus) + { + case PGASYNC_COPY_IN: + case PGASYNC_COPY_OUT: + case PGASYNC_COPY_BOTH: + case PGASYNC_READY: + case PGASYNC_READY_MORE: + case PGASYNC_BUSY: + /* client still has to process current query or results */ + return; + + case PGASYNC_IDLE: + + /* + * If we're in IDLE mode and there's some command in the queue, + * get us into PIPELINE_IDLE mode and process normally. Otherwise + * there's nothing for us to do. + */ + if (conn->cmd_queue_head != NULL) + { + conn->asyncStatus = PGASYNC_PIPELINE_IDLE; + break; + } + return; + + case PGASYNC_PIPELINE_IDLE: + Assert(conn->pipelineStatus != PQ_PIPELINE_OFF); + /* next query please */ + break; + } + + /* + * Reset single-row processing mode. (Client has to set it up for each + * query, if desired.) + */ + conn->singleRowMode = false; + + /* + * If there are no further commands to process in the queue, get us in + * "real idle" mode now. + */ + if (conn->cmd_queue_head == NULL) + { + conn->asyncStatus = PGASYNC_IDLE; + return; + } + + /* + * Reset the error state. This and the next couple of steps correspond to + * what PQsendQueryStart didn't do for this query. + */ + pqClearConnErrorState(conn); + + /* Initialize async result-accumulation state */ + pqClearAsyncResult(conn); + + if (conn->pipelineStatus == PQ_PIPELINE_ABORTED && + conn->cmd_queue_head->queryclass != PGQUERY_SYNC) + { + /* + * In an aborted pipeline we don't get anything from the server for + * each result; we're just discarding commands from the queue until we + * get to the next sync from the server. + * + * The PGRES_PIPELINE_ABORTED results tell the client that its queries + * got aborted. + */ + conn->result = PQmakeEmptyPGresult(conn, PGRES_PIPELINE_ABORTED); + if (!conn->result) + { + libpq_append_conn_error(conn, "out of memory"); + pqSaveErrorResult(conn); + return; + } + conn->asyncStatus = PGASYNC_READY; + } + else + { + /* allow parsing to continue */ + conn->asyncStatus = PGASYNC_BUSY; + } +} + +/* + * PQpipelineSync + * Send a Sync message as part of a pipeline, and flush to server + * + * It's legal to start submitting more commands in the pipeline immediately, + * without waiting for the results of the current pipeline. There's no need to + * end pipeline mode and start it again. + * + * If a command in a pipeline fails, every subsequent command up to and including + * the result to the Sync message sent by PQpipelineSync gets set to + * PGRES_PIPELINE_ABORTED state. If the whole pipeline is processed without + * error, a PGresult with PGRES_PIPELINE_SYNC is produced. + * + * Queries can already have been sent before PQpipelineSync is called, but + * PQpipelineSync need to be called before retrieving command results. + * + * The connection will remain in pipeline mode and unavailable for new + * synchronous command execution functions until all results from the pipeline + * are processed by the client. + */ +int +PQpipelineSync(PGconn *conn) +{ + PGcmdQueueEntry *entry; + + if (!conn) + return 0; + + if (conn->pipelineStatus == PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "cannot send pipeline when not in pipeline mode"); + return 0; + } + + switch (conn->asyncStatus) + { + case PGASYNC_COPY_IN: + case PGASYNC_COPY_OUT: + case PGASYNC_COPY_BOTH: + /* should be unreachable */ + appendPQExpBufferStr(&conn->errorMessage, + "internal error: cannot send pipeline while in COPY\n"); + return 0; + case PGASYNC_READY: + case PGASYNC_READY_MORE: + case PGASYNC_BUSY: + case PGASYNC_IDLE: + case PGASYNC_PIPELINE_IDLE: + /* OK to send sync */ + break; + } + + entry = pqAllocCmdQueueEntry(conn); + if (entry == NULL) + return 0; /* error msg already set */ + + entry->queryclass = PGQUERY_SYNC; + entry->query = NULL; + + /* construct the Sync message */ + if (pqPutMsgStart('S', conn) < 0 || + pqPutMsgEnd(conn) < 0) + goto sendFailed; + + /* + * 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! */ + pqAppendCmdQueueEntry(conn, entry); + + return 1; + +sendFailed: + pqRecycleCmdQueueEntry(conn, entry); + /* error message should be set up already */ + return 0; +} + +/* + * PQsendFlushRequest + * Send request for server to flush its buffer. Useful in pipeline + * mode when a sync point is not desired. + */ +int +PQsendFlushRequest(PGconn *conn) +{ + if (!conn) + return 0; + + /* Don't try to send if we know there's no live connection. */ + if (conn->status != CONNECTION_OK) + { + libpq_append_conn_error(conn, "no connection to the server"); + return 0; + } + + /* Can't send while already busy, either, unless enqueuing for later */ + if (conn->asyncStatus != PGASYNC_IDLE && + conn->pipelineStatus == PQ_PIPELINE_OFF) + { + libpq_append_conn_error(conn, "another command is already in progress"); + return 0; + } + + if (pqPutMsgStart('H', conn) < 0 || + pqPutMsgEnd(conn) < 0) + { + return 0; + } + + return 1; +} + +/* ====== 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 >= lengthof(pgresStatus)) + 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); + + 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/MERGE/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 || + strncmp(res->cmdStatus, "MERGE ", 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. + * + * Clear error state in case pqFlush adds to it, unless we're actively + * pipelining, in which case it seems best not to. + */ + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + /* 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) +{ + if (!conn || conn->status == CONNECTION_BAD) + return false; + 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) +{ + if (!conn || conn->status == CONNECTION_BAD) + return -1; + return pqFlush(conn); +} + +/* + * pqPipelineFlush + * + * In pipeline mode, data will be flushed only when the out buffer reaches the + * threshold value. In non-pipeline mode, it behaves as stock pqFlush. + * + * Returns 0 on success. + */ +static int +pqPipelineFlush(PGconn *conn) +{ + if ((conn->pipelineStatus != PQ_PIPELINE_ON) || + (conn->outCount >= OUTBUFFER_THRESHOLD)) + return pqFlush(conn); + return 0; +} + + +/* + * PQfreemem - safely frees memory allocated + * + * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6) + * Used for freeing memory from PQescapeBytea()/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) + libpq_append_conn_error(conn, "incomplete multibyte character"); + 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; + } + + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + 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; + + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + /* 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) + { + libpq_append_conn_error(conn, "incomplete multibyte character"); + 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) + { + libpq_append_conn_error(conn, "out of memory"); + 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) + libpq_append_conn_error(conn, "out of memory"); + 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; + + if (conn->cmd_queue_head == NULL) + pqClearConnErrorState(conn); + + 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/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c b/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c new file mode 100644 index 0000000000..206266fd04 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-lobj.c @@ -0,0 +1,1064 @@ +/*------------------------------------------------------------------------- + * + * fe-lobj.c + * Front-end large object interface + * + * Portions Copyright (c) 1996-2023, 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 <io.h> +#endif + +#include "postgres_fe.h" + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#endif + +#include <fcntl.h> +#include <limits.h> +#include <sys/stat.h> + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "libpq/libpq-fs.h" /* must come after sys/stat.h */ +#include "port/pg_bswap.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 (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 (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 (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) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_truncate"); + 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) + { + libpq_append_conn_error(conn, "argument of lo_truncate exceeds integer range"); + 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 (lo_initialize(conn) < 0) + return -1; + + if (conn->lobjfuncs->fn_lo_truncate64 == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_truncate64"); + 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 (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) + { + libpq_append_conn_error(conn, "argument of lo_read exceeds integer range"); + 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 (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) + { + libpq_append_conn_error(conn, "argument of lo_write exceeds integer range"); + 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 *) unconstify(char *, 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 (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 (lo_initialize(conn) < 0) + return -1; + + if (conn->lobjfuncs->fn_lo_lseek64 == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_lseek64"); + 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 (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 (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) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_create"); + 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 (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 (lo_initialize(conn) < 0) + return -1; + + if (conn->lobjfuncs->fn_lo_tell64 == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_tell64"); + 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 (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[PG_STRERROR_R_BUFLEN]; + + if (conn == NULL) + return InvalidOid; + + /* Since this is the beginning of a query cycle, reset the error state */ + pqClearConnErrorState(conn); + + /* + * open the file to be read in + */ + fd = open(filename, O_RDONLY | PG_BINARY, 0666); + if (fd < 0) + { /* error */ + libpq_append_conn_error(conn, "could not open file \"%s\": %s", + filename, strerror_r(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); + /* deliberately overwrite any error from lo_close */ + pqClearConnErrorState(conn); + libpq_append_conn_error(conn, "could not read from file \"%s\": %s", + filename, + strerror_r(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[PG_STRERROR_R_BUFLEN]; + + /* + * 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); + /* deliberately overwrite any error from lo_close */ + pqClearConnErrorState(conn); + libpq_append_conn_error(conn, "could not open file \"%s\": %s", + filename, + strerror_r(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); + /* deliberately overwrite any error from lo_close */ + pqClearConnErrorState(conn); + libpq_append_conn_error(conn, "could not write to file \"%s\": %s", + filename, + strerror_r(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) != 0 && result >= 0) + { + libpq_append_conn_error(conn, "could not write to file \"%s\": %s", + filename, strerror_r(errno, sebuf, sizeof(sebuf))); + result = -1; + } + + return result; +} + + +/* + * lo_initialize + * + * Initialize for a new large-object operation on an existing connection. + * Return 0 if OK, -1 on failure. + * + * If we haven't previously done so, we collect the function OIDs from + * 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; + + /* Nothing we can do with no connection */ + if (conn == NULL) + return -1; + + /* Since this is the beginning of a query cycle, reset the error state */ + pqClearConnErrorState(conn); + + /* Nothing else to do if we already collected info */ + if (conn->lobjfuncs != NULL) + return 0; + + /* + * Allocate the structure to hold the function OIDs. We don't store it + * into the PGconn until it's successfully filled. + */ + lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs)); + if (lobjfuncs == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return -1; + } + MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs)); + + /* + * Execute the query to get all the functions at once. (Not all of them + * may exist in older server versions.) + */ + 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')"; + + res = PQexec(conn, query); + if (res == NULL) + { + free(lobjfuncs); + return -1; + } + + if (res->resultStatus != PGRES_TUPLES_OK) + { + free(lobjfuncs); + PQclear(res); + libpq_append_conn_error(conn, "query to initialize large object functions did not return data"); + 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) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_open"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_close == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_close"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_creat == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_creat"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_unlink == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_unlink"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_lseek == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_lseek"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_tell == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lo_tell"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_read == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "loread"); + free(lobjfuncs); + return -1; + } + if (lobjfuncs->fn_lo_write == 0) + { + libpq_append_conn_error(conn, "cannot determine OID of function %s", + "lowrite"); + 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] = pg_hton32(t); + + /* Now the low order half */ + t = (uint32) host64; + swap.i32[1] = pg_hton32(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) pg_ntoh32(swap.i32[0]); + result <<= 32; + result |= (uint32) pg_ntoh32(swap.i32[1]); + + return result; +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c b/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c new file mode 100644 index 0000000000..660cdec93c --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-misc.c @@ -0,0 +1,1333 @@ +/*------------------------------------------------------------------------- + * + * 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/pqformat.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-2023, 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 <signal.h> +#include <time.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#include <sys/select.h> +#include <sys/time.h> +#endif + +#ifdef HAVE_POLL_H +#include <poll.h> +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "mb/pg_wchar.h" +#include "pg_config_paths.h" +#include "port/pg_bswap.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; +} + + +/* + * 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++]; + + return 0; +} + + +/* + * pqPutc: write 1 char to the current message + */ +int +pqPutc(char c, PGconn *conn) +{ + if (pqPutMsgBytes(&c, 1, conn)) + return EOF; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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) pg_ntoh16(tmp2); + break; + case 4: + if (conn->inCursor + 4 > conn->inEnd) + return EOF; + memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4); + conn->inCursor += 4; + *result = (int) pg_ntoh32(tmp4); + break; + default: + pqInternalNotice(&conn->noticeHooks, + "integer of size %lu not supported by pqGetInt", + (unsigned long) bytes); + return EOF; + } + + 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 = pg_hton16((uint16) value); + if (pqPutMsgBytes((const char *) &tmp2, 2, conn)) + return EOF; + break; + case 4: + tmp4 = pg_hton32((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; + } + + 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 */ + appendPQExpBufferStr(&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 */ + appendPQExpBufferStr(&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) + * + * 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. The state variable conn->outMsgEnd is the end of + * the data collected so far. + */ +int +pqPutMsgStart(char msg_type, 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? */ + lenPos = endPos; + /* allow room for message length */ + endPos += 4; + + /* 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 */ + + 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) +{ + /* Fill in length word if needed */ + if (conn->outMsgStart >= 0) + { + uint32 msgLen = conn->outMsgEnd - conn->outMsgStart; + + msgLen = pg_hton32(msgLen); + memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4); + } + + /* trace client-to-server message */ + if (conn->Pfdebug) + { + if (conn->outCount < conn->outMsgStart) + pqTraceOutputMessage(conn, conn->outBuffer + conn->outCount, true); + else + pqTraceOutputNoTypeByteMessage(conn, + conn->outBuffer + conn->outMsgStart); + } + + /* 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) + { + libpq_append_conn_error(conn, "connection not open"); + 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) + { + switch (SOCK_ERRNO) + { + case EINTR: + goto retry3; + + /* Some systems return EAGAIN/EWOULDBLOCK for no data */ +#ifdef EAGAIN + case EAGAIN: + return someread; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: + return someread; +#endif + + /* We might get ECONNRESET etc here if connection failed */ + case ALL_CONNECTION_FAILURE_ERRNOS: + goto definitelyFailed; + + default: + /* 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) + { + switch (SOCK_ERRNO) + { + case EINTR: + goto retry4; + + /* Some systems return EAGAIN/EWOULDBLOCK for no data */ +#ifdef EAGAIN + case EAGAIN: + return 0; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: + return 0; +#endif + + /* We might get ECONNRESET etc here if connection failed */ + case ALL_CONNECTION_FAILURE_ERRNOS: + goto definitelyFailed; + + default: + /* 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: + libpq_append_conn_error(conn, "server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request."); + + /* 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. + * + * Note that this is also responsible for consuming data from the socket + * (putting it in conn->inBuffer) in any situation where we can't send + * all the specified data immediately. + * + * If a socket-level write failure occurs, conn->write_failed is set and the + * error message is saved in conn->write_err_msg, but we clear the output + * buffer and return zero anyway; this is because callers should soldier on + * until we have read what we can from the server and checked for an error + * message. write_err_msg should be reported only when we are unable to + * obtain a server error first. Much of that behavior is implemented at + * lower levels, but this function deals with some edge cases. + */ +static int +pqSendSome(PGconn *conn, int len) +{ + char *ptr = conn->outBuffer; + int remaining = conn->outCount; + int result = 0; + + /* + * If we already had a write failure, we will never again try to send data + * on that connection. Even if the kernel would let us, we've probably + * lost message boundary sync with the server. conn->write_failed + * therefore persists until the connection is reset, and we just discard + * all data presented to be written. However, as long as we still have a + * valid socket, we should continue to absorb data from the backend, so + * that we can collect any final error messages. + */ + if (conn->write_failed) + { + /* conn->write_err_msg should be set up already */ + conn->outCount = 0; + /* Absorb input data if any, and detect socket closure */ + if (conn->sock != PGINVALID_SOCKET) + { + if (pqReadData(conn) < 0) + return -1; + } + return 0; + } + + if (conn->sock == PGINVALID_SOCKET) + { + conn->write_failed = true; + /* Store error message in conn->write_err_msg, if possible */ + /* (strdup failure is OK, we'll cope later) */ + conn->write_err_msg = strdup(libpq_gettext("connection not open\n")); + /* Discard queued data; no chance it'll ever be sent */ + conn->outCount = 0; + return 0; + } + + /* 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: + /* Discard queued data; no chance it'll ever be sent */ + conn->outCount = 0; + + /* Absorb input data if any, and detect socket closure */ + if (conn->sock != PGINVALID_SOCKET) + { + if (pqReadData(conn) < 0) + return -1; + } + + /* + * Lower-level code should already have filled + * conn->write_err_msg (and set conn->write_failed) or + * conn->errorMessage. In the former case, we pretend + * there's no problem; the write_failed condition will be + * dealt with later. Otherwise, report the error now. + */ + if (conn->write_failed) + return 0; + else + 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.) + * + * Note that errors here don't result in write_failed becoming + * set. + */ + 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. + * (See pqSendSome comments about how failure should be handled.) + */ +int +pqFlush(PGconn *conn) +{ + if (conn->outCount > 0) + { + if (conn->Pfdebug) + fflush(conn->Pfdebug); + + 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. + * + * finish_time = ((time_t) -1) disables the wait limit. + * + * Returns -1 on failure, 0 if the socket is readable/writable, 1 if it timed out. + */ +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 -1; /* errorMessage is already set */ + + if (result == 0) + { + libpq_append_conn_error(conn, "timeout expired"); + return 1; + } + + 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) + { + libpq_append_conn_error(conn, "invalid socket"); + return -1; + } + +#ifdef USE_SSL + /* Check for SSL library buffering read bytes */ + if (forRead && conn->ssl_in_use && pgtls_read_pending(conn)) + { + /* 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[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "%s() failed: %s", "select", + 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. + * + * Caution: when dealing with text that is not certainly valid in the + * specified encoding, the result may exceed the actual remaining + * string length. Callers that are not prepared to deal with that + * should use PQmblenBounded() instead. + */ +int +PQmblen(const char *s, int encoding) +{ + return pg_encoding_mblen(encoding, s); +} + +/* + * Returns the byte length of the character beginning at s, using the + * specified encoding; but not more than the distance to end of string. + */ +int +PQmblenBounded(const char *s, int encoding) +{ + return strnlen(s, 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(void) +{ + /* + * If multiple threads come through here at about the same time, it's okay + * for more than one of them to call bindtextdomain(). But it's not okay + * for any of them to return to caller before bindtextdomain() is + * complete, so don't set the flag till that's done. Use "volatile" just + * to be sure the compiler doesn't try to get cute. + */ + static volatile 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; + + /* No relocatable lookup here because the binary could be anywhere */ + ldir = getenv("PGLOCALEDIR"); + if (!ldir) + ldir = LOCALEDIR; + bindtextdomain(PG_TEXTDOMAIN("libpq"), ldir); + already_bound = true; +#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 */ + + +/* + * Append a formatted string to the given buffer, after translating it. A + * newline is automatically appended; the format should not end with a + * newline. + */ +void +libpq_append_error(PQExpBuffer errorMessage, const char *fmt,...) +{ + int save_errno = errno; + bool done; + va_list args; + + Assert(fmt[strlen(fmt) - 1] != '\n'); + + if (PQExpBufferBroken(errorMessage)) + return; /* already failed */ + + /* Loop in case we have to retry after enlarging the buffer. */ + do + { + errno = save_errno; + va_start(args, fmt); + done = appendPQExpBufferVA(errorMessage, libpq_gettext(fmt), args); + va_end(args); + } while (!done); + + appendPQExpBufferChar(errorMessage, '\n'); +} + +/* + * Append a formatted string to the error message buffer of the given + * connection, after translating it. A newline is automatically appended; the + * format should not end with a newline. + */ +void +libpq_append_conn_error(PGconn *conn, const char *fmt,...) +{ + int save_errno = errno; + bool done; + va_list args; + + Assert(fmt[strlen(fmt) - 1] != '\n'); + + if (PQExpBufferBroken(&conn->errorMessage)) + return; /* already failed */ + + /* Loop in case we have to retry after enlarging the buffer. */ + do + { + errno = save_errno; + va_start(args, fmt); + done = appendPQExpBufferVA(&conn->errorMessage, libpq_gettext(fmt), args); + va_end(args); + } while (!done); + + appendPQExpBufferChar(&conn->errorMessage, '\n'); +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-print.c b/contrib/libs/libpq/src/interfaces/libpq/fe-print.c new file mode 100644 index 0000000000..40620b47e9 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-print.c @@ -0,0 +1,773 @@ +/*------------------------------------------------------------------------- + * + * fe-print.c + * functions for pretty-printing query results + * + * Portions Copyright (c) 1996-2023, 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 <signal.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#else +#ifndef WIN32 +#include <sys/termios.h> +#endif +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" + + +static bool 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 = NULL; + int fieldMaxLen = 0; + int numFieldName; + int fs_len = strlen(po->fieldSep); + int total_line_length = 0; + bool usePipe = false; + 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); + fieldNames = (const char **) calloc(nFields, sizeof(char *)); + fieldNotNum = (unsigned char *) calloc(nFields, 1); + fieldMax = (int *) calloc(nFields, sizeof(int)); + if (!fieldNames || !fieldNotNum || !fieldMax) + { + fprintf(stderr, libpq_gettext("out of memory\n")); + goto exit; + } + 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 + + /* + * Since this function is no longer used by psql, we don't examine + * PSQL_PAGER. It's possible that the hypothetical external users + * of the function would like that to happen, but in the name of + * backwards compatibility, we'll stick to just examining PAGER. + */ + 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 */ + ))) + { + fflush(NULL); + fout = popen(pagerenv, "w"); + if (fout) + { + usePipe = true; +#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)) + { + fields = (char **) calloc((size_t) nTups + 1, + nFields * sizeof(char *)); + if (!fields) + { + fprintf(stderr, libpq_gettext("out of memory\n")); + goto exit; + } + } + 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, "<center><h2>%s</h2></center>\n", po->caption); + else + fprintf(fout, + "<center><h2>" + "Query retrieved %d rows * %d fields" + "</h2></center>\n", + nTups, nFields); + } + for (i = 0; i < nTups; i++) + { + if (po->expanded) + { + if (po->html3) + fprintf(fout, + "<table %s><caption align=\"top\">%d</caption>\n", + po->tableOpt ? po->tableOpt : "", i); + else + fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i); + } + for (j = 0; j < nFields; j++) + { + if (!do_field(po, res, i, j, fs_len, fields, nFields, + fieldNames, fieldNotNum, + fieldMax, fieldMaxLen, fout)) + goto exit; + } + if (po->html3 && po->expanded) + fputs("</table>\n", fout); + } + if (!po->expanded && (po->align || po->html3)) + { + if (po->html3) + { + if (po->header) + { + if (po->caption) + fprintf(fout, + "<table %s><caption align=\"top\">%s</caption>\n", + po->tableOpt ? po->tableOpt : "", + po->caption); + else + fprintf(fout, + "<table %s><caption align=\"top\">" + "Retrieved %d rows * %d fields" + "</caption>\n", + po->tableOpt ? po->tableOpt : "", nTups, nFields); + } + else + fprintf(fout, "<table %s>", 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); + } + if (po->header && !po->html3) + fprintf(fout, "(%d row%s)\n\n", PQntuples(res), + (PQntuples(res) == 1) ? "" : "s"); + if (po->html3 && !po->expanded) + fputs("</table>\n", fout); + +exit: + free(fieldMax); + free(fieldNotNum); + free(border); + if (fields) + { + /* if calloc succeeded, this shouldn't overflow size_t */ + size_t numfields = ((size_t) nTups + 1) * (size_t) nFields; + + while (numfields-- > 0) + free(fields[numfields]); + free(fields); + } + free(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 */ + } + } +} + + +static bool +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 += PQmblenBounded(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")); + return false; + } + strcpy(fields[i * nFields + j], pval); + } + else + { + if (po->expanded) + { + if (po->html3) + fprintf(fout, + "<tr><td align=\"left\"><b>%s</b></td>" + "<td align=\"%s\">%s</td></tr>\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); + } + } + } + } + return true; +} + + +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("<tr>", 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")); + return NULL; + } + 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, "<th align=\"%s\">%s</th>", + 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("</tr>\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("<tr>", 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, "<td align=\"%s\">%s</td>", + 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 (po->html3) + fputs("</tr>", 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")); + return; + } + + 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); + + 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")); + return; + } + 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); + } + } + + 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/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c b/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c new file mode 100644 index 0000000000..32b66d561c --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-protocol3.c @@ -0,0 +1,2306 @@ +/*------------------------------------------------------------------------- + * + * fe-protocol3.c + * functions that are specific to frontend/backend protocol version 3 + * + * Portions Copyright (c) 1996-2023, 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 <ctype.h> +#include <fcntl.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#include <netinet/tcp.h> +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "mb/pg_wchar.h" +#include "port/pg_bswap.h" + +/* + * 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 + { + /* Any other case is unexpected and we summarily skip it */ + 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 (!pgHavePendingResult(conn)) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_COMMAND_OK); + if (!conn->result) + { + libpq_append_conn_error(conn, "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': /* sync response, backend is ready for new + * query */ + if (getReadyForQuery(conn)) + return; + if (conn->pipelineStatus != PQ_PIPELINE_OFF) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_PIPELINE_SYNC); + if (!conn->result) + { + libpq_append_conn_error(conn, "out of memory"); + pqSaveErrorResult(conn); + } + else + { + conn->pipelineStatus = PQ_PIPELINE_ON; + conn->asyncStatus = PGASYNC_READY; + } + } + else + { + /* + * In simple query protocol, advance the command queue + * (see PQgetResult). + */ + if (conn->cmd_queue_head && + conn->cmd_queue_head->queryclass == PGQUERY_SIMPLE) + pqCommandQueueAdvance(conn); + conn->asyncStatus = PGASYNC_IDLE; + } + break; + case 'I': /* empty query */ + if (!pgHavePendingResult(conn)) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_EMPTY_QUERY); + if (!conn->result) + { + libpq_append_conn_error(conn, "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->cmd_queue_head && + conn->cmd_queue_head->queryclass == PGQUERY_PREPARE) + { + if (!pgHavePendingResult(conn)) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_COMMAND_OK); + if (!conn->result) + { + libpq_append_conn_error(conn, "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->error_result || + (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->cmd_queue_head && + conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE)) + { + /* First 'T' in a query sequence */ + if (getRowDescriptions(conn, msgLength)) + return; + } + 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 PGRES_TUPLES_OK. Otherwise we can just + * ignore this message. + */ + if (conn->cmd_queue_head && + conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE) + { + if (!pgHavePendingResult(conn)) + { + conn->result = PQmakeEmptyPGresult(conn, + PGRES_COMMAND_OK); + if (!conn->result) + { + libpq_append_conn_error(conn, "out of memory"); + pqSaveErrorResult(conn); + } + } + conn->asyncStatus = PGASYNC_READY; + } + break; + case 't': /* Parameter Description */ + if (getParamDescriptions(conn, msgLength)) + return; + break; + 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; + } + else if (conn->error_result || + (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 */ + libpq_append_conn_error(conn, "server sent data (\"D\" message) without prior row description (\"T\" message)"); + 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: + libpq_append_conn_error(conn, "unexpected response from server; first received character was \"%c\"", 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) + { + /* trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + + /* Normal case: parsing agrees with specified length */ + conn->inStart = conn->inCursor; + } + else + { + /* Trouble --- report it */ + libpq_append_conn_error(conn, "message contents do not agree with length in message type \"%c\"", 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) +{ + libpq_append_conn_error(conn, "lost synchronization with server: got message type \"%c\", length %d", + id, msgLength); + /* build an error result holding the error message */ + pqSaveErrorResult(conn); + conn->asyncStatus = PGASYNC_READY; /* drop out of PQgetResult 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). + */ +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->cmd_queue_head || + (conn->cmd_queue_head && + conn->cmd_queue_head->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; + } + + /* Success! */ + conn->result = result; + + /* + * If we're doing a Describe, we're done, and ready to pass the result + * back to the client. + */ + if ((!conn->cmd_queue_head) || + (conn->cmd_queue_head && + conn->cmd_queue_head->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); + + /* + * 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"); + + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + pqSaveErrorResult(conn); + + /* + * Show the message as fully consumed, else pqParseInput3 will overwrite + * our error with a complaint about that. + */ + conn->inCursor = conn->inStart + 5 + msgLength; + + /* + * 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 processed message successfully, EOF to suspend parsing + * (the latter case is not actually used currently). + */ +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; + } + + /* Success! */ + conn->result = result; + + return 0; + +not_enough_data: + errmsg = libpq_gettext("insufficient data in \"t\" message"); + +advance_and_error: + /* Discard unsaved result, if any */ + if (result && result != conn->result) + PQclear(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"); + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + pqSaveErrorResult(conn); + + /* + * Show the message as fully consumed, else pqParseInput3 will overwrite + * our error with a complaint about that. + */ + conn->inCursor = conn->inStart + 5 + msgLength; + + /* + * 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). + */ +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; + } + } + } + + /* Process the collected row */ + errmsg = NULL; + if (pqRowProcessor(conn, &errmsg)) + return 0; /* normal, successful exit */ + + /* pqRowProcessor failed, fall through to report it */ + +advance_and_error: + + /* + * 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"); + + appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg); + pqSaveErrorResult(conn); + + /* + * Show the message as fully consumed, else pqParseInput3 will overwrite + * our error with a complaint about that. + */ + conn->inCursor = conn->inStart + 5 + msgLength; + + /* + * 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; + + /* If in pipeline mode, set error indicator for it */ + if (isError && conn->pipelineStatus != PQ_PIPELINE_OFF) + conn->pipelineStatus = PQ_PIPELINE_ABORTED; + + /* + * If this is an error message, pre-emptively clear any incomplete query + * result we may have. We'd just throw it away below anyway, and + * releasing it before collecting the error might avoid out-of-memory. + */ + if (isError) + pqClearAsyncResult(conn); + + /* + * 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 && res && conn->cmd_queue_head && conn->cmd_queue_head->query) + res->errQuery = pqResultStrdup(res, conn->cmd_queue_head->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) + { + pqClearAsyncResult(conn); /* redundant, but be safe */ + if (res) + { + pqSetResultError(res, &workBuf, 0); + conn->result = res; + } + else + { + /* Fall back to using the internal-error processing paths */ + conn->error_result = true; + } + + if (PQExpBufferDataBroken(workBuf)) + libpq_append_conn_error(conn, "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. But if we + * were unlucky enough to run out of memory while filling workBuf, + * insert "out of memory", as in pqSetResultError. + */ + if (PQExpBufferDataBroken(workBuf)) + res->errMsg = libpq_gettext("out of memory\n"); + else + 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) + { + appendPQExpBufferStr(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 + appendPQExpBufferStr(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_SQLSTATE) + { + /* + * If we have a SQLSTATE, print that and nothing else. If not (which + * shouldn't happen for server-generated errors, but might possibly + * happen for libpq-generated ones), fall back to TERSE format, as + * that seems better than printing nothing at all. + */ + val = PQresultErrorField(res, PG_DIAG_SQLSTATE); + if (val) + { + appendPQExpBuffer(msg, "%s\n", val); + return; + } + verbosity = PQERRORS_TERSE; + } + + 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 += PQmblenBounded(&wquery[qoffset], encoding); + } + 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 += PQmblenBounded(&msg->data[i], encoding)) + { + 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 NegotiateProtocolVersion message. + * Entry: 'v' message type and length have already been consumed. + * Exit: returns 0 if successfully consumed message. + * returns EOF if not enough data. + */ +int +pqGetNegotiateProtocolVersion3(PGconn *conn) +{ + int tmp; + ProtocolVersion their_version; + int num; + PQExpBufferData buf; + + if (pqGetInt(&tmp, 4, conn) != 0) + return EOF; + their_version = tmp; + + if (pqGetInt(&num, 4, conn) != 0) + return EOF; + + initPQExpBuffer(&buf); + for (int i = 0; i < num; i++) + { + if (pqGets(&conn->workBuffer, conn)) + { + termPQExpBuffer(&buf); + return EOF; + } + if (buf.len > 0) + appendPQExpBufferChar(&buf, ' '); + appendPQExpBufferStr(&buf, conn->workBuffer.data); + } + + if (their_version < conn->pversion) + libpq_append_conn_error(conn, "protocol version not supported by server: client uses %u.%u, server supports up to %u.%u", + PG_PROTOCOL_MAJOR(conn->pversion), PG_PROTOCOL_MINOR(conn->pversion), + PG_PROTOCOL_MAJOR(their_version), PG_PROTOCOL_MINOR(their_version)); + if (num > 0) + { + appendPQExpBuffer(&conn->errorMessage, + libpq_ngettext("protocol extension not supported by server: %s", + "protocol extensions not supported by server: %s", num), + buf.data); + appendPQExpBufferChar(&conn->errorMessage, '\n'); + } + + /* neither -- server shouldn't have sent it */ + if (!(their_version < conn->pversion) && !(num > 0)) + libpq_append_conn_error(conn, "invalid %s message", "NegotiateProtocolVersion"); + + termPQExpBuffer(&buf); + return 0; +} + + +/* + * 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 PGnotify 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; + } + + /* trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + + /* 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) + { + libpq_append_conn_error(conn, "out of memory"); + 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) + { + libpq_append_conn_error(conn, "PQgetline: not doing text COPY OUT"); + *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) + { + libpq_append_conn_error(conn, "no COPY in progress"); + return 1; + } + + /* Send the CopyDone message if needed */ + if (conn->asyncStatus == PGASYNC_COPY_IN || + conn->asyncStatus == PGASYNC_COPY_BOTH) + { + if (pqPutMsgStart('c', 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->cmd_queue_head && + conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE) + { + if (pqPutMsgStart('S', 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; + + /* + * 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; + + /* already validated by PQfn */ + Assert(conn->pipelineStatus == PQ_PIPELINE_OFF); + + /* PQfn already validated connection state */ + + if (pqPutMsgStart('F', 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 */ + { + /* error message should be set up already */ + return NULL; + } + + for (i = 0; i < nargs; ++i) + { /* len.int4 + contents */ + if (pqPutInt(args[i].len, 4, 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)) + return NULL; + } + else + { + if (pqPutnchar((char *) args[i].u.ptr, args[i].len, conn)) + return NULL; + } + } + + if (pqPutInt(1, 2, conn) < 0) /* result format code: BINARY */ + return NULL; + + if (pqPutMsgEnd(conn) < 0 || + pqFlush(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 already have a result object (probably an error), use + * that. Otherwise, if we saw a function result message, + * report COMMAND_OK. Otherwise, the backend violated the + * protocol, so complain. + */ + if (!pgHavePendingResult(conn)) + { + if (status == PGRES_COMMAND_OK) + { + conn->result = PQmakeEmptyPGresult(conn, status); + if (!conn->result) + { + libpq_append_conn_error(conn, "out of memory"); + pqSaveErrorResult(conn); + } + } + else + { + libpq_append_conn_error(conn, "protocol error: no function result"); + pqSaveErrorResult(conn); + } + } + return pqPrepareAsyncResult(conn); + case 'S': /* parameter status */ + if (getParameterStatus(conn)) + continue; + break; + default: + /* The backend violates the protocol. */ + libpq_append_conn_error(conn, "protocol error: id=0x%x", id); + pqSaveErrorResult(conn); + /* trust the specified message length as what to skip */ + conn->inStart += 5 + msgLength; + return pqPrepareAsyncResult(conn); + } + + /* trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + + /* 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 = pg_hton32(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/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c new file mode 100644 index 0000000000..3ecc7bf615 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.c @@ -0,0 +1,307 @@ +/*------------------------------------------------------------------------- + * + * fe-secure-common.c + * + * common implementation-independent SSL support code + * + * While fe-secure.c contains the interfaces that the rest of libpq call, this + * file contains support routines that are used by the library-specific + * implementations such as fe-secure-openssl.c. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/interfaces/libpq/fe-secure-common.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <arpa/inet.h> + +#include "fe-secure-common.h" + +#include "libpq-int.h" +#include "pqexpbuffer.h" + +/* + * Check if a wildcard certificate matches the server hostname. + * + * The rule for this is: + * 1. We only match the '*' character as wildcard + * 2. We match only wildcards at the start of the string + * 3. The '*' character does *not* match '.', meaning that we match only + * a single pathname component. + * 4. We don't support more than one '*' in a single pattern. + * + * This is roughly in line with RFC2818, but contrary to what most browsers + * appear to be implementing (point 3 being the difference) + * + * Matching is always case-insensitive, since DNS is case insensitive. + */ +static bool +wildcard_certificate_match(const char *pattern, const char *string) +{ + int lenpat = strlen(pattern); + int lenstr = strlen(string); + + /* If we don't start with a wildcard, it's not a match (rule 1 & 2) */ + if (lenpat < 3 || + pattern[0] != '*' || + pattern[1] != '.') + return false; + + /* If pattern is longer than the string, we can never match */ + if (lenpat > lenstr) + return false; + + /* + * If string does not end in pattern (minus the wildcard), we don't match + */ + if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0) + return false; + + /* + * If there is a dot left of where the pattern started to match, we don't + * match (rule 3) + */ + if (strchr(string, '.') < string + lenstr - lenpat) + return false; + + /* String ended with pattern, and didn't have a dot before, so we match */ + return true; +} + +/* + * Check if a name from a server's certificate matches the peer's hostname. + * + * Returns 1 if the name matches, and 0 if it does not. On error, returns + * -1, and sets the libpq error message. + * + * The name extracted from the certificate is returned in *store_name. The + * caller is responsible for freeing it. + */ +int +pq_verify_peer_name_matches_certificate_name(PGconn *conn, + const char *namedata, size_t namelen, + char **store_name) +{ + char *name; + int result; + char *host = conn->connhost[conn->whichhost].host; + + *store_name = NULL; + + if (!(host && host[0] != '\0')) + { + libpq_append_conn_error(conn, "host name must be specified"); + return -1; + } + + /* + * There is no guarantee the string returned from the certificate is + * NULL-terminated, so make a copy that is. + */ + name = malloc(namelen + 1); + if (name == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return -1; + } + memcpy(name, namedata, namelen); + name[namelen] = '\0'; + + /* + * Reject embedded NULLs in certificate common or alternative name to + * prevent attacks like CVE-2009-4034. + */ + if (namelen != strlen(name)) + { + free(name); + libpq_append_conn_error(conn, "SSL certificate's name contains embedded null"); + return -1; + } + + if (pg_strcasecmp(name, host) == 0) + { + /* Exact name match */ + result = 1; + } + else if (wildcard_certificate_match(name, host)) + { + /* Matched wildcard name */ + result = 1; + } + else + { + result = 0; + } + + *store_name = name; + return result; +} + +/* + * Check if an IP address from a server's certificate matches the peer's + * hostname (which must itself be an IPv4/6 address). + * + * Returns 1 if the address matches, and 0 if it does not. On error, returns + * -1, and sets the libpq error message. + * + * A string representation of the certificate's IP address is returned in + * *store_name. The caller is responsible for freeing it. + */ +int +pq_verify_peer_name_matches_certificate_ip(PGconn *conn, + const unsigned char *ipdata, + size_t iplen, + char **store_name) +{ + char *addrstr; + int match = 0; + char *host = conn->connhost[conn->whichhost].host; + int family; + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + char sebuf[PG_STRERROR_R_BUFLEN]; + + *store_name = NULL; + + if (!(host && host[0] != '\0')) + { + libpq_append_conn_error(conn, "host name must be specified"); + return -1; + } + + /* + * The data from the certificate is in network byte order. Convert our + * host string to network-ordered bytes as well, for comparison. (The host + * string isn't guaranteed to actually be an IP address, so if this + * conversion fails we need to consider it a mismatch rather than an + * error.) + */ + if (iplen == 4) + { + /* IPv4 */ + struct in_addr addr; + + family = AF_INET; + + /* + * The use of inet_aton() is deliberate; we accept alternative IPv4 + * address notations that are accepted by inet_aton() but not + * inet_pton() as server addresses. + */ + if (inet_aton(host, &addr)) + { + if (memcmp(ipdata, &addr.s_addr, iplen) == 0) + match = 1; + } + } + + /* + * If they don't have inet_pton(), skip this. Then, an IPv6 address in a + * certificate will cause an error. + */ +#ifdef HAVE_INET_PTON + else if (iplen == 16) + { + /* IPv6 */ + struct in6_addr addr; + + family = AF_INET6; + + if (inet_pton(AF_INET6, host, &addr) == 1) + { + if (memcmp(ipdata, &addr.s6_addr, iplen) == 0) + match = 1; + } + } +#endif + else + { + /* + * Not IPv4 or IPv6. We could ignore the field, but leniency seems + * wrong given the subject matter. + */ + libpq_append_conn_error(conn, "certificate contains IP address with invalid length %zu", + iplen); + return -1; + } + + /* Generate a human-readable representation of the certificate's IP. */ + addrstr = pg_inet_net_ntop(family, ipdata, 8 * iplen, tmp, sizeof(tmp)); + if (!addrstr) + { + libpq_append_conn_error(conn, "could not convert certificate's IP address to string: %s", + strerror_r(errno, sebuf, sizeof(sebuf))); + return -1; + } + + *store_name = strdup(addrstr); + return match; +} + +/* + * Verify that the server certificate matches the hostname we connected to. + * + * The certificate's Common Name and Subject Alternative Names are considered. + */ +bool +pq_verify_peer_name_matches_certificate(PGconn *conn) +{ + char *host = conn->connhost[conn->whichhost].host; + int rc; + int names_examined = 0; + char *first_name = NULL; + + /* + * If told not to verify the peer name, don't do it. Return true + * indicating that the verification was successful. + */ + if (strcmp(conn->sslmode, "verify-full") != 0) + return true; + + /* Check that we have a hostname to compare with. */ + if (!(host && host[0] != '\0')) + { + libpq_append_conn_error(conn, "host name must be specified for a verified SSL connection"); + return false; + } + + rc = pgtls_verify_peer_name_matches_certificate_guts(conn, &names_examined, &first_name); + + if (rc == 0) + { + /* + * No match. Include the name from the server certificate in the error + * message, to aid debugging broken configurations. If there are + * multiple names, only print the first one to avoid an overly long + * error message. + */ + if (names_examined > 1) + { + appendPQExpBuffer(&conn->errorMessage, + libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"", + "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"", + names_examined - 1), + first_name, names_examined - 1, host); + appendPQExpBufferChar(&conn->errorMessage, '\n'); + } + else if (names_examined == 1) + { + libpq_append_conn_error(conn, "server certificate for \"%s\" does not match host name \"%s\"", + first_name, host); + } + else + { + libpq_append_conn_error(conn, "could not get server's host name from server certificate"); + } + } + + /* clean up */ + free(first_name); + + return (rc == 1); +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.h b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.h new file mode 100644 index 0000000000..e048f97b01 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-common.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * fe-secure-common.h + * + * common implementation-independent SSL support code + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/interfaces/libpq/fe-secure-common.h + * + *------------------------------------------------------------------------- + */ + +#ifndef FE_SECURE_COMMON_H +#define FE_SECURE_COMMON_H + +#include "libpq-fe.h" + +extern int pq_verify_peer_name_matches_certificate_name(PGconn *conn, + const char *namedata, size_t namelen, + char **store_name); +extern int pq_verify_peer_name_matches_certificate_ip(PGconn *conn, + const unsigned char *ipdata, + size_t iplen, + char **store_name); +extern bool pq_verify_peer_name_matches_certificate(PGconn *conn); + +#endif /* FE_SECURE_COMMON_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c new file mode 100644 index 0000000000..5c220e0e69 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-secure-openssl.c @@ -0,0 +1,2062 @@ +/*------------------------------------------------------------------------- + * + * fe-secure-openssl.c + * OpenSSL support + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/interfaces/libpq/fe-secure-openssl.c + * + * NOTES + * + * We don't provide informational callbacks here (like + * info_cb() in be-secure-openssl.c), since there's no good mechanism to + * display such information to the user. + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <signal.h> +#include <fcntl.h> +#include <ctype.h> + +#include "libpq-fe.h" +#include "fe-auth.h" +#include "fe-secure-common.h" +#include "libpq-int.h" + +#ifdef WIN32 +#include "win32.h" +#else +#include <sys/socket.h> +#include <unistd.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#endif + +#include <sys/stat.h> + +#ifdef ENABLE_THREAD_SAFETY +#ifdef WIN32 +#include "pthread-win32.h" +#else +#include <pthread.h> +#endif +#endif + +/* + * These SSL-related #includes must come after all system-provided headers. + * This ensures that OpenSSL can take care of conflicts with Windows' + * <wincrypt.h> by #undef'ing the conflicting macros. (We don't directly + * include <wincrypt.h>, but some other Windows headers do.) + */ +#include "common/openssl.h" +#include <openssl/conf.h> +#ifdef USE_SSL_ENGINE +#include <openssl/engine.h> +#endif +#include <openssl/x509v3.h> + + +static int verify_cb(int ok, X509_STORE_CTX *ctx); +static int openssl_verify_peer_name_matches_certificate_name(PGconn *conn, + ASN1_STRING *name_entry, + char **store_name); +static int openssl_verify_peer_name_matches_certificate_ip(PGconn *conn, + ASN1_OCTET_STRING *addr_entry, + char **store_name); +static void destroy_ssl_system(void); +static int initialize_SSL(PGconn *conn); +static PostgresPollingStatusType open_client_SSL(PGconn *conn); +static char *SSLerrmessage(unsigned long ecode); +static void SSLerrfree(char *buf); +static int PQssl_passwd_cb(char *buf, int size, int rwflag, void *userdata); + +static int my_sock_read(BIO *h, char *buf, int size); +static int my_sock_write(BIO *h, const char *buf, int size); +static BIO_METHOD *my_BIO_s_socket(void); +static int my_SSL_set_fd(PGconn *conn, int fd); + + +static bool pq_init_ssl_lib = true; +static bool pq_init_crypto_lib = true; + +static bool ssl_lib_initialized = false; + +#ifdef ENABLE_THREAD_SAFETY +static long crypto_open_connections = 0; + +#ifndef WIN32 +static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; +#else +static pthread_mutex_t ssl_config_mutex = NULL; +static long win32_ssl_create_mutex = 0; +#endif +#endif /* ENABLE_THREAD_SAFETY */ + +static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL; +static int ssl_protocol_version_to_openssl(const char *protocol); + +/* ------------------------------------------------------------ */ +/* Procedures common to all secure sessions */ +/* ------------------------------------------------------------ */ + +void +pgtls_init_library(bool do_ssl, int do_crypto) +{ +#ifdef ENABLE_THREAD_SAFETY + + /* + * Disallow changing the flags while we have open connections, else we'd + * get completely confused. + */ + if (crypto_open_connections != 0) + return; +#endif + + pq_init_ssl_lib = do_ssl; + pq_init_crypto_lib = do_crypto; +} + +PostgresPollingStatusType +pgtls_open_client(PGconn *conn) +{ + /* First time through? */ + if (conn->ssl == NULL) + { + /* + * Create a connection-specific SSL object, and load client + * certificate, private key, and trusted CA certs. + */ + if (initialize_SSL(conn) != 0) + { + /* initialize_SSL already put a message in conn->errorMessage */ + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + } + + /* Begin or continue the actual handshake */ + return open_client_SSL(conn); +} + +ssize_t +pgtls_read(PGconn *conn, void *ptr, size_t len) +{ + ssize_t n; + int result_errno = 0; + char sebuf[PG_STRERROR_R_BUFLEN]; + int err; + unsigned long ecode; + +rloop: + + /* + * Prepare to call SSL_get_error() by clearing thread's OpenSSL error + * queue. In general, the current thread's error queue must be empty + * before the TLS/SSL I/O operation is attempted, or SSL_get_error() will + * not work reliably. Since the possibility exists that other OpenSSL + * clients running in the same thread but not under our control will fail + * to call ERR_get_error() themselves (after their own I/O operations), + * pro-actively clear the per-thread error queue now. + */ + SOCK_ERRNO_SET(0); + ERR_clear_error(); + n = SSL_read(conn->ssl, ptr, len); + err = SSL_get_error(conn->ssl, n); + + /* + * Other clients of OpenSSL may fail to call ERR_get_error(), but we + * always do, so as to not cause problems for OpenSSL clients that don't + * call ERR_clear_error() defensively. Be sure that this happens by + * calling now. SSL_get_error() relies on the OpenSSL per-thread error + * queue being intact, so this is the earliest possible point + * ERR_get_error() may be called. + */ + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; + switch (err) + { + case SSL_ERROR_NONE: + if (n < 0) + { + /* Not supposed to happen, so we don't translate the msg */ + appendPQExpBufferStr(&conn->errorMessage, + "SSL_read failed but did not provide error information\n"); + /* assume the connection is broken */ + result_errno = ECONNRESET; + } + break; + case SSL_ERROR_WANT_READ: + n = 0; + break; + case SSL_ERROR_WANT_WRITE: + + /* + * Returning 0 here would cause caller to wait for read-ready, + * which is not correct since what SSL wants is wait for + * write-ready. The former could get us stuck in an infinite + * wait, so don't risk it; busy-loop instead. + */ + goto rloop; + case SSL_ERROR_SYSCALL: + if (n < 0) + { + result_errno = SOCK_ERRNO; + if (result_errno == EPIPE || + result_errno == ECONNRESET) + libpq_append_conn_error(conn, "server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request."); + else + libpq_append_conn_error(conn, "SSL SYSCALL error: %s", + SOCK_STRERROR(result_errno, + sebuf, sizeof(sebuf))); + } + else + { + libpq_append_conn_error(conn, "SSL SYSCALL error: EOF detected"); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + } + break; + case SSL_ERROR_SSL: + { + char *errm = SSLerrmessage(ecode); + + libpq_append_conn_error(conn, "SSL error: %s", errm); + SSLerrfree(errm); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + break; + } + case SSL_ERROR_ZERO_RETURN: + + /* + * Per OpenSSL documentation, this error code is only returned for + * a clean connection closure, so we should not report it as a + * server crash. + */ + libpq_append_conn_error(conn, "SSL connection has been closed unexpectedly"); + result_errno = ECONNRESET; + n = -1; + break; + default: + libpq_append_conn_error(conn, "unrecognized SSL error code: %d", err); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + break; + } + + /* ensure we return the intended errno to caller */ + SOCK_ERRNO_SET(result_errno); + + return n; +} + +bool +pgtls_read_pending(PGconn *conn) +{ + return SSL_pending(conn->ssl) > 0; +} + +ssize_t +pgtls_write(PGconn *conn, const void *ptr, size_t len) +{ + ssize_t n; + int result_errno = 0; + char sebuf[PG_STRERROR_R_BUFLEN]; + int err; + unsigned long ecode; + + SOCK_ERRNO_SET(0); + ERR_clear_error(); + n = SSL_write(conn->ssl, ptr, len); + err = SSL_get_error(conn->ssl, n); + ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0; + switch (err) + { + case SSL_ERROR_NONE: + if (n < 0) + { + /* Not supposed to happen, so we don't translate the msg */ + appendPQExpBufferStr(&conn->errorMessage, + "SSL_write failed but did not provide error information\n"); + /* assume the connection is broken */ + result_errno = ECONNRESET; + } + break; + case SSL_ERROR_WANT_READ: + + /* + * Returning 0 here causes caller to wait for write-ready, which + * is not really the right thing, but it's the best we can do. + */ + n = 0; + break; + case SSL_ERROR_WANT_WRITE: + n = 0; + break; + case SSL_ERROR_SYSCALL: + if (n < 0) + { + result_errno = SOCK_ERRNO; + if (result_errno == EPIPE || result_errno == ECONNRESET) + libpq_append_conn_error(conn, "server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request."); + else + libpq_append_conn_error(conn, "SSL SYSCALL error: %s", + SOCK_STRERROR(result_errno, + sebuf, sizeof(sebuf))); + } + else + { + libpq_append_conn_error(conn, "SSL SYSCALL error: EOF detected"); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + } + break; + case SSL_ERROR_SSL: + { + char *errm = SSLerrmessage(ecode); + + libpq_append_conn_error(conn, "SSL error: %s", errm); + SSLerrfree(errm); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + break; + } + case SSL_ERROR_ZERO_RETURN: + + /* + * Per OpenSSL documentation, this error code is only returned for + * a clean connection closure, so we should not report it as a + * server crash. + */ + libpq_append_conn_error(conn, "SSL connection has been closed unexpectedly"); + result_errno = ECONNRESET; + n = -1; + break; + default: + libpq_append_conn_error(conn, "unrecognized SSL error code: %d", err); + /* assume the connection is broken */ + result_errno = ECONNRESET; + n = -1; + break; + } + + /* ensure we return the intended errno to caller */ + SOCK_ERRNO_SET(result_errno); + + return n; +} + +#if defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO) +char * +pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) +{ + X509 *peer_cert; + const EVP_MD *algo_type; + unsigned char hash[EVP_MAX_MD_SIZE]; /* size for SHA-512 */ + unsigned int hash_size; + int algo_nid; + char *cert_hash; + + *len = 0; + + if (!conn->peer) + return NULL; + + peer_cert = conn->peer; + + /* + * Get the signature algorithm of the certificate to determine the hash + * algorithm to use for the result. Prefer X509_get_signature_info(), + * introduced in OpenSSL 1.1.1, which can handle RSA-PSS signatures. + */ +#if HAVE_X509_GET_SIGNATURE_INFO + if (!X509_get_signature_info(peer_cert, &algo_nid, NULL, NULL, NULL)) +#else + if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert), + &algo_nid, NULL)) +#endif + { + libpq_append_conn_error(conn, "could not determine server certificate signature algorithm"); + return NULL; + } + + /* + * The TLS server's certificate bytes need to be hashed with SHA-256 if + * its signature algorithm is MD5 or SHA-1 as per RFC 5929 + * (https://tools.ietf.org/html/rfc5929#section-4.1). If something else + * is used, the same hash as the signature algorithm is used. + */ + switch (algo_nid) + { + case NID_md5: + case NID_sha1: + algo_type = EVP_sha256(); + break; + default: + algo_type = EVP_get_digestbynid(algo_nid); + if (algo_type == NULL) + { + libpq_append_conn_error(conn, "could not find digest for NID %s", + OBJ_nid2sn(algo_nid)); + return NULL; + } + break; + } + + if (!X509_digest(peer_cert, algo_type, hash, &hash_size)) + { + libpq_append_conn_error(conn, "could not generate peer certificate hash"); + return NULL; + } + + /* save result */ + cert_hash = malloc(hash_size); + if (cert_hash == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return NULL; + } + memcpy(cert_hash, hash, hash_size); + *len = hash_size; + + return cert_hash; +} +#endif /* HAVE_X509_GET_SIGNATURE_NID */ + +/* ------------------------------------------------------------ */ +/* OpenSSL specific code */ +/* ------------------------------------------------------------ */ + +/* + * Certificate verification callback + * + * This callback allows us to log intermediate problems during + * verification, but there doesn't seem to be a clean way to get + * our PGconn * structure. So we can't log anything! + * + * This callback also allows us to override the default acceptance + * criteria (e.g., accepting self-signed or expired certs), but + * for now we accept the default checks. + */ +static int +verify_cb(int ok, X509_STORE_CTX *ctx) +{ + return ok; +} + +#ifdef HAVE_SSL_CTX_SET_CERT_CB +/* + * Certificate selection callback + * + * This callback lets us choose the client certificate we send to the server + * after seeing its CertificateRequest. We only support sending a single + * hard-coded certificate via sslcert, so we don't actually set any certificates + * here; we just use it to record whether or not the server has actually asked + * for one and whether we have one to send. + */ +static int +cert_cb(SSL *ssl, void *arg) +{ + PGconn *conn = arg; + + conn->ssl_cert_requested = true; + + /* Do we have a certificate loaded to send back? */ + if (SSL_get_certificate(ssl)) + conn->ssl_cert_sent = true; + + /* + * Tell OpenSSL that the callback succeeded; we're not required to + * actually make any changes to the SSL handle. + */ + return 1; +} +#endif + +/* + * OpenSSL-specific wrapper around + * pq_verify_peer_name_matches_certificate_name(), converting the ASN1_STRING + * into a plain C string. + */ +static int +openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry, + char **store_name) +{ + int len; + const unsigned char *namedata; + + /* Should not happen... */ + if (name_entry == NULL) + { + libpq_append_conn_error(conn, "SSL certificate's name entry is missing"); + return -1; + } + + /* + * GEN_DNS can be only IA5String, equivalent to US ASCII. + */ +#ifdef HAVE_ASN1_STRING_GET0_DATA + namedata = ASN1_STRING_get0_data(name_entry); +#else + namedata = ASN1_STRING_data(name_entry); +#endif + len = ASN1_STRING_length(name_entry); + + /* OK to cast from unsigned to plain char, since it's all ASCII. */ + return pq_verify_peer_name_matches_certificate_name(conn, (const char *) namedata, len, store_name); +} + +/* + * OpenSSL-specific wrapper around + * pq_verify_peer_name_matches_certificate_ip(), converting the + * ASN1_OCTET_STRING into a plain C string. + */ +static int +openssl_verify_peer_name_matches_certificate_ip(PGconn *conn, + ASN1_OCTET_STRING *addr_entry, + char **store_name) +{ + int len; + const unsigned char *addrdata; + + /* Should not happen... */ + if (addr_entry == NULL) + { + libpq_append_conn_error(conn, "SSL certificate's address entry is missing"); + return -1; + } + + /* + * GEN_IPADD is an OCTET STRING containing an IP address in network byte + * order. + */ +#ifdef HAVE_ASN1_STRING_GET0_DATA + addrdata = ASN1_STRING_get0_data(addr_entry); +#else + addrdata = ASN1_STRING_data(addr_entry); +#endif + len = ASN1_STRING_length(addr_entry); + + return pq_verify_peer_name_matches_certificate_ip(conn, addrdata, len, store_name); +} + +static bool +is_ip_address(const char *host) +{ + struct in_addr dummy4; +#ifdef HAVE_INET_PTON + struct in6_addr dummy6; +#endif + + return inet_aton(host, &dummy4) +#ifdef HAVE_INET_PTON + || (inet_pton(AF_INET6, host, &dummy6) == 1) +#endif + ; +} + +/* + * Verify that the server certificate matches the hostname we connected to. + * + * The certificate's Common Name and Subject Alternative Names are considered. + */ +int +pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn, + int *names_examined, + char **first_name) +{ + STACK_OF(GENERAL_NAME) * peer_san; + int i; + int rc = 0; + char *host = conn->connhost[conn->whichhost].host; + int host_type; + bool check_cn = true; + + Assert(host && host[0]); /* should be guaranteed by caller */ + + /* + * We try to match the NSS behavior here, which is a slight departure from + * the spec but seems to make more intuitive sense: + * + * If connhost contains a DNS name, and the certificate's SANs contain any + * dNSName entries, then we'll ignore the Subject Common Name entirely; + * otherwise, we fall back to checking the CN. (This behavior matches the + * RFC.) + * + * If connhost contains an IP address, and the SANs contain iPAddress + * entries, we again ignore the CN. Otherwise, we allow the CN to match, + * EVEN IF there is a dNSName in the SANs. (RFC 6125 prohibits this: "A + * client MUST NOT seek a match for a reference identifier of CN-ID if the + * presented identifiers include a DNS-ID, SRV-ID, URI-ID, or any + * application-specific identifier types supported by the client.") + * + * NOTE: Prior versions of libpq did not consider iPAddress entries at + * all, so this new behavior might break a certificate that has different + * IP addresses in the Subject CN and the SANs. + */ + if (is_ip_address(host)) + host_type = GEN_IPADD; + else + host_type = GEN_DNS; + + /* + * First, get the Subject Alternative Names (SANs) from the certificate, + * and compare them against the originally given hostname. + */ + peer_san = (STACK_OF(GENERAL_NAME) *) + X509_get_ext_d2i(conn->peer, NID_subject_alt_name, NULL, NULL); + + if (peer_san) + { + int san_len = sk_GENERAL_NAME_num(peer_san); + + for (i = 0; i < san_len; i++) + { + const GENERAL_NAME *name = sk_GENERAL_NAME_value(peer_san, i); + char *alt_name = NULL; + + if (name->type == host_type) + { + /* + * This SAN is of the same type (IP or DNS) as our host name, + * so don't allow a fallback check of the CN. + */ + check_cn = false; + } + + if (name->type == GEN_DNS) + { + (*names_examined)++; + rc = openssl_verify_peer_name_matches_certificate_name(conn, + name->d.dNSName, + &alt_name); + } + else if (name->type == GEN_IPADD) + { + (*names_examined)++; + rc = openssl_verify_peer_name_matches_certificate_ip(conn, + name->d.iPAddress, + &alt_name); + } + + if (alt_name) + { + if (!*first_name) + *first_name = alt_name; + else + free(alt_name); + } + + if (rc != 0) + { + /* + * Either we hit an error or a match, and either way we should + * not fall back to the CN. + */ + check_cn = false; + break; + } + } + sk_GENERAL_NAME_pop_free(peer_san, GENERAL_NAME_free); + } + + /* + * If there is no subjectAltName extension of the matching type, check the + * Common Name. + * + * (Per RFC 2818 and RFC 6125, if the subjectAltName extension of type + * dNSName is present, the CN must be ignored. We break this rule if host + * is an IP address; see the comment above.) + */ + if (check_cn) + { + X509_NAME *subject_name; + + subject_name = X509_get_subject_name(conn->peer); + if (subject_name != NULL) + { + int cn_index; + + cn_index = X509_NAME_get_index_by_NID(subject_name, + NID_commonName, -1); + if (cn_index >= 0) + { + char *common_name = NULL; + + (*names_examined)++; + rc = openssl_verify_peer_name_matches_certificate_name(conn, + X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject_name, cn_index)), + &common_name); + + if (common_name) + { + if (!*first_name) + *first_name = common_name; + else + free(common_name); + } + } + } + } + + return rc; +} + +#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) +/* + * Callback functions for OpenSSL internal locking. (OpenSSL 1.1.0 + * does its own locking, and doesn't need these anymore. The + * CRYPTO_lock() function was removed in 1.1.0, when the callbacks + * were made obsolete, so we assume that if CRYPTO_lock() exists, + * the callbacks are still required.) + */ + +static unsigned long +pq_threadidcallback(void) +{ + /* + * This is not standards-compliant. pthread_self() returns pthread_t, and + * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires + * it, so we have to do it. + */ + return (unsigned long) pthread_self(); +} + +static pthread_mutex_t *pq_lockarray; + +static void +pq_lockingcallback(int mode, int n, const char *file, int line) +{ + /* + * There's no way to report a mutex-primitive failure, so we just Assert + * in development builds, and ignore any errors otherwise. Fortunately + * this is all obsolete in modern OpenSSL. + */ + if (mode & CRYPTO_LOCK) + { + if (pthread_mutex_lock(&pq_lockarray[n])) + Assert(false); + } + else + { + if (pthread_mutex_unlock(&pq_lockarray[n])) + Assert(false); + } +} +#endif /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */ + +/* + * Initialize SSL library. + * + * In threadsafe mode, this includes setting up libcrypto callback functions + * to do thread locking. + * + * If the caller has told us (through PQinitOpenSSL) that he's taking care + * of libcrypto, we expect that callbacks are already set, and won't try to + * override it. + */ +int +pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto) +{ +#ifdef ENABLE_THREAD_SAFETY +#ifdef WIN32 + /* Also see similar code in fe-connect.c, default_threadlock() */ + if (ssl_config_mutex == NULL) + { + while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1) + /* loop, another thread own the lock */ ; + if (ssl_config_mutex == NULL) + { + if (pthread_mutex_init(&ssl_config_mutex, NULL)) + return -1; + } + InterlockedExchange(&win32_ssl_create_mutex, 0); + } +#endif + if (pthread_mutex_lock(&ssl_config_mutex)) + return -1; + +#ifdef HAVE_CRYPTO_LOCK + if (pq_init_crypto_lib) + { + /* + * If necessary, set up an array to hold locks for libcrypto. + * libcrypto will tell us how big to make this array. + */ + if (pq_lockarray == NULL) + { + int i; + + pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); + if (!pq_lockarray) + { + pthread_mutex_unlock(&ssl_config_mutex); + return -1; + } + for (i = 0; i < CRYPTO_num_locks(); i++) + { + if (pthread_mutex_init(&pq_lockarray[i], NULL)) + { + free(pq_lockarray); + pq_lockarray = NULL; + pthread_mutex_unlock(&ssl_config_mutex); + return -1; + } + } + } + + if (do_crypto && !conn->crypto_loaded) + { + if (crypto_open_connections++ == 0) + { + /* + * These are only required for threaded libcrypto + * applications, but make sure we don't stomp on them if + * they're already set. + */ + if (CRYPTO_get_id_callback() == NULL) + CRYPTO_set_id_callback(pq_threadidcallback); + if (CRYPTO_get_locking_callback() == NULL) + CRYPTO_set_locking_callback(pq_lockingcallback); + } + + conn->crypto_loaded = true; + } + } +#endif /* HAVE_CRYPTO_LOCK */ +#endif /* ENABLE_THREAD_SAFETY */ + + if (!ssl_lib_initialized && do_ssl) + { + if (pq_init_ssl_lib) + { +#ifdef HAVE_OPENSSL_INIT_SSL + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else + OPENSSL_config(NULL); + SSL_library_init(); + SSL_load_error_strings(); +#endif + } + ssl_lib_initialized = true; + } + +#ifdef ENABLE_THREAD_SAFETY + pthread_mutex_unlock(&ssl_config_mutex); +#endif + return 0; +} + +/* + * This function is needed because if the libpq library is unloaded + * from the application, the callback functions will no longer exist when + * libcrypto is used by other parts of the system. For this reason, + * we unregister the callback functions when the last libpq + * connection is closed. (The same would apply for OpenSSL callbacks + * if we had any.) + * + * Callbacks are only set when we're compiled in threadsafe mode, so + * we only need to remove them in this case. They are also not needed + * with OpenSSL 1.1.0 anymore. + */ +static void +destroy_ssl_system(void) +{ +#if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK) + /* Mutex is created in pgtls_init() */ + if (pthread_mutex_lock(&ssl_config_mutex)) + return; + + if (pq_init_crypto_lib && crypto_open_connections > 0) + --crypto_open_connections; + + if (pq_init_crypto_lib && crypto_open_connections == 0) + { + /* + * No connections left, unregister libcrypto callbacks, if no one + * registered different ones in the meantime. + */ + if (CRYPTO_get_locking_callback() == pq_lockingcallback) + CRYPTO_set_locking_callback(NULL); + if (CRYPTO_get_id_callback() == pq_threadidcallback) + CRYPTO_set_id_callback(NULL); + + /* + * We don't free the lock array. If we get another connection in this + * process, we will just re-use them with the existing mutexes. + * + * This means we leak a little memory on repeated load/unload of the + * library. + */ + } + + pthread_mutex_unlock(&ssl_config_mutex); +#endif +} + +/* + * Create per-connection SSL object, and load the client certificate, + * private key, and trusted CA certs. + * + * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage). + */ +static int +initialize_SSL(PGconn *conn) +{ + SSL_CTX *SSL_context; + struct stat buf; + char homedir[MAXPGPATH]; + char fnbuf[MAXPGPATH]; + char sebuf[PG_STRERROR_R_BUFLEN]; + bool have_homedir; + bool have_cert; + bool have_rootcert; + EVP_PKEY *pkey = NULL; + + /* + * We'll need the home directory if any of the relevant parameters are + * defaulted. If pqGetHomeDirectory fails, act as though none of the + * files could be found. + */ + if (!(conn->sslcert && strlen(conn->sslcert) > 0) || + !(conn->sslkey && strlen(conn->sslkey) > 0) || + !(conn->sslrootcert && strlen(conn->sslrootcert) > 0) || + !((conn->sslcrl && strlen(conn->sslcrl) > 0) || + (conn->sslcrldir && strlen(conn->sslcrldir) > 0))) + have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir)); + else /* won't need it */ + have_homedir = false; + + /* + * Create a new SSL_CTX object. + * + * We used to share a single SSL_CTX between all connections, but it was + * complicated if connections used different certificates. So now we + * create a separate context for each connection, and accept the overhead. + */ + SSL_context = SSL_CTX_new(SSLv23_method()); + if (!SSL_context) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not create SSL context: %s", err); + SSLerrfree(err); + return -1; + } + + /* + * Delegate the client cert password prompt to the libpq wrapper callback + * if any is defined. + * + * If the application hasn't installed its own and the sslpassword + * parameter is non-null, we install ours now to make sure we supply + * PGconn->sslpassword to OpenSSL instead of letting it prompt on stdin. + * + * This will replace OpenSSL's default PEM_def_callback (which prompts on + * stdin), but we're only setting it for this SSL context so it's + * harmless. + */ + if (PQsslKeyPassHook + || (conn->sslpassword && strlen(conn->sslpassword) > 0)) + { + SSL_CTX_set_default_passwd_cb(SSL_context, PQssl_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(SSL_context, conn); + } + +#ifdef HAVE_SSL_CTX_SET_CERT_CB + /* Set up a certificate selection callback. */ + SSL_CTX_set_cert_cb(SSL_context, cert_cb, conn); +#endif + + /* Disable old protocol versions */ + SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + + /* Set the minimum and maximum protocol versions if necessary */ + if (conn->ssl_min_protocol_version && + strlen(conn->ssl_min_protocol_version) != 0) + { + int ssl_min_ver; + + ssl_min_ver = ssl_protocol_version_to_openssl(conn->ssl_min_protocol_version); + + if (ssl_min_ver == -1) + { + libpq_append_conn_error(conn, "invalid value \"%s\" for minimum SSL protocol version", + conn->ssl_min_protocol_version); + SSL_CTX_free(SSL_context); + return -1; + } + + if (!SSL_CTX_set_min_proto_version(SSL_context, ssl_min_ver)) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not set minimum SSL protocol version: %s", err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + } + + if (conn->ssl_max_protocol_version && + strlen(conn->ssl_max_protocol_version) != 0) + { + int ssl_max_ver; + + ssl_max_ver = ssl_protocol_version_to_openssl(conn->ssl_max_protocol_version); + + if (ssl_max_ver == -1) + { + libpq_append_conn_error(conn, "invalid value \"%s\" for maximum SSL protocol version", + conn->ssl_max_protocol_version); + SSL_CTX_free(SSL_context); + return -1; + } + + if (!SSL_CTX_set_max_proto_version(SSL_context, ssl_max_ver)) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not set maximum SSL protocol version: %s", err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + } + + /* + * Disable OpenSSL's moving-write-buffer sanity check, because it causes + * unnecessary failures in nonblocking send cases. + */ + SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + /* + * If the root cert file exists, load it so we can perform certificate + * verification. If sslmode is "verify-full" we will also do further + * verification after the connection has been completed. + */ + if (conn->sslrootcert && strlen(conn->sslrootcert) > 0) + strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf)); + else if (have_homedir) + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE); + else + fnbuf[0] = '\0'; + + if (strcmp(fnbuf, "system") == 0) + { + /* + * The "system" sentinel value indicates that we should load whatever + * root certificates are installed for use by OpenSSL; these locations + * differ by platform. Note that the default system locations may be + * further overridden by the SSL_CERT_DIR and SSL_CERT_FILE + * environment variables. + */ + if (SSL_CTX_set_default_verify_paths(SSL_context) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not load system root certificate paths: %s", + err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + have_rootcert = true; + } + else if (fnbuf[0] != '\0' && + stat(fnbuf, &buf) == 0) + { + X509_STORE *cvstore; + + if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not read root certificate file \"%s\": %s", + fnbuf, err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + + if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL) + { + char *fname = NULL; + char *dname = NULL; + + if (conn->sslcrl && strlen(conn->sslcrl) > 0) + fname = conn->sslcrl; + if (conn->sslcrldir && strlen(conn->sslcrldir) > 0) + dname = conn->sslcrldir; + + /* defaults to use the default CRL file */ + if (!fname && !dname && have_homedir) + { + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE); + fname = fnbuf; + } + + /* Set the flags to check against the complete CRL chain */ + if ((fname || dname) && + X509_STORE_load_locations(cvstore, fname, dname) == 1) + { + X509_STORE_set_flags(cvstore, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + } + + /* if not found, silently ignore; we do not require CRL */ + ERR_clear_error(); + } + have_rootcert = true; + } + else + { + /* + * stat() failed; assume root file doesn't exist. If sslmode is + * verify-ca or verify-full, this is an error. Otherwise, continue + * without performing any server cert verification. + */ + if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */ + { + /* + * The only way to reach here with an empty filename is if + * pqGetHomeDirectory failed. That's a sufficiently unusual case + * that it seems worth having a specialized error message for it. + */ + if (fnbuf[0] == '\0') + libpq_append_conn_error(conn, "could not get home directory to locate root certificate file\n" + "Either provide the file, use the system's trusted roots with sslrootcert=system, or change sslmode to disable server certificate verification."); + else + libpq_append_conn_error(conn, "root certificate file \"%s\" does not exist\n" + "Either provide the file, use the system's trusted roots with sslrootcert=system, or change sslmode to disable server certificate verification.", fnbuf); + SSL_CTX_free(SSL_context); + return -1; + } + have_rootcert = false; + } + + /* Read the client certificate file */ + if (conn->sslcert && strlen(conn->sslcert) > 0) + strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf)); + else if (have_homedir) + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE); + else + fnbuf[0] = '\0'; + + if (conn->sslcertmode[0] == 'd') /* disable */ + { + /* don't send a client cert even if we have one */ + have_cert = false; + } + else if (fnbuf[0] == '\0') + { + /* no home directory, proceed without a client cert */ + have_cert = false; + } + else if (stat(fnbuf, &buf) != 0) + { + /* + * If file is not present, just go on without a client cert; server + * might or might not accept the connection. Any other error, + * however, is grounds for complaint. + */ + if (errno != ENOENT && errno != ENOTDIR) + { + libpq_append_conn_error(conn, "could not open certificate file \"%s\": %s", + fnbuf, strerror_r(errno, sebuf, sizeof(sebuf))); + SSL_CTX_free(SSL_context); + return -1; + } + have_cert = false; + } + else + { + /* + * Cert file exists, so load it. Since OpenSSL doesn't provide the + * equivalent of "SSL_use_certificate_chain_file", we have to load it + * into the SSL context, rather than the SSL object. + */ + if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not read certificate file \"%s\": %s", + fnbuf, err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + + /* need to load the associated private key, too */ + have_cert = true; + } + + /* + * The SSL context is now loaded with the correct root and client + * certificates. Create a connection-specific SSL object. The private key + * is loaded directly into the SSL object. (We could load the private key + * into the context, too, but we have done it this way historically, and + * it doesn't really matter.) + */ + if (!(conn->ssl = SSL_new(SSL_context)) || + !SSL_set_app_data(conn->ssl, conn) || + !my_SSL_set_fd(conn, conn->sock)) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not establish SSL connection: %s", err); + SSLerrfree(err); + SSL_CTX_free(SSL_context); + return -1; + } + conn->ssl_in_use = true; + + /* + * SSL contexts are reference counted by OpenSSL. We can free it as soon + * as we have created the SSL object, and it will stick around for as long + * as it's actually needed. + */ + SSL_CTX_free(SSL_context); + SSL_context = NULL; + + /* + * Set Server Name Indication (SNI), if enabled by connection parameters. + * Per RFC 6066, do not set it if the host is a literal IP address (IPv4 + * or IPv6). + */ + if (conn->sslsni && conn->sslsni[0] == '1') + { + const char *host = conn->connhost[conn->whichhost].host; + + if (host && host[0] && + !(strspn(host, "0123456789.") == strlen(host) || + strchr(host, ':'))) + { + if (SSL_set_tlsext_host_name(conn->ssl, host) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not set SSL Server Name Indication (SNI): %s", err); + SSLerrfree(err); + return -1; + } + } + } + + /* + * Read the SSL key. If a key is specified, treat it as an engine:key + * combination if there is colon present - we don't support files with + * colon in the name. The exception is if the second character is a colon, + * in which case it can be a Windows filename with drive specification. + */ + if (have_cert && conn->sslkey && strlen(conn->sslkey) > 0) + { +#ifdef USE_SSL_ENGINE + if (strchr(conn->sslkey, ':') +#ifdef WIN32 + && conn->sslkey[1] != ':' +#endif + ) + { + /* Colon, but not in second character, treat as engine:key */ + char *engine_str = strdup(conn->sslkey); + char *engine_colon; + + if (engine_str == NULL) + { + libpq_append_conn_error(conn, "out of memory"); + return -1; + } + + /* cannot return NULL because we already checked before strdup */ + engine_colon = strchr(engine_str, ':'); + + *engine_colon = '\0'; /* engine_str now has engine name */ + engine_colon++; /* engine_colon now has key name */ + + conn->engine = ENGINE_by_id(engine_str); + if (conn->engine == NULL) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not load SSL engine \"%s\": %s", + engine_str, err); + SSLerrfree(err); + free(engine_str); + return -1; + } + + if (ENGINE_init(conn->engine) == 0) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not initialize SSL engine \"%s\": %s", + engine_str, err); + SSLerrfree(err); + ENGINE_free(conn->engine); + conn->engine = NULL; + free(engine_str); + return -1; + } + + pkey = ENGINE_load_private_key(conn->engine, engine_colon, + NULL, NULL); + if (pkey == NULL) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not read private SSL key \"%s\" from engine \"%s\": %s", + engine_colon, engine_str, err); + SSLerrfree(err); + ENGINE_finish(conn->engine); + ENGINE_free(conn->engine); + conn->engine = NULL; + free(engine_str); + return -1; + } + if (SSL_use_PrivateKey(conn->ssl, pkey) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "could not load private SSL key \"%s\" from engine \"%s\": %s", + engine_colon, engine_str, err); + SSLerrfree(err); + ENGINE_finish(conn->engine); + ENGINE_free(conn->engine); + conn->engine = NULL; + free(engine_str); + return -1; + } + + free(engine_str); + + fnbuf[0] = '\0'; /* indicate we're not going to load from a + * file */ + } + else +#endif /* USE_SSL_ENGINE */ + { + /* PGSSLKEY is not an engine, treat it as a filename */ + strlcpy(fnbuf, conn->sslkey, sizeof(fnbuf)); + } + } + else if (have_homedir) + { + /* No PGSSLKEY specified, load default file */ + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE); + } + else + fnbuf[0] = '\0'; + + if (have_cert && fnbuf[0] != '\0') + { + /* read the client key from file */ + + if (stat(fnbuf, &buf) != 0) + { + if (errno == ENOENT) + libpq_append_conn_error(conn, "certificate present, but not private key file \"%s\"", + fnbuf); + else + libpq_append_conn_error(conn, "could not stat private key file \"%s\": %m", + fnbuf); + return -1; + } + + /* Key file must be a regular file */ + if (!S_ISREG(buf.st_mode)) + { + libpq_append_conn_error(conn, "private key file \"%s\" is not a regular file", + fnbuf); + return -1; + } + + /* + * Refuse to load world-readable key files. We accept root-owned + * files with mode 0640 or less, so that we can access system-wide + * certificates if we have a supplementary group membership that + * allows us to read 'em. For files with non-root ownership, require + * mode 0600 or less. We need not check the file's ownership exactly; + * if we're able to read it despite it having such restrictive + * permissions, it must have the right ownership. + * + * Note: be very careful about tightening these rules. Some people + * expect, for example, that a client process running as root should + * be able to use a non-root-owned key file. + * + * Note that roughly similar checks are performed in + * src/backend/libpq/be-secure-common.c so any changes here may need + * to be made there as well. However, this code caters for the case + * of current user == root, while that code does not. + * + * Ideally we would do similar permissions checks on Windows, but it + * is not clear how that would work since Unix-style permissions may + * not be available. + */ +#if !defined(WIN32) && !defined(__CYGWIN__) + if (buf.st_uid == 0 ? + buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO) : + buf.st_mode & (S_IRWXG | S_IRWXO)) + { + libpq_append_conn_error(conn, + "private key file \"%s\" has group or world access; file must have permissions u=rw (0600) or less if owned by the current user, or permissions u=rw,g=r (0640) or less if owned by root", + fnbuf); + return -1; + } +#endif + + if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + /* + * We'll try to load the file in DER (binary ASN.1) format, and if + * that fails too, report the original error. This could mask + * issues where there's something wrong with a DER-format cert, + * but we'd have to duplicate openssl's format detection to be + * smarter than this. We can't just probe for a leading -----BEGIN + * because PEM can have leading non-matching lines and blanks. + * OpenSSL doesn't expose its get_name(...) and its PEM routines + * don't differentiate between failure modes in enough detail to + * let us tell the difference between "not PEM, try DER" and + * "wrong password". + */ + if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_ASN1) != 1) + { + libpq_append_conn_error(conn, "could not load private key file \"%s\": %s", + fnbuf, err); + SSLerrfree(err); + return -1; + } + + SSLerrfree(err); + } + } + + /* verify that the cert and key go together */ + if (have_cert && + SSL_check_private_key(conn->ssl) != 1) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "certificate does not match private key file \"%s\": %s", + fnbuf, err); + SSLerrfree(err); + return -1; + } + + /* + * If a root cert was loaded, also set our certificate verification + * callback. + */ + if (have_rootcert) + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb); + + /* + * Set compression option if necessary. + */ + if (conn->sslcompression && conn->sslcompression[0] == '0') + SSL_set_options(conn->ssl, SSL_OP_NO_COMPRESSION); + else + SSL_clear_options(conn->ssl, SSL_OP_NO_COMPRESSION); + + return 0; +} + +/* + * Attempt to negotiate SSL connection. + */ +static PostgresPollingStatusType +open_client_SSL(PGconn *conn) +{ + int r; + + SOCK_ERRNO_SET(0); + ERR_clear_error(); + r = SSL_connect(conn->ssl); + if (r <= 0) + { + int save_errno = SOCK_ERRNO; + int err = SSL_get_error(conn->ssl, r); + unsigned long ecode; + + ecode = ERR_get_error(); + switch (err) + { + case SSL_ERROR_WANT_READ: + return PGRES_POLLING_READING; + + case SSL_ERROR_WANT_WRITE: + return PGRES_POLLING_WRITING; + + case SSL_ERROR_SYSCALL: + { + char sebuf[PG_STRERROR_R_BUFLEN]; + unsigned long vcode; + + vcode = SSL_get_verify_result(conn->ssl); + + /* + * If we get an X509 error here for failing to load the + * local issuer cert, without an error in the socket layer + * it means that verification failed due to a missing + * system CA pool without it being a protocol error. We + * inspect the sslrootcert setting to ensure that the user + * was using the system CA pool. For other errors, log + * them using the normal SYSCALL logging. + */ + if (!save_errno && vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY && + strcmp(conn->sslrootcert, "system") == 0) + libpq_append_conn_error(conn, "SSL error: certificate verify failed: %s", + X509_verify_cert_error_string(vcode)); + else if (r == -1) + libpq_append_conn_error(conn, "SSL SYSCALL error: %s", + SOCK_STRERROR(save_errno, sebuf, sizeof(sebuf))); + else + libpq_append_conn_error(conn, "SSL SYSCALL error: EOF detected"); + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + case SSL_ERROR_SSL: + { + char *err = SSLerrmessage(ecode); + + libpq_append_conn_error(conn, "SSL error: %s", err); + SSLerrfree(err); + switch (ERR_GET_REASON(ecode)) + { + /* + * UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and + * TLSV1_ALERT_PROTOCOL_VERSION have been observed + * when trying to communicate with an old OpenSSL + * library, or when the client and server specify + * disjoint protocol ranges. + * NO_PROTOCOLS_AVAILABLE occurs if there's a + * local misconfiguration (which can happen + * despite our checks, if openssl.cnf injects a + * limit we didn't account for). It's not very + * clear what would make OpenSSL return the other + * codes listed here, but a hint about protocol + * versions seems like it's appropriate for all. + */ + case SSL_R_NO_PROTOCOLS_AVAILABLE: + case SSL_R_UNSUPPORTED_PROTOCOL: + case SSL_R_BAD_PROTOCOL_VERSION_NUMBER: + case SSL_R_UNKNOWN_PROTOCOL: + case SSL_R_UNKNOWN_SSL_VERSION: + case SSL_R_UNSUPPORTED_SSL_VERSION: + case SSL_R_WRONG_SSL_VERSION: + case SSL_R_WRONG_VERSION_NUMBER: + case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: +#ifdef SSL_R_VERSION_TOO_HIGH + case SSL_R_VERSION_TOO_HIGH: + case SSL_R_VERSION_TOO_LOW: +#endif + libpq_append_conn_error(conn, "This may indicate that the server does not support any SSL protocol version between %s and %s.", + conn->ssl_min_protocol_version ? + conn->ssl_min_protocol_version : + MIN_OPENSSL_TLS_VERSION, + conn->ssl_max_protocol_version ? + conn->ssl_max_protocol_version : + MAX_OPENSSL_TLS_VERSION); + break; + default: + break; + } + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + + default: + libpq_append_conn_error(conn, "unrecognized SSL error code: %d", err); + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + } + + /* + * We already checked the server certificate in initialize_SSL() using + * SSL_CTX_set_verify(), if root.crt exists. + */ + + /* get server certificate */ + conn->peer = SSL_get_peer_certificate(conn->ssl); + if (conn->peer == NULL) + { + char *err = SSLerrmessage(ERR_get_error()); + + libpq_append_conn_error(conn, "certificate could not be obtained: %s", err); + SSLerrfree(err); + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + + if (!pq_verify_peer_name_matches_certificate(conn)) + { + pgtls_close(conn); + return PGRES_POLLING_FAILED; + } + + /* SSL handshake is complete */ + return PGRES_POLLING_OK; +} + +void +pgtls_close(PGconn *conn) +{ + bool destroy_needed = false; + + if (conn->ssl_in_use) + { + if (conn->ssl) + { + /* + * We can't destroy everything SSL-related here due to the + * possible later calls to OpenSSL routines which may need our + * thread callbacks, so set a flag here and check at the end. + */ + + if (SSL_shutdown(conn->ssl) < 0) { + // Pop an error and ignore it. We might have already printed one + // and SSL_shutdown just yields logic warnings as errors. + ERR_get_error(); + } + SSL_free(conn->ssl); + conn->ssl = NULL; + conn->ssl_in_use = false; + + destroy_needed = true; + } + + if (conn->peer) + { + X509_free(conn->peer); + conn->peer = NULL; + } + +#ifdef USE_SSL_ENGINE + if (conn->engine) + { + ENGINE_finish(conn->engine); + ENGINE_free(conn->engine); + conn->engine = NULL; + } +#endif + } + else + { + /* + * In the non-SSL case, just remove the crypto callbacks if the + * connection has then loaded. This code path has no dependency on + * any pending SSL calls. + */ + if (conn->crypto_loaded) + destroy_needed = true; + } + + /* + * This will remove our crypto locking hooks if this is the last + * connection using libcrypto which means we must wait to call it until + * after all the potential SSL calls have been made, otherwise we can end + * up with a race condition and possible deadlocks. + * + * See comments above destroy_ssl_system(). + */ + if (destroy_needed) + { + destroy_ssl_system(); + conn->crypto_loaded = false; + } +} + + +/* + * Obtain reason string for passed SSL errcode + * + * ERR_get_error() is used by caller to get errcode to pass here. + * + * Some caution is needed here since ERR_reason_error_string will + * return NULL if it doesn't recognize the error code. We don't + * want to return NULL ever. + */ +static char ssl_nomem[] = "out of memory allocating error description"; + +#define SSL_ERR_LEN 128 + +static char * +SSLerrmessage(unsigned long ecode) +{ + const char *errreason; + char *errbuf; + + errbuf = malloc(SSL_ERR_LEN); + if (!errbuf) + return ssl_nomem; + if (ecode == 0) + { + snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported")); + return errbuf; + } + errreason = ERR_reason_error_string(ecode); + if (errreason != NULL) + { + strlcpy(errbuf, errreason, SSL_ERR_LEN); + return errbuf; + } + snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), ecode); + return errbuf; +} + +static void +SSLerrfree(char *buf) +{ + if (buf != ssl_nomem) + free(buf); +} + +/* ------------------------------------------------------------ */ +/* SSL information functions */ +/* ------------------------------------------------------------ */ + +/* + * Return pointer to OpenSSL object. + */ +void * +PQgetssl(PGconn *conn) +{ + if (!conn) + return NULL; + return conn->ssl; +} + +void * +PQsslStruct(PGconn *conn, const char *struct_name) +{ + if (!conn) + return NULL; + if (strcmp(struct_name, "OpenSSL") == 0) + return conn->ssl; + return NULL; +} + +const char *const * +PQsslAttributeNames(PGconn *conn) +{ + static const char *const openssl_attrs[] = { + "library", + "key_bits", + "cipher", + "compression", + "protocol", + NULL + }; + static const char *const empty_attrs[] = {NULL}; + + if (!conn) + { + /* Return attributes of default SSL library */ + return openssl_attrs; + } + + /* No attrs for unencrypted connection */ + if (conn->ssl == NULL) + return empty_attrs; + + return openssl_attrs; +} + +const char * +PQsslAttribute(PGconn *conn, const char *attribute_name) +{ + if (!conn) + { + /* PQsslAttribute(NULL, "library") reports the default SSL library */ + if (strcmp(attribute_name, "library") == 0) + return "OpenSSL"; + return NULL; + } + + /* All attributes read as NULL for a non-encrypted connection */ + if (conn->ssl == NULL) + return NULL; + + if (strcmp(attribute_name, "library") == 0) + return "OpenSSL"; + + if (strcmp(attribute_name, "key_bits") == 0) + { + static char sslbits_str[12]; + int sslbits; + + SSL_get_cipher_bits(conn->ssl, &sslbits); + snprintf(sslbits_str, sizeof(sslbits_str), "%d", sslbits); + return sslbits_str; + } + + if (strcmp(attribute_name, "cipher") == 0) + return SSL_get_cipher(conn->ssl); + + if (strcmp(attribute_name, "compression") == 0) + return SSL_get_current_compression(conn->ssl) ? "on" : "off"; + + if (strcmp(attribute_name, "protocol") == 0) + return SSL_get_version(conn->ssl); + + return NULL; /* unknown attribute */ +} + +/* + * Private substitute BIO: this does the sending and receiving using + * pqsecure_raw_write() and pqsecure_raw_read() instead, to allow those + * functions to disable SIGPIPE and give better error messages on I/O errors. + * + * These functions are closely modelled on the standard socket BIO in OpenSSL; + * see sock_read() and sock_write() in OpenSSL's crypto/bio/bss_sock.c. + * XXX OpenSSL 1.0.1e considers many more errcodes than just EINTR as reasons + * to retry; do we need to adopt their logic for that? + */ + +#ifndef HAVE_BIO_GET_DATA +#define BIO_get_data(bio) (bio->ptr) +#define BIO_set_data(bio, data) (bio->ptr = data) +#endif + +static BIO_METHOD *my_bio_methods; + +static int +my_sock_read(BIO *h, char *buf, int size) +{ + int res; + + res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size); + BIO_clear_retry_flags(h); + if (res < 0) + { + /* If we were interrupted, tell caller to retry */ + switch (SOCK_ERRNO) + { +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif + case EINTR: + BIO_set_retry_read(h); + break; + + default: + break; + } + } + + return res; +} + +static int +my_sock_write(BIO *h, const char *buf, int size) +{ + int res; + + res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size); + BIO_clear_retry_flags(h); + if (res < 0) + { + /* If we were interrupted, tell caller to retry */ + switch (SOCK_ERRNO) + { +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif + case EINTR: + BIO_set_retry_write(h); + break; + + default: + break; + } + } + + return res; +} + +static BIO_METHOD * +my_BIO_s_socket(void) +{ + if (!my_bio_methods) + { + BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); +#ifdef HAVE_BIO_METH_NEW + int my_bio_index; + + my_bio_index = BIO_get_new_index(); + if (my_bio_index == -1) + return NULL; + my_bio_index |= (BIO_TYPE_DESCRIPTOR | BIO_TYPE_SOURCE_SINK); + my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket"); + if (!my_bio_methods) + return NULL; + + /* + * As of this writing, these functions never fail. But check anyway, + * like OpenSSL's own examples do. + */ + if (!BIO_meth_set_write(my_bio_methods, my_sock_write) || + !BIO_meth_set_read(my_bio_methods, my_sock_read) || + !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) || + !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) || + !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) || + !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) || + !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) || + !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom))) + { + BIO_meth_free(my_bio_methods); + my_bio_methods = NULL; + return NULL; + } +#else + my_bio_methods = malloc(sizeof(BIO_METHOD)); + if (!my_bio_methods) + return NULL; + memcpy(my_bio_methods, biom, sizeof(BIO_METHOD)); + my_bio_methods->bread = my_sock_read; + my_bio_methods->bwrite = my_sock_write; +#endif + } + return my_bio_methods; +} + +/* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */ +static int +my_SSL_set_fd(PGconn *conn, int fd) +{ + int ret = 0; + BIO *bio; + BIO_METHOD *bio_method; + + bio_method = my_BIO_s_socket(); + if (bio_method == NULL) + { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + bio = BIO_new(bio_method); + if (bio == NULL) + { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + BIO_set_data(bio, conn); + + SSL_set_bio(conn->ssl, bio, bio); + BIO_set_fd(bio, fd, BIO_NOCLOSE); + ret = 1; +err: + return ret; +} + +/* + * This is the default handler to return a client cert password from + * conn->sslpassword. Apps may install it explicitly if they want to + * prevent openssl from ever prompting on stdin. + */ +int +PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn) +{ + if (conn && conn->sslpassword) + { + if (strlen(conn->sslpassword) + 1 > size) + fprintf(stderr, libpq_gettext("WARNING: sslpassword truncated\n")); + strncpy(buf, conn->sslpassword, size); + buf[size - 1] = '\0'; + return strlen(buf); + } + else + { + buf[0] = '\0'; + return 0; + } +} + +PQsslKeyPassHook_OpenSSL_type +PQgetSSLKeyPassHook_OpenSSL(void) +{ + return PQsslKeyPassHook; +} + +void +PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook) +{ + PQsslKeyPassHook = hook; +} + +/* + * Supply a password to decrypt a client certificate. + * + * This must match OpenSSL type pem_password_cb. + */ +static int +PQssl_passwd_cb(char *buf, int size, int rwflag, void *userdata) +{ + PGconn *conn = userdata; + + if (PQsslKeyPassHook) + return PQsslKeyPassHook(buf, size, conn); + else + return PQdefaultSSLKeyPassHook_OpenSSL(buf, size, conn); +} + +/* + * Convert TLS protocol version string to OpenSSL values + * + * If a version is passed that is not supported by the current OpenSSL version, + * then we return -1. If a non-negative value is returned, subsequent code can + * assume it is working with a supported version. + * + * Note: this is rather similar to the backend routine in be-secure-openssl.c, + * so make sure to update both routines if changing this one. + */ +static int +ssl_protocol_version_to_openssl(const char *protocol) +{ + if (pg_strcasecmp("TLSv1", protocol) == 0) + return TLS1_VERSION; + +#ifdef TLS1_1_VERSION + if (pg_strcasecmp("TLSv1.1", protocol) == 0) + return TLS1_1_VERSION; +#endif + +#ifdef TLS1_2_VERSION + if (pg_strcasecmp("TLSv1.2", protocol) == 0) + return TLS1_2_VERSION; +#endif + +#ifdef TLS1_3_VERSION + if (pg_strcasecmp("TLSv1.3", protocol) == 0) + return TLS1_3_VERSION; +#endif + + return -1; +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c b/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c new file mode 100644 index 0000000000..8069e38142 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-secure.c @@ -0,0 +1,611 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/interfaces/libpq/fe-secure.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <signal.h> +#include <fcntl.h> +#include <ctype.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <sys/socket.h> +#include <unistd.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#endif + +#include <sys/stat.h> + +#ifdef ENABLE_THREAD_SAFETY +#ifdef WIN32 +#include "pthread-win32.h" +#else +#include <pthread.h> +#endif +#endif + +#include "fe-auth.h" +#include "libpq-fe.h" +#include "libpq-int.h" + +/* + * 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 */ +/* ------------------------------------------------------------ */ + + +int +PQsslInUse(PGconn *conn) +{ + if (!conn) + return 0; + return conn->ssl_in_use; +} + +/* + * 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, bool do_ssl, bool do_crypto) +{ + int r = 0; + +#ifdef USE_SSL + r = pgtls_init(conn, do_ssl, do_crypto); +#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 + pgtls_close(conn); +#endif +} + +/* + * Read data from a secure connection. + * + * On failure, this function is responsible for appending a suitable message + * to 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 +#ifdef ENABLE_GSS + if (conn->gssenc) + { + n = pg_GSS_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[PG_STRERROR_R_BUFLEN]; + + 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; + + case EPIPE: + case ECONNRESET: + libpq_append_conn_error(conn, "server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request."); + break; + + default: + libpq_append_conn_error(conn, "could not receive data from server: %s", + 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. + * + * Returns the number of bytes written, or a negative value (with errno + * set) upon failure. The write count could be less than requested. + * + * Note that socket-level hard failures are masked from the caller, + * instead setting conn->write_failed and storing an error message + * in conn->write_err_msg; see pqsecure_raw_write. This allows us to + * postpone reporting of write failures until we're sure no error + * message is available from the server. + * + * However, errors detected in the SSL or GSS management level are reported + * via a negative result, with message appended to conn->errorMessage. + * It's frequently unclear whether such errors should be considered read or + * write errors, so we don't attempt to postpone reporting them. + * + * The caller must still inspect errno upon failure, but only to determine + * whether to continue/retry; a message has been saved someplace in any case. + */ +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 +#ifdef ENABLE_GSS + if (conn->gssenc) + { + n = pg_GSS_write(conn, ptr, len); + } + else +#endif + { + n = pqsecure_raw_write(conn, ptr, len); + } + + return n; +} + +/* + * Low-level implementation of pqsecure_write. + * + * This is used directly for an unencrypted connection. For encrypted + * connections, this does the physical I/O on behalf of pgtls_write or + * pg_GSS_write. + * + * This function reports failure (i.e., returns a negative result) only + * for retryable errors such as EINTR. Looping for such cases is to be + * handled at some outer level, maybe all the way up to the application. + * For hard failures, we set conn->write_failed and store an error message + * in conn->write_err_msg, but then claim to have written the data anyway. + * This is because we don't want to report write failures so long as there + * is a possibility of reading from the server and getting an error message + * that could explain why the connection dropped. Many TCP stacks have + * race conditions such that a write failure may or may not be reported + * before all incoming data has been read. + * + * Note that this error behavior happens below the SSL management level when + * we are using SSL. That's because at least some versions of OpenSSL are + * too quick to report a write failure when there's still a possibility to + * get a more useful error from the server. + */ +ssize_t +pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len) +{ + ssize_t n; + int flags = 0; + int result_errno = 0; + char msgbuf[1024]; + char sebuf[PG_STRERROR_R_BUFLEN]; + + DECLARE_SIGPIPE_INFO(spinfo); + + /* + * If we already had a write failure, we will never again try to send data + * on that connection. Even if the kernel would let us, we've probably + * lost message boundary sync with the server. conn->write_failed + * therefore persists until the connection is reset, and we just discard + * all data presented to be written. + */ + if (conn->write_failed) + return len; + +#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 */ + + case ECONNRESET: + conn->write_failed = true; + /* Store error message in conn->write_err_msg, if possible */ + /* (strdup failure is OK, we'll cope later) */ + snprintf(msgbuf, sizeof(msgbuf), + libpq_gettext("server closed the connection unexpectedly\n" + "\tThis probably means the server terminated abnormally\n" + "\tbefore or while processing the request.")); + /* keep newline out of translated string */ + strlcat(msgbuf, "\n", sizeof(msgbuf)); + conn->write_err_msg = strdup(msgbuf); + /* Now claim the write succeeded */ + n = len; + break; + + default: + conn->write_failed = true; + /* Store error message in conn->write_err_msg, if possible */ + /* (strdup failure is OK, we'll cope later) */ + snprintf(msgbuf, sizeof(msgbuf), + libpq_gettext("could not send data to server: %s"), + SOCK_STRERROR(result_errno, + sebuf, sizeof(sebuf))); + /* keep newline out of translated string */ + strlcat(msgbuf, "\n", sizeof(msgbuf)); + conn->write_err_msg = strdup(msgbuf); + /* Now claim the write succeeded */ + n = len; + 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 + +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 */ + +/* + * Dummy versions of OpenSSL key password hook functions, when built without + * OpenSSL. + */ +#ifndef USE_OPENSSL + +PQsslKeyPassHook_OpenSSL_type +PQgetSSLKeyPassHook_OpenSSL(void) +{ + return NULL; +} + +void +PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook) +{ + return; +} + +int +PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn) +{ + return 0; +} +#endif /* USE_OPENSSL */ + +/* Dummy version of GSSAPI information functions, when built without GSS support */ +#ifndef ENABLE_GSS + +void * +PQgetgssctx(PGconn *conn) +{ + return NULL; +} + +int +PQgssEncInUse(PGconn *conn) +{ + return 0; +} + +#endif /* ENABLE_GSS */ + + +#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/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c b/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c new file mode 100644 index 0000000000..402784f40e --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/fe-trace.c @@ -0,0 +1,729 @@ +/*------------------------------------------------------------------------- + * + * fe-trace.c + * functions for libpq protocol tracing + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/interfaces/libpq/fe-trace.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <ctype.h> +#include <limits.h> +#include <sys/time.h> +#include <time.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "port/pg_bswap.h" + + +/* Enable tracing */ +void +PQtrace(PGconn *conn, FILE *debug_port) +{ + if (conn == NULL) + return; + PQuntrace(conn); + if (debug_port == NULL) + return; + + conn->Pfdebug = debug_port; + conn->traceFlags = 0; +} + +/* Disable tracing */ +void +PQuntrace(PGconn *conn) +{ + if (conn == NULL) + return; + if (conn->Pfdebug) + { + fflush(conn->Pfdebug); + conn->Pfdebug = NULL; + } + + conn->traceFlags = 0; +} + +/* Set flags for current tracing session */ +void +PQsetTraceFlags(PGconn *conn, int flags) +{ + if (conn == NULL) + return; + /* If PQtrace() failed, do nothing. */ + if (conn->Pfdebug == NULL) + return; + conn->traceFlags = flags; +} + +/* + * Print the current time, with microseconds, into a caller-supplied + * buffer. + * Cribbed from get_formatted_log_time, but much simpler. + */ +static void +pqTraceFormatTimestamp(char *timestr, size_t ts_len) +{ + struct timeval tval; + time_t now; + + gettimeofday(&tval, NULL); + + /* + * MSVC's implementation of timeval uses a long for tv_sec, however, + * localtime() expects a time_t pointer. Here we'll assign tv_sec to a + * local time_t variable so that we pass localtime() the correct pointer + * type. + */ + now = tval.tv_sec; + strftime(timestr, ts_len, + "%Y-%m-%d %H:%M:%S", + localtime(&now)); + /* append microseconds */ + snprintf(timestr + strlen(timestr), ts_len - strlen(timestr), + ".%06u", (unsigned int) (tval.tv_usec)); +} + +/* + * pqTraceOutputByte1: output a 1-char message to the log + */ +static void +pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) +{ + const char *v = data + *cursor; + + /* + * Show non-printable data in hex format, including the terminating \0 + * that completes ErrorResponse and NoticeResponse messages. + */ + if (!isprint((unsigned char) *v)) + fprintf(pfdebug, " \\x%02x", *v); + else + fprintf(pfdebug, " %c", *v); + *cursor += 1; +} + +/* + * pqTraceOutputInt16: output a 2-byte integer message to the log + */ +static int +pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor) +{ + uint16 tmp; + int result; + + memcpy(&tmp, data + *cursor, 2); + *cursor += 2; + result = (int) pg_ntoh16(tmp); + fprintf(pfdebug, " %d", result); + + return result; +} + +/* + * pqTraceOutputInt32: output a 4-byte integer message to the log + * + * If 'suppress' is true, print a literal NNNN instead of the actual number. + */ +static int +pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress) +{ + int result; + + memcpy(&result, data + *cursor, 4); + *cursor += 4; + result = (int) pg_ntoh32(result); + if (suppress) + fprintf(pfdebug, " NNNN"); + else + fprintf(pfdebug, " %d", result); + + return result; +} + +/* + * pqTraceOutputString: output a string message to the log + */ +static void +pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress) +{ + int len; + + if (suppress) + { + fprintf(pfdebug, " \"SSSS\""); + *cursor += strlen(data + *cursor) + 1; + } + else + { + len = fprintf(pfdebug, " \"%s\"", data + *cursor); + + /* + * This is a null-terminated string. So add 1 after subtracting 3 + * which is the double quotes and space length from len. + */ + *cursor += (len - 3 + 1); + } +} + +/* + * pqTraceOutputNchar: output a string of exactly len bytes message to the log + */ +static void +pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor) +{ + int i, + next; /* first char not yet printed */ + const char *v = data + *cursor; + + fprintf(pfdebug, " \'"); + + for (next = i = 0; i < len; ++i) + { + if (isprint((unsigned char) v[i])) + continue; + else + { + fwrite(v + next, 1, i - next, pfdebug); + fprintf(pfdebug, "\\x%02x", v[i]); + next = i + 1; + } + } + if (next < len) + fwrite(v + next, 1, len - next, pfdebug); + + fprintf(pfdebug, "\'"); + *cursor += len; +} + +/* + * Output functions by protocol message type + */ + +/* NotificationResponse */ +static void +pqTraceOutputA(FILE *f, const char *message, int *cursor, bool regress) +{ + fprintf(f, "NotificationResponse\t"); + pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(f, message, cursor, false); +} + +/* Bind */ +static void +pqTraceOutputB(FILE *f, const char *message, int *cursor) +{ + int nparams; + + fprintf(f, "Bind\t"); + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(f, message, cursor, false); + nparams = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nparams; i++) + pqTraceOutputInt16(f, message, cursor); + + nparams = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nparams; i++) + { + int nbytes; + + nbytes = pqTraceOutputInt32(f, message, cursor, false); + if (nbytes == -1) + continue; + pqTraceOutputNchar(f, nbytes, message, cursor); + } + + nparams = pqTraceOutputInt16(f, message, cursor); + for (int i = 0; i < nparams; i++) + pqTraceOutputInt16(f, message, cursor); +} + +/* Close(F) or CommandComplete(B) */ +static void +pqTraceOutputC(FILE *f, bool toServer, const char *message, int *cursor) +{ + if (toServer) + { + fprintf(f, "Close\t"); + pqTraceOutputByte1(f, message, cursor); + pqTraceOutputString(f, message, cursor, false); + } + else + { + fprintf(f, "CommandComplete\t"); + pqTraceOutputString(f, message, cursor, false); + } +} + +/* Describe(F) or DataRow(B) */ +static void +pqTraceOutputD(FILE *f, bool toServer, const char *message, int *cursor) +{ + if (toServer) + { + fprintf(f, "Describe\t"); + pqTraceOutputByte1(f, message, cursor); + pqTraceOutputString(f, message, cursor, false); + } + else + { + int nfields; + int len; + int i; + + fprintf(f, "DataRow\t"); + nfields = pqTraceOutputInt16(f, message, cursor); + for (i = 0; i < nfields; i++) + { + len = pqTraceOutputInt32(f, message, cursor, false); + if (len == -1) + continue; + pqTraceOutputNchar(f, len, message, cursor); + } + } +} + +/* NoticeResponse / ErrorResponse */ +static void +pqTraceOutputNR(FILE *f, const char *type, const char *message, int *cursor, + bool regress) +{ + fprintf(f, "%s\t", type); + for (;;) + { + char field; + bool suppress; + + pqTraceOutputByte1(f, message, cursor); + field = message[*cursor - 1]; + if (field == '\0') + break; + + suppress = regress && (field == 'L' || field == 'F' || field == 'R'); + pqTraceOutputString(f, message, cursor, suppress); + } +} + +/* Execute(F) or ErrorResponse(B) */ +static void +pqTraceOutputE(FILE *f, bool toServer, const char *message, int *cursor, bool regress) +{ + if (toServer) + { + fprintf(f, "Execute\t"); + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputInt32(f, message, cursor, false); + } + else + pqTraceOutputNR(f, "ErrorResponse", message, cursor, regress); +} + +/* CopyFail */ +static void +pqTraceOutputf(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "CopyFail\t"); + pqTraceOutputString(f, message, cursor, false); +} + +/* FunctionCall */ +static void +pqTraceOutputF(FILE *f, const char *message, int *cursor, bool regress) +{ + int nfields; + int nbytes; + + fprintf(f, "FunctionCall\t"); + pqTraceOutputInt32(f, message, cursor, regress); + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); + + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + { + nbytes = pqTraceOutputInt32(f, message, cursor, false); + if (nbytes == -1) + continue; + pqTraceOutputNchar(f, nbytes, message, cursor); + } + + pqTraceOutputInt16(f, message, cursor); +} + +/* CopyInResponse */ +static void +pqTraceOutputG(FILE *f, const char *message, int *cursor) +{ + int nfields; + + fprintf(f, "CopyInResponse\t"); + pqTraceOutputByte1(f, message, cursor); + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); +} + +/* CopyOutResponse */ +static void +pqTraceOutputH(FILE *f, const char *message, int *cursor) +{ + int nfields; + + fprintf(f, "CopyOutResponse\t"); + pqTraceOutputByte1(f, message, cursor); + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); +} + +/* BackendKeyData */ +static void +pqTraceOutputK(FILE *f, const char *message, int *cursor, bool regress) +{ + fprintf(f, "BackendKeyData\t"); + pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputInt32(f, message, cursor, regress); +} + +/* Parse */ +static void +pqTraceOutputP(FILE *f, const char *message, int *cursor, bool regress) +{ + int nparams; + + fprintf(f, "Parse\t"); + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(f, message, cursor, false); + nparams = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nparams; i++) + pqTraceOutputInt32(f, message, cursor, regress); +} + +/* Query */ +static void +pqTraceOutputQ(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "Query\t"); + pqTraceOutputString(f, message, cursor, false); +} + +/* Authentication */ +static void +pqTraceOutputR(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "Authentication\t"); + pqTraceOutputInt32(f, message, cursor, false); +} + +/* ParameterStatus */ +static void +pqTraceOutputS(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "ParameterStatus\t"); + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(f, message, cursor, false); +} + +/* ParameterDescription */ +static void +pqTraceOutputt(FILE *f, const char *message, int *cursor, bool regress) +{ + int nfields; + + fprintf(f, "ParameterDescription\t"); + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + pqTraceOutputInt32(f, message, cursor, regress); +} + +/* RowDescription */ +static void +pqTraceOutputT(FILE *f, const char *message, int *cursor, bool regress) +{ + int nfields; + + fprintf(f, "RowDescription\t"); + nfields = pqTraceOutputInt16(f, message, cursor); + + for (int i = 0; i < nfields; i++) + { + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt32(f, message, cursor, false); + pqTraceOutputInt16(f, message, cursor); + } +} + +/* NegotiateProtocolVersion */ +static void +pqTraceOutputv(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "NegotiateProtocolVersion\t"); + pqTraceOutputInt32(f, message, cursor, false); + pqTraceOutputInt32(f, message, cursor, false); +} + +/* FunctionCallResponse */ +static void +pqTraceOutputV(FILE *f, const char *message, int *cursor) +{ + int len; + + fprintf(f, "FunctionCallResponse\t"); + len = pqTraceOutputInt32(f, message, cursor, false); + if (len != -1) + pqTraceOutputNchar(f, len, message, cursor); +} + +/* CopyBothResponse */ +static void +pqTraceOutputW(FILE *f, const char *message, int *cursor, int length) +{ + fprintf(f, "CopyBothResponse\t"); + pqTraceOutputByte1(f, message, cursor); + + while (length > *cursor) + pqTraceOutputInt16(f, message, cursor); +} + +/* ReadyForQuery */ +static void +pqTraceOutputZ(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "ReadyForQuery\t"); + pqTraceOutputByte1(f, message, cursor); +} + +/* + * Print the given message to the trace output stream. + */ +void +pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) +{ + char id; + int length; + char *prefix = toServer ? "F" : "B"; + int logCursor = 0; + bool regress; + + if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) + { + char timestr[128]; + + pqTraceFormatTimestamp(timestr, sizeof(timestr)); + fprintf(conn->Pfdebug, "%s\t", timestr); + } + regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0; + + id = message[logCursor++]; + + memcpy(&length, message + logCursor, 4); + length = (int) pg_ntoh32(length); + logCursor += 4; + + /* + * In regress mode, suppress the length of ErrorResponse and + * NoticeResponse. The F (file name), L (line number) and R (routine + * name) fields can change as server code is modified, and if their + * lengths differ from the originals, that would break tests. + */ + if (regress && !toServer && (id == 'E' || id == 'N')) + fprintf(conn->Pfdebug, "%s\tNN\t", prefix); + else + fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length); + + switch (id) + { + case '1': + fprintf(conn->Pfdebug, "ParseComplete"); + /* No message content */ + break; + case '2': + fprintf(conn->Pfdebug, "BindComplete"); + /* No message content */ + break; + case '3': + fprintf(conn->Pfdebug, "CloseComplete"); + /* No message content */ + break; + case 'A': /* Notification Response */ + pqTraceOutputA(conn->Pfdebug, message, &logCursor, regress); + break; + case 'B': /* Bind */ + pqTraceOutputB(conn->Pfdebug, message, &logCursor); + break; + case 'c': + fprintf(conn->Pfdebug, "CopyDone"); + /* No message content */ + break; + case 'C': /* Close(F) or Command Complete(B) */ + pqTraceOutputC(conn->Pfdebug, toServer, message, &logCursor); + break; + case 'd': /* Copy Data */ + /* Drop COPY data to reduce the overhead of logging. */ + break; + case 'D': /* Describe(F) or Data Row(B) */ + pqTraceOutputD(conn->Pfdebug, toServer, message, &logCursor); + break; + case 'E': /* Execute(F) or Error Response(B) */ + pqTraceOutputE(conn->Pfdebug, toServer, message, &logCursor, + regress); + break; + case 'f': /* Copy Fail */ + pqTraceOutputf(conn->Pfdebug, message, &logCursor); + break; + case 'F': /* Function Call */ + pqTraceOutputF(conn->Pfdebug, message, &logCursor, regress); + break; + case 'G': /* Start Copy In */ + pqTraceOutputG(conn->Pfdebug, message, &logCursor); + break; + case 'H': /* Flush(F) or Start Copy Out(B) */ + if (!toServer) + pqTraceOutputH(conn->Pfdebug, message, &logCursor); + else + fprintf(conn->Pfdebug, "Flush"); /* no message content */ + break; + case 'I': + fprintf(conn->Pfdebug, "EmptyQueryResponse"); + /* No message content */ + break; + case 'K': /* secret key data from the backend */ + pqTraceOutputK(conn->Pfdebug, message, &logCursor, regress); + break; + case 'n': + fprintf(conn->Pfdebug, "NoData"); + /* No message content */ + break; + case 'N': + pqTraceOutputNR(conn->Pfdebug, "NoticeResponse", message, + &logCursor, regress); + break; + case 'P': /* Parse */ + pqTraceOutputP(conn->Pfdebug, message, &logCursor, regress); + break; + case 'Q': /* Query */ + pqTraceOutputQ(conn->Pfdebug, message, &logCursor); + break; + case 'R': /* Authentication */ + pqTraceOutputR(conn->Pfdebug, message, &logCursor); + break; + case 's': + fprintf(conn->Pfdebug, "PortalSuspended"); + /* No message content */ + break; + case 'S': /* Parameter Status(B) or Sync(F) */ + if (!toServer) + pqTraceOutputS(conn->Pfdebug, message, &logCursor); + else + fprintf(conn->Pfdebug, "Sync"); /* no message content */ + break; + case 't': /* Parameter Description */ + pqTraceOutputt(conn->Pfdebug, message, &logCursor, regress); + break; + case 'T': /* Row Description */ + pqTraceOutputT(conn->Pfdebug, message, &logCursor, regress); + break; + case 'v': /* Negotiate Protocol Version */ + pqTraceOutputv(conn->Pfdebug, message, &logCursor); + break; + case 'V': /* Function Call response */ + pqTraceOutputV(conn->Pfdebug, message, &logCursor); + break; + case 'W': /* Start Copy Both */ + pqTraceOutputW(conn->Pfdebug, message, &logCursor, length); + break; + case 'X': + fprintf(conn->Pfdebug, "Terminate"); + /* No message content */ + break; + case 'Z': /* Ready For Query */ + pqTraceOutputZ(conn->Pfdebug, message, &logCursor); + break; + default: + fprintf(conn->Pfdebug, "Unknown message: %02x", id); + break; + } + + fputc('\n', conn->Pfdebug); + + /* + * Verify the printing routine did it right. Note that the one-byte + * message identifier is not included in the length, but our cursor does + * include it. + */ + if (logCursor - 1 != length) + fprintf(conn->Pfdebug, + "mismatched message length: consumed %d, expected %d\n", + logCursor - 1, length); +} + +/* + * Print special messages (those containing no type byte) to the trace output + * stream. + */ +void +pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) +{ + int length; + int logCursor = 0; + + if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) + { + char timestr[128]; + + pqTraceFormatTimestamp(timestr, sizeof(timestr)); + fprintf(conn->Pfdebug, "%s\t", timestr); + } + + memcpy(&length, message + logCursor, 4); + length = (int) pg_ntoh32(length); + logCursor += 4; + + fprintf(conn->Pfdebug, "F\t%d\t", length); + + switch (length) + { + case 16: /* CancelRequest */ + fprintf(conn->Pfdebug, "CancelRequest\t"); + pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false); + pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false); + pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false); + break; + case 8: /* GSSENCRequest or SSLRequest */ + /* These messages do not reach here. */ + default: + fprintf(conn->Pfdebug, "Unknown message: length is %d", length); + break; + } + + fputc('\n', conn->Pfdebug); +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c b/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c new file mode 100644 index 0000000000..229bed910f --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/libpq-events.c @@ -0,0 +1,211 @@ +/*------------------------------------------------------------------------- + * + * libpq-events.c + * functions for supporting the libpq "events" API + * + * Portions Copyright (c) 1996-2023, 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 result = true; + int i; + + if (!res) + return false; + + for (i = 0; i < res->nEvents; i++) + { + /* It's possible event was already fired, if so don't repeat it */ + 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)) + res->events[i].resultInitialized = true; + else + result = false; + } + } + + return result; +} diff --git a/contrib/libs/libpq/src/interfaces/libpq/libpq-events.h b/contrib/libs/libpq/src/interfaces/libpq/libpq-events.h new file mode 100644 index 0000000000..b9d5137634 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/libpq-events.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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/contrib/libs/libpq/src/interfaces/libpq/libpq-fe.h b/contrib/libs/libpq/src/interfaces/libpq/libpq-fe.h new file mode 100644 index 0000000000..7476dbe0e9 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/libpq-fe.h @@ -0,0 +1,675 @@ +/*------------------------------------------------------------------------- + * + * libpq-fe.h + * This file contains definitions for structures and + * externs for functions used by frontend postgres applications. + * + * Portions Copyright (c) 1996-2023, 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 <stdio.h> + +/* + * postgres_ext.h defines the backend's externally visible types, + * such as Oid. + */ +#include "postgres_ext.h" + +/* + * These symbols may be used in compile-time #ifdef tests for the availability + * of newer libpq features. + */ +/* Indicates presence of PQenterPipelineMode and friends */ +#define LIBPQ_HAS_PIPELINING 1 +/* Indicates presence of PQsetTraceFlags; also new PQtrace output format */ +#define LIBPQ_HAS_TRACE_FLAGS 1 +/* Indicates that PQsslAttribute(NULL, "library") is useful */ +#define LIBPQ_HAS_SSL_LIBRARY_DETECTION 1 + +/* + * 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, /* This state is no longer used. */ + CONNECTION_SSL_STARTUP, /* Negotiating SSL. */ + CONNECTION_NEEDED, /* Internal state: connect() needed */ + CONNECTION_CHECK_WRITABLE, /* Checking if session is read-write. */ + CONNECTION_CONSUME, /* Consuming any extra messages. */ + CONNECTION_GSS_STARTUP, /* Negotiating GSSAPI. */ + CONNECTION_CHECK_TARGET, /* Checking target server properties. */ + CONNECTION_CHECK_STANDBY /* Checking if server is in standby mode. */ +} 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 */ + PGRES_PIPELINE_SYNC, /* pipeline synchronization point */ + PGRES_PIPELINE_ABORTED /* Command didn't run because of an abort + * earlier in a pipeline */ +} 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 */ + PQERRORS_SQLSTATE /* only error severity and SQLSTATE code */ +} 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; + +/* + * PGpipelineStatus - Current status of pipeline mode + */ +typedef enum +{ + PQ_PIPELINE_OFF, + PQ_PIPELINE_ON, + PQ_PIPELINE_ABORTED +} PGpipelineStatus; + +/* 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 <table ...> */ + char *caption; /* HTML <caption> */ + 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 reestablish 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 *PQhostaddr(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 PGpipelineStatus PQpipelineStatus(const PGconn *conn); +extern int PQconnectionNeedsPassword(const PGconn *conn); +extern int PQconnectionUsedPassword(const PGconn *conn); +extern int PQconnectionUsedGSSAPI(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); + +/* Return true if GSSAPI encryption is in use */ +extern int PQgssEncInUse(PGconn *conn); + +/* Returns GSSAPI context if GSSAPI is in use */ +extern void *PQgetgssctx(PGconn *conn); + +/* 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); + +/* 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-trace.c === */ +extern void PQtrace(PGconn *conn, FILE *debug_port); +extern void PQuntrace(PGconn *conn); + +/* flags controlling trace output: */ +/* omit timestamps from each line */ +#define PQTRACE_SUPPRESS_TIMESTAMPS (1<<0) +/* redact portions of some messages, for testing frameworks */ +#define PQTRACE_REGRESS_MODE (1<<1) +extern void PQsetTraceFlags(PGconn *conn, int flags); + +/* === 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 */ +#define PQ_QUERY_PARAM_MAX_LIMIT 65535 + +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); + +/* Routines for pipeline mode management */ +extern int PQenterPipelineMode(PGconn *conn); +extern int PQexitPipelineMode(PGconn *conn); +extern int PQpipelineSync(PGconn *conn); +extern int PQsendFlushRequest(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 *buffer, 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 size_t PQresultMemorySize(const PGresult *res); +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 *po); /* 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 PrintAttNames, /* print attribute names */ + int TerseOutput, /* delimiter bars */ + int colWidth); /* 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); + +/* Same, but not more than the distance to the end of string s */ +extern int PQmblenBounded(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); +extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm); + +/* === 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); + +/* === in fe-secure-openssl.c === */ + +/* Support for overriding sslpassword handling with a callback */ +typedef int (*PQsslKeyPassHook_OpenSSL_type) (char *buf, int size, PGconn *conn); +extern PQsslKeyPassHook_OpenSSL_type PQgetSSLKeyPassHook_OpenSSL(void); +extern void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook); +extern int PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBPQ_FE_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/libpq-int.h b/contrib/libs/libpq/src/interfaces/libpq/libpq-int.h new file mode 100644 index 0000000000..0045f83cbf --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/libpq-int.h @@ -0,0 +1,939 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 "libpq-events.h" + +#include <netdb.h> +#include <sys/socket.h> +#include <time.h> +/* MinGW has sys/time.h, but MSVC doesn't */ +#ifndef _MSC_VER +#include <sys/time.h> +#endif + +#ifdef ENABLE_THREAD_SAFETY +#ifdef WIN32 +#include "pthread-win32.h" +#else +#include <pthread.h> +#endif +#include <signal.h> +#endif + +/* include stuff common to fe and be */ +#include "libpq/pqcomm.h" +/* include stuff found in fe only */ +#include "fe-auth-sasl.h" +#include "pqexpbuffer.h" + +#ifdef ENABLE_GSS +#if defined(HAVE_GSSAPI_H) +#include <gssapi.h> +#else +#include <gssapi/gssapi.h> +#endif +#endif + +#ifdef ENABLE_SSPI +#define SECURITY_WIN32 +#if defined(WIN32) && !defined(_MSC_VER) +#include <ntsecapi.h> +#endif +#include <security.h> +#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 <openssl/ssl.h> +#include <openssl/err.h> + +#ifndef OPENSSL_NO_ENGINE +#define USE_SSL_ENGINE +#endif +#endif /* USE_OPENSSL */ + +#include "common/pg_prng.h" + +/* + * 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 PGresult tuple 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 */ + + size_t memorySize; /* total space allocated for this PGresult */ +}; + +/* 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, /* query done, waiting for client to fetch + * result */ + PGASYNC_READY_MORE, /* query done, waiting for client to fetch + * result, more results expected from this + * query */ + 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 */ + PGASYNC_PIPELINE_IDLE, /* "Idle" between commands in pipeline mode */ +} PGAsyncStatusType; + +/* Target server type (decoded value of target_session_attrs) */ +typedef enum +{ + SERVER_TYPE_ANY = 0, /* Any server (default) */ + SERVER_TYPE_READ_WRITE, /* Read-write server */ + SERVER_TYPE_READ_ONLY, /* Read-only server */ + SERVER_TYPE_PRIMARY, /* Primary server */ + SERVER_TYPE_STANDBY, /* Standby server */ + SERVER_TYPE_PREFER_STANDBY, /* Prefer standby server */ + SERVER_TYPE_PREFER_STANDBY_PASS2 /* second pass - behaves same as ANY */ +} PGTargetServerType; + +/* Target server type (decoded value of load_balance_hosts) */ +typedef enum +{ + LOAD_BALANCE_DISABLE = 0, /* Use the existing host order (default) */ + LOAD_BALANCE_RANDOM, /* Randomly shuffle the hosts */ +} PGLoadBalanceType; + +/* Boolean value plus a not-known state, for GUCs we might have to fetch */ +typedef enum +{ + PG_BOOL_UNKNOWN = 0, /* Currently unknown */ + PG_BOOL_YES, /* Yes (true) */ + PG_BOOL_NO /* No (false) */ +} PGTernaryBool; + +/* 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; + +/* Host address type enum for struct pg_conn_host */ +typedef enum pg_conn_host_type +{ + CHT_HOST_NAME, + CHT_HOST_ADDRESS, + CHT_UNIX_SOCKET +} pg_conn_host_type; + +/* + * PGQueryClass tracks which query protocol is in use for each command queue + * entry, or special operation in execution + */ +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 */ + PGQUERY_SYNC, /* Sync (at end of a pipeline) */ + PGQUERY_CLOSE +} PGQueryClass; + +/* + * An entry in the pending command queue. + */ +typedef struct PGcmdQueueEntry +{ + PGQueryClass queryclass; /* Query type */ + char *query; /* SQL command, or NULL if none/unknown/OOM */ + struct PGcmdQueueEntry *next; /* list link */ +} PGcmdQueueEntry; + +/* + * pg_conn_host stores all information about each of possibly several hosts + * mentioned in the connection string. Most fields are derived by splitting + * the relevant connection parameter (e.g., pghost) at commas. + */ +typedef struct pg_conn_host +{ + pg_conn_host_type type; /* type of host address */ + char *host; /* host name or socket path */ + char *hostaddr; /* host numeric IP address */ + char *port; /* port number (always provided) */ + char *password; /* password for this host, read from the + * password file; NULL if not sought or not + * found in password file. */ +} pg_conn_host; + +/* + * 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, + * or a path to a UNIX-domain socket, or a + * comma-separated list of machines and/or + * paths; if NULL, use DEFAULT_PGSOCKET_DIR */ + char *pghostaddr; /* the numeric IP address of the machine on + * which the server is running, or a + * comma-separated list of same. Takes + * precedence over pghost. */ + char *pgport; /* the server's communication port number, or + * a comma-separated list of ports */ + char *connect_timeout; /* connection timeout (numeric string) */ + char *pgtcp_user_timeout; /* tcp user 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 *pgpassfile; /* path to a file containing password(s) */ + char *channel_binding; /* channel binding mode + * (require,prefer,disable) */ + 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 *sslpassword; /* client key file password */ + char *sslcertmode; /* client cert mode (require,allow,disable) */ + char *sslrootcert; /* root certificate filename */ + char *sslcrl; /* certificate revocation list filename */ + char *sslcrldir; /* certificate revocation list directory name */ + char *sslsni; /* use SSL SNI extension (0 or 1) */ + char *requirepeer; /* required peer credentials for local sockets */ + char *gssencmode; /* GSS mode (require,prefer,disable) */ + char *krbsrvname; /* Kerberos service name */ + char *gsslib; /* What GSS library to use ("gssapi" or + * "sspi") */ + char *gssdelegation; /* Try to delegate GSS credentials? (0 or 1) */ + char *ssl_min_protocol_version; /* minimum TLS protocol version */ + char *ssl_max_protocol_version; /* maximum TLS protocol version */ + char *target_session_attrs; /* desired session properties */ + char *require_auth; /* name of the expected auth method */ + char *load_balance_hosts; /* load balance over hosts */ + + /* Optional file to write trace info to */ + FILE *Pfdebug; + int traceFlags; + + /* 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 */ + 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 */ + PGpipelineStatus pipelineStatus; /* status of pipeline mode */ + 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 */ + + /* Support for multiple hosts in connection string */ + int nconnhost; /* # of hosts named in conn string */ + int whichhost; /* host we're currently trying/connected to */ + pg_conn_host *connhost; /* details about each named host */ + char *connip; /* IP address for current network connection */ + + /* + * The pending command queue as a singly-linked list. Head is the command + * currently in execution, tail is where new commands are added. + */ + PGcmdQueueEntry *cmd_queue_head; + PGcmdQueueEntry *cmd_queue_tail; + + /* + * To save malloc traffic, we don't free entries right away; instead we + * save them in this list for possible reuse. + */ + PGcmdQueueEntry *cmd_queue_recycle; + + /* Connection data */ + 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 gssapi_used; /* true if authenticated via gssapi */ + bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */ + bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */ + bool write_failed; /* have we had a write failure on sock? */ + char *write_err_msg; /* write error message, or NULL if OOM */ + + bool auth_required; /* require an authentication challenge from + * the server? */ + uint32 allowed_auth_methods; /* bitmask of acceptable AuthRequest + * codes */ + bool client_finished_auth; /* have we finished our half of the + * authentication exchange? */ + + + /* Transient state needed while establishing connection */ + PGTargetServerType target_server_type; /* desired session properties */ + PGLoadBalanceType load_balance_type; /* desired load balancing + * algorithm */ + bool try_next_addr; /* time to advance to next address/host? */ + bool try_next_host; /* time to advance to next connhost[]? */ + int naddr; /* number of addresses returned by getaddrinfo */ + int whichaddr; /* the address currently being tried */ + AddrInfo *addr; /* the array of addresses for the currently + * tried host */ + 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 */ + pgParameterStatus *pstatus; /* ParameterStatus data */ + int client_encoding; /* encoding id */ + bool std_strings; /* standard_conforming_strings */ + PGTernaryBool default_transaction_read_only; /* default_transaction_read_only */ + PGTernaryBool in_hot_standby; /* in_hot_standby */ + PGVerbosity verbosity; /* error/notice message verbosity */ + PGContextVisibility show_context; /* whether to show CONTEXT field */ + PGlobjfuncs *lobjfuncs; /* private state for large-object access fns */ + pg_prng_state prng_state; /* prng state for load balancing connections */ + + + /* 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. If result isn't NULL, it + * is a result being constructed or ready to return. If result is NULL + * and error_result is true, then we need to return a PGRES_FATAL_ERROR + * result, but haven't yet constructed it; text for the error has been + * appended to conn->errorMessage. (Delaying construction simplifies + * dealing with out-of-memory cases.) If next_result isn't NULL, it is a + * PGresult that will replace "result" after we return that one. + */ + PGresult *result; /* result being constructed */ + bool error_result; /* do we need to make an ERROR result? */ + PGresult *next_result; /* next result (used in single-row mode) */ + + /* Assorted state for SASL, SSL, GSS, etc */ + const pg_fe_sasl_mech *sasl; + void *sasl_state; + int scram_sha_256_iterations; + + /* SSL structures */ + bool ssl_in_use; + bool ssl_cert_requested; /* Did the server ask us for a cert? */ + bool ssl_cert_sent; /* Did we send one in reply? */ + +#ifdef USE_SSL + bool allow_ssl_try; /* Allowed to try SSL negotiation */ + bool wait_ssl_try; /* Delay SSL negotiation until after + * attempting normal connection */ +#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 + bool crypto_loaded; /* Track if libcrypto locking callbacks have + * been done for this connection. This can be + * removed once support for OpenSSL 1.0.2 is + * removed as this locking is handled + * internally in OpenSSL >= 1.1.0. */ +#endif /* USE_OPENSSL */ +#endif /* USE_SSL */ + +#ifdef ENABLE_GSS + gss_ctx_id_t gctx; /* GSS context */ + gss_name_t gtarg_nam; /* GSS target name */ + + /* The following are encryption-only */ + bool try_gss; /* GSS attempting permitted */ + bool gssenc; /* GSS encryption is usable */ + gss_cred_id_t gcred; /* GSS credential temp storage. */ + + /* GSS encryption I/O state --- see fe-secure-gssapi.c */ + char *gss_SendBuffer; /* Encrypted data waiting to be sent */ + int gss_SendLength; /* End of data available in gss_SendBuffer */ + int gss_SendNext; /* Next index to send a byte from + * gss_SendBuffer */ + int gss_SendConsumed; /* Number of *unencrypted* bytes consumed + * for current contents of gss_SendBuffer */ + char *gss_RecvBuffer; /* Received, encrypted data */ + int gss_RecvLength; /* End of data available in gss_RecvBuffer */ + char *gss_ResultBuffer; /* Decryption of data in gss_RecvBuffer */ + int gss_ResultLength; /* End of data available in + * gss_ResultBuffer */ + int gss_ResultNext; /* Next index to read a byte from + * gss_ResultBuffer */ + uint32 gss_MaxPktSize; /* Maximum size we can encrypt and fit the + * results into our output buffer */ +#endif + +#ifdef ENABLE_SSPI + 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. This is cleared at the start of any + * connection attempt or query cycle; after that, all code should append + * messages to it, never overwrite. + * + * In some situations we might report an error more than once in a query + * cycle. If so, errorMessage accumulates text from all the errors, and + * errorReported tracks how much we've already reported, so that the + * individual error PGresult objects don't contain duplicative text. + */ + PQExpBufferData errorMessage; /* expansible string */ + int errorReported; /* # bytes of string already reported */ + + /* 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 */ + int pgtcp_user_timeout; /* tcp user timeout */ + int keepalives; /* use TCP keepalives? */ + int keepalives_idle; /* time between TCP keepalives */ + int keepalives_interval; /* time between TCP keepalive + * retransmits */ + int keepalives_count; /* maximum number of TCP keepalive + * retransmits */ +}; + + +/* 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 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, PQExpBuffer errorMessage, int offset); +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 pqCommandQueueAdvance(PGconn *conn); +extern int PQsendQueryContinue(PGconn *conn, const char *query); + +/* === 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 pqGetNegotiateProtocolVersion3(PGconn *conn); +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, 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 *, bool, bool); +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 + +/* === SSL === */ + +/* + * The SSL implementation provides these functions. + */ + +/* + * Implementation of PQinitSSL(). + */ +extern void pgtls_init_library(bool do_ssl, int do_crypto); + +/* + * Initialize SSL library. + * + * The conn parameter is only used to be able to pass back an error + * message - no connection-local setup is made here. do_ssl controls + * if SSL is initialized, and do_crypto does the same for the crypto + * part. + * + * Returns 0 if OK, -1 on failure (adding a message to conn->errorMessage). + */ +extern int pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto); + +/* + * Begin or continue negotiating a secure session. + */ +extern PostgresPollingStatusType pgtls_open_client(PGconn *conn); + +/* + * Close SSL connection. + */ +extern void pgtls_close(PGconn *conn); + +/* + * Read data from a secure connection. + * + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only + * to determine whether to continue/retry after error. + */ +extern ssize_t pgtls_read(PGconn *conn, void *ptr, size_t len); + +/* + * Is there unread data waiting in the SSL read buffer? + */ +extern bool pgtls_read_pending(PGconn *conn); + +/* + * Write data to a secure connection. + * + * On failure, this function is responsible for appending a suitable message + * to conn->errorMessage. The caller must still inspect errno, but only + * to determine whether to continue/retry after error. + */ +extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); + +/* + * Get the hash of the server certificate, for SCRAM channel binding type + * tls-server-end-point. + * + * NULL is sent back to the caller in the event of an error, with an + * error message for the caller to consume. + * + * This is not supported with old versions of OpenSSL that don't have + * the X509_get_signature_nid() function. + */ +#if defined(USE_OPENSSL) && (defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO)) +#define HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH +extern char *pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len); +#endif + +/* + * Verify that the server certificate matches the host name we connected to. + * + * The certificate's Common Name and Subject Alternative Names are considered. + * + * Returns 1 if the name matches, and 0 if it does not. On error, returns + * -1, and sets the libpq error message. + * + */ +extern int pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn, + int *names_examined, + char **first_name); + +/* === GSSAPI === */ + +#ifdef ENABLE_GSS + +/* + * Establish a GSSAPI-encrypted connection. + */ +extern PostgresPollingStatusType pqsecure_open_gss(PGconn *conn); + +/* + * Read and write functions for GSSAPI-encrypted connections, with internal + * buffering to handle nonblocking sockets. + */ +extern ssize_t pg_GSS_write(PGconn *conn, const void *ptr, size_t len); +extern ssize_t pg_GSS_read(PGconn *conn, void *ptr, size_t len); +#endif + +/* === in fe-trace.c === */ + +extern void pqTraceOutputMessage(PGconn *conn, const char *message, + bool toServer); +extern void pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message); + +/* === miscellaneous macros === */ + +/* + * Reset the conn's error-reporting state. + */ +#define pqClearConnErrorState(conn) \ + (resetPQExpBuffer(&(conn)->errorMessage), \ + (conn)->errorReported = 0) + +/* + * Check whether we have a PGresult pending to be returned --- either a + * constructed one in conn->result, or a "virtual" error result that we + * don't intend to materialize until the end of the query cycle. + */ +#define pgHavePendingResult(conn) \ + ((conn)->result != NULL || (conn)->error_result) + +/* + * 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) + +/* + * Connection's outbuffer threshold, for pipeline mode. + */ +#define OUTBUFFER_THRESHOLD 65536 + +#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 +/* + * libpq code should use the above, not _(), since that would use the + * surrounding programs's message catalog. + */ +#undef _ + +extern void libpq_append_error(PQExpBuffer errorMessage, const char *fmt,...) pg_attribute_printf(2, 3); +extern void libpq_append_conn_error(PGconn *conn, const char *fmt,...) pg_attribute_printf(2, 3); + +/* + * 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 strerror_r +#define SOCK_ERRNO_SET(e) (errno = (e)) +#endif + +#endif /* LIBPQ_INT_H */ diff --git a/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c b/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c new file mode 100644 index 0000000000..de7e0328db --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.c @@ -0,0 +1,412 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/interfaces/libpq/pqexpbuffer.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <limits.h> + +#include "pqexpbuffer.h" + +#ifdef WIN32 +#include "win32.h" +#endif + + +/* All "broken" PQExpBuffers point to this string. */ +static const char oom_buffer[1] = ""; + +/* Need a char * for unconstify() compatibility */ +static const char *oom_buffer_ptr = oom_buffer; + + +/* + * 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 = unconstify(char *, oom_buffer_ptr); + 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 = unconstify(char *, oom_buffer_ptr); /* 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 = unconstify(char *, oom_buffer_ptr); /* 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,...) +{ + int save_errno = errno; + 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 + { + errno = save_errno; + 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,...) +{ + int save_errno = errno; + va_list args; + bool done; + + if (PQExpBufferBroken(str)) + return; /* already failed */ + + /* Loop in case we have to retry after enlarging the buffer. */ + do + { + errno = save_errno; + 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. + * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + */ +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) + { + avail = str->maxlen - str->len; + + nprinted = vsnprintf(str->data + str->len, avail, fmt, args); + + /* + * If vsnprintf reports an error, fail (we assume this means there's + * something wrong with the format string). + */ + if (unlikely(nprinted < 0)) + { + markPQExpBufferBroken(str); + return true; + } + + if ((size_t) nprinted < avail) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += nprinted; + return true; + } + + /* + * We assume a C99-compliant vsnprintf, so believe its estimate of the + * required space, and add one for the trailing null. (If it's wrong, + * the logic will still work, but we may loop multiple times.) + * + * Choke if the required space would exceed INT_MAX, since str->maxlen + * can't represent more than that. + */ + if (unlikely(nprinted > INT_MAX - 1)) + { + markPQExpBufferBroken(str); + return true; + } + needed = nprinted + 1; + } + else + { + /* + * We have to guess at how much to enlarge, since we're skipping the + * formatting work. Fortunately, because of enlargePQExpBuffer's + * preference for power-of-2 sizes, this number isn't very sensitive; + * the net effect is that we'll double the buffer size before trying + * to run vsnprintf, which seems sensible. + */ + 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/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.h b/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.h new file mode 100644 index 0000000000..020e94e357 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/pqexpbuffer.h @@ -0,0 +1,192 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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); + +/*------------------------ + * appendPQExpBufferVA + * Attempt to format data and append it to str. Returns true if done + * (either successful or hard failure), false if need to retry. + * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + */ +extern bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0); + +/*------------------------ + * 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/contrib/libs/libpq/src/interfaces/libpq/pthread-win32.c b/contrib/libs/libpq/src/interfaces/libpq/pthread-win32.c new file mode 100644 index 0000000000..8e65637387 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/pthread-win32.c @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- +* +* pthread-win32.c +* partial pthread implementation for win32 +* +* Copyright (c) 2004-2023, PostgreSQL Global Development Group +* IDENTIFICATION +* src/interfaces/libpq/pthread-win32.c +* +*------------------------------------------------------------------------- +*/ + +#include "postgres_fe.h" + +#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/contrib/libs/libpq/src/interfaces/libpq/win32.c b/contrib/libs/libpq/src/interfaces/libpq/win32.c new file mode 100644 index 0000000000..e4d29eefa6 --- /dev/null +++ b/contrib/libs/libpq/src/interfaces/libpq/win32.c @@ -0,0 +1,320 @@ +/* + * 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-2023, 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. + */ + +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/contrib/libs/libpq/src/port/README b/contrib/libs/libpq/src/port/README new file mode 100644 index 0000000000..97f18a6233 --- /dev/null +++ b/contrib/libs/libpq/src/port/README @@ -0,0 +1,32 @@ +src/port/README + +libpgport +========= + +libpgport must have special behavior. It supplies functions to both +libraries and applications. However, there are two complexities: + +1) Libraries need to use object files that are compiled with exactly +the same flags as the library. libpgport might not use the same flags, +so it is necessary to recompile the object files for individual +libraries. This is done by removing -lpgport from the link line: + + # Need to recompile any libpgport object files + LIBS := $(filter-out -lpgport, $(LIBS)) + +and adding infrastructure to recompile the object files: + + OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \ + connect.o misc.o path.o exec.o \ + $(filter strlcat.o, $(LIBOBJS)) + +The problem is that there is no testing of which object files need to be +added, but missing functions usually show up when linking user +applications. + +2) For applications, we use -lpgport before -lpq, so the static files +from libpgport are linked first. This avoids having applications +dependent on symbols that are _used_ by libpq, but not intended to be +exported by libpq. libpq's libpgport usage changes over time, so such a +dependency is a problem. Windows, Linux, AIX, and macOS use an export +list to control the symbols exported by libpq. diff --git a/contrib/libs/libpq/src/port/bsearch_arg.c b/contrib/libs/libpq/src/port/bsearch_arg.c new file mode 100644 index 0000000000..641b40c353 --- /dev/null +++ b/contrib/libs/libpq/src/port/bsearch_arg.c @@ -0,0 +1,78 @@ +/* + * bsearch_arg.c: bsearch variant with a user-supplied pointer + * + * Copyright (c) 2021-2023, PostgreSQL Global Development Group + * Copyright (c) 1990 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. [rescinded 22 July 1999] + * 4. 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/bsearch_arg.c + */ + +#include "c.h" + +/* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involves halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ +void * +bsearch_arg(const void *key, const void *base0, + size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + void *arg) +{ + const char *base = (const char *) base0; + int lim, + cmp; + const void *p; + + for (lim = nmemb; lim != 0; lim >>= 1) + { + p = base + (lim >> 1) * size; + cmp = (*compar) (key, p, arg); + if (cmp == 0) + return (void *) p; + if (cmp > 0) + { /* key > p: move right */ + base = (const char *) p + size; + lim--; + } /* else move left */ + } + return (NULL); +} diff --git a/contrib/libs/libpq/src/port/chklocale.c b/contrib/libs/libpq/src/port/chklocale.c new file mode 100644 index 0000000000..6fa6810a46 --- /dev/null +++ b/contrib/libs/libpq/src/port/chklocale.c @@ -0,0 +1,433 @@ +/*------------------------------------------------------------------------- + * + * chklocale.c + * Functions for handling locale-related info + * + * + * Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/port/chklocale.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#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<code page number> instead of the nl_langinfo() result + * + * 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 + * <Language>_<Country>.<CodePage> as a base. + * + * Returns a malloc()'d string for the caller to free. + */ +static char * +win32_langinfo(const char *ctype) +{ + char *r = NULL; + char *codepage; + +#if defined(_MSC_VER) + 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) + { + /* + * If the return value is CP_ACP that means no ANSI code page is + * available, so only Unicode can be used for the locale. + */ + if (cp == CP_ACP) + strcpy(r, "utf8"); + else + sprintf(r, "CP%u", cp); + } + } + else +#endif + { + /* + * Locale format on Win32 is <Language>_<Country>.<CodePage>. For + * example, English_United States.1252. If we see digits after the + * last dot, assume it's a codepage number. Otherwise, we might be + * dealing with a Unix-style locale string; Windows' setlocale() will + * take those even though GetLocaleInfoEx() won't, so we end up here. + * In that case, just return what's after the last dot and hope we can + * find it in our table. + */ + codepage = strrchr(ctype, '.'); + if (codepage != NULL) + { + size_t ln; + + codepage++; + ln = strlen(codepage); + r = malloc(ln + 3); + if (r != NULL) + { + if (strspn(codepage, "0123456789") == ln) + sprintf(r, "CP%s", codepage); + else + strcpy(r, codepage); + } + } + } + + 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))); + + 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 macOS 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))); +#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/contrib/libs/libpq/src/port/dirmod.c b/contrib/libs/libpq/src/port/dirmod.c new file mode 100644 index 0000000000..07dd190cbc --- /dev/null +++ b/contrib/libs/libpq/src/port/dirmod.c @@ -0,0 +1,422 @@ +/*------------------------------------------------------------------------- + * + * dirmod.c + * directory handling functions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * This includes replacement versions of functions that work on + * Windows. + * + * IDENTIFICATION + * src/port/dirmod.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +/* Don't modify declarations in system headers */ +#if defined(WIN32) || defined(__CYGWIN__) +#undef rename +#undef unlink +#endif + +#include <unistd.h> +#include <sys/stat.h> + +#if defined(WIN32) || defined(__CYGWIN__) +#ifndef __CYGWIN__ +#include <winioctl.h> +#else +#include <windows.h> +#include <w32api/winioctl.h> +#endif +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +#include "port/win32ntdll.h" +#endif + +#if defined(WIN32) || defined(__CYGWIN__) + +/* + * pgrename + */ +int +pgrename(const char *from, const char *to) +{ + int loops = 0; + + /* + * We need to loop because even though PostgreSQL uses flags that allow + * rename while the file is open, other applications might have the file + * open without those flags. However, we won't wait indefinitely for + * someone else to close the file, as the caller might be holding locks + * and blocking other backends. + */ +#if defined(WIN32) && !defined(__CYGWIN__) + while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)) +#else + while (rename(from, to) < 0) +#endif + { +#if defined(WIN32) && !defined(__CYGWIN__) + DWORD err = GetLastError(); + + _dosmaperr(err); + + /* + * Modern NT-based Windows versions return ERROR_SHARING_VIOLATION if + * another process has the file open without FILE_SHARE_DELETE. + * ERROR_LOCK_VIOLATION has also been seen with some anti-virus + * software. This used to check for just ERROR_ACCESS_DENIED, so + * presumably you can get that too with some OS versions. We don't + * expect real permission errors where we currently use rename(). + */ + if (err != ERROR_ACCESS_DENIED && + err != ERROR_SHARING_VIOLATION && + err != ERROR_LOCK_VIOLATION) + return -1; +#else + if (errno != EACCES) + return -1; +#endif + + if (++loops > 100) /* time out after 10 sec */ + return -1; + pg_usleep(100000); /* us */ + } + return 0; +} + +/* + * Check if _pglstat64()'s reason for failure was STATUS_DELETE_PENDING. + * This doesn't apply to Cygwin, which has its own lstat() that would report + * the case as EACCES. +*/ +static bool +lstat_error_was_status_delete_pending(void) +{ + if (errno != ENOENT) + return false; +#if defined(WIN32) && !defined(__CYGWIN__) + if (pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING) + return true; +#endif + return false; +} + +/* + * pgunlink + */ +int +pgunlink(const char *path) +{ + bool is_lnk; + int loops = 0; + struct stat st; + + /* + * This function might be called for a regular file or for a junction + * point (which we use to emulate symlinks). The latter must be unlinked + * with rmdir() on Windows. Before we worry about any of that, let's see + * if we can unlink directly, since that's expected to be the most common + * case. + */ + if (unlink(path) == 0) + return 0; + if (errno != EACCES) + return -1; + + /* + * EACCES is reported for many reasons including unlink() of a junction + * point. Check if that's the case so we can redirect to rmdir(). + * + * Note that by checking only once, we can't cope with a path that changes + * from regular file to junction point underneath us while we're retrying + * due to sharing violations, but that seems unlikely. We could perhaps + * prevent that by holding a file handle ourselves across the lstat() and + * the retry loop, but that seems like over-engineering for now. + * + * In the special case of a STATUS_DELETE_PENDING error (file already + * unlinked, but someone still has it open), we don't want to report + * ENOENT to the caller immediately, because rmdir(parent) would probably + * fail. We want to wait until the file truly goes away so that simple + * recursive directory unlink algorithms work. + */ + if (lstat(path, &st) < 0) + { + if (lstat_error_was_status_delete_pending()) + is_lnk = false; + else + return -1; + } + else + is_lnk = S_ISLNK(st.st_mode); + + /* + * We need to loop because even though PostgreSQL uses flags that allow + * unlink while the file is open, other applications might have the file + * open without those flags. However, we won't wait indefinitely for + * someone else to close the file, as the caller might be holding locks + * and blocking other backends. + */ + while ((is_lnk ? rmdir(path) : unlink(path)) < 0) + { + if (errno != EACCES) + return -1; + if (++loops > 100) /* time out after 10 sec */ + return -1; + pg_usleep(100000); /* us */ + } + return 0; +} + +/* We undefined these above; now redefine for possible use below */ +#define rename(from, to) pgrename(from, to) +#define unlink(path) pgunlink(path) +#endif /* defined(WIN32) || defined(__CYGWIN__) */ + + +#if defined(WIN32) && !defined(__CYGWIN__) /* Cygwin has its own symlinks */ + +/* + * pgsymlink support: + * + * This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h + * but omitted in later SDK functions. + * We only need the SymbolicLinkReparseBuffer part of the original struct's union. + */ +typedef struct +{ + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + /* SymbolicLinkReparseBuffer */ + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[FLEXIBLE_ARRAY_MEMBER]; +} REPARSE_JUNCTION_DATA_BUFFER; + +#define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \ + FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset) + + +/* + * pgsymlink - uses Win32 junction points + * + * For reference: http://www.codeproject.com/KB/winsdk/junctionpoints.aspx + */ +int +pgsymlink(const char *oldpath, const char *newpath) +{ + HANDLE dirhandle; + DWORD len; + char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)]; + char nativeTarget[MAX_PATH]; + char *p = nativeTarget; + REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer; + + CreateDirectory(newpath, 0); + dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE, + 0, 0, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); + + if (dirhandle == INVALID_HANDLE_VALUE) + { + _dosmaperr(GetLastError()); + return -1; + } + + /* make sure we have an unparsed native win32 path */ + if (memcmp("\\??\\", oldpath, 4) != 0) + snprintf(nativeTarget, sizeof(nativeTarget), "\\??\\%s", oldpath); + else + strlcpy(nativeTarget, oldpath, sizeof(nativeTarget)); + + while ((p = strchr(p, '/')) != NULL) + *p++ = '\\'; + + len = strlen(nativeTarget) * sizeof(WCHAR); + reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + reparseBuf->ReparseDataLength = len + 12; + reparseBuf->Reserved = 0; + reparseBuf->SubstituteNameOffset = 0; + reparseBuf->SubstituteNameLength = len; + reparseBuf->PrintNameOffset = len + sizeof(WCHAR); + reparseBuf->PrintNameLength = 0; + MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1, + reparseBuf->PathBuffer, MAX_PATH); + + /* + * FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version; + * we use our own definition + */ + if (!DeviceIoControl(dirhandle, + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS), + reparseBuf, + reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE, + 0, 0, &len, 0)) + { + LPSTR msg; + int save_errno; + + _dosmaperr(GetLastError()); + save_errno = errno; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + (LPSTR) &msg, 0, NULL); +#ifndef FRONTEND + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not set junction for \"%s\": %s", + nativeTarget, msg))); +#else + fprintf(stderr, _("could not set junction for \"%s\": %s\n"), + nativeTarget, msg); +#endif + LocalFree(msg); + + CloseHandle(dirhandle); + RemoveDirectory(newpath); + + errno = save_errno; + + return -1; + } + + CloseHandle(dirhandle); + + return 0; +} + +/* + * pgreadlink - uses Win32 junction points + */ +int +pgreadlink(const char *path, char *buf, size_t size) +{ + DWORD attr; + HANDLE h; + char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)]; + REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer; + DWORD len; + int r; + + attr = GetFileAttributes(path); + if (attr == INVALID_FILE_ATTRIBUTES) + { + _dosmaperr(GetLastError()); + return -1; + } + if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + { + errno = EINVAL; + return -1; + } + + h = CreateFile(path, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + 0); + if (h == INVALID_HANDLE_VALUE) + { + _dosmaperr(GetLastError()); + return -1; + } + + if (!DeviceIoControl(h, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + (LPVOID) reparseBuf, + sizeof(buffer), + &len, + NULL)) + { + LPSTR msg; + + errno = 0; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + (LPSTR) &msg, 0, NULL); +#ifndef FRONTEND + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not get junction for \"%s\": %s", + path, msg))); +#else + fprintf(stderr, _("could not get junction for \"%s\": %s\n"), + path, msg); +#endif + LocalFree(msg); + CloseHandle(h); + errno = EINVAL; + return -1; + } + CloseHandle(h); + + /* Got it, let's get some results from this */ + if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) + { + errno = EINVAL; + return -1; + } + + r = WideCharToMultiByte(CP_ACP, 0, + reparseBuf->PathBuffer, -1, + buf, + size, + NULL, NULL); + + if (r <= 0) + { + errno = EINVAL; + return -1; + } + + /* r includes the null terminator */ + r -= 1; + + /* + * If the path starts with "\??\" followed by a "drive absolute" path + * (known to Windows APIs as RtlPathTypeDriveAbsolute), then strip that + * prefix. This undoes some of the transformation performed by + * pgsymlink(), to get back to a format that users are used to seeing. We + * don't know how to transform other path types that might be encountered + * outside PGDATA, so we just return them directly. + */ + if (r >= 7 && + buf[0] == '\\' && + buf[1] == '?' && + buf[2] == '?' && + buf[3] == '\\' && + isalpha(buf[4]) && + buf[5] == ':' && + buf[6] == '\\') + { + memmove(buf, buf + 4, strlen(buf + 4) + 1); + r -= 4; + } + return r; +} + +#endif /* defined(WIN32) && !defined(__CYGWIN__) */ diff --git a/contrib/libs/libpq/src/port/getpeereid.c b/contrib/libs/libpq/src/port/getpeereid.c new file mode 100644 index 0000000000..3b040e076b --- /dev/null +++ b/contrib/libs/libpq/src/port/getpeereid.c @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + * + * getpeereid.c + * get peer userid for UNIX-domain socket connection + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/port/getpeereid.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#ifdef HAVE_UCRED_H +#include <ucred.h> +#endif +#ifdef HAVE_SYS_UCRED_H +#include <sys/ucred.h> +#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; + socklen_t 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; + socklen_t 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/contrib/libs/libpq/src/port/inet_aton.c b/contrib/libs/libpq/src/port/inet_aton.c new file mode 100644 index 0000000000..adaf18adb3 --- /dev/null +++ b/contrib/libs/libpq/src/port/inet_aton.c @@ -0,0 +1,149 @@ +/* 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 <netinet/in.h> +#include <ctype.h> + +#include "port/pg_bswap.h" + +/* + * 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 = pg_hton32(val); + return 1; +} diff --git a/contrib/libs/libpq/src/port/inet_net_ntop.c b/contrib/libs/libpq/src/port/inet_net_ntop.c new file mode 100644 index 0000000000..4044f22450 --- /dev/null +++ b/contrib/libs/libpq/src/port/inet_net_ntop.c @@ -0,0 +1,296 @@ +/* + * 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/port/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 <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifndef FRONTEND +#error #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 pg_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 * + * pg_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 pg_inet_net_pton() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +char * +pg_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. + */ + switch (af) + { + case PGSQL_AF_INET: + return (inet_net_ntop_ipv4(src, bits, dst, size)); + case PGSQL_AF_INET6: +#if 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/contrib/libs/libpq/src/port/noblock.c b/contrib/libs/libpq/src/port/noblock.c new file mode 100644 index 0000000000..d050a03085 --- /dev/null +++ b/contrib/libs/libpq/src/port/noblock.c @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * noblock.c + * set a file descriptor as blocking or non-blocking + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/port/noblock.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <fcntl.h> + + +/* + * 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/contrib/libs/libpq/src/port/open.c b/contrib/libs/libpq/src/port/open.c new file mode 100644 index 0000000000..0bd9755006 --- /dev/null +++ b/contrib/libs/libpq/src/port/open.c @@ -0,0 +1,222 @@ +/*------------------------------------------------------------------------- + * + * open.c + * Win32 open() replacement + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * src/port/open.c + * + *------------------------------------------------------------------------- + */ + +#ifdef WIN32 + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "port/win32ntdll.h" + +#include <fcntl.h> +#include <assert.h> +#include <sys/stat.h> + +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; +} + +/* + * Internal function used by pgwin32_open() and _pgstat64(). When + * backup_semantics is true, directories may be opened (for limited uses). On + * failure, INVALID_HANDLE_VALUE is returned and errno is set. + */ +HANDLE +pgwin32_open_handle(const char *fileName, int fileFlags, bool backup_semantics) +{ + HANDLE h; + SECURITY_ATTRIBUTES sa; + int loops = 0; + + if (initialize_ntdll() < 0) + return INVALID_HANDLE_VALUE; + + /* 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 | + (backup_semantics ? FILE_FLAG_BACKUP_SEMANTICS : 0) | + ((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. Wait a bit and try + * again, giving up after 30 seconds. + */ + DWORD err = GetLastError(); + + if (err == ERROR_SHARING_VIOLATION || + err == ERROR_LOCK_VIOLATION) + { +#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) + { + pg_usleep(100000); + loops++; + continue; + } + } + + /* + * ERROR_ACCESS_DENIED is returned if the file is deleted but not yet + * gone (Windows NT status code is STATUS_DELETE_PENDING). In that + * case, we'd better ask for the NT status too so we can translate it + * to a more Unix-like error. We hope that nothing clobbers the NT + * status in between the internal NtCreateFile() call and CreateFile() + * returning. + * + * If there's no O_CREAT flag, then we'll pretend the file is + * invisible. With O_CREAT, we have no choice but to report that + * there's a file in the way (which wouldn't happen on Unix). + */ + if (err == ERROR_ACCESS_DENIED && + pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING) + { + if (fileFlags & O_CREAT) + err = ERROR_FILE_EXISTS; + else + err = ERROR_FILE_NOT_FOUND; + } + + _dosmaperr(err); + return INVALID_HANDLE_VALUE; + } + + return h; +} + +int +pgwin32_open(const char *fileName, int fileFlags,...) +{ + HANDLE h; + int fd; + + h = pgwin32_open_handle(fileName, fileFlags, false); + if (h == INVALID_HANDLE_VALUE) + return -1; + +#ifdef FRONTEND + + /* + * Since PostgreSQL 12, those concurrent-safe versions of open() and + * fopen() can be used by frontends, having as side-effect to switch the + * file-translation mode from O_TEXT to O_BINARY if none is specified. + * Caller may want to enforce the binary or text mode, but if nothing is + * defined make sure that the default mode maps with what versions older + * than 12 have been doing. + */ + if ((fileFlags & O_BINARY) == 0) + fileFlags |= O_TEXT; +#endif + + /* _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/contrib/libs/libpq/src/port/path.c b/contrib/libs/libpq/src/port/path.c new file mode 100644 index 0000000000..65c7943fee --- /dev/null +++ b/contrib/libs/libpq/src/port/path.c @@ -0,0 +1,1057 @@ +/*------------------------------------------------------------------------- + * + * path.c + * portable path handling routines + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/path.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <ctype.h> +#include <sys/stat.h> +#ifdef WIN32 +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0500 +#ifdef near +#undef near +#endif +#define near +#include <shlobj.h> +#else +#include <unistd.h> +#endif + +#include "pg_config_paths.h" + + +#ifndef WIN32 +#define IS_PATH_VAR_SEP(ch) ((ch) == ':') +#else +#define IS_PATH_VAR_SEP(ch) ((ch) == ';') +#endif + +static void make_relative_path(char *ret_path, const char *target_path, + const char *bin_path, const char *my_exec_path); +static char *trim_directory(char *path); +static void trim_trailing_separator(char *path); +static char *append_subdir_to_path(char *path, char *subdir); + + +/* + * skip_drive + * + * On Windows, a path may begin with "C:" or "//network/". Advance over + * this and point to the effective start of the path. + */ +#ifdef WIN32 + +static char * +skip_drive(const char *path) +{ + if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1])) + { + path += 2; + while (*path && !IS_DIR_SEP(*path)) + path++; + } + else if (isalpha((unsigned char) path[0]) && path[1] == ':') + { + path += 2; + } + return (char *) path; +} +#else + +#define skip_drive(path) (path) +#endif + +/* + * has_drive_prefix + * + * Return true if the given pathname has a drive prefix. + */ +bool +has_drive_prefix(const char *path) +{ +#ifdef WIN32 + return skip_drive(path) != path; +#else + return false; +#endif +} + +/* + * first_dir_separator + * + * Find the location of the first directory separator, return + * NULL if not found. + */ +char * +first_dir_separator(const char *filename) +{ + const char *p; + + for (p = skip_drive(filename); *p; p++) + if (IS_DIR_SEP(*p)) + return unconstify(char *, p); + return NULL; +} + +/* + * first_path_var_separator + * + * Find the location of the first path separator (i.e. ':' on + * Unix, ';' on Windows), return NULL if not found. + */ +char * +first_path_var_separator(const char *pathlist) +{ + const char *p; + + /* skip_drive is not needed */ + for (p = pathlist; *p; p++) + if (IS_PATH_VAR_SEP(*p)) + return unconstify(char *, p); + return NULL; +} + +/* + * last_dir_separator + * + * Find the location of the last directory separator, return + * NULL if not found. + */ +char * +last_dir_separator(const char *filename) +{ + const char *p, + *ret = NULL; + + for (p = skip_drive(filename); *p; p++) + if (IS_DIR_SEP(*p)) + ret = p; + return unconstify(char *, ret); +} + + +/* + * make_native_path - on WIN32, change / to \ in the path + * + * This effectively undoes canonicalize_path. + * + * This is required because WIN32 COPY is an internal CMD.EXE + * command and doesn't process forward slashes in the same way + * as external commands. Quoting the first argument to COPY + * does not convert forward to backward slashes, but COPY does + * properly process quoted forward slashes in the second argument. + * + * COPY works with quoted forward slashes in the first argument + * only if the current directory is the same as the directory + * of the first argument. + */ +void +make_native_path(char *filename) +{ +#ifdef WIN32 + char *p; + + for (p = filename; *p; p++) + if (*p == '/') + *p = '\\'; +#endif +} + + +/* + * This function cleans up the paths for use with either cmd.exe or Msys + * on Windows. We need them to use filenames without spaces, for which a + * short filename is the safest equivalent, eg: + * C:/Progra~1/ + */ +void +cleanup_path(char *path) +{ +#ifdef WIN32 + char *ptr; + + /* + * GetShortPathName() will fail if the path does not exist, or short names + * are disabled on this file system. In both cases, we just return the + * original path. This is particularly useful for --sysconfdir, which + * might not exist. + */ + GetShortPathName(path, path, MAXPGPATH - 1); + + /* Replace '\' with '/' */ + for (ptr = path; *ptr; ptr++) + { + if (*ptr == '\\') + *ptr = '/'; + } +#endif +} + + +/* + * join_path_components - join two path components, inserting a slash + * + * We omit the slash if either given component is empty. + * + * ret_path is the output area (must be of size MAXPGPATH) + * + * ret_path can be the same as head, but not the same as tail. + */ +void +join_path_components(char *ret_path, + const char *head, const char *tail) +{ + if (ret_path != head) + strlcpy(ret_path, head, MAXPGPATH); + + /* + * We used to try to simplify some cases involving "." and "..", but now + * we just leave that to be done by canonicalize_path() later. + */ + + if (*tail) + { + /* only separate with slash if head wasn't empty */ + snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path), + "%s%s", + (*(skip_drive(head)) != '\0') ? "/" : "", + tail); + } +} + + +/* State-machine states for canonicalize_path */ +typedef enum +{ + ABSOLUTE_PATH_INIT, /* Just past the leading '/' (and Windows + * drive name if any) of an absolute path */ + ABSOLUTE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in an + * absolute path */ + RELATIVE_PATH_INIT, /* At start of a relative path */ + RELATIVE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in a + * relative path */ + RELATIVE_WITH_PARENT_REF /* Relative path containing only double-dots */ +} canonicalize_state; + +/* + * Clean up path by: + * o make Win32 path use Unix slashes + * o remove trailing quote on Win32 + * o remove trailing slash + * o remove duplicate (adjacent) separators + * o remove '.' (unless path reduces to only '.') + * o process '..' ourselves, removing it if possible + */ +void +canonicalize_path(char *path) +{ + char *p, + *to_p; + char *spath; + char *parsed; + char *unparse; + bool was_sep = false; + canonicalize_state state; + int pathdepth = 0; /* counts collected regular directory names */ + +#ifdef WIN32 + + /* + * The Windows command processor will accept suitably quoted paths with + * forward slashes, but barfs badly with mixed forward and back slashes. + */ + for (p = path; *p; p++) + { + if (*p == '\\') + *p = '/'; + } + + /* + * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d" + * as argv[2], so trim off trailing quote. + */ + if (p > path && *(p - 1) == '"') + *(p - 1) = '/'; +#endif + + /* + * Removing the trailing slash on a path means we never get ugly double + * trailing slashes. Also, Win32 can't stat() a directory with a trailing + * slash. Don't remove a leading slash, though. + */ + trim_trailing_separator(path); + + /* + * Remove duplicate adjacent separators + */ + p = path; +#ifdef WIN32 + /* Don't remove leading double-slash on Win32 */ + if (*p) + p++; +#endif + to_p = p; + for (; *p; p++, to_p++) + { + /* Handle many adjacent slashes, like "/a///b" */ + while (*p == '/' && was_sep) + p++; + if (to_p != p) + *to_p = *p; + was_sep = (*p == '/'); + } + *to_p = '\0'; + + /* + * Remove any uses of "." and process ".." ourselves + * + * Note that "/../.." should reduce to just "/", while "../.." has to be + * kept as-is. Also note that we want a Windows drive spec to be visible + * to trim_directory(), but it's not part of the logic that's looking at + * the name components; hence distinction between path and spath. + * + * This loop overwrites the path in-place. This is safe since we'll never + * make the path longer. "unparse" points to where we are reading the + * path, "parse" to where we are writing. + */ + spath = skip_drive(path); + if (*spath == '\0') + return; /* empty path is returned as-is */ + + if (*spath == '/') + { + state = ABSOLUTE_PATH_INIT; + /* Skip the leading slash for absolute path */ + parsed = unparse = (spath + 1); + } + else + { + state = RELATIVE_PATH_INIT; + parsed = unparse = spath; + } + + while (*unparse != '\0') + { + char *unparse_next; + bool is_double_dot; + + /* Split off this dir name, and set unparse_next to the next one */ + unparse_next = unparse; + while (*unparse_next && *unparse_next != '/') + unparse_next++; + if (*unparse_next != '\0') + *unparse_next++ = '\0'; + + /* Identify type of this dir name */ + if (strcmp(unparse, ".") == 0) + { + /* We can ignore "." components in all cases */ + unparse = unparse_next; + continue; + } + + if (strcmp(unparse, "..") == 0) + is_double_dot = true; + else + { + /* adjacent separators were eliminated above */ + Assert(*unparse != '\0'); + is_double_dot = false; + } + + switch (state) + { + case ABSOLUTE_PATH_INIT: + /* We can ignore ".." immediately after / */ + if (!is_double_dot) + { + /* Append first dir name (we already have leading slash) */ + parsed = append_subdir_to_path(parsed, unparse); + state = ABSOLUTE_WITH_N_DEPTH; + pathdepth++; + } + break; + case ABSOLUTE_WITH_N_DEPTH: + if (is_double_dot) + { + /* Remove last parsed dir */ + /* (trim_directory won't remove the leading slash) */ + *parsed = '\0'; + parsed = trim_directory(path); + if (--pathdepth == 0) + state = ABSOLUTE_PATH_INIT; + } + else + { + /* Append normal dir */ + *parsed++ = '/'; + parsed = append_subdir_to_path(parsed, unparse); + pathdepth++; + } + break; + case RELATIVE_PATH_INIT: + if (is_double_dot) + { + /* Append irreducible double-dot (..) */ + parsed = append_subdir_to_path(parsed, unparse); + state = RELATIVE_WITH_PARENT_REF; + } + else + { + /* Append normal dir */ + parsed = append_subdir_to_path(parsed, unparse); + state = RELATIVE_WITH_N_DEPTH; + pathdepth++; + } + break; + case RELATIVE_WITH_N_DEPTH: + if (is_double_dot) + { + /* Remove last parsed dir */ + *parsed = '\0'; + parsed = trim_directory(path); + if (--pathdepth == 0) + { + /* + * If the output path is now empty, we're back to the + * INIT state. However, we could have processed a + * path like "../dir/.." and now be down to "..", in + * which case enter the correct state for that. + */ + if (parsed == spath) + state = RELATIVE_PATH_INIT; + else + state = RELATIVE_WITH_PARENT_REF; + } + } + else + { + /* Append normal dir */ + *parsed++ = '/'; + parsed = append_subdir_to_path(parsed, unparse); + pathdepth++; + } + break; + case RELATIVE_WITH_PARENT_REF: + if (is_double_dot) + { + /* Append next irreducible double-dot (..) */ + *parsed++ = '/'; + parsed = append_subdir_to_path(parsed, unparse); + } + else + { + /* Append normal dir */ + *parsed++ = '/'; + parsed = append_subdir_to_path(parsed, unparse); + + /* + * We can now start counting normal dirs. But if later + * double-dots make us remove this dir again, we'd better + * revert to RELATIVE_WITH_PARENT_REF not INIT state. + */ + state = RELATIVE_WITH_N_DEPTH; + pathdepth = 1; + } + break; + } + + unparse = unparse_next; + } + + /* + * If our output path is empty at this point, insert ".". We don't want + * to do this any earlier because it'd result in an extra dot in corner + * cases such as "../dir/..". Since we rejected the wholly-empty-path + * case above, there is certainly room. + */ + if (parsed == spath) + *parsed++ = '.'; + + /* And finally, ensure the output path is nul-terminated. */ + *parsed = '\0'; +} + +/* + * Detect whether a path contains any parent-directory references ("..") + * + * The input *must* have been put through canonicalize_path previously. + */ +bool +path_contains_parent_reference(const char *path) +{ + /* + * Once canonicalized, an absolute path cannot contain any ".." at all, + * while a relative path could contain ".."(s) only at the start. So it + * is sufficient to check the start of the path, after skipping any + * Windows drive/network specifier. + */ + path = skip_drive(path); /* C: shouldn't affect our conclusion */ + + if (path[0] == '.' && + path[1] == '.' && + (path[2] == '\0' || path[2] == '/')) + return true; + + return false; +} + +/* + * Detect whether a path is only in or below the current working directory. + * + * The input *must* have been put through canonicalize_path previously. + * + * An absolute path that matches the current working directory should + * return false (we only want relative to the cwd). + */ +bool +path_is_relative_and_below_cwd(const char *path) +{ + if (is_absolute_path(path)) + return false; + /* don't allow anything above the cwd */ + else if (path_contains_parent_reference(path)) + return false; +#ifdef WIN32 + + /* + * On Win32, a drive letter _not_ followed by a slash, e.g. 'E:abc', is + * relative to the cwd on that drive, or the drive's root directory if + * that drive has no cwd. Because the path itself cannot tell us which is + * the case, we have to assume the worst, i.e. that it is not below the + * cwd. We could use GetFullPathName() to find the full path but that + * could change if the current directory for the drive changes underneath + * us, so we just disallow it. + */ + else if (isalpha((unsigned char) path[0]) && path[1] == ':' && + !IS_DIR_SEP(path[2])) + return false; +#endif + else + return true; +} + +/* + * Detect whether path1 is a prefix of path2 (including equality). + * + * This is pretty trivial, but it seems better to export a function than + * to export IS_DIR_SEP. + */ +bool +path_is_prefix_of_path(const char *path1, const char *path2) +{ + int path1_len = strlen(path1); + + if (strncmp(path1, path2, path1_len) == 0 && + (IS_DIR_SEP(path2[path1_len]) || path2[path1_len] == '\0')) + return true; + return false; +} + +/* + * Extracts the actual name of the program as called - + * stripped of .exe suffix if any + */ +const char * +get_progname(const char *argv0) +{ + const char *nodir_name; + char *progname; + + nodir_name = last_dir_separator(argv0); + if (nodir_name) + nodir_name++; + else + nodir_name = skip_drive(argv0); + + /* + * Make a copy in case argv[0] is modified by ps_status. Leaks memory, but + * called only once. + */ + progname = strdup(nodir_name); + if (progname == NULL) + { + fprintf(stderr, "%s: out of memory\n", nodir_name); + abort(); /* This could exit the postmaster */ + } + +#if defined(__CYGWIN__) || defined(WIN32) + /* strip ".exe" suffix, regardless of case */ + if (strlen(progname) > sizeof(EXE) - 1 && + pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0) + progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0'; +#endif + + return progname; +} + + +/* + * dir_strcmp: strcmp except any two DIR_SEP characters are considered equal, + * and we honor filesystem case insensitivity if known + */ +static int +dir_strcmp(const char *s1, const char *s2) +{ + while (*s1 && *s2) + { + if ( +#ifndef WIN32 + *s1 != *s2 +#else + /* On windows, paths are case-insensitive */ + pg_tolower((unsigned char) *s1) != pg_tolower((unsigned char) *s2) +#endif + && !(IS_DIR_SEP(*s1) && IS_DIR_SEP(*s2))) + return (int) *s1 - (int) *s2; + s1++, s2++; + } + if (*s1) + return 1; /* s1 longer */ + if (*s2) + return -1; /* s2 longer */ + return 0; +} + + +/* + * make_relative_path - make a path relative to the actual binary location + * + * This function exists to support relocation of installation trees. + * + * ret_path is the output area (must be of size MAXPGPATH) + * target_path is the compiled-in path to the directory we want to find + * bin_path is the compiled-in path to the directory of executables + * my_exec_path is the actual location of my executable + * + * We determine the common prefix of target_path and bin_path, then compare + * the remainder of bin_path to the last directory component(s) of + * my_exec_path. If they match, build the result as the part of my_exec_path + * preceding the match, joined to the remainder of target_path. If no match, + * return target_path as-is. + * + * For example: + * target_path = '/usr/local/share/postgresql' + * bin_path = '/usr/local/bin' + * my_exec_path = '/opt/pgsql/bin/postgres' + * Given these inputs, the common prefix is '/usr/local/', the tail of + * bin_path is 'bin' which does match the last directory component of + * my_exec_path, so we would return '/opt/pgsql/share/postgresql' + */ +static void +make_relative_path(char *ret_path, const char *target_path, + const char *bin_path, const char *my_exec_path) +{ + int prefix_len; + int tail_start; + int tail_len; + int i; + + /* + * Determine the common prefix --- note we require it to end on a + * directory separator, consider eg '/usr/lib' and '/usr/libexec'. + */ + prefix_len = 0; + for (i = 0; target_path[i] && bin_path[i]; i++) + { + if (IS_DIR_SEP(target_path[i]) && IS_DIR_SEP(bin_path[i])) + prefix_len = i + 1; + else if (target_path[i] != bin_path[i]) + break; + } + if (prefix_len == 0) + goto no_match; /* no common prefix? */ + tail_len = strlen(bin_path) - prefix_len; + + /* + * Set up my_exec_path without the actual executable name, and + * canonicalize to simplify comparison to bin_path. + */ + strlcpy(ret_path, my_exec_path, MAXPGPATH); + trim_directory(ret_path); /* remove my executable name */ + canonicalize_path(ret_path); + + /* + * Tail match? + */ + tail_start = (int) strlen(ret_path) - tail_len; + if (tail_start > 0 && + IS_DIR_SEP(ret_path[tail_start - 1]) && + dir_strcmp(ret_path + tail_start, bin_path + prefix_len) == 0) + { + ret_path[tail_start] = '\0'; + trim_trailing_separator(ret_path); + join_path_components(ret_path, ret_path, target_path + prefix_len); + canonicalize_path(ret_path); + return; + } + +no_match: + strlcpy(ret_path, target_path, MAXPGPATH); + canonicalize_path(ret_path); +} + + +/* + * make_absolute_path + * + * If the given pathname isn't already absolute, make it so, interpreting + * it relative to the current working directory. + * + * Also canonicalizes the path. The result is always a malloc'd copy. + * + * In backend, failure cases result in ereport(ERROR); in frontend, + * we write a complaint on stderr and return NULL. + * + * Note: interpretation of relative-path arguments during postmaster startup + * should happen before doing ChangeToDataDir(), else the user will probably + * not like the results. + */ +char * +make_absolute_path(const char *path) +{ + char *new; + + /* Returning null for null input is convenient for some callers */ + if (path == NULL) + return NULL; + + if (!is_absolute_path(path)) + { + char *buf; + size_t buflen; + + buflen = MAXPGPATH; + for (;;) + { + buf = malloc(buflen); + if (!buf) + { +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#else + fprintf(stderr, _("out of memory\n")); + return NULL; +#endif + } + + if (getcwd(buf, buflen)) + break; + else if (errno == ERANGE) + { + free(buf); + buflen *= 2; + continue; + } + else + { + int save_errno = errno; + + free(buf); + errno = save_errno; +#ifndef FRONTEND + elog(ERROR, "could not get current working directory: %m"); +#else + fprintf(stderr, _("could not get current working directory: %s\n"), + strerror(errno)); + return NULL; +#endif + } + } + + new = malloc(strlen(buf) + strlen(path) + 2); + if (!new) + { + free(buf); +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#else + fprintf(stderr, _("out of memory\n")); + return NULL; +#endif + } + sprintf(new, "%s/%s", buf, path); + free(buf); + } + else + { + new = strdup(path); + if (!new) + { +#ifndef FRONTEND + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +#else + fprintf(stderr, _("out of memory\n")); + return NULL; +#endif + } + } + + /* Make sure punctuation is canonical, too */ + canonicalize_path(new); + + return new; +} + + +/* + * get_share_path + */ +void +get_share_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, PGSHAREDIR, PGBINDIR, my_exec_path); +} + +/* + * get_etc_path + */ +void +get_etc_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, SYSCONFDIR, PGBINDIR, my_exec_path); +} + +/* + * get_include_path + */ +void +get_include_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, INCLUDEDIR, PGBINDIR, my_exec_path); +} + +/* + * get_pkginclude_path + */ +void +get_pkginclude_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, PKGINCLUDEDIR, PGBINDIR, my_exec_path); +} + +/* + * get_includeserver_path + */ +void +get_includeserver_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, INCLUDEDIRSERVER, PGBINDIR, my_exec_path); +} + +/* + * get_lib_path + */ +void +get_lib_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path); +} + +/* + * get_pkglib_path + */ +void +get_pkglib_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path); +} + +/* + * get_locale_path + */ +void +get_locale_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, LOCALEDIR, PGBINDIR, my_exec_path); +} + +/* + * get_doc_path + */ +void +get_doc_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, DOCDIR, PGBINDIR, my_exec_path); +} + +/* + * get_html_path + */ +void +get_html_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, HTMLDIR, PGBINDIR, my_exec_path); +} + +/* + * get_man_path + */ +void +get_man_path(const char *my_exec_path, char *ret_path) +{ + make_relative_path(ret_path, MANDIR, PGBINDIR, my_exec_path); +} + + +/* + * get_home_path + * + * On Unix, this actually returns the user's home directory. On Windows + * it returns the PostgreSQL-specific application data folder. + */ +bool +get_home_path(char *ret_path) +{ +#ifndef WIN32 + /* + * We first consult $HOME. If that's unset, try to get the info from + * <pwd.h>. + */ + const char *home; + + home = getenv("HOME"); + if (home == NULL || home[0] == '\0') + return pg_get_user_home_dir(geteuid(), ret_path, MAXPGPATH); + strlcpy(ret_path, home, MAXPGPATH); + return true; +#else + char *tmppath; + + /* + * Note: We use getenv() here because the more modern SHGetFolderPath() + * would force the backend to link with shell32.lib, which eats valuable + * desktop heap. XXX This function is used only in psql, which already + * brings in shell32 via libpq. Moving this function to its own file + * would keep it out of the backend, freeing it from this concern. + */ + tmppath = getenv("APPDATA"); + if (!tmppath) + return false; + snprintf(ret_path, MAXPGPATH, "%s/postgresql", tmppath); + return true; +#endif +} + + +/* + * get_parent_directory + * + * Modify the given string in-place to name the parent directory of the + * named file. + * + * If the input is just a file name with no directory part, the result is + * an empty string, not ".". This is appropriate when the next step is + * join_path_components(), but might need special handling otherwise. + * + * Caution: this will not produce desirable results if the string ends + * with "..". For most callers this is not a problem since the string + * is already known to name a regular file. If in doubt, apply + * canonicalize_path() first. + */ +void +get_parent_directory(char *path) +{ + trim_directory(path); +} + + +/* + * trim_directory + * + * Trim trailing directory from path, that is, remove any trailing slashes, + * the last pathname component, and the slash just ahead of it --- but never + * remove a leading slash. + * + * For the convenience of canonicalize_path, the path's new end location + * is returned. + */ +static char * +trim_directory(char *path) +{ + char *p; + + path = skip_drive(path); + + if (path[0] == '\0') + return path; + + /* back up over trailing slash(es) */ + for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--) + ; + /* back up over directory name */ + for (; !IS_DIR_SEP(*p) && p > path; p--) + ; + /* if multiple slashes before directory name, remove 'em all */ + for (; p > path && IS_DIR_SEP(*(p - 1)); p--) + ; + /* don't erase a leading slash */ + if (p == path && IS_DIR_SEP(*p)) + p++; + *p = '\0'; + return p; +} + + +/* + * trim_trailing_separator + * + * trim off trailing slashes, but not a leading slash + */ +static void +trim_trailing_separator(char *path) +{ + char *p; + + path = skip_drive(path); + p = path + strlen(path); + if (p > path) + for (p--; p > path && IS_DIR_SEP(*p); p--) + *p = '\0'; +} + +/* + * append_subdir_to_path + * + * Append the currently-considered subdirectory name to the output + * path in canonicalize_path. Return the new end location of the + * output path. + * + * Since canonicalize_path updates the path in-place, we must use + * memmove not memcpy, and we don't yet terminate the path with '\0'. + */ +static char * +append_subdir_to_path(char *path, char *subdir) +{ + size_t len = strlen(subdir); + + /* No need to copy data if path and subdir are the same. */ + if (path != subdir) + memmove(path, subdir, len); + + return path + len; +} diff --git a/contrib/libs/libpq/src/port/pg_bitutils.c b/contrib/libs/libpq/src/port/pg_bitutils.c new file mode 100644 index 0000000000..1f3dea2d4b --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_bitutils.c @@ -0,0 +1,335 @@ +/*------------------------------------------------------------------------- + * + * pg_bitutils.c + * Miscellaneous functions for bit-wise operations. + * + * Copyright (c) 2019-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/pg_bitutils.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#ifdef HAVE__GET_CPUID +#include <cpuid.h> +#endif +#ifdef HAVE__CPUID +#include <intrin.h> +#endif + +#include "port/pg_bitutils.h" + + +/* + * Array giving the position of the left-most set bit for each possible + * byte value. We count the right-most position as the 0th bit, and the + * left-most the 7th bit. The 0th entry of the array should not be used. + * + * Note: this is not used by the functions in pg_bitutils.h when + * HAVE__BUILTIN_CLZ is defined, but we provide it anyway, so that + * extensions possibly compiled with a different compiler can use it. + */ +const uint8 pg_leftmost_one_pos[256] = { + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +/* + * Array giving the position of the right-most set bit for each possible + * byte value. We count the right-most position as the 0th bit, and the + * left-most the 7th bit. The 0th entry of the array should not be used. + * + * Note: this is not used by the functions in pg_bitutils.h when + * HAVE__BUILTIN_CTZ is defined, but we provide it anyway, so that + * extensions possibly compiled with a different compiler can use it. + */ +const uint8 pg_rightmost_one_pos[256] = { + 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* + * Array giving the number of 1-bits in each possible byte value. + * + * Note: we export this for use by functions in which explicit use + * of the popcount functions seems unlikely to be a win. + */ +const uint8 pg_number_of_ones[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; + +static int pg_popcount32_slow(uint32 word); +static int pg_popcount64_slow(uint64 word); + +#ifdef TRY_POPCNT_FAST +static bool pg_popcount_available(void); +static int pg_popcount32_choose(uint32 word); +static int pg_popcount64_choose(uint64 word); +static int pg_popcount32_fast(uint32 word); +static int pg_popcount64_fast(uint64 word); + +int (*pg_popcount32) (uint32 word) = pg_popcount32_choose; +int (*pg_popcount64) (uint64 word) = pg_popcount64_choose; +#endif /* TRY_POPCNT_FAST */ + +#ifdef TRY_POPCNT_FAST + +/* + * Return true if CPUID indicates that the POPCNT instruction is available. + */ +static bool +pg_popcount_available(void) +{ + unsigned int exx[4] = {0, 0, 0, 0}; + +#if defined(HAVE__GET_CPUID) + __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]); +#elif defined(HAVE__CPUID) + __cpuid(exx, 1); +#else +#error cpuid instruction not available +#endif + + return (exx[2] & (1 << 23)) != 0; /* POPCNT */ +} + +/* + * These functions get called on the first call to pg_popcount32 etc. + * They detect whether we can use the asm implementations, and replace + * the function pointers so that subsequent calls are routed directly to + * the chosen implementation. + */ +static int +pg_popcount32_choose(uint32 word) +{ + if (pg_popcount_available()) + { + pg_popcount32 = pg_popcount32_fast; + pg_popcount64 = pg_popcount64_fast; + } + else + { + pg_popcount32 = pg_popcount32_slow; + pg_popcount64 = pg_popcount64_slow; + } + + return pg_popcount32(word); +} + +static int +pg_popcount64_choose(uint64 word) +{ + if (pg_popcount_available()) + { + pg_popcount32 = pg_popcount32_fast; + pg_popcount64 = pg_popcount64_fast; + } + else + { + pg_popcount32 = pg_popcount32_slow; + pg_popcount64 = pg_popcount64_slow; + } + + return pg_popcount64(word); +} + +/* + * pg_popcount32_fast + * Return the number of 1 bits set in word + */ +static int +pg_popcount32_fast(uint32 word) +{ +#ifdef _MSC_VER + return __popcnt(word); +#else + uint32 res; + +__asm__ __volatile__(" popcntl %1,%0\n":"=q"(res):"rm"(word):"cc"); + return (int) res; +#endif +} + +/* + * pg_popcount64_fast + * Return the number of 1 bits set in word + */ +static int +pg_popcount64_fast(uint64 word) +{ +#ifdef _MSC_VER + return __popcnt64(word); +#else + uint64 res; + +__asm__ __volatile__(" popcntq %1,%0\n":"=q"(res):"rm"(word):"cc"); + return (int) res; +#endif +} + +#endif /* TRY_POPCNT_FAST */ + + +/* + * pg_popcount32_slow + * Return the number of 1 bits set in word + */ +static int +pg_popcount32_slow(uint32 word) +{ +#ifdef HAVE__BUILTIN_POPCOUNT + return __builtin_popcount(word); +#else /* !HAVE__BUILTIN_POPCOUNT */ + int result = 0; + + while (word != 0) + { + result += pg_number_of_ones[word & 255]; + word >>= 8; + } + + return result; +#endif /* HAVE__BUILTIN_POPCOUNT */ +} + +/* + * pg_popcount64_slow + * Return the number of 1 bits set in word + */ +static int +pg_popcount64_slow(uint64 word) +{ +#ifdef HAVE__BUILTIN_POPCOUNT +#if defined(HAVE_LONG_INT_64) + return __builtin_popcountl(word); +#elif defined(HAVE_LONG_LONG_INT_64) + return __builtin_popcountll(word); +#else +#error must have a working 64-bit integer datatype +#endif +#else /* !HAVE__BUILTIN_POPCOUNT */ + int result = 0; + + while (word != 0) + { + result += pg_number_of_ones[word & 255]; + word >>= 8; + } + + return result; +#endif /* HAVE__BUILTIN_POPCOUNT */ +} + +#ifndef TRY_POPCNT_FAST + +/* + * When the POPCNT instruction is not available, there's no point in using + * function pointers to vary the implementation between the fast and slow + * method. We instead just make these actual external functions when + * TRY_POPCNT_FAST is not defined. The compiler should be able to inline + * the slow versions here. + */ +int +pg_popcount32(uint32 word) +{ + return pg_popcount32_slow(word); +} + +int +pg_popcount64(uint64 word) +{ + return pg_popcount64_slow(word); +} + +#endif /* !TRY_POPCNT_FAST */ + +/* + * pg_popcount + * Returns the number of 1-bits in buf + */ +uint64 +pg_popcount(const char *buf, int bytes) +{ + uint64 popcnt = 0; + +#if SIZEOF_VOID_P >= 8 + /* Process in 64-bit chunks if the buffer is aligned. */ + if (buf == (const char *) TYPEALIGN(8, buf)) + { + const uint64 *words = (const uint64 *) buf; + + while (bytes >= 8) + { + popcnt += pg_popcount64(*words++); + bytes -= 8; + } + + buf = (const char *) words; + } +#else + /* Process in 32-bit chunks if the buffer is aligned. */ + if (buf == (const char *) TYPEALIGN(4, buf)) + { + const uint32 *words = (const uint32 *) buf; + + while (bytes >= 4) + { + popcnt += pg_popcount32(*words++); + bytes -= 4; + } + + buf = (const char *) words; + } +#endif + + /* Process any remaining bytes */ + while (bytes--) + popcnt += pg_number_of_ones[(unsigned char) *buf++]; + + return popcnt; +} diff --git a/contrib/libs/libpq/src/port/pg_config_paths.h b/contrib/libs/libpq/src/port/pg_config_paths.h new file mode 100644 index 0000000000..2e2db6a40c --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_config_paths.h @@ -0,0 +1,12 @@ +#define PGBINDIR "/var/empty/postgresql-16.1/bin" +#define PGSHAREDIR "/var/empty/postgresql-16.1/share" +#define SYSCONFDIR "/etc/postgresql" +#define INCLUDEDIR "/var/empty/postgresql-16.1/include" +#define PKGINCLUDEDIR "/var/empty/postgresql-16.1/include" +#define INCLUDEDIRSERVER "/var/empty/postgresql-16.1/include/server" +#define LIBDIR "/var/empty/tmp/out/lib" +#define PKGLIBDIR "/var/empty/tmp/out/lib/postgresql" +#define LOCALEDIR "/var/empty/postgresql-16.1/share/locale" +#define DOCDIR "/var/empty/postgresql-16.1/share/doc/" +#define HTMLDIR "/var/empty/postgresql-16.1/share/doc/" +#define MANDIR "/var/empty/postgresql-16.1/share/man" diff --git a/contrib/libs/libpq/src/port/pg_crc32c_sb8.c b/contrib/libs/libpq/src/port/pg_crc32c_sb8.c new file mode 100644 index 0000000000..cdd3e05123 --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_crc32c_sb8.c @@ -0,0 +1,1169 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c_sb8.c + * Compute CRC-32C checksum using slicing-by-8 algorithm. + * + * Michael E. Kounavis, Frank L. Berry, + * "Novel Table Lookup-Based Algorithms for High-Performance CRC + * Generation", IEEE Transactions on Computers, vol.57, no. 11, + * pp. 1550-1560, November 2008, doi:10.1109/TC.2008.85 + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/pg_crc32c_sb8.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include "port/pg_crc32c.h" + +static const uint32 pg_crc32c_table[8][256]; + +/* Accumulate one input byte */ +#ifdef WORDS_BIGENDIAN +#define CRC8(x) pg_crc32c_table[0][((crc >> 24) ^ (x)) & 0xFF] ^ (crc << 8) +#else +#define CRC8(x) pg_crc32c_table[0][(crc ^ (x)) & 0xFF] ^ (crc >> 8) +#endif + +pg_crc32c +pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len) +{ + const unsigned char *p = data; + const uint32 *p4; + + /* + * Handle 0-3 initial bytes one at a time, so that the loop below starts + * with a pointer aligned to four bytes. + */ + while (len > 0 && ((uintptr_t) p & 3)) + { + crc = CRC8(*p++); + len--; + } + + /* + * Process eight bytes of data at a time. + */ + p4 = (const uint32 *) p; + while (len >= 8) + { + uint32 a = *p4++ ^ crc; + uint32 b = *p4++; + +#ifdef WORDS_BIGENDIAN + const uint8 c0 = b; + const uint8 c1 = b >> 8; + const uint8 c2 = b >> 16; + const uint8 c3 = b >> 24; + const uint8 c4 = a; + const uint8 c5 = a >> 8; + const uint8 c6 = a >> 16; + const uint8 c7 = a >> 24; +#else + const uint8 c0 = b >> 24; + const uint8 c1 = b >> 16; + const uint8 c2 = b >> 8; + const uint8 c3 = b; + const uint8 c4 = a >> 24; + const uint8 c5 = a >> 16; + const uint8 c6 = a >> 8; + const uint8 c7 = a; +#endif + + crc = + pg_crc32c_table[0][c0] ^ pg_crc32c_table[1][c1] ^ + pg_crc32c_table[2][c2] ^ pg_crc32c_table[3][c3] ^ + pg_crc32c_table[4][c4] ^ pg_crc32c_table[5][c5] ^ + pg_crc32c_table[6][c6] ^ pg_crc32c_table[7][c7]; + + len -= 8; + } + + /* + * Handle any remaining bytes one at a time. + */ + p = (const unsigned char *) p4; + while (len > 0) + { + crc = CRC8(*p++); + len--; + } + + return crc; +} + +/* + * Lookup tables for the slicing-by-8 algorithm, for the so-called Castagnoli + * polynomial (the same that is used e.g. in iSCSI), 0x1EDC6F41. Using + * Williams' terms, this is the "normal", not "reflected" version. However, on + * big-endian systems the values in the tables are stored in byte-reversed + * order (IOW, the tables are stored in little-endian order even on big-endian + * systems). + */ +static const uint32 pg_crc32c_table[8][256] = { +#ifndef WORDS_BIGENDIAN + { + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, + 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, + 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, + 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, + 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, + 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, + 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, + 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, + 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, + 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, + 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, + 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, + 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, + 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, + 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, + 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, + 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, + 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, + 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, + 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, + 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, + 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, + 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, + 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, + 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, + 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, + 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, + 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, + 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, + 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, + 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, + 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, + 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 + }, + { + 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, + 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, + 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, + 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, + 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, + 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, + 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, + 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, + 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, + 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, + 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, + 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, + 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, + 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, + 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, + 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, + 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, + 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, + 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, + 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, + 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, + 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, + 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, + 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, + 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, + 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, + 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, + 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, + 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, + 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, + 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, + 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, + 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, + 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, + 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, + 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, + 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, + 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, + 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, + 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, + 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, + 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, + 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, + 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, + 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, + 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, + 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, + 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, + 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, + 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, + 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, + 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, + 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, + 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, + 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, + 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, + 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, + 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, + 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, + 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, + 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, + 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, + 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, + 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 + }, + { + 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, + 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, + 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, + 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, + 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, + 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, + 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, + 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, + 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, + 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, + 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, + 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, + 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, + 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, + 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, + 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, + 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, + 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, + 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, + 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, + 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, + 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, + 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, + 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, + 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, + 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, + 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, + 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, + 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, + 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, + 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, + 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, + 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, + 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, + 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, + 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, + 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, + 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, + 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, + 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, + 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, + 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, + 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, + 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, + 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, + 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, + 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, + 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, + 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, + 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, + 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, + 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, + 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, + 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, + 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, + 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, + 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, + 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, + 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, + 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, + 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, + 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, + 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, + 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 + }, + { + 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, + 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, + 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, + 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, + 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, + 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, + 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, + 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, + 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, + 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, + 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, + 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, + 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, + 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, + 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, + 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, + 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, + 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, + 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, + 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, + 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, + 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, + 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, + 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, + 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, + 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, + 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, + 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, + 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, + 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, + 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, + 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, + 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, + 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, + 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, + 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, + 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, + 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, + 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, + 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, + 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, + 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, + 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, + 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, + 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, + 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, + 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, + 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, + 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, + 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, + 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, + 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, + 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, + 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, + 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, + 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, + 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, + 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, + 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, + 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, + 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, + 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, + 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, + 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 + }, + { + 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, + 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, + 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, + 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, + 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, + 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, + 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, + 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, + 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, + 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, + 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, + 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, + 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, + 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, + 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, + 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, + 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, + 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, + 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, + 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, + 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, + 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, + 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, + 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, + 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, + 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, + 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, + 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, + 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, + 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, + 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, + 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, + 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, + 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, + 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, + 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, + 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, + 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, + 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, + 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, + 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, + 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, + 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, + 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, + 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, + 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, + 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, + 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, + 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, + 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, + 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, + 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, + 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, + 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, + 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, + 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, + 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, + 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, + 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, + 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, + 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, + 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, + 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, + 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 + }, + { + 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, + 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, + 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, + 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, + 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, + 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, + 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, + 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, + 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, + 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, + 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, + 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, + 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, + 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, + 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, + 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, + 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, + 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, + 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, + 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, + 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, + 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, + 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, + 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, + 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, + 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, + 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, + 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, + 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, + 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, + 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, + 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, + 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, + 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, + 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, + 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, + 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, + 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, + 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, + 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, + 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, + 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, + 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, + 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, + 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, + 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, + 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, + 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, + 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, + 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, + 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, + 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, + 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, + 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, + 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, + 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, + 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, + 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, + 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, + 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, + 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, + 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, + 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, + 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C + }, + { + 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, + 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, + 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, + 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, + 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, + 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, + 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, + 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, + 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, + 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, + 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, + 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, + 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, + 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, + 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, + 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, + 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, + 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, + 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, + 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, + 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, + 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, + 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, + 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, + 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, + 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, + 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, + 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, + 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, + 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, + 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, + 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, + 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, + 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, + 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, + 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, + 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, + 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, + 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, + 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, + 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, + 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, + 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, + 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, + 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, + 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, + 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, + 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, + 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, + 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, + 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, + 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, + 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, + 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, + 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, + 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, + 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, + 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, + 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, + 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, + 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, + 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, + 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, + 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F + }, + { + 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, + 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, + 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, + 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, + 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, + 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, + 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, + 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, + 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, + 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, + 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, + 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, + 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, + 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, + 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, + 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, + 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, + 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, + 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, + 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, + 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, + 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, + 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, + 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, + 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, + 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, + 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, + 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, + 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, + 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, + 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, + 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, + 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, + 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, + 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, + 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, + 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, + 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, + 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, + 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, + 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, + 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, + 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, + 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, + 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, + 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, + 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, + 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, + 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, + 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, + 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, + 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, + 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, + 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, + 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, + 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, + 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, + 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, + 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, + 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, + 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, + 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, + 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, + 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 + } +#else /* !WORDS_BIGENDIAN */ + { + 0x00000000, 0x03836BF2, 0xF7703BE1, 0xF4F35013, + 0x1F979AC7, 0x1C14F135, 0xE8E7A126, 0xEB64CAD4, + 0xCF58D98A, 0xCCDBB278, 0x3828E26B, 0x3BAB8999, + 0xD0CF434D, 0xD34C28BF, 0x27BF78AC, 0x243C135E, + 0x6FC75E10, 0x6C4435E2, 0x98B765F1, 0x9B340E03, + 0x7050C4D7, 0x73D3AF25, 0x8720FF36, 0x84A394C4, + 0xA09F879A, 0xA31CEC68, 0x57EFBC7B, 0x546CD789, + 0xBF081D5D, 0xBC8B76AF, 0x487826BC, 0x4BFB4D4E, + 0xDE8EBD20, 0xDD0DD6D2, 0x29FE86C1, 0x2A7DED33, + 0xC11927E7, 0xC29A4C15, 0x36691C06, 0x35EA77F4, + 0x11D664AA, 0x12550F58, 0xE6A65F4B, 0xE52534B9, + 0x0E41FE6D, 0x0DC2959F, 0xF931C58C, 0xFAB2AE7E, + 0xB149E330, 0xB2CA88C2, 0x4639D8D1, 0x45BAB323, + 0xAEDE79F7, 0xAD5D1205, 0x59AE4216, 0x5A2D29E4, + 0x7E113ABA, 0x7D925148, 0x8961015B, 0x8AE26AA9, + 0x6186A07D, 0x6205CB8F, 0x96F69B9C, 0x9575F06E, + 0xBC1D7B41, 0xBF9E10B3, 0x4B6D40A0, 0x48EE2B52, + 0xA38AE186, 0xA0098A74, 0x54FADA67, 0x5779B195, + 0x7345A2CB, 0x70C6C939, 0x8435992A, 0x87B6F2D8, + 0x6CD2380C, 0x6F5153FE, 0x9BA203ED, 0x9821681F, + 0xD3DA2551, 0xD0594EA3, 0x24AA1EB0, 0x27297542, + 0xCC4DBF96, 0xCFCED464, 0x3B3D8477, 0x38BEEF85, + 0x1C82FCDB, 0x1F019729, 0xEBF2C73A, 0xE871ACC8, + 0x0315661C, 0x00960DEE, 0xF4655DFD, 0xF7E6360F, + 0x6293C661, 0x6110AD93, 0x95E3FD80, 0x96609672, + 0x7D045CA6, 0x7E873754, 0x8A746747, 0x89F70CB5, + 0xADCB1FEB, 0xAE487419, 0x5ABB240A, 0x59384FF8, + 0xB25C852C, 0xB1DFEEDE, 0x452CBECD, 0x46AFD53F, + 0x0D549871, 0x0ED7F383, 0xFA24A390, 0xF9A7C862, + 0x12C302B6, 0x11406944, 0xE5B33957, 0xE63052A5, + 0xC20C41FB, 0xC18F2A09, 0x357C7A1A, 0x36FF11E8, + 0xDD9BDB3C, 0xDE18B0CE, 0x2AEBE0DD, 0x29688B2F, + 0x783BF682, 0x7BB89D70, 0x8F4BCD63, 0x8CC8A691, + 0x67AC6C45, 0x642F07B7, 0x90DC57A4, 0x935F3C56, + 0xB7632F08, 0xB4E044FA, 0x401314E9, 0x43907F1B, + 0xA8F4B5CF, 0xAB77DE3D, 0x5F848E2E, 0x5C07E5DC, + 0x17FCA892, 0x147FC360, 0xE08C9373, 0xE30FF881, + 0x086B3255, 0x0BE859A7, 0xFF1B09B4, 0xFC986246, + 0xD8A47118, 0xDB271AEA, 0x2FD44AF9, 0x2C57210B, + 0xC733EBDF, 0xC4B0802D, 0x3043D03E, 0x33C0BBCC, + 0xA6B54BA2, 0xA5362050, 0x51C57043, 0x52461BB1, + 0xB922D165, 0xBAA1BA97, 0x4E52EA84, 0x4DD18176, + 0x69ED9228, 0x6A6EF9DA, 0x9E9DA9C9, 0x9D1EC23B, + 0x767A08EF, 0x75F9631D, 0x810A330E, 0x828958FC, + 0xC97215B2, 0xCAF17E40, 0x3E022E53, 0x3D8145A1, + 0xD6E58F75, 0xD566E487, 0x2195B494, 0x2216DF66, + 0x062ACC38, 0x05A9A7CA, 0xF15AF7D9, 0xF2D99C2B, + 0x19BD56FF, 0x1A3E3D0D, 0xEECD6D1E, 0xED4E06EC, + 0xC4268DC3, 0xC7A5E631, 0x3356B622, 0x30D5DDD0, + 0xDBB11704, 0xD8327CF6, 0x2CC12CE5, 0x2F424717, + 0x0B7E5449, 0x08FD3FBB, 0xFC0E6FA8, 0xFF8D045A, + 0x14E9CE8E, 0x176AA57C, 0xE399F56F, 0xE01A9E9D, + 0xABE1D3D3, 0xA862B821, 0x5C91E832, 0x5F1283C0, + 0xB4764914, 0xB7F522E6, 0x430672F5, 0x40851907, + 0x64B90A59, 0x673A61AB, 0x93C931B8, 0x904A5A4A, + 0x7B2E909E, 0x78ADFB6C, 0x8C5EAB7F, 0x8FDDC08D, + 0x1AA830E3, 0x192B5B11, 0xEDD80B02, 0xEE5B60F0, + 0x053FAA24, 0x06BCC1D6, 0xF24F91C5, 0xF1CCFA37, + 0xD5F0E969, 0xD673829B, 0x2280D288, 0x2103B97A, + 0xCA6773AE, 0xC9E4185C, 0x3D17484F, 0x3E9423BD, + 0x756F6EF3, 0x76EC0501, 0x821F5512, 0x819C3EE0, + 0x6AF8F434, 0x697B9FC6, 0x9D88CFD5, 0x9E0BA427, + 0xBA37B779, 0xB9B4DC8B, 0x4D478C98, 0x4EC4E76A, + 0xA5A02DBE, 0xA623464C, 0x52D0165F, 0x51537DAD, + }, + { + 0x00000000, 0x7798A213, 0xEE304527, 0x99A8E734, + 0xDC618A4E, 0xABF9285D, 0x3251CF69, 0x45C96D7A, + 0xB8C3149D, 0xCF5BB68E, 0x56F351BA, 0x216BF3A9, + 0x64A29ED3, 0x133A3CC0, 0x8A92DBF4, 0xFD0A79E7, + 0x81F1C53F, 0xF669672C, 0x6FC18018, 0x1859220B, + 0x5D904F71, 0x2A08ED62, 0xB3A00A56, 0xC438A845, + 0x3932D1A2, 0x4EAA73B1, 0xD7029485, 0xA09A3696, + 0xE5535BEC, 0x92CBF9FF, 0x0B631ECB, 0x7CFBBCD8, + 0x02E38B7F, 0x757B296C, 0xECD3CE58, 0x9B4B6C4B, + 0xDE820131, 0xA91AA322, 0x30B24416, 0x472AE605, + 0xBA209FE2, 0xCDB83DF1, 0x5410DAC5, 0x238878D6, + 0x664115AC, 0x11D9B7BF, 0x8871508B, 0xFFE9F298, + 0x83124E40, 0xF48AEC53, 0x6D220B67, 0x1ABAA974, + 0x5F73C40E, 0x28EB661D, 0xB1438129, 0xC6DB233A, + 0x3BD15ADD, 0x4C49F8CE, 0xD5E11FFA, 0xA279BDE9, + 0xE7B0D093, 0x90287280, 0x098095B4, 0x7E1837A7, + 0x04C617FF, 0x735EB5EC, 0xEAF652D8, 0x9D6EF0CB, + 0xD8A79DB1, 0xAF3F3FA2, 0x3697D896, 0x410F7A85, + 0xBC050362, 0xCB9DA171, 0x52354645, 0x25ADE456, + 0x6064892C, 0x17FC2B3F, 0x8E54CC0B, 0xF9CC6E18, + 0x8537D2C0, 0xF2AF70D3, 0x6B0797E7, 0x1C9F35F4, + 0x5956588E, 0x2ECEFA9D, 0xB7661DA9, 0xC0FEBFBA, + 0x3DF4C65D, 0x4A6C644E, 0xD3C4837A, 0xA45C2169, + 0xE1954C13, 0x960DEE00, 0x0FA50934, 0x783DAB27, + 0x06259C80, 0x71BD3E93, 0xE815D9A7, 0x9F8D7BB4, + 0xDA4416CE, 0xADDCB4DD, 0x347453E9, 0x43ECF1FA, + 0xBEE6881D, 0xC97E2A0E, 0x50D6CD3A, 0x274E6F29, + 0x62870253, 0x151FA040, 0x8CB74774, 0xFB2FE567, + 0x87D459BF, 0xF04CFBAC, 0x69E41C98, 0x1E7CBE8B, + 0x5BB5D3F1, 0x2C2D71E2, 0xB58596D6, 0xC21D34C5, + 0x3F174D22, 0x488FEF31, 0xD1270805, 0xA6BFAA16, + 0xE376C76C, 0x94EE657F, 0x0D46824B, 0x7ADE2058, + 0xF9FAC3FB, 0x8E6261E8, 0x17CA86DC, 0x605224CF, + 0x259B49B5, 0x5203EBA6, 0xCBAB0C92, 0xBC33AE81, + 0x4139D766, 0x36A17575, 0xAF099241, 0xD8913052, + 0x9D585D28, 0xEAC0FF3B, 0x7368180F, 0x04F0BA1C, + 0x780B06C4, 0x0F93A4D7, 0x963B43E3, 0xE1A3E1F0, + 0xA46A8C8A, 0xD3F22E99, 0x4A5AC9AD, 0x3DC26BBE, + 0xC0C81259, 0xB750B04A, 0x2EF8577E, 0x5960F56D, + 0x1CA99817, 0x6B313A04, 0xF299DD30, 0x85017F23, + 0xFB194884, 0x8C81EA97, 0x15290DA3, 0x62B1AFB0, + 0x2778C2CA, 0x50E060D9, 0xC94887ED, 0xBED025FE, + 0x43DA5C19, 0x3442FE0A, 0xADEA193E, 0xDA72BB2D, + 0x9FBBD657, 0xE8237444, 0x718B9370, 0x06133163, + 0x7AE88DBB, 0x0D702FA8, 0x94D8C89C, 0xE3406A8F, + 0xA68907F5, 0xD111A5E6, 0x48B942D2, 0x3F21E0C1, + 0xC22B9926, 0xB5B33B35, 0x2C1BDC01, 0x5B837E12, + 0x1E4A1368, 0x69D2B17B, 0xF07A564F, 0x87E2F45C, + 0xFD3CD404, 0x8AA47617, 0x130C9123, 0x64943330, + 0x215D5E4A, 0x56C5FC59, 0xCF6D1B6D, 0xB8F5B97E, + 0x45FFC099, 0x3267628A, 0xABCF85BE, 0xDC5727AD, + 0x999E4AD7, 0xEE06E8C4, 0x77AE0FF0, 0x0036ADE3, + 0x7CCD113B, 0x0B55B328, 0x92FD541C, 0xE565F60F, + 0xA0AC9B75, 0xD7343966, 0x4E9CDE52, 0x39047C41, + 0xC40E05A6, 0xB396A7B5, 0x2A3E4081, 0x5DA6E292, + 0x186F8FE8, 0x6FF72DFB, 0xF65FCACF, 0x81C768DC, + 0xFFDF5F7B, 0x8847FD68, 0x11EF1A5C, 0x6677B84F, + 0x23BED535, 0x54267726, 0xCD8E9012, 0xBA163201, + 0x471C4BE6, 0x3084E9F5, 0xA92C0EC1, 0xDEB4ACD2, + 0x9B7DC1A8, 0xECE563BB, 0x754D848F, 0x02D5269C, + 0x7E2E9A44, 0x09B63857, 0x901EDF63, 0xE7867D70, + 0xA24F100A, 0xD5D7B219, 0x4C7F552D, 0x3BE7F73E, + 0xC6ED8ED9, 0xB1752CCA, 0x28DDCBFE, 0x5F4569ED, + 0x1A8C0497, 0x6D14A684, 0xF4BC41B0, 0x8324E3A3, + }, + { + 0x00000000, 0x7E9241A5, 0x0D526F4F, 0x73C02EEA, + 0x1AA4DE9E, 0x64369F3B, 0x17F6B1D1, 0x6964F074, + 0xC53E5138, 0xBBAC109D, 0xC86C3E77, 0xB6FE7FD2, + 0xDF9A8FA6, 0xA108CE03, 0xD2C8E0E9, 0xAC5AA14C, + 0x8A7DA270, 0xF4EFE3D5, 0x872FCD3F, 0xF9BD8C9A, + 0x90D97CEE, 0xEE4B3D4B, 0x9D8B13A1, 0xE3195204, + 0x4F43F348, 0x31D1B2ED, 0x42119C07, 0x3C83DDA2, + 0x55E72DD6, 0x2B756C73, 0x58B54299, 0x2627033C, + 0x14FB44E1, 0x6A690544, 0x19A92BAE, 0x673B6A0B, + 0x0E5F9A7F, 0x70CDDBDA, 0x030DF530, 0x7D9FB495, + 0xD1C515D9, 0xAF57547C, 0xDC977A96, 0xA2053B33, + 0xCB61CB47, 0xB5F38AE2, 0xC633A408, 0xB8A1E5AD, + 0x9E86E691, 0xE014A734, 0x93D489DE, 0xED46C87B, + 0x8422380F, 0xFAB079AA, 0x89705740, 0xF7E216E5, + 0x5BB8B7A9, 0x252AF60C, 0x56EAD8E6, 0x28789943, + 0x411C6937, 0x3F8E2892, 0x4C4E0678, 0x32DC47DD, + 0xD98065C7, 0xA7122462, 0xD4D20A88, 0xAA404B2D, + 0xC324BB59, 0xBDB6FAFC, 0xCE76D416, 0xB0E495B3, + 0x1CBE34FF, 0x622C755A, 0x11EC5BB0, 0x6F7E1A15, + 0x061AEA61, 0x7888ABC4, 0x0B48852E, 0x75DAC48B, + 0x53FDC7B7, 0x2D6F8612, 0x5EAFA8F8, 0x203DE95D, + 0x49591929, 0x37CB588C, 0x440B7666, 0x3A9937C3, + 0x96C3968F, 0xE851D72A, 0x9B91F9C0, 0xE503B865, + 0x8C674811, 0xF2F509B4, 0x8135275E, 0xFFA766FB, + 0xCD7B2126, 0xB3E96083, 0xC0294E69, 0xBEBB0FCC, + 0xD7DFFFB8, 0xA94DBE1D, 0xDA8D90F7, 0xA41FD152, + 0x0845701E, 0x76D731BB, 0x05171F51, 0x7B855EF4, + 0x12E1AE80, 0x6C73EF25, 0x1FB3C1CF, 0x6121806A, + 0x47068356, 0x3994C2F3, 0x4A54EC19, 0x34C6ADBC, + 0x5DA25DC8, 0x23301C6D, 0x50F03287, 0x2E627322, + 0x8238D26E, 0xFCAA93CB, 0x8F6ABD21, 0xF1F8FC84, + 0x989C0CF0, 0xE60E4D55, 0x95CE63BF, 0xEB5C221A, + 0x4377278B, 0x3DE5662E, 0x4E2548C4, 0x30B70961, + 0x59D3F915, 0x2741B8B0, 0x5481965A, 0x2A13D7FF, + 0x864976B3, 0xF8DB3716, 0x8B1B19FC, 0xF5895859, + 0x9CEDA82D, 0xE27FE988, 0x91BFC762, 0xEF2D86C7, + 0xC90A85FB, 0xB798C45E, 0xC458EAB4, 0xBACAAB11, + 0xD3AE5B65, 0xAD3C1AC0, 0xDEFC342A, 0xA06E758F, + 0x0C34D4C3, 0x72A69566, 0x0166BB8C, 0x7FF4FA29, + 0x16900A5D, 0x68024BF8, 0x1BC26512, 0x655024B7, + 0x578C636A, 0x291E22CF, 0x5ADE0C25, 0x244C4D80, + 0x4D28BDF4, 0x33BAFC51, 0x407AD2BB, 0x3EE8931E, + 0x92B23252, 0xEC2073F7, 0x9FE05D1D, 0xE1721CB8, + 0x8816ECCC, 0xF684AD69, 0x85448383, 0xFBD6C226, + 0xDDF1C11A, 0xA36380BF, 0xD0A3AE55, 0xAE31EFF0, + 0xC7551F84, 0xB9C75E21, 0xCA0770CB, 0xB495316E, + 0x18CF9022, 0x665DD187, 0x159DFF6D, 0x6B0FBEC8, + 0x026B4EBC, 0x7CF90F19, 0x0F3921F3, 0x71AB6056, + 0x9AF7424C, 0xE46503E9, 0x97A52D03, 0xE9376CA6, + 0x80539CD2, 0xFEC1DD77, 0x8D01F39D, 0xF393B238, + 0x5FC91374, 0x215B52D1, 0x529B7C3B, 0x2C093D9E, + 0x456DCDEA, 0x3BFF8C4F, 0x483FA2A5, 0x36ADE300, + 0x108AE03C, 0x6E18A199, 0x1DD88F73, 0x634ACED6, + 0x0A2E3EA2, 0x74BC7F07, 0x077C51ED, 0x79EE1048, + 0xD5B4B104, 0xAB26F0A1, 0xD8E6DE4B, 0xA6749FEE, + 0xCF106F9A, 0xB1822E3F, 0xC24200D5, 0xBCD04170, + 0x8E0C06AD, 0xF09E4708, 0x835E69E2, 0xFDCC2847, + 0x94A8D833, 0xEA3A9996, 0x99FAB77C, 0xE768F6D9, + 0x4B325795, 0x35A01630, 0x466038DA, 0x38F2797F, + 0x5196890B, 0x2F04C8AE, 0x5CC4E644, 0x2256A7E1, + 0x0471A4DD, 0x7AE3E578, 0x0923CB92, 0x77B18A37, + 0x1ED57A43, 0x60473BE6, 0x1387150C, 0x6D1554A9, + 0xC14FF5E5, 0xBFDDB440, 0xCC1D9AAA, 0xB28FDB0F, + 0xDBEB2B7B, 0xA5796ADE, 0xD6B94434, 0xA82B0591, + }, + { + 0x00000000, 0xB8AA45DD, 0x812367BF, 0x39892262, + 0xF331227B, 0x4B9B67A6, 0x721245C4, 0xCAB80019, + 0xE66344F6, 0x5EC9012B, 0x67402349, 0xDFEA6694, + 0x1552668D, 0xADF82350, 0x94710132, 0x2CDB44EF, + 0x3DB164E9, 0x851B2134, 0xBC920356, 0x0438468B, + 0xCE804692, 0x762A034F, 0x4FA3212D, 0xF70964F0, + 0xDBD2201F, 0x637865C2, 0x5AF147A0, 0xE25B027D, + 0x28E30264, 0x904947B9, 0xA9C065DB, 0x116A2006, + 0x8B1425D7, 0x33BE600A, 0x0A374268, 0xB29D07B5, + 0x782507AC, 0xC08F4271, 0xF9066013, 0x41AC25CE, + 0x6D776121, 0xD5DD24FC, 0xEC54069E, 0x54FE4343, + 0x9E46435A, 0x26EC0687, 0x1F6524E5, 0xA7CF6138, + 0xB6A5413E, 0x0E0F04E3, 0x37862681, 0x8F2C635C, + 0x45946345, 0xFD3E2698, 0xC4B704FA, 0x7C1D4127, + 0x50C605C8, 0xE86C4015, 0xD1E56277, 0x694F27AA, + 0xA3F727B3, 0x1B5D626E, 0x22D4400C, 0x9A7E05D1, + 0xE75FA6AB, 0x5FF5E376, 0x667CC114, 0xDED684C9, + 0x146E84D0, 0xACC4C10D, 0x954DE36F, 0x2DE7A6B2, + 0x013CE25D, 0xB996A780, 0x801F85E2, 0x38B5C03F, + 0xF20DC026, 0x4AA785FB, 0x732EA799, 0xCB84E244, + 0xDAEEC242, 0x6244879F, 0x5BCDA5FD, 0xE367E020, + 0x29DFE039, 0x9175A5E4, 0xA8FC8786, 0x1056C25B, + 0x3C8D86B4, 0x8427C369, 0xBDAEE10B, 0x0504A4D6, + 0xCFBCA4CF, 0x7716E112, 0x4E9FC370, 0xF63586AD, + 0x6C4B837C, 0xD4E1C6A1, 0xED68E4C3, 0x55C2A11E, + 0x9F7AA107, 0x27D0E4DA, 0x1E59C6B8, 0xA6F38365, + 0x8A28C78A, 0x32828257, 0x0B0BA035, 0xB3A1E5E8, + 0x7919E5F1, 0xC1B3A02C, 0xF83A824E, 0x4090C793, + 0x51FAE795, 0xE950A248, 0xD0D9802A, 0x6873C5F7, + 0xA2CBC5EE, 0x1A618033, 0x23E8A251, 0x9B42E78C, + 0xB799A363, 0x0F33E6BE, 0x36BAC4DC, 0x8E108101, + 0x44A88118, 0xFC02C4C5, 0xC58BE6A7, 0x7D21A37A, + 0x3FC9A052, 0x8763E58F, 0xBEEAC7ED, 0x06408230, + 0xCCF88229, 0x7452C7F4, 0x4DDBE596, 0xF571A04B, + 0xD9AAE4A4, 0x6100A179, 0x5889831B, 0xE023C6C6, + 0x2A9BC6DF, 0x92318302, 0xABB8A160, 0x1312E4BD, + 0x0278C4BB, 0xBAD28166, 0x835BA304, 0x3BF1E6D9, + 0xF149E6C0, 0x49E3A31D, 0x706A817F, 0xC8C0C4A2, + 0xE41B804D, 0x5CB1C590, 0x6538E7F2, 0xDD92A22F, + 0x172AA236, 0xAF80E7EB, 0x9609C589, 0x2EA38054, + 0xB4DD8585, 0x0C77C058, 0x35FEE23A, 0x8D54A7E7, + 0x47ECA7FE, 0xFF46E223, 0xC6CFC041, 0x7E65859C, + 0x52BEC173, 0xEA1484AE, 0xD39DA6CC, 0x6B37E311, + 0xA18FE308, 0x1925A6D5, 0x20AC84B7, 0x9806C16A, + 0x896CE16C, 0x31C6A4B1, 0x084F86D3, 0xB0E5C30E, + 0x7A5DC317, 0xC2F786CA, 0xFB7EA4A8, 0x43D4E175, + 0x6F0FA59A, 0xD7A5E047, 0xEE2CC225, 0x568687F8, + 0x9C3E87E1, 0x2494C23C, 0x1D1DE05E, 0xA5B7A583, + 0xD89606F9, 0x603C4324, 0x59B56146, 0xE11F249B, + 0x2BA72482, 0x930D615F, 0xAA84433D, 0x122E06E0, + 0x3EF5420F, 0x865F07D2, 0xBFD625B0, 0x077C606D, + 0xCDC46074, 0x756E25A9, 0x4CE707CB, 0xF44D4216, + 0xE5276210, 0x5D8D27CD, 0x640405AF, 0xDCAE4072, + 0x1616406B, 0xAEBC05B6, 0x973527D4, 0x2F9F6209, + 0x034426E6, 0xBBEE633B, 0x82674159, 0x3ACD0484, + 0xF075049D, 0x48DF4140, 0x71566322, 0xC9FC26FF, + 0x5382232E, 0xEB2866F3, 0xD2A14491, 0x6A0B014C, + 0xA0B30155, 0x18194488, 0x219066EA, 0x993A2337, + 0xB5E167D8, 0x0D4B2205, 0x34C20067, 0x8C6845BA, + 0x46D045A3, 0xFE7A007E, 0xC7F3221C, 0x7F5967C1, + 0x6E3347C7, 0xD699021A, 0xEF102078, 0x57BA65A5, + 0x9D0265BC, 0x25A82061, 0x1C210203, 0xA48B47DE, + 0x88500331, 0x30FA46EC, 0x0973648E, 0xB1D92153, + 0x7B61214A, 0xC3CB6497, 0xFA4246F5, 0x42E80328, + }, + { + 0x00000000, 0xAC6F1138, 0x58DF2270, 0xF4B03348, + 0xB0BE45E0, 0x1CD154D8, 0xE8616790, 0x440E76A8, + 0x910B67C5, 0x3D6476FD, 0xC9D445B5, 0x65BB548D, + 0x21B52225, 0x8DDA331D, 0x796A0055, 0xD505116D, + 0xD361228F, 0x7F0E33B7, 0x8BBE00FF, 0x27D111C7, + 0x63DF676F, 0xCFB07657, 0x3B00451F, 0x976F5427, + 0x426A454A, 0xEE055472, 0x1AB5673A, 0xB6DA7602, + 0xF2D400AA, 0x5EBB1192, 0xAA0B22DA, 0x066433E2, + 0x57B5A81B, 0xFBDAB923, 0x0F6A8A6B, 0xA3059B53, + 0xE70BEDFB, 0x4B64FCC3, 0xBFD4CF8B, 0x13BBDEB3, + 0xC6BECFDE, 0x6AD1DEE6, 0x9E61EDAE, 0x320EFC96, + 0x76008A3E, 0xDA6F9B06, 0x2EDFA84E, 0x82B0B976, + 0x84D48A94, 0x28BB9BAC, 0xDC0BA8E4, 0x7064B9DC, + 0x346ACF74, 0x9805DE4C, 0x6CB5ED04, 0xC0DAFC3C, + 0x15DFED51, 0xB9B0FC69, 0x4D00CF21, 0xE16FDE19, + 0xA561A8B1, 0x090EB989, 0xFDBE8AC1, 0x51D19BF9, + 0xAE6A5137, 0x0205400F, 0xF6B57347, 0x5ADA627F, + 0x1ED414D7, 0xB2BB05EF, 0x460B36A7, 0xEA64279F, + 0x3F6136F2, 0x930E27CA, 0x67BE1482, 0xCBD105BA, + 0x8FDF7312, 0x23B0622A, 0xD7005162, 0x7B6F405A, + 0x7D0B73B8, 0xD1646280, 0x25D451C8, 0x89BB40F0, + 0xCDB53658, 0x61DA2760, 0x956A1428, 0x39050510, + 0xEC00147D, 0x406F0545, 0xB4DF360D, 0x18B02735, + 0x5CBE519D, 0xF0D140A5, 0x046173ED, 0xA80E62D5, + 0xF9DFF92C, 0x55B0E814, 0xA100DB5C, 0x0D6FCA64, + 0x4961BCCC, 0xE50EADF4, 0x11BE9EBC, 0xBDD18F84, + 0x68D49EE9, 0xC4BB8FD1, 0x300BBC99, 0x9C64ADA1, + 0xD86ADB09, 0x7405CA31, 0x80B5F979, 0x2CDAE841, + 0x2ABEDBA3, 0x86D1CA9B, 0x7261F9D3, 0xDE0EE8EB, + 0x9A009E43, 0x366F8F7B, 0xC2DFBC33, 0x6EB0AD0B, + 0xBBB5BC66, 0x17DAAD5E, 0xE36A9E16, 0x4F058F2E, + 0x0B0BF986, 0xA764E8BE, 0x53D4DBF6, 0xFFBBCACE, + 0x5CD5A26E, 0xF0BAB356, 0x040A801E, 0xA8659126, + 0xEC6BE78E, 0x4004F6B6, 0xB4B4C5FE, 0x18DBD4C6, + 0xCDDEC5AB, 0x61B1D493, 0x9501E7DB, 0x396EF6E3, + 0x7D60804B, 0xD10F9173, 0x25BFA23B, 0x89D0B303, + 0x8FB480E1, 0x23DB91D9, 0xD76BA291, 0x7B04B3A9, + 0x3F0AC501, 0x9365D439, 0x67D5E771, 0xCBBAF649, + 0x1EBFE724, 0xB2D0F61C, 0x4660C554, 0xEA0FD46C, + 0xAE01A2C4, 0x026EB3FC, 0xF6DE80B4, 0x5AB1918C, + 0x0B600A75, 0xA70F1B4D, 0x53BF2805, 0xFFD0393D, + 0xBBDE4F95, 0x17B15EAD, 0xE3016DE5, 0x4F6E7CDD, + 0x9A6B6DB0, 0x36047C88, 0xC2B44FC0, 0x6EDB5EF8, + 0x2AD52850, 0x86BA3968, 0x720A0A20, 0xDE651B18, + 0xD80128FA, 0x746E39C2, 0x80DE0A8A, 0x2CB11BB2, + 0x68BF6D1A, 0xC4D07C22, 0x30604F6A, 0x9C0F5E52, + 0x490A4F3F, 0xE5655E07, 0x11D56D4F, 0xBDBA7C77, + 0xF9B40ADF, 0x55DB1BE7, 0xA16B28AF, 0x0D043997, + 0xF2BFF359, 0x5ED0E261, 0xAA60D129, 0x060FC011, + 0x4201B6B9, 0xEE6EA781, 0x1ADE94C9, 0xB6B185F1, + 0x63B4949C, 0xCFDB85A4, 0x3B6BB6EC, 0x9704A7D4, + 0xD30AD17C, 0x7F65C044, 0x8BD5F30C, 0x27BAE234, + 0x21DED1D6, 0x8DB1C0EE, 0x7901F3A6, 0xD56EE29E, + 0x91609436, 0x3D0F850E, 0xC9BFB646, 0x65D0A77E, + 0xB0D5B613, 0x1CBAA72B, 0xE80A9463, 0x4465855B, + 0x006BF3F3, 0xAC04E2CB, 0x58B4D183, 0xF4DBC0BB, + 0xA50A5B42, 0x09654A7A, 0xFDD57932, 0x51BA680A, + 0x15B41EA2, 0xB9DB0F9A, 0x4D6B3CD2, 0xE1042DEA, + 0x34013C87, 0x986E2DBF, 0x6CDE1EF7, 0xC0B10FCF, + 0x84BF7967, 0x28D0685F, 0xDC605B17, 0x700F4A2F, + 0x766B79CD, 0xDA0468F5, 0x2EB45BBD, 0x82DB4A85, + 0xC6D53C2D, 0x6ABA2D15, 0x9E0A1E5D, 0x32650F65, + 0xE7601E08, 0x4B0F0F30, 0xBFBF3C78, 0x13D02D40, + 0x57DE5BE8, 0xFBB14AD0, 0x0F017998, 0xA36E68A0, + }, + { + 0x00000000, 0x196B30EF, 0xC3A08CDB, 0xDACBBC34, + 0x7737F5B2, 0x6E5CC55D, 0xB4977969, 0xADFC4986, + 0x1F180660, 0x0673368F, 0xDCB88ABB, 0xC5D3BA54, + 0x682FF3D2, 0x7144C33D, 0xAB8F7F09, 0xB2E44FE6, + 0x3E300CC0, 0x275B3C2F, 0xFD90801B, 0xE4FBB0F4, + 0x4907F972, 0x506CC99D, 0x8AA775A9, 0x93CC4546, + 0x21280AA0, 0x38433A4F, 0xE288867B, 0xFBE3B694, + 0x561FFF12, 0x4F74CFFD, 0x95BF73C9, 0x8CD44326, + 0x8D16F485, 0x947DC46A, 0x4EB6785E, 0x57DD48B1, + 0xFA210137, 0xE34A31D8, 0x39818DEC, 0x20EABD03, + 0x920EF2E5, 0x8B65C20A, 0x51AE7E3E, 0x48C54ED1, + 0xE5390757, 0xFC5237B8, 0x26998B8C, 0x3FF2BB63, + 0xB326F845, 0xAA4DC8AA, 0x7086749E, 0x69ED4471, + 0xC4110DF7, 0xDD7A3D18, 0x07B1812C, 0x1EDAB1C3, + 0xAC3EFE25, 0xB555CECA, 0x6F9E72FE, 0x76F54211, + 0xDB090B97, 0xC2623B78, 0x18A9874C, 0x01C2B7A3, + 0xEB5B040E, 0xF23034E1, 0x28FB88D5, 0x3190B83A, + 0x9C6CF1BC, 0x8507C153, 0x5FCC7D67, 0x46A74D88, + 0xF443026E, 0xED283281, 0x37E38EB5, 0x2E88BE5A, + 0x8374F7DC, 0x9A1FC733, 0x40D47B07, 0x59BF4BE8, + 0xD56B08CE, 0xCC003821, 0x16CB8415, 0x0FA0B4FA, + 0xA25CFD7C, 0xBB37CD93, 0x61FC71A7, 0x78974148, + 0xCA730EAE, 0xD3183E41, 0x09D38275, 0x10B8B29A, + 0xBD44FB1C, 0xA42FCBF3, 0x7EE477C7, 0x678F4728, + 0x664DF08B, 0x7F26C064, 0xA5ED7C50, 0xBC864CBF, + 0x117A0539, 0x081135D6, 0xD2DA89E2, 0xCBB1B90D, + 0x7955F6EB, 0x603EC604, 0xBAF57A30, 0xA39E4ADF, + 0x0E620359, 0x170933B6, 0xCDC28F82, 0xD4A9BF6D, + 0x587DFC4B, 0x4116CCA4, 0x9BDD7090, 0x82B6407F, + 0x2F4A09F9, 0x36213916, 0xECEA8522, 0xF581B5CD, + 0x4765FA2B, 0x5E0ECAC4, 0x84C576F0, 0x9DAE461F, + 0x30520F99, 0x29393F76, 0xF3F28342, 0xEA99B3AD, + 0xD6B7081C, 0xCFDC38F3, 0x151784C7, 0x0C7CB428, + 0xA180FDAE, 0xB8EBCD41, 0x62207175, 0x7B4B419A, + 0xC9AF0E7C, 0xD0C43E93, 0x0A0F82A7, 0x1364B248, + 0xBE98FBCE, 0xA7F3CB21, 0x7D387715, 0x645347FA, + 0xE88704DC, 0xF1EC3433, 0x2B278807, 0x324CB8E8, + 0x9FB0F16E, 0x86DBC181, 0x5C107DB5, 0x457B4D5A, + 0xF79F02BC, 0xEEF43253, 0x343F8E67, 0x2D54BE88, + 0x80A8F70E, 0x99C3C7E1, 0x43087BD5, 0x5A634B3A, + 0x5BA1FC99, 0x42CACC76, 0x98017042, 0x816A40AD, + 0x2C96092B, 0x35FD39C4, 0xEF3685F0, 0xF65DB51F, + 0x44B9FAF9, 0x5DD2CA16, 0x87197622, 0x9E7246CD, + 0x338E0F4B, 0x2AE53FA4, 0xF02E8390, 0xE945B37F, + 0x6591F059, 0x7CFAC0B6, 0xA6317C82, 0xBF5A4C6D, + 0x12A605EB, 0x0BCD3504, 0xD1068930, 0xC86DB9DF, + 0x7A89F639, 0x63E2C6D6, 0xB9297AE2, 0xA0424A0D, + 0x0DBE038B, 0x14D53364, 0xCE1E8F50, 0xD775BFBF, + 0x3DEC0C12, 0x24873CFD, 0xFE4C80C9, 0xE727B026, + 0x4ADBF9A0, 0x53B0C94F, 0x897B757B, 0x90104594, + 0x22F40A72, 0x3B9F3A9D, 0xE15486A9, 0xF83FB646, + 0x55C3FFC0, 0x4CA8CF2F, 0x9663731B, 0x8F0843F4, + 0x03DC00D2, 0x1AB7303D, 0xC07C8C09, 0xD917BCE6, + 0x74EBF560, 0x6D80C58F, 0xB74B79BB, 0xAE204954, + 0x1CC406B2, 0x05AF365D, 0xDF648A69, 0xC60FBA86, + 0x6BF3F300, 0x7298C3EF, 0xA8537FDB, 0xB1384F34, + 0xB0FAF897, 0xA991C878, 0x735A744C, 0x6A3144A3, + 0xC7CD0D25, 0xDEA63DCA, 0x046D81FE, 0x1D06B111, + 0xAFE2FEF7, 0xB689CE18, 0x6C42722C, 0x752942C3, + 0xD8D50B45, 0xC1BE3BAA, 0x1B75879E, 0x021EB771, + 0x8ECAF457, 0x97A1C4B8, 0x4D6A788C, 0x54014863, + 0xF9FD01E5, 0xE096310A, 0x3A5D8D3E, 0x2336BDD1, + 0x91D2F237, 0x88B9C2D8, 0x52727EEC, 0x4B194E03, + 0xE6E50785, 0xFF8E376A, 0x25458B5E, 0x3C2EBBB1, + }, + { + 0x00000000, 0xC82C0368, 0x905906D0, 0x587505B8, + 0xD1C5E0A5, 0x19E9E3CD, 0x419CE675, 0x89B0E51D, + 0x53FD2D4E, 0x9BD12E26, 0xC3A42B9E, 0x0B8828F6, + 0x8238CDEB, 0x4A14CE83, 0x1261CB3B, 0xDA4DC853, + 0xA6FA5B9C, 0x6ED658F4, 0x36A35D4C, 0xFE8F5E24, + 0x773FBB39, 0xBF13B851, 0xE766BDE9, 0x2F4ABE81, + 0xF50776D2, 0x3D2B75BA, 0x655E7002, 0xAD72736A, + 0x24C29677, 0xECEE951F, 0xB49B90A7, 0x7CB793CF, + 0xBD835B3D, 0x75AF5855, 0x2DDA5DED, 0xE5F65E85, + 0x6C46BB98, 0xA46AB8F0, 0xFC1FBD48, 0x3433BE20, + 0xEE7E7673, 0x2652751B, 0x7E2770A3, 0xB60B73CB, + 0x3FBB96D6, 0xF79795BE, 0xAFE29006, 0x67CE936E, + 0x1B7900A1, 0xD35503C9, 0x8B200671, 0x430C0519, + 0xCABCE004, 0x0290E36C, 0x5AE5E6D4, 0x92C9E5BC, + 0x48842DEF, 0x80A82E87, 0xD8DD2B3F, 0x10F12857, + 0x9941CD4A, 0x516DCE22, 0x0918CB9A, 0xC134C8F2, + 0x7A07B77A, 0xB22BB412, 0xEA5EB1AA, 0x2272B2C2, + 0xABC257DF, 0x63EE54B7, 0x3B9B510F, 0xF3B75267, + 0x29FA9A34, 0xE1D6995C, 0xB9A39CE4, 0x718F9F8C, + 0xF83F7A91, 0x301379F9, 0x68667C41, 0xA04A7F29, + 0xDCFDECE6, 0x14D1EF8E, 0x4CA4EA36, 0x8488E95E, + 0x0D380C43, 0xC5140F2B, 0x9D610A93, 0x554D09FB, + 0x8F00C1A8, 0x472CC2C0, 0x1F59C778, 0xD775C410, + 0x5EC5210D, 0x96E92265, 0xCE9C27DD, 0x06B024B5, + 0xC784EC47, 0x0FA8EF2F, 0x57DDEA97, 0x9FF1E9FF, + 0x16410CE2, 0xDE6D0F8A, 0x86180A32, 0x4E34095A, + 0x9479C109, 0x5C55C261, 0x0420C7D9, 0xCC0CC4B1, + 0x45BC21AC, 0x8D9022C4, 0xD5E5277C, 0x1DC92414, + 0x617EB7DB, 0xA952B4B3, 0xF127B10B, 0x390BB263, + 0xB0BB577E, 0x78975416, 0x20E251AE, 0xE8CE52C6, + 0x32839A95, 0xFAAF99FD, 0xA2DA9C45, 0x6AF69F2D, + 0xE3467A30, 0x2B6A7958, 0x731F7CE0, 0xBB337F88, + 0xF40E6EF5, 0x3C226D9D, 0x64576825, 0xAC7B6B4D, + 0x25CB8E50, 0xEDE78D38, 0xB5928880, 0x7DBE8BE8, + 0xA7F343BB, 0x6FDF40D3, 0x37AA456B, 0xFF864603, + 0x7636A31E, 0xBE1AA076, 0xE66FA5CE, 0x2E43A6A6, + 0x52F43569, 0x9AD83601, 0xC2AD33B9, 0x0A8130D1, + 0x8331D5CC, 0x4B1DD6A4, 0x1368D31C, 0xDB44D074, + 0x01091827, 0xC9251B4F, 0x91501EF7, 0x597C1D9F, + 0xD0CCF882, 0x18E0FBEA, 0x4095FE52, 0x88B9FD3A, + 0x498D35C8, 0x81A136A0, 0xD9D43318, 0x11F83070, + 0x9848D56D, 0x5064D605, 0x0811D3BD, 0xC03DD0D5, + 0x1A701886, 0xD25C1BEE, 0x8A291E56, 0x42051D3E, + 0xCBB5F823, 0x0399FB4B, 0x5BECFEF3, 0x93C0FD9B, + 0xEF776E54, 0x275B6D3C, 0x7F2E6884, 0xB7026BEC, + 0x3EB28EF1, 0xF69E8D99, 0xAEEB8821, 0x66C78B49, + 0xBC8A431A, 0x74A64072, 0x2CD345CA, 0xE4FF46A2, + 0x6D4FA3BF, 0xA563A0D7, 0xFD16A56F, 0x353AA607, + 0x8E09D98F, 0x4625DAE7, 0x1E50DF5F, 0xD67CDC37, + 0x5FCC392A, 0x97E03A42, 0xCF953FFA, 0x07B93C92, + 0xDDF4F4C1, 0x15D8F7A9, 0x4DADF211, 0x8581F179, + 0x0C311464, 0xC41D170C, 0x9C6812B4, 0x544411DC, + 0x28F38213, 0xE0DF817B, 0xB8AA84C3, 0x708687AB, + 0xF93662B6, 0x311A61DE, 0x696F6466, 0xA143670E, + 0x7B0EAF5D, 0xB322AC35, 0xEB57A98D, 0x237BAAE5, + 0xAACB4FF8, 0x62E74C90, 0x3A924928, 0xF2BE4A40, + 0x338A82B2, 0xFBA681DA, 0xA3D38462, 0x6BFF870A, + 0xE24F6217, 0x2A63617F, 0x721664C7, 0xBA3A67AF, + 0x6077AFFC, 0xA85BAC94, 0xF02EA92C, 0x3802AA44, + 0xB1B24F59, 0x799E4C31, 0x21EB4989, 0xE9C74AE1, + 0x9570D92E, 0x5D5CDA46, 0x0529DFFE, 0xCD05DC96, + 0x44B5398B, 0x8C993AE3, 0xD4EC3F5B, 0x1CC03C33, + 0xC68DF460, 0x0EA1F708, 0x56D4F2B0, 0x9EF8F1D8, + 0x174814C5, 0xDF6417AD, 0x87111215, 0x4F3D117D, + }, + { + 0x00000000, 0x277D3C49, 0x4EFA7892, 0x698744DB, + 0x6D821D21, 0x4AFF2168, 0x237865B3, 0x040559FA, + 0xDA043B42, 0xFD79070B, 0x94FE43D0, 0xB3837F99, + 0xB7862663, 0x90FB1A2A, 0xF97C5EF1, 0xDE0162B8, + 0xB4097684, 0x93744ACD, 0xFAF30E16, 0xDD8E325F, + 0xD98B6BA5, 0xFEF657EC, 0x97711337, 0xB00C2F7E, + 0x6E0D4DC6, 0x4970718F, 0x20F73554, 0x078A091D, + 0x038F50E7, 0x24F26CAE, 0x4D752875, 0x6A08143C, + 0x9965000D, 0xBE183C44, 0xD79F789F, 0xF0E244D6, + 0xF4E71D2C, 0xD39A2165, 0xBA1D65BE, 0x9D6059F7, + 0x43613B4F, 0x641C0706, 0x0D9B43DD, 0x2AE67F94, + 0x2EE3266E, 0x099E1A27, 0x60195EFC, 0x476462B5, + 0x2D6C7689, 0x0A114AC0, 0x63960E1B, 0x44EB3252, + 0x40EE6BA8, 0x679357E1, 0x0E14133A, 0x29692F73, + 0xF7684DCB, 0xD0157182, 0xB9923559, 0x9EEF0910, + 0x9AEA50EA, 0xBD976CA3, 0xD4102878, 0xF36D1431, + 0x32CB001A, 0x15B63C53, 0x7C317888, 0x5B4C44C1, + 0x5F491D3B, 0x78342172, 0x11B365A9, 0x36CE59E0, + 0xE8CF3B58, 0xCFB20711, 0xA63543CA, 0x81487F83, + 0x854D2679, 0xA2301A30, 0xCBB75EEB, 0xECCA62A2, + 0x86C2769E, 0xA1BF4AD7, 0xC8380E0C, 0xEF453245, + 0xEB406BBF, 0xCC3D57F6, 0xA5BA132D, 0x82C72F64, + 0x5CC64DDC, 0x7BBB7195, 0x123C354E, 0x35410907, + 0x314450FD, 0x16396CB4, 0x7FBE286F, 0x58C31426, + 0xABAE0017, 0x8CD33C5E, 0xE5547885, 0xC22944CC, + 0xC62C1D36, 0xE151217F, 0x88D665A4, 0xAFAB59ED, + 0x71AA3B55, 0x56D7071C, 0x3F5043C7, 0x182D7F8E, + 0x1C282674, 0x3B551A3D, 0x52D25EE6, 0x75AF62AF, + 0x1FA77693, 0x38DA4ADA, 0x515D0E01, 0x76203248, + 0x72256BB2, 0x555857FB, 0x3CDF1320, 0x1BA22F69, + 0xC5A34DD1, 0xE2DE7198, 0x8B593543, 0xAC24090A, + 0xA82150F0, 0x8F5C6CB9, 0xE6DB2862, 0xC1A6142B, + 0x64960134, 0x43EB3D7D, 0x2A6C79A6, 0x0D1145EF, + 0x09141C15, 0x2E69205C, 0x47EE6487, 0x609358CE, + 0xBE923A76, 0x99EF063F, 0xF06842E4, 0xD7157EAD, + 0xD3102757, 0xF46D1B1E, 0x9DEA5FC5, 0xBA97638C, + 0xD09F77B0, 0xF7E24BF9, 0x9E650F22, 0xB918336B, + 0xBD1D6A91, 0x9A6056D8, 0xF3E71203, 0xD49A2E4A, + 0x0A9B4CF2, 0x2DE670BB, 0x44613460, 0x631C0829, + 0x671951D3, 0x40646D9A, 0x29E32941, 0x0E9E1508, + 0xFDF30139, 0xDA8E3D70, 0xB30979AB, 0x947445E2, + 0x90711C18, 0xB70C2051, 0xDE8B648A, 0xF9F658C3, + 0x27F73A7B, 0x008A0632, 0x690D42E9, 0x4E707EA0, + 0x4A75275A, 0x6D081B13, 0x048F5FC8, 0x23F26381, + 0x49FA77BD, 0x6E874BF4, 0x07000F2F, 0x207D3366, + 0x24786A9C, 0x030556D5, 0x6A82120E, 0x4DFF2E47, + 0x93FE4CFF, 0xB48370B6, 0xDD04346D, 0xFA790824, + 0xFE7C51DE, 0xD9016D97, 0xB086294C, 0x97FB1505, + 0x565D012E, 0x71203D67, 0x18A779BC, 0x3FDA45F5, + 0x3BDF1C0F, 0x1CA22046, 0x7525649D, 0x525858D4, + 0x8C593A6C, 0xAB240625, 0xC2A342FE, 0xE5DE7EB7, + 0xE1DB274D, 0xC6A61B04, 0xAF215FDF, 0x885C6396, + 0xE25477AA, 0xC5294BE3, 0xACAE0F38, 0x8BD33371, + 0x8FD66A8B, 0xA8AB56C2, 0xC12C1219, 0xE6512E50, + 0x38504CE8, 0x1F2D70A1, 0x76AA347A, 0x51D70833, + 0x55D251C9, 0x72AF6D80, 0x1B28295B, 0x3C551512, + 0xCF380123, 0xE8453D6A, 0x81C279B1, 0xA6BF45F8, + 0xA2BA1C02, 0x85C7204B, 0xEC406490, 0xCB3D58D9, + 0x153C3A61, 0x32410628, 0x5BC642F3, 0x7CBB7EBA, + 0x78BE2740, 0x5FC31B09, 0x36445FD2, 0x1139639B, + 0x7B3177A7, 0x5C4C4BEE, 0x35CB0F35, 0x12B6337C, + 0x16B36A86, 0x31CE56CF, 0x58491214, 0x7F342E5D, + 0xA1354CE5, 0x864870AC, 0xEFCF3477, 0xC8B2083E, + 0xCCB751C4, 0xEBCA6D8D, 0x824D2956, 0xA530151F + } +#endif /* WORDS_BIGENDIAN */ +}; diff --git a/contrib/libs/libpq/src/port/pg_crc32c_sse42.c b/contrib/libs/libpq/src/port/pg_crc32c_sse42.c new file mode 100644 index 0000000000..0bac452717 --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_crc32c_sse42.c @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c_sse42.c + * Compute CRC-32C checksum using Intel SSE 4.2 instructions. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/pg_crc32c_sse42.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include <nmmintrin.h> + +#include "port/pg_crc32c.h" + +pg_attribute_no_sanitize_alignment() +pg_crc32c +pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len) +{ + const unsigned char *p = data; + const unsigned char *pend = p + len; + + /* + * Process eight bytes of data at a time. + * + * NB: We do unaligned accesses here. The Intel architecture allows that, + * and performance testing didn't show any performance gain from aligning + * the begin address. + */ +#ifdef __x86_64__ + while (p + 8 <= pend) + { + crc = (uint32) _mm_crc32_u64(crc, *((const uint64 *) p)); + p += 8; + } + + /* Process remaining full four bytes if any */ + if (p + 4 <= pend) + { + crc = _mm_crc32_u32(crc, *((const unsigned int *) p)); + p += 4; + } +#else + + /* + * Process four bytes at a time. (The eight byte instruction is not + * available on the 32-bit x86 architecture). + */ + while (p + 4 <= pend) + { + crc = _mm_crc32_u32(crc, *((const unsigned int *) p)); + p += 4; + } +#endif /* __x86_64__ */ + + /* Process any remaining bytes one at a time. */ + while (p < pend) + { + crc = _mm_crc32_u8(crc, *p); + p++; + } + + return crc; +} diff --git a/contrib/libs/libpq/src/port/pg_crc32c_sse42_choose.c b/contrib/libs/libpq/src/port/pg_crc32c_sse42_choose.c new file mode 100644 index 0000000000..41ff4a35ad --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_crc32c_sse42_choose.c @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c_sse42_choose.c + * Choose between Intel SSE 4.2 and software CRC-32C implementation. + * + * On first call, checks if the CPU we're running on supports Intel SSE + * 4.2. If it does, use the special SSE instructions for CRC-32C + * computation. Otherwise, fall back to the pure software implementation + * (slicing-by-8). + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/pg_crc32c_sse42_choose.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#ifdef HAVE__GET_CPUID +#include <cpuid.h> +#endif + +#ifdef HAVE__CPUID +#include <intrin.h> +#endif + +#include "port/pg_crc32c.h" + +static bool +pg_crc32c_sse42_available(void) +{ + unsigned int exx[4] = {0, 0, 0, 0}; + +#if defined(HAVE__GET_CPUID) + __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]); +#elif defined(HAVE__CPUID) + __cpuid(exx, 1); +#else +#error cpuid instruction not available +#endif + + return (exx[2] & (1 << 20)) != 0; /* SSE 4.2 */ +} + +/* + * This gets called on the first call. It replaces the function pointer + * so that subsequent calls are routed directly to the chosen implementation. + */ +static pg_crc32c +pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len) +{ + if (pg_crc32c_sse42_available()) + pg_comp_crc32c = pg_comp_crc32c_sse42; + else + pg_comp_crc32c = pg_comp_crc32c_sb8; + + return pg_comp_crc32c(crc, data, len); +} + +pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose; diff --git a/contrib/libs/libpq/src/port/pg_strong_random.c b/contrib/libs/libpq/src/port/pg_strong_random.c new file mode 100644 index 0000000000..862c84aa6f --- /dev/null +++ b/contrib/libs/libpq/src/port/pg_strong_random.c @@ -0,0 +1,182 @@ +/*------------------------------------------------------------------------- + * + * pg_strong_random.c + * generate a cryptographically secure random number + * + * Our definition of "strong" is that it's suitable for generating random + * salts and query cancellation keys, during authentication. + * + * Note: this code is run quite early in postmaster and backend startup; + * therefore, even when built for backend, it cannot rely on backend + * infrastructure such as elog() or palloc(). + * + * Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/port/pg_strong_random.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> + +/* + * pg_strong_random & pg_strong_random_init + * + * Generate requested number of random bytes. The returned bytes are + * cryptographically secure, suitable for use e.g. in authentication. + * + * Before pg_strong_random is called in any process, the generator must first + * be initialized by calling pg_strong_random_init(). + * + * We rely on system facilities for actually generating the numbers. + * We support a number of sources: + * + * 1. OpenSSL's RAND_bytes() + * 2. Windows' CryptGenRandom() function + * 3. /dev/urandom + * + * Returns true on success, and false if none of the sources + * were available. NB: It is important to check the return value! + * Proceeding with key generation when no random data was available + * would lead to predictable keys and security issues. + */ + + + +#ifdef USE_OPENSSL + +#include <openssl/rand.h> + +void +pg_strong_random_init(void) +{ + /* + * Make sure processes do not share OpenSSL randomness state. This is no + * longer required in OpenSSL 1.1.1 and later versions, but until we drop + * support for version < 1.1.1 we need to do this. + */ + RAND_poll(); +} + +bool +pg_strong_random(void *buf, size_t len) +{ + int i; + + /* + * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not + * add more seed data using RAND_poll(). With some older versions of + * OpenSSL, it may be necessary to call RAND_poll() a number of times. If + * RAND_poll() fails to generate seed data within the given amount of + * retries, subsequent RAND_bytes() calls will fail, but we allow that to + * happen to let pg_strong_random() callers handle that with appropriate + * error handling. + */ +#define NUM_RAND_POLL_RETRIES 8 + + for (i = 0; i < NUM_RAND_POLL_RETRIES; i++) + { + if (RAND_status() == 1) + { + /* The CSPRNG is sufficiently seeded */ + break; + } + + RAND_poll(); + } + + if (RAND_bytes(buf, len) == 1) + return true; + return false; +} + +#elif WIN32 + +#include <wincrypt.h> +/* + * Cache a global crypto provider that only gets freed when the process + * exits, in case we need random numbers more than once. + */ +static HCRYPTPROV hProvider = 0; + +void +pg_strong_random_init(void) +{ + /* No initialization needed on WIN32 */ +} + +bool +pg_strong_random(void *buf, size_t len) +{ + if (hProvider == 0) + { + if (!CryptAcquireContext(&hProvider, + NULL, + MS_DEF_PROV, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + /* + * On failure, set back to 0 in case the value was for some reason + * modified. + */ + hProvider = 0; + } + } + /* Re-check in case we just retrieved the provider */ + if (hProvider != 0) + { + if (CryptGenRandom(hProvider, len, buf)) + return true; + } + return false; +} + +#else /* not USE_OPENSSL or WIN32 */ + +/* + * Without OpenSSL or Win32 support, just read /dev/urandom ourselves. + */ + +void +pg_strong_random_init(void) +{ + /* No initialization needed */ +} + +bool +pg_strong_random(void *buf, size_t len) +{ + int f; + char *p = buf; + ssize_t res; + + f = open("/dev/urandom", O_RDONLY, 0); + if (f == -1) + return false; + + while (len) + { + res = read(f, p, len); + if (res <= 0) + { + if (errno == EINTR) + continue; /* interrupted by signal, just retry */ + + close(f); + return false; + } + + p += res; + len -= res; + } + + close(f); + return true; +} +#endif diff --git a/contrib/libs/libpq/src/port/pgcheckdir.c b/contrib/libs/libpq/src/port/pgcheckdir.c new file mode 100644 index 0000000000..94aa40ca8f --- /dev/null +++ b/contrib/libs/libpq/src/port/pgcheckdir.c @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- + * + * pgcheckdir.c + * + * A simple subroutine to check whether a directory exists and is empty or not. + * Useful in both initdb and the backend. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/port/pgcheckdir.c + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <dirent.h> + + +/* + * Test to see if a directory exists and is empty or not. + * + * Returns: + * 0 if nonexistent + * 1 if exists and empty + * 2 if exists and contains _only_ dot files + * 3 if exists and contains a mount point + * 4 if exists and not empty + * -1 if trouble accessing directory (errno reflects the error) + */ +int +pg_check_dir(const char *dir) +{ + int result = 1; + DIR *chkdir; + struct dirent *file; + bool dot_found = false; + bool mount_found = false; + int readdir_errno; + + chkdir = opendir(dir); + if (chkdir == NULL) + return (errno == ENOENT) ? 0 : -1; + + while (errno = 0, (file = readdir(chkdir)) != NULL) + { + if (strcmp(".", file->d_name) == 0 || + strcmp("..", file->d_name) == 0) + { + /* skip this and parent directory */ + continue; + } +#ifndef WIN32 + /* file starts with "." */ + else if (file->d_name[0] == '.') + { + dot_found = true; + } + /* lost+found directory */ + else if (strcmp("lost+found", file->d_name) == 0) + { + mount_found = true; + } +#endif + else + { + result = 4; /* not empty */ + break; + } + } + + if (errno) + result = -1; /* some kind of I/O error? */ + + /* Close chkdir and avoid overwriting the readdir errno on success */ + readdir_errno = errno; + if (closedir(chkdir)) + result = -1; /* error executing closedir */ + else + errno = readdir_errno; + + /* We report on mount point if we find a lost+found directory */ + if (result == 1 && mount_found) + result = 3; + + /* We report on dot-files if we _only_ find dot files */ + if (result == 1 && dot_found) + result = 2; + + return result; +} diff --git a/contrib/libs/libpq/src/port/pgmkdirp.c b/contrib/libs/libpq/src/port/pgmkdirp.c new file mode 100644 index 0000000000..d943559760 --- /dev/null +++ b/contrib/libs/libpq/src/port/pgmkdirp.c @@ -0,0 +1,148 @@ +/* + * This is adapted from FreeBSD's src/bin/mkdir/mkdir.c, which bears + * the following copyright notice: + * + * Copyright (c) 1983, 1992, 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. + * 4. 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 <sys/stat.h> + + +/* + * pg_mkdir_p --- create a directory and, if necessary, parent directories + * + * This is equivalent to "mkdir -p" except we don't complain if the target + * directory already exists. + * + * We assume the path is in canonical form, i.e., uses / as the separator. + * + * omode is the file permissions bits for the target directory. Note that any + * parent directories that have to be created get permissions according to the + * prevailing umask, but with u+wx forced on to ensure we can create there. + * (We declare omode as int, not mode_t, to minimize dependencies for port.h.) + * + * Returns 0 on success, -1 (with errno set) on failure. + * + * Note that on failure, the path arg has been modified to show the particular + * directory level we had problems with. + */ +int +pg_mkdir_p(char *path, int omode) +{ + struct stat sb; + mode_t numask, + oumask; + int last, + retval; + char *p; + + retval = 0; + p = path; + +#ifdef WIN32 + /* skip network and drive specifiers for win32 */ + if (strlen(p) >= 2) + { + if (p[0] == '/' && p[1] == '/') + { + /* network drive */ + p = strstr(p + 2, "/"); + if (p == NULL) + { + errno = EINVAL; + return -1; + } + } + else if (p[1] == ':' && + ((p[0] >= 'a' && p[0] <= 'z') || + (p[0] >= 'A' && p[0] <= 'Z'))) + { + /* local drive */ + p += 2; + } + } +#endif + + /* + * POSIX 1003.2: For each dir operand that does not name an existing + * directory, effects equivalent to those caused by the following command + * shall occur: + * + * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir + * + * We change the user's umask and then restore it, instead of doing + * chmod's. Note we assume umask() can't change errno. + */ + oumask = umask(0); + numask = oumask & ~(S_IWUSR | S_IXUSR); + (void) umask(numask); + + if (p[0] == '/') /* Skip leading '/'. */ + ++p; + for (last = 0; !last; ++p) + { + if (p[0] == '\0') + last = 1; + else if (p[0] != '/') + continue; + *p = '\0'; + if (!last && p[1] == '\0') + last = 1; + + if (last) + (void) umask(oumask); + + /* check for pre-existing directory */ + if (stat(path, &sb) == 0) + { + if (!S_ISDIR(sb.st_mode)) + { + if (last) + errno = EEXIST; + else + errno = ENOTDIR; + retval = -1; + break; + } + } + else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0) + { + retval = -1; + break; + } + if (!last) + *p = '/'; + } + + /* ensure we restored umask */ + (void) umask(oumask); + + return retval; +} diff --git a/contrib/libs/libpq/src/port/pgsleep.c b/contrib/libs/libpq/src/port/pgsleep.c new file mode 100644 index 0000000000..a1bcd78e4b --- /dev/null +++ b/contrib/libs/libpq/src/port/pgsleep.c @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * pgsleep.c + * Portable delay handling. + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * src/port/pgsleep.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include <time.h> + +/* + * 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, older Unixen and + * Windows use periodic kernel ticks to wake up, which might increase the delay + * time significantly. We've observed delay increases as large as 20 + * milliseconds on supported platforms. + * + * On machines where "long" is 32 bits, the maximum delay is ~2000 seconds. + * + * CAUTION: It's not a good idea to use long sleeps in the backend. They will + * silently return early if a signal is caught, but that doesn't include + * latches being set on most OSes, and even signal handlers that set MyLatch + * might happen to run before the sleep begins, allowing the full delay. + * Better practice is to use WaitLatch() with a timeout, so that backends + * respond to latches and signals promptly. + */ +void +pg_usleep(long microsec) +{ + if (microsec > 0) + { +#ifndef WIN32 + struct timespec delay; + + delay.tv_sec = microsec / 1000000L; + delay.tv_nsec = (microsec % 1000000L) * 1000; + (void) nanosleep(&delay, NULL); +#else + SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); +#endif + } +} + +#endif /* defined(FRONTEND) || !defined(WIN32) */ diff --git a/contrib/libs/libpq/src/port/pgstrcasecmp.c b/contrib/libs/libpq/src/port/pgstrcasecmp.c new file mode 100644 index 0000000000..27c1546f6f --- /dev/null +++ b/contrib/libs/libpq/src/port/pgstrcasecmp.c @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, PostgreSQL Global Development Group + * + * src/port/pgstrcasecmp.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +#include <ctype.h> + + +/* + * 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/contrib/libs/libpq/src/port/pgstrsignal.c b/contrib/libs/libpq/src/port/pgstrsignal.c new file mode 100644 index 0000000000..7d76d1cca9 --- /dev/null +++ b/contrib/libs/libpq/src/port/pgstrsignal.c @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * pgstrsignal.c + * Identify a Unix signal number + * + * On platforms compliant with modern POSIX, this just wraps strsignal(3). + * Elsewhere, we do the best we can. + * + * This file is not currently built in MSVC builds, since it's useless + * on non-Unix platforms. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/port/pgstrsignal.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + + +/* + * pg_strsignal + * + * Return a string identifying the given Unix signal number. + * + * The result is declared "const char *" because callers should not + * modify the string. Note, however, that POSIX does not promise that + * the string will remain valid across later calls to strsignal(). + * + * This version guarantees to return a non-NULL pointer, although + * some platforms' versions of strsignal() reputedly do not. + * + * Note that the fallback cases just return constant strings such as + * "unrecognized signal". Project style is for callers to print the + * numeric signal value along with the result of this function, so + * there's no need to work harder than that. + */ +const char * +pg_strsignal(int signum) +{ + const char *result; + + /* + * If we have strsignal(3), use that --- but check its result for NULL. + */ +#ifdef HAVE_STRSIGNAL + result = strsignal(signum); + if (result == NULL) + result = "unrecognized signal"; +#else + + /* + * We used to have code here to try to use sys_siglist[] if available. + * However, it seems that all platforms with sys_siglist[] have also had + * strsignal() for many years now, so that was just a waste of code. + */ + result = "(signal names not available on this platform)"; +#endif + + return result; +} diff --git a/contrib/libs/libpq/src/port/pqsignal.c b/contrib/libs/libpq/src/port/pqsignal.c new file mode 100644 index 0000000000..de9ed2c566 --- /dev/null +++ b/contrib/libs/libpq/src/port/pqsignal.c @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * pqsignal.c + * reliable BSD-style signal(2) routine stolen from RWW who stole it + * from Stevens... + * + * Portions Copyright (c) 1996-2023, 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 <signal.h> + +#ifndef FRONTEND +#error #include "libpq/pqsignal.h" +#endif + +/* + * Set up a signal handler, with SA_RESTART, for signal "signo" + * + * Returns the previous handler. + */ +pqsigfunc +pqsignal(int signo, pqsigfunc func) +{ +#if !(defined(WIN32) && defined(FRONTEND)) + 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 + /* Forward to Windows native signal system. */ + return signal(signo, func); +#endif +} diff --git a/contrib/libs/libpq/src/port/pthread-win32.h b/contrib/libs/libpq/src/port/pthread-win32.h new file mode 100644 index 0000000000..97ccc17a12 --- /dev/null +++ b/contrib/libs/libpq/src/port/pthread-win32.h @@ -0,0 +1,22 @@ +/* + * 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/contrib/libs/libpq/src/port/qsort.c b/contrib/libs/libpq/src/port/qsort.c new file mode 100644 index 0000000000..7879e6cd56 --- /dev/null +++ b/contrib/libs/libpq/src/port/qsort.c @@ -0,0 +1,22 @@ +/* + * qsort.c: standard quicksort algorithm + */ + +#include "c.h" + +#define ST_SORT pg_qsort +#define ST_ELEMENT_TYPE_VOID +#define ST_COMPARE_RUNTIME_POINTER +#define ST_SCOPE +#define ST_DECLARE +#define ST_DEFINE +#include "lib/sort_template.h" + +/* + * qsort comparator wrapper for strcmp. + */ +int +pg_qsort_strcmp(const void *a, const void *b) +{ + return strcmp(*(const char *const *) a, *(const char *const *) b); +} diff --git a/contrib/libs/libpq/src/port/qsort_arg.c b/contrib/libs/libpq/src/port/qsort_arg.c new file mode 100644 index 0000000000..fa7e11a3b8 --- /dev/null +++ b/contrib/libs/libpq/src/port/qsort_arg.c @@ -0,0 +1,14 @@ +/* + * qsort_arg.c: qsort with a passthrough "void *" argument + */ + +#include "c.h" + +#define ST_SORT qsort_arg +#define ST_ELEMENT_TYPE_VOID +#define ST_COMPARATOR_TYPE_NAME qsort_arg_comparator +#define ST_COMPARE_RUNTIME_POINTER +#define ST_COMPARE_ARG_TYPE void +#define ST_SCOPE +#define ST_DEFINE +#include "lib/sort_template.h" diff --git a/contrib/libs/libpq/src/port/quotes.c b/contrib/libs/libpq/src/port/quotes.c new file mode 100644 index 0000000000..a80e88d69b --- /dev/null +++ b/contrib/libs/libpq/src/port/quotes.c @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * quotes.c + * string quoting and escaping functions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/quotes.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +/* + * Escape (by doubling) any single quotes or backslashes in given string + * + * Note: this is used to process postgresql.conf entries and to quote + * string literals in pg_basebackup for writing the recovery configuration. + * Since postgresql.conf strings are defined to treat backslashes as escapes, + * we have to double backslashes here. + * + * Since this function is only used for parsing or creating configuration + * files, we do not care about encoding considerations. + * + * Returns a malloced() string that it's the responsibility of the caller + * to free. + */ +char * +escape_single_quotes_ascii(const char *src) +{ + int len = strlen(src), + i, + j; + char *result = malloc(len * 2 + 1); + + if (!result) + return NULL; + + for (i = 0, j = 0; i < len; i++) + { + if (SQL_STR_DOUBLE(src[i], true)) + result[j++] = src[i]; + result[j++] = src[i]; + } + result[j] = '\0'; + return result; +} diff --git a/contrib/libs/libpq/src/port/snprintf.c b/contrib/libs/libpq/src/port/snprintf.c new file mode 100644 index 0000000000..e3e316e049 --- /dev/null +++ b/contrib/libs/libpq/src/port/snprintf.c @@ -0,0 +1,1535 @@ +/* + * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * 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 <math.h> + +/* + * We used to use the platform's NL_ARGMAX here, but that's a bad idea, + * first because the point of this module is to remove platform dependencies + * not perpetuate them, and second because some platforms use ridiculously + * large values, leading to excessive stack consumption in dopr(). + */ +#define PG_NL_ARGMAX 31 + + +/* + * 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 C99 + * 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. + * + * In addition, we support some extensions over C99: + * + * 1. Argument order control through "%n$" and "*n$", as required by POSIX. + * + * 2. "%m" expands to the value of strerror(errno), where errno is the + * value that variable had at the start of the call. This is a glibc + * extension, but a very useful one. + * + * + * Historically the result values of sprintf/snprintf varied across platforms. + * This implementation now follows the C99 standard: + * + * 1. -1 is returned if an error is detected in the format string, or if + * a write to the target stream fails (as reported by fwrite). Note that + * overrunning snprintf's target buffer is *not* an error. + * + * 2. For successful writes to streams, the actual number of bytes written + * to the stream is returned. + * + * 3. For successful sprintf/snprintf, the number of bytes that would have + * been written to an infinite-size buffer (excluding the trailing '\0') + * is returned. snprintf will truncate its output to fit in the buffer + * (ensuring a trailing '\0' unless count == 0), but this is not reflected + * in the function result. + * + * snprintf buffer overrun can be detected by checking for function result + * greater than or equal to the supplied count. + */ + +/************************************************************** + * 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 vsprintf +#undef sprintf +#undef vfprintf +#undef fprintf +#undef vprintf +#undef printf + +/* + * Info about where the formatted output is going. + * + * dopr and subroutines will not write at/past bufend, but snprintf + * reserves one byte, ensuring it may place the trailing '\0' there. + * + * In snprintf, we use nchars to count the number of bytes dropped on the + * floor due to buffer overrun. The correct result of snprintf is thus + * (bufptr - bufstart) + nchars. (This isn't as inconsistent as it might + * seem: nchars is the number of emitted bytes that are not in the buffer now, + * either because we sent them to the stream or because we couldn't fit them + * into the buffer to begin with.) + */ +typedef struct +{ + char *bufptr; /* next buffer output position */ + char *bufstart; /* first buffer element */ + char *bufend; /* last+1 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 sent to stream, or dropped */ + 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; + long long ll; + double d; + char *cptr; +} PrintfArgValue; + + +static void flushbuffer(PrintfTarget *target); +static void dopr(PrintfTarget *target, const char *format, va_list args); + + +/* + * Externally visible entry points. + * + * All of these are just wrappers around dopr(). Note it's essential that + * they not change the value of "errno" before reaching dopr(). + */ + +int +pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + PrintfTarget target; + char onebyte[1]; + + /* + * C99 allows the case str == NULL when count == 0. Rather than + * special-casing this situation further down, we substitute a one-byte + * local buffer. Callers cannot tell, since the function result doesn't + * depend on count. + */ + if (count == 0) + { + str = onebyte; + count = 1; + } + target.bufstart = target.bufptr = str; + target.bufend = str + count - 1; + target.stream = NULL; + target.nchars = 0; + target.failed = false; + dopr(&target, fmt, args); + *(target.bufptr) = '\0'; + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); +} + +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; +} + +int +pg_vsprintf(char *str, const char *fmt, va_list args) +{ + PrintfTarget target; + + target.bufstart = target.bufptr = str; + target.bufend = NULL; + target.stream = NULL; + target.nchars = 0; /* not really used in this case */ + target.failed = false; + dopr(&target, fmt, args); + *(target.bufptr) = '\0'; + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); +} + +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); /* use the whole buffer */ + 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_vprintf(const char *fmt, va_list args) +{ + return pg_vfprintf(stdout, fmt, args); +} + +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; + + /* + * Don't write anything if we already failed; this is to ensure we + * preserve the original failure's errno. + */ + 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 bool find_arguments(const char *format, va_list args, + PrintfArgValue *argvalues); +static void fmtstr(const char *value, int leftjust, int minlen, int maxwidth, + int pointflag, PrintfTarget *target); +static void fmtptr(const void *value, PrintfTarget *target); +static void fmtint(long long 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 void dopr_outchmulti(int c, int slen, PrintfTarget *target); +static int adjust_sign(int is_negative, int forcesign, int *signvalue); +static int compute_padlen(int minlen, int vallen, int leftjust); +static void leading_pad(int zpad, int signvalue, int *padlen, + PrintfTarget *target); +static void trailing_pad(int padlen, PrintfTarget *target); + +/* + * If strchrnul exists (it's a glibc-ism), it's a good bit faster than the + * equivalent manual loop. If it doesn't exist, provide a replacement. + * + * Note: glibc declares this as returning "char *", but that would require + * casting away const internally, so we don't follow that detail. + */ +#ifndef HAVE_STRCHRNUL + +static inline const char * +strchrnul(const char *s, int c) +{ + while (*s != '\0' && *s != c) + s++; + return s; +} + +#else + +/* + * glibc's <string.h> declares strchrnul only if _GNU_SOURCE is defined. + * While we typically use that on glibc platforms, configure will set + * HAVE_STRCHRNUL whether it's used or not. Fill in the missing declaration + * so that this file will compile cleanly with or without _GNU_SOURCE. + */ +#ifndef _GNU_SOURCE +extern char *strchrnul(const char *s, int c); +#endif + +#endif /* HAVE_STRCHRNUL */ + + +/* + * dopr(): the guts of *printf for all cases. + */ +static void +dopr(PrintfTarget *target, const char *format, va_list args) +{ + int save_errno = errno; + const char *first_pct = NULL; + int ch; + bool have_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 fmtpos; + int cvalue; + long long numvalue; + double fvalue; + const char *strvalue; + PrintfArgValue argvalues[PG_NL_ARGMAX + 1]; + + /* + * Initially, we suppose the format string does not use %n$. The first + * time we come to a conversion spec that has that, we'll call + * find_arguments() to check for consistent use of %n$ and fill the + * argvalues array with the argument values in the correct order. + */ + have_dollar = false; + + while (*format != '\0') + { + /* Locate next conversion specifier */ + if (*format != '%') + { + /* Scan to next '%' or end of string */ + const char *next_pct = strchrnul(format + 1, '%'); + + /* Dump literal data we just scanned over */ + dostr(format, next_pct - format, target); + if (target->failed) + break; + + if (*next_pct == '\0') + break; + format = next_pct; + } + + /* + * Remember start of first conversion spec; if we find %n$, then it's + * sufficient for find_arguments() to start here, without rescanning + * earlier literal text. + */ + if (first_pct == NULL) + first_pct = format; + + /* Process conversion spec starting at *format */ + format++; + + /* Fast path for conversion spec that is exactly %s */ + if (*format == 's') + { + format++; + strvalue = va_arg(args, char *); + if (strvalue == NULL) + strvalue = "(null)"; + dostr(strvalue, strlen(strvalue), target); + if (target->failed) + break; + continue; + } + + fieldwidth = precision = zpad = leftjust = forcesign = 0; + longflag = longlongflag = pointflag = 0; + fmtpos = accum = 0; + have_star = afterstar = false; +nextch2: + ch = *format++; + 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) + { + /* + * We'll process value after reading n$. Note it's OK to + * assume have_dollar is set correctly, because in a valid + * format string the initial % must have had n$ if * does. + */ + 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 '$': + /* First dollar sign? */ + if (!have_dollar) + { + /* Yup, so examine all conversion specs in format */ + if (!find_arguments(first_pct, args, argvalues)) + goto bad_format; + have_dollar = true; + } + 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, long long); + 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 = (unsigned long long) argvalues[fmtpos].ll; + else if (longflag) + numvalue = (unsigned long) argvalues[fmtpos].l; + else + numvalue = (unsigned int) argvalues[fmtpos].i; + } + else + { + if (longlongflag) + numvalue = (unsigned long long) va_arg(args, long long); + 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 *); + /* If string is NULL, silently substitute "(null)" */ + if (strvalue == NULL) + strvalue = "(null)"; + 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((const 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 'm': + { + char errbuf[PG_STRERROR_R_BUFLEN]; + const char *errm = strerror_r(save_errno, + errbuf, sizeof(errbuf)); + + dostr(errm, strlen(errm), target); + } + break; + case '%': + dopr_outch('%', target); + break; + default: + + /* + * Anything else --- in particular, '\0' indicating end of + * format string --- is bogus. + */ + goto bad_format; + } + + /* Check for failure after each conversion spec */ + if (target->failed) + break; + } + + return; + +bad_format: + errno = EINVAL; + target->failed = true; +} + +/* + * find_arguments(): sort out the arguments for a format spec with %n$ + * + * If format is valid, return true and fill argvalues[i] with the value + * for the conversion spec that has %i$ or *i$. Else return false. + */ +static bool +find_arguments(const char *format, va_list args, + PrintfArgValue *argvalues) +{ + int ch; + bool afterstar; + int accum; + int longlongflag; + int longflag; + int fmtpos; + int i; + int last_dollar = 0; /* Init to "no dollar arguments known" */ + PrintfArgType argtypes[PG_NL_ARGMAX + 1] = {0}; + + /* + * This loop must accept the same format strings as the one in dopr(). + * However, we don't need to analyze them to the same level of detail. + * + * Since we're only called if there's a dollar-type spec somewhere, we can + * fail immediately if we find a non-dollar spec. Per the C99 standard, + * all argument references in the format string must be one or the other. + */ + while (*format != '\0') + { + /* Locate next conversion specifier */ + if (*format != '%') + { + /* Unlike dopr, we can just quit if there's no more specifiers */ + format = strchr(format + 1, '%'); + if (format == NULL) + break; + } + + /* Process conversion spec starting at *format */ + format++; + longflag = longlongflag = 0; + fmtpos = accum = 0; + afterstar = false; +nextch1: + ch = *format++; + 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 '.': + accum = 0; + goto nextch1; + case '*': + if (afterstar) + return false; /* previous star missing dollar */ + afterstar = true; + accum = 0; + goto nextch1; + case '$': + if (accum <= 0 || accum > PG_NL_ARGMAX) + return false; + if (afterstar) + { + if (argtypes[accum] && + argtypes[accum] != ATYPE_INT) + return false; + 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) + return false; + argtypes[fmtpos] = atype; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'c': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_INT) + return false; + argtypes[fmtpos] = ATYPE_INT; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 's': + case 'p': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_CHARPTR) + return false; + argtypes[fmtpos] = ATYPE_CHARPTR; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_DOUBLE) + return false; + argtypes[fmtpos] = ATYPE_DOUBLE; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'm': + case '%': + break; + default: + return false; /* bogus format string */ + } + + /* + * If we finish the spec with afterstar still set, there's a + * non-dollar star in there. + */ + if (afterstar) + return false; /* non-dollar conversion spec */ + } + + /* + * Format appears valid so far, so collect the arguments in physical + * order. (Since we rejected any non-dollar specs that would have + * collected arguments, we know that dopr() hasn't collected any yet.) + */ + for (i = 1; i <= last_dollar; i++) + { + switch (argtypes[i]) + { + case ATYPE_NONE: + return false; + 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, long long); + break; + case ATYPE_DOUBLE: + argvalues[i].d = va_arg(args, double); + break; + case ATYPE_CHARPTR: + argvalues[i].cptr = va_arg(args, char *); + break; + } + } + + return true; +} + +static void +fmtstr(const 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 = strnlen(value, maxwidth); + else + vallen = strlen(value); + + padlen = compute_padlen(minlen, vallen, leftjust); + + if (padlen > 0) + { + dopr_outchmulti(' ', padlen, target); + padlen = 0; + } + + dostr(value, vallen, target); + + trailing_pad(padlen, target); +} + +static void +fmtptr(const void *value, PrintfTarget *target) +{ + int vallen; + char convert[64]; + + /* we rely on regular C library's snprintf to do the basic conversion */ + vallen = snprintf(convert, sizeof(convert), "%p", value); + if (vallen < 0) + target->failed = true; + else + dostr(convert, vallen, target); +} + +static void +fmtint(long long value, char type, int forcesign, int leftjust, + int minlen, int zpad, int precision, int pointflag, + PrintfTarget *target) +{ + unsigned long long uvalue; + int base; + int dosign; + const char *cvt = "0123456789abcdef"; + int signvalue = 0; + char convert[64]; + int vallen = 0; + int padlen; /* 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 */ + } + + /* disable MSVC warning about applying unary minus to an unsigned value */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4146) +#endif + /* Handle +/- */ + if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) + uvalue = -(unsigned long long) value; + else + uvalue = (unsigned long long) value; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + /* + * SUS: the result of converting 0 with an explicit precision of 0 is no + * characters + */ + if (value == 0 && pointflag && precision == 0) + vallen = 0; + else + { + /* + * Convert integer to string. We special-case each of the possible + * base values so as to avoid general-purpose divisions. On most + * machines, division by a fixed constant can be done much more + * cheaply than a general divide. + */ + if (base == 10) + { + do + { + convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 10]; + uvalue = uvalue / 10; + } while (uvalue); + } + else if (base == 16) + { + do + { + convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 16]; + uvalue = uvalue / 16; + } while (uvalue); + } + else /* base == 8 */ + { + do + { + convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 8]; + uvalue = uvalue / 8; + } while (uvalue); + } + } + + zeropad = Max(0, precision - vallen); + + padlen = compute_padlen(minlen, vallen + zeropad, leftjust); + + leading_pad(zpad, signvalue, &padlen, target); + + if (zeropad > 0) + dopr_outchmulti('0', zeropad, target); + + dostr(convert + sizeof(convert) - vallen, vallen, target); + + trailing_pad(padlen, target); +} + +static void +fmtchar(int value, int leftjust, int minlen, PrintfTarget *target) +{ + int padlen; /* amount to pad */ + + padlen = compute_padlen(minlen, 1, leftjust); + + if (padlen > 0) + { + dopr_outchmulti(' ', padlen, target); + padlen = 0; + } + + 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[8]; + char convert[1024]; + int zeropadlen = 0; /* amount to pad with zeroes */ + int padlen; /* amount to pad with spaces */ + + /* + * We rely on the regular C library's snprintf 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, snprintf + * 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. + * + * We handle infinities and NaNs specially to ensure platform-independent + * output. + */ + if (precision < 0) /* cover possible overflow of "accum" */ + precision = 0; + prec = Min(precision, 350); + + if (isnan(value)) + { + strcpy(convert, "NaN"); + vallen = 3; + /* no zero padding, regardless of precision spec */ + } + else + { + /* + * Handle sign (NaNs have no sign, so we don't do this in the case + * above). "value < 0.0" will not be true for IEEE minus zero, so we + * detect that by looking for the case where value equals 0.0 + * according to == but not according to memcmp. + */ + static const double dzero = 0.0; + + if (adjust_sign((value < 0.0 || + (value == 0.0 && + memcmp(&value, &dzero, sizeof(double)) != 0)), + forcesign, &signvalue)) + value = -value; + + if (isinf(value)) + { + strcpy(convert, "Infinity"); + vallen = 8; + /* no zero padding, regardless of precision spec */ + } + else if (pointflag) + { + zeropadlen = precision - prec; + fmt[0] = '%'; + fmt[1] = '.'; + fmt[2] = '*'; + fmt[3] = type; + fmt[4] = '\0'; + vallen = snprintf(convert, sizeof(convert), fmt, prec, value); + } + else + { + fmt[0] = '%'; + fmt[1] = type; + fmt[2] = '\0'; + vallen = snprintf(convert, sizeof(convert), fmt, value); + } + if (vallen < 0) + goto fail; + + /* + * Windows, alone among our supported platforms, likes to emit + * three-digit exponent fields even when two digits would do. Hack + * such results to look like the way everyone else does it. + */ +#ifdef WIN32 + if (vallen >= 6 && + convert[vallen - 5] == 'e' && + convert[vallen - 3] == '0') + { + convert[vallen - 3] = convert[vallen - 2]; + convert[vallen - 2] = convert[vallen - 1]; + vallen--; + } +#endif + } + + padlen = compute_padlen(minlen, vallen + zeropadlen, leftjust); + + 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 before exponent */ + dostr(convert, epos - convert, target); + dopr_outchmulti('0', zeropadlen, target); + dostr(epos, vallen - (epos - convert), target); + } + else + { + /* no exponent, pad after the digits */ + dostr(convert, vallen, target); + dopr_outchmulti('0', zeropadlen, target); + } + } + else + { + /* no zero padding, just emit the number as-is */ + dostr(convert, vallen, target); + } + + trailing_pad(padlen, target); + return; + +fail: + target->failed = true; +} + +/* + * Nonstandard entry point to print a double value efficiently. + * + * This is approximately equivalent to strfromd(), but has an API more + * adapted to what float8out() wants. The behavior is like snprintf() + * with a format of "%.ng", where n is the specified precision. + * However, the target buffer must be nonempty (i.e. count > 0), and + * the precision is silently bounded to a sane range. + */ +int +pg_strfromd(char *str, size_t count, int precision, double value) +{ + PrintfTarget target; + int signvalue = 0; + int vallen; + char fmt[8]; + char convert[64]; + + /* Set up the target like pg_snprintf, but require nonempty buffer */ + Assert(count > 0); + target.bufstart = target.bufptr = str; + target.bufend = str + count - 1; + target.stream = NULL; + target.nchars = 0; + target.failed = false; + + /* + * We bound precision to a reasonable range; the combination of this and + * the knowledge that we're using "g" format without padding allows the + * convert[] buffer to be reasonably small. + */ + if (precision < 1) + precision = 1; + else if (precision > 32) + precision = 32; + + /* + * The rest is just an inlined version of the fmtfloat() logic above, + * simplified using the knowledge that no padding is wanted. + */ + if (isnan(value)) + { + strcpy(convert, "NaN"); + vallen = 3; + } + else + { + static const double dzero = 0.0; + + if (value < 0.0 || + (value == 0.0 && + memcmp(&value, &dzero, sizeof(double)) != 0)) + { + signvalue = '-'; + value = -value; + } + + if (isinf(value)) + { + strcpy(convert, "Infinity"); + vallen = 8; + } + else + { + fmt[0] = '%'; + fmt[1] = '.'; + fmt[2] = '*'; + fmt[3] = 'g'; + fmt[4] = '\0'; + vallen = snprintf(convert, sizeof(convert), fmt, precision, value); + if (vallen < 0) + { + target.failed = true; + goto fail; + } + +#ifdef WIN32 + if (vallen >= 6 && + convert[vallen - 5] == 'e' && + convert[vallen - 3] == '0') + { + convert[vallen - 3] = convert[vallen - 2]; + convert[vallen - 2] = convert[vallen - 1]; + vallen--; + } +#endif + } + } + + if (signvalue) + dopr_outch(signvalue, &target); + + dostr(convert, vallen, &target); + +fail: + *(target.bufptr) = '\0'; + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); +} + + +static void +dostr(const char *str, int slen, PrintfTarget *target) +{ + /* fast path for common case of slen == 1 */ + if (slen == 1) + { + dopr_outch(*str, target); + return; + } + + 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) + { + target->nchars += slen; /* no, lose the data */ + return; + } + 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) + { + target->nchars++; /* no, lose the data */ + return; + } + flushbuffer(target); + } + *(target->bufptr++) = c; +} + +static void +dopr_outchmulti(int c, int slen, PrintfTarget *target) +{ + /* fast path for common case of slen == 1 */ + if (slen == 1) + { + dopr_outch(c, target); + return; + } + + 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) + { + target->nchars += slen; /* no, lose the data */ + return; + } + flushbuffer(target); + continue; + } + avail = Min(avail, slen); + memset(target->bufptr, c, avail); + target->bufptr += avail; + slen -= avail; + } +} + + +static int +adjust_sign(int is_negative, int forcesign, int *signvalue) +{ + if (is_negative) + { + *signvalue = '-'; + return true; + } + else if (forcesign) + *signvalue = '+'; + return false; +} + + +static int +compute_padlen(int minlen, int vallen, int leftjust) +{ + int padlen; + + padlen = minlen - vallen; + if (padlen < 0) + padlen = 0; + if (leftjust) + padlen = -padlen; + return padlen; +} + + +static void +leading_pad(int zpad, int signvalue, int *padlen, PrintfTarget *target) +{ + int maxpad; + + if (*padlen > 0 && zpad) + { + if (signvalue) + { + dopr_outch(signvalue, target); + --(*padlen); + signvalue = 0; + } + if (*padlen > 0) + { + dopr_outchmulti(zpad, *padlen, target); + *padlen = 0; + } + } + maxpad = (signvalue != 0); + if (*padlen > maxpad) + { + dopr_outchmulti(' ', *padlen - maxpad, target); + *padlen = maxpad; + } + if (signvalue) + { + dopr_outch(signvalue, target); + if (*padlen > 0) + --(*padlen); + else if (*padlen < 0) + ++(*padlen); + } +} + + +static void +trailing_pad(int padlen, PrintfTarget *target) +{ + if (padlen < 0) + dopr_outchmulti(' ', -padlen, target); +} diff --git a/contrib/libs/libpq/src/port/strerror.c b/contrib/libs/libpq/src/port/strerror.c new file mode 100644 index 0000000000..26827d6db4 --- /dev/null +++ b/contrib/libs/libpq/src/port/strerror.c @@ -0,0 +1,312 @@ +/*------------------------------------------------------------------------- + * + * strerror.c + * Replacements for standard strerror() and strerror_r() functions + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/strerror.c + * + *------------------------------------------------------------------------- + */ +#include "c.h" + +/* + * Within this file, "strerror" means the platform's function not pg_strerror, + * and likewise for "strerror_r" + */ +#undef strerror +#undef strerror_r + +static char *gnuish_strerror_r(int errnum, char *buf, size_t buflen); +static char *get_errno_symbol(int errnum); +#ifdef WIN32 +static char *win32_socket_strerror(int errnum, char *buf, size_t buflen); +#endif + + +/* + * A slightly cleaned-up version of strerror() + */ +char * +pg_strerror(int errnum) +{ + static char errorstr_buf[PG_STRERROR_R_BUFLEN]; + + return pg_strerror_r(errnum, errorstr_buf, sizeof(errorstr_buf)); +} + +/* + * A slightly cleaned-up version of strerror_r() + */ +char * +pg_strerror_r(int errnum, char *buf, size_t buflen) +{ + char *str; + + /* If it's a Windows Winsock error, that needs special handling */ +#ifdef WIN32 + /* Winsock error code range, per WinError.h */ + if (errnum >= 10000 && errnum <= 11999) + return win32_socket_strerror(errnum, buf, buflen); +#endif + + /* Try the platform's strerror_r(), or maybe just strerror() */ + str = gnuish_strerror_r(errnum, buf, buflen); + + /* + * Some strerror()s return an empty string for out-of-range errno. This + * is ANSI C spec compliant, but not exactly useful. Also, we may get + * back strings of question marks if libc cannot transcode the message to + * the codeset specified by LC_CTYPE. If we get nothing useful, first try + * get_errno_symbol(), and if that fails, print the numeric errno. + */ + if (str == NULL || *str == '\0' || *str == '?') + str = get_errno_symbol(errnum); + + if (str == NULL) + { + snprintf(buf, buflen, _("operating system error %d"), errnum); + str = buf; + } + + return str; +} + +/* + * Simple wrapper to emulate GNU strerror_r if what the platform provides is + * POSIX. Also, if platform lacks strerror_r altogether, fall back to plain + * strerror; it might not be very thread-safe, but tough luck. + */ +static char * +gnuish_strerror_r(int errnum, char *buf, size_t buflen) +{ +#ifdef HAVE_STRERROR_R +#ifdef STRERROR_R_INT + /* POSIX API */ + if (strerror_r(errnum, buf, buflen) == 0) + return buf; + return NULL; /* let caller deal with failure */ +#else + /* GNU API */ + return strerror_r(errnum, buf, buflen); +#endif +#else /* !HAVE_STRERROR_R */ + char *sbuf = strerror(errnum); + + if (sbuf == NULL) /* can this still happen anywhere? */ + return NULL; + /* To minimize thread-unsafety hazard, copy into caller's buffer */ + strlcpy(buf, sbuf, buflen); + return buf; +#endif +} + +/* + * Returns a symbol (e.g. "ENOENT") for an errno code. + * Returns NULL if the code is unrecognized. + */ +static char * +get_errno_symbol(int errnum) +{ + switch (errnum) + { + case E2BIG: + return "E2BIG"; + case EACCES: + return "EACCES"; + case EADDRINUSE: + return "EADDRINUSE"; + case EADDRNOTAVAIL: + return "EADDRNOTAVAIL"; + case EAFNOSUPPORT: + return "EAFNOSUPPORT"; +#ifdef EAGAIN + case EAGAIN: + return "EAGAIN"; +#endif +#ifdef EALREADY + case EALREADY: + return "EALREADY"; +#endif + case EBADF: + return "EBADF"; +#ifdef EBADMSG + case EBADMSG: + return "EBADMSG"; +#endif + case EBUSY: + return "EBUSY"; + case ECHILD: + return "ECHILD"; + case ECONNABORTED: + return "ECONNABORTED"; + case ECONNREFUSED: + return "ECONNREFUSED"; + case ECONNRESET: + return "ECONNRESET"; + case EDEADLK: + return "EDEADLK"; + case EDOM: + return "EDOM"; + case EEXIST: + return "EEXIST"; + case EFAULT: + return "EFAULT"; + case EFBIG: + return "EFBIG"; + case EHOSTDOWN: + return "EHOSTDOWN"; + case EHOSTUNREACH: + return "EHOSTUNREACH"; + case EIDRM: + return "EIDRM"; + case EINPROGRESS: + return "EINPROGRESS"; + case EINTR: + return "EINTR"; + case EINVAL: + return "EINVAL"; + case EIO: + return "EIO"; + case EISCONN: + return "EISCONN"; + case EISDIR: + return "EISDIR"; +#ifdef ELOOP + case ELOOP: + return "ELOOP"; +#endif + case EMFILE: + return "EMFILE"; + case EMLINK: + return "EMLINK"; + case EMSGSIZE: + return "EMSGSIZE"; + case ENAMETOOLONG: + return "ENAMETOOLONG"; + case ENETDOWN: + return "ENETDOWN"; + case ENETRESET: + return "ENETRESET"; + case ENETUNREACH: + return "ENETUNREACH"; + case ENFILE: + return "ENFILE"; + case ENOBUFS: + return "ENOBUFS"; + case ENODEV: + return "ENODEV"; + case ENOENT: + return "ENOENT"; + case ENOEXEC: + return "ENOEXEC"; + case ENOMEM: + return "ENOMEM"; + case ENOSPC: + return "ENOSPC"; + case ENOSYS: + return "ENOSYS"; + case ENOTCONN: + return "ENOTCONN"; + case ENOTDIR: + return "ENOTDIR"; +#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */ + case ENOTEMPTY: + return "ENOTEMPTY"; +#endif + case ENOTSOCK: + return "ENOTSOCK"; +#ifdef ENOTSUP + case ENOTSUP: + return "ENOTSUP"; +#endif + case ENOTTY: + return "ENOTTY"; + case ENXIO: + return "ENXIO"; +#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP != ENOTSUP)) + case EOPNOTSUPP: + return "EOPNOTSUPP"; +#endif +#ifdef EOVERFLOW + case EOVERFLOW: + return "EOVERFLOW"; +#endif + case EPERM: + return "EPERM"; + case EPIPE: + return "EPIPE"; + case EPROTONOSUPPORT: + return "EPROTONOSUPPORT"; + case ERANGE: + return "ERANGE"; +#ifdef EROFS + case EROFS: + return "EROFS"; +#endif + case ESRCH: + return "ESRCH"; + case ETIMEDOUT: + return "ETIMEDOUT"; +#ifdef ETXTBSY + case ETXTBSY: + return "ETXTBSY"; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: + return "EWOULDBLOCK"; +#endif + case EXDEV: + return "EXDEV"; + } + + return NULL; +} + + +#ifdef WIN32 + +/* + * Windows' strerror() doesn't know the Winsock codes, so handle them this way + */ +static char * +win32_socket_strerror(int errnum, char *buf, size_t buflen) +{ + static HANDLE handleDLL = INVALID_HANDLE_VALUE; + + if (handleDLL == INVALID_HANDLE_VALUE) + { + handleDLL = LoadLibraryEx("netmsg.dll", NULL, + DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + if (handleDLL == NULL) + { + snprintf(buf, buflen, + "winsock error %d (could not load netmsg.dll to translate: error code %lu)", + errnum, GetLastError()); + return buf; + } + } + + ZeroMemory(buf, buflen); + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_FROM_HMODULE, + handleDLL, + errnum, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + buf, + buflen - 1, + NULL) == 0) + { + /* Failed to get id */ + snprintf(buf, buflen, "unrecognized winsock error %d", errnum); + } + + return buf; +} + +#endif /* WIN32 */ diff --git a/contrib/libs/libpq/src/port/tar.c b/contrib/libs/libpq/src/port/tar.c new file mode 100644 index 0000000000..4afe9f2533 --- /dev/null +++ b/contrib/libs/libpq/src/port/tar.c @@ -0,0 +1,206 @@ +#include "c.h" + +#include <sys/stat.h> + +#include "pgtar.h" + +/* + * Print a numeric field in a tar header. The field starts at *s and is of + * length len; val is the value to be written. + * + * Per POSIX, the way to write a number is in octal with leading zeroes and + * one trailing space (or NUL, but we use space) at the end of the specified + * field width. + * + * However, the given value may not fit in the available space in octal form. + * If that's true, we use the GNU extension of writing \200 followed by the + * number in base-256 form (ie, stored in binary MSB-first). (Note: here we + * support only non-negative numbers, so we don't worry about the GNU rules + * for handling negative numbers.) + */ +void +print_tar_number(char *s, int len, uint64 val) +{ + if (val < (((uint64) 1) << ((len - 1) * 3))) + { + /* Use octal with trailing space */ + s[--len] = ' '; + while (len) + { + s[--len] = (val & 7) + '0'; + val >>= 3; + } + } + else + { + /* Use base-256 with leading \200 */ + s[0] = '\200'; + while (len > 1) + { + s[--len] = (val & 255); + val >>= 8; + } + } +} + + +/* + * Read a numeric field in a tar header. The field starts at *s and is of + * length len. + * + * The POSIX-approved format for a number is octal, ending with a space or + * NUL. However, for values that don't fit, we recognize the GNU extension + * of \200 followed by the number in base-256 form (ie, stored in binary + * MSB-first). (Note: here we support only non-negative numbers, so we don't + * worry about the GNU rules for handling negative numbers.) + */ +uint64 +read_tar_number(const char *s, int len) +{ + uint64 result = 0; + + if (*s == '\200') + { + /* base-256 */ + while (--len) + { + result <<= 8; + result |= (unsigned char) (*++s); + } + } + else + { + /* octal */ + while (len-- && *s >= '0' && *s <= '7') + { + result <<= 3; + result |= (*s - '0'); + s++; + } + } + return result; +} + + +/* + * Calculate the tar checksum for a header. The header is assumed to always + * be 512 bytes, per the tar standard. + */ +int +tarChecksum(char *header) +{ + int i, + sum; + + /* + * Per POSIX, the checksum is the simple sum of all bytes in the header, + * treating the bytes as unsigned, and treating the checksum field (at + * offset 148) as though it contained 8 spaces. + */ + sum = 8 * ' '; /* presumed value for checksum field */ + for (i = 0; i < 512; i++) + if (i < 148 || i >= 156) + sum += 0xFF & header[i]; + return sum; +} + + +/* + * Fill in the buffer pointed to by h with a tar format header. This buffer + * must always have space for 512 characters, which is a requirement of + * the tar format. + */ +enum tarError +tarCreateHeader(char *h, const char *filename, const char *linktarget, + pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime) +{ + if (strlen(filename) > 99) + return TAR_NAME_TOO_LONG; + + if (linktarget && strlen(linktarget) > 99) + return TAR_SYMLINK_TOO_LONG; + + memset(h, 0, 512); /* assume tar header size */ + + /* Name 100 */ + strlcpy(&h[0], filename, 100); + if (linktarget != NULL || S_ISDIR(mode)) + { + /* + * We only support symbolic links to directories, and this is + * indicated in the tar format by adding a slash at the end of the + * name, the same as for regular directories. + */ + int flen = strlen(filename); + + flen = Min(flen, 99); + h[flen] = '/'; + h[flen + 1] = '\0'; + } + + /* Mode 8 - this doesn't include the file type bits (S_IFMT) */ + print_tar_number(&h[100], 8, (mode & 07777)); + + /* User ID 8 */ + print_tar_number(&h[108], 8, uid); + + /* Group 8 */ + print_tar_number(&h[116], 8, gid); + + /* File size 12 */ + if (linktarget != NULL || S_ISDIR(mode)) + /* Symbolic link or directory has size zero */ + print_tar_number(&h[124], 12, 0); + else + print_tar_number(&h[124], 12, size); + + /* Mod Time 12 */ + print_tar_number(&h[136], 12, mtime); + + /* Checksum 8 cannot be calculated until we've filled all other fields */ + + if (linktarget != NULL) + { + /* Type - Symbolic link */ + h[156] = '2'; + /* Link Name 100 */ + strlcpy(&h[157], linktarget, 100); + } + else if (S_ISDIR(mode)) + { + /* Type - directory */ + h[156] = '5'; + } + else + { + /* Type - regular file */ + h[156] = '0'; + } + + /* Magic 6 */ + strcpy(&h[257], "ustar"); + + /* Version 2 */ + memcpy(&h[263], "00", 2); + + /* User 32 */ + /* XXX: Do we need to care about setting correct username? */ + strlcpy(&h[265], "postgres", 32); + + /* Group 32 */ + /* XXX: Do we need to care about setting correct group name? */ + strlcpy(&h[297], "postgres", 32); + + /* Major Dev 8 */ + print_tar_number(&h[329], 8, 0); + + /* Minor Dev 8 */ + print_tar_number(&h[337], 8, 0); + + /* Prefix 155 - not used, leave as nulls */ + + /* Finally, compute and insert the checksum */ + print_tar_number(&h[148], 8, tarChecksum(h)); + + return TAR_OK; +} diff --git a/contrib/libs/libpq/src/port/thread.c b/contrib/libs/libpq/src/port/thread.c new file mode 100644 index 0000000000..375c89b297 --- /dev/null +++ b/contrib/libs/libpq/src/port/thread.c @@ -0,0 +1,96 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, PostgreSQL Global Development Group + * + * src/port/thread.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include <pwd.h> + + +/* + * Historically, the code in this module had to deal with operating systems + * that lacked getpwuid_r(). + */ + +#ifndef WIN32 + +/* + * pg_get_user_name - get the name of the user with the given ID + * + * On success, the user name is returned into the buffer (of size buflen), + * and "true" is returned. On failure, a localized error message is + * returned into the buffer, and "false" is returned. + */ +bool +pg_get_user_name(uid_t user_id, char *buffer, size_t buflen) +{ + char pwdbuf[BUFSIZ]; + struct passwd pwdstr; + struct passwd *pw = NULL; + int pwerr; + + pwerr = getpwuid_r(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw); + if (pw != NULL) + { + strlcpy(buffer, pw->pw_name, buflen); + return true; + } + if (pwerr != 0) + snprintf(buffer, buflen, + _("could not look up local user ID %d: %s"), + (int) user_id, + strerror_r(pwerr, pwdbuf, sizeof(pwdbuf))); + else + snprintf(buffer, buflen, + _("local user with ID %d does not exist"), + (int) user_id); + return false; +} + +/* + * pg_get_user_home_dir - get the home directory of the user with the given ID + * + * On success, the directory path is returned into the buffer (of size buflen), + * and "true" is returned. On failure, a localized error message is + * returned into the buffer, and "false" is returned. + * + * Note that this does not incorporate the common behavior of checking + * $HOME first, since it's independent of which user_id is queried. + */ +bool +pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen) +{ + char pwdbuf[BUFSIZ]; + struct passwd pwdstr; + struct passwd *pw = NULL; + int pwerr; + + pwerr = getpwuid_r(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw); + if (pw != NULL) + { + strlcpy(buffer, pw->pw_dir, buflen); + return true; + } + if (pwerr != 0) + snprintf(buffer, buflen, + _("could not look up local user ID %d: %s"), + (int) user_id, + strerror_r(pwerr, pwdbuf, sizeof(pwdbuf))); + else + snprintf(buffer, buflen, + _("local user with ID %d does not exist"), + (int) user_id); + return false; +} + +#endif /* !WIN32 */ diff --git a/contrib/libs/libpq/src/port/win32common.c b/contrib/libs/libpq/src/port/win32common.c new file mode 100644 index 0000000000..2fd78f7f93 --- /dev/null +++ b/contrib/libs/libpq/src/port/win32common.c @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + * + * win32common.c + * Common routines shared among the win32*.c ports. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/win32common.c + * + *------------------------------------------------------------------------- + */ + +#ifdef FRONTEND +#include "postgres_fe.h" +#else +#include "postgres.h" +#endif + +#ifdef WIN32 + +/* + * pgwin32_get_file_type + * + * Convenience wrapper for GetFileType() with specific error handling for all the + * port implementations. Returns the file type associated with a HANDLE. + * + * On error, sets errno with FILE_TYPE_UNKNOWN as file type. + */ +DWORD +pgwin32_get_file_type(HANDLE hFile) +{ + DWORD fileType = FILE_TYPE_UNKNOWN; + DWORD lastError; + + errno = 0; + + /* + * When stdin, stdout, and stderr aren't associated with a stream the + * special value -2 is returned: + * https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle + */ + if (hFile == INVALID_HANDLE_VALUE || hFile == (HANDLE) -2) + { + errno = EINVAL; + return FILE_TYPE_UNKNOWN; + } + + fileType = GetFileType(hFile); + lastError = GetLastError(); + + /* + * Invoke GetLastError in order to distinguish between a "valid" return of + * FILE_TYPE_UNKNOWN and its return due to a calling error. In case of + * success, GetLastError() returns NO_ERROR. + */ + if (fileType == FILE_TYPE_UNKNOWN && lastError != NO_ERROR) + { + _dosmaperr(lastError); + return FILE_TYPE_UNKNOWN; + } + + return fileType; +} + +#endif /* WIN32 */ diff --git a/contrib/libs/libpq/src/port/win32error.c b/contrib/libs/libpq/src/port/win32error.c new file mode 100644 index 0000000000..d7c3048eba --- /dev/null +++ b/contrib/libs/libpq/src/port/win32error.c @@ -0,0 +1,214 @@ +/*------------------------------------------------------------------------- + * + * win32error.c + * Map win32 error codes to errno values + * + * Portions Copyright (c) 1996-2023, 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 + }, + { + ERROR_DELETE_PENDING, ENOENT + }, + { + ERROR_INVALID_NAME, ENOENT + }, + { + ERROR_CANT_RESOLVE_FILENAME, ENOENT + } +}; + +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 defined(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; +} diff --git a/contrib/libs/libpq/src/port/win32gettimeofday.c b/contrib/libs/libpq/src/port/win32gettimeofday.c new file mode 100644 index 0000000000..1e00f7ee14 --- /dev/null +++ b/contrib/libs/libpq/src/port/win32gettimeofday.c @@ -0,0 +1,75 @@ +/* + * win32gettimeofday.c + * Win32 gettimeofday() replacement + * + * src/port/win32gettimeofday.c + * + * Copyright (c) 2003 SRA, Inc. + * Copyright (c) 2003 SKC, Inc. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose, without fee, and without a + * written agreement is hereby granted, provided that the above + * copyright notice and this paragraph and the following two + * paragraphs appear in all copies. + * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS + * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS + * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "c.h" + +#include <sysinfoapi.h> + +#include <sys/time.h> + +/* FILETIME of Jan 1 1970 00:00:00, the PostgreSQL epoch */ +static const unsigned __int64 epoch = UINT64CONST(116444736000000000); + +/* + * FILETIME represents the number of 100-nanosecond intervals since + * January 1, 1601 (UTC). + */ +#define FILETIME_UNITS_PER_SEC 10000000L +#define FILETIME_UNITS_PER_USEC 10 + + +/* + * timezone information is stored outside the kernel so tzp isn't used anymore. + * + * Note: this function is not for Win32 high precision timing purposes. See + * elapsed_time(). + */ +int +gettimeofday(struct timeval *tp, void *tzp) +{ + FILETIME file_time; + ULARGE_INTEGER ularge; + + /* + * POSIX declines to define what tzp points to, saying "If tzp is not a + * null pointer, the behavior is unspecified". Let's take this + * opportunity to verify that noplace in Postgres tries to use any + * unportable behavior. + */ + Assert(tzp == NULL); + + GetSystemTimePreciseAsFileTime(&file_time); + ularge.LowPart = file_time.dwLowDateTime; + ularge.HighPart = file_time.dwHighDateTime; + + tp->tv_sec = (long) ((ularge.QuadPart - epoch) / FILETIME_UNITS_PER_SEC); + tp->tv_usec = (long) (((ularge.QuadPart - epoch) % FILETIME_UNITS_PER_SEC) + / FILETIME_UNITS_PER_USEC); + + return 0; +} diff --git a/contrib/libs/libpq/src/port/win32ntdll.c b/contrib/libs/libpq/src/port/win32ntdll.c new file mode 100644 index 0000000000..3b38cdb34c --- /dev/null +++ b/contrib/libs/libpq/src/port/win32ntdll.c @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------- + * + * win32ntdll.c + * Dynamically loaded Windows NT functions. + * + * Portions Copyright (c) 2021-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/win32ntdll.c + * + *------------------------------------------------------------------------- + */ + +#include "c.h" + +#include "port/win32ntdll.h" + +RtlGetLastNtStatus_t pg_RtlGetLastNtStatus; +RtlNtStatusToDosError_t pg_RtlNtStatusToDosError; +NtFlushBuffersFileEx_t pg_NtFlushBuffersFileEx; + +typedef struct NtDllRoutine +{ + const char *name; + pg_funcptr_t *address; +} NtDllRoutine; + +static const NtDllRoutine routines[] = { + {"RtlGetLastNtStatus", (pg_funcptr_t *) &pg_RtlGetLastNtStatus}, + {"RtlNtStatusToDosError", (pg_funcptr_t *) &pg_RtlNtStatusToDosError}, + {"NtFlushBuffersFileEx", (pg_funcptr_t *) &pg_NtFlushBuffersFileEx} +}; + +static bool initialized; + +int +initialize_ntdll(void) +{ + HMODULE module; + + if (initialized) + return 0; + + if (!(module = LoadLibraryEx("ntdll.dll", NULL, 0))) + { + _dosmaperr(GetLastError()); + return -1; + } + + for (int i = 0; i < lengthof(routines); ++i) + { + pg_funcptr_t address; + + address = (pg_funcptr_t) GetProcAddress(module, routines[i].name); + if (!address) + { + _dosmaperr(GetLastError()); + FreeLibrary(module); + + return -1; + } + + *(pg_funcptr_t *) routines[i].address = address; + } + + initialized = true; + + return 0; +} diff --git a/contrib/libs/libpq/src/port/win32setlocale.c b/contrib/libs/libpq/src/port/win32setlocale.c new file mode 100644 index 0000000000..e2c85b0048 --- /dev/null +++ b/contrib/libs/libpq/src/port/win32setlocale.c @@ -0,0 +1,193 @@ +/*------------------------------------------------------------------------- + * + * win32setlocale.c + * Wrapper to work around bugs in Windows setlocale() implementation + * + * Copyright (c) 2011-2023, 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)". + * + * Just to make life even more complicated, some versions of Windows spell + * the locale name without parentheses. Translate that too. + */ + {"Norwegian (Bokm", "l)_Norway", "Norwegian_Norway"}, + {"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 = unconstify(char *, map_locale(locale_map_result, result)); + + return result; +} diff --git a/contrib/libs/libpq/src/port/win32stat.c b/contrib/libs/libpq/src/port/win32stat.c new file mode 100644 index 0000000000..aa3a0c174e --- /dev/null +++ b/contrib/libs/libpq/src/port/win32stat.c @@ -0,0 +1,306 @@ +/*------------------------------------------------------------------------- + * + * win32stat.c + * Replacements for <sys/stat.h> functions using GetFileInformationByHandle + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/win32stat.c + * + *------------------------------------------------------------------------- + */ + +#ifdef WIN32 + +#include "c.h" +#include "port/win32ntdll.h" + +#include <windows.h> + +/* + * Convert a FILETIME struct into a 64 bit time_t. + */ +static __time64_t +filetime_to_time(const FILETIME *ft) +{ + ULARGE_INTEGER unified_ft = {0}; + static const uint64 EpochShift = UINT64CONST(116444736000000000); + + unified_ft.LowPart = ft->dwLowDateTime; + unified_ft.HighPart = ft->dwHighDateTime; + + if (unified_ft.QuadPart < EpochShift) + return -1; + + unified_ft.QuadPart -= EpochShift; + unified_ft.QuadPart /= 10 * 1000 * 1000; + + return unified_ft.QuadPart; +} + +/* + * Convert WIN32 file attributes to a Unix-style mode. + * + * Only owner permissions are set. + */ +static unsigned short +fileattr_to_unixmode(int attr) +{ + unsigned short uxmode = 0; + + uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_DIRECTORY) ? + (_S_IFDIR) : (_S_IFREG)); + + uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_READONLY) ? + (_S_IREAD) : (_S_IREAD | _S_IWRITE)); + + /* there is no need to simulate _S_IEXEC using CMD's PATHEXT extensions */ + uxmode |= _S_IEXEC; + + return uxmode; +} + +/* + * Convert WIN32 file information (from a HANDLE) to a struct stat. + */ +static int +fileinfo_to_stat(HANDLE hFile, struct stat *buf) +{ + BY_HANDLE_FILE_INFORMATION fiData; + + memset(buf, 0, sizeof(*buf)); + + /* + * GetFileInformationByHandle minimum supported version: Windows XP and + * Windows Server 2003, so it exists everywhere we care about. + */ + if (!GetFileInformationByHandle(hFile, &fiData)) + { + _dosmaperr(GetLastError()); + return -1; + } + + if (fiData.ftLastWriteTime.dwLowDateTime || + fiData.ftLastWriteTime.dwHighDateTime) + buf->st_mtime = filetime_to_time(&fiData.ftLastWriteTime); + + if (fiData.ftLastAccessTime.dwLowDateTime || + fiData.ftLastAccessTime.dwHighDateTime) + buf->st_atime = filetime_to_time(&fiData.ftLastAccessTime); + else + buf->st_atime = buf->st_mtime; + + if (fiData.ftCreationTime.dwLowDateTime || + fiData.ftCreationTime.dwHighDateTime) + buf->st_ctime = filetime_to_time(&fiData.ftCreationTime); + else + buf->st_ctime = buf->st_mtime; + + buf->st_mode = fileattr_to_unixmode(fiData.dwFileAttributes); + buf->st_nlink = fiData.nNumberOfLinks; + + buf->st_size = ((((uint64) fiData.nFileSizeHigh) << 32) | + fiData.nFileSizeLow); + + return 0; +} + +/* + * Windows implementation of lstat(). + */ +int +_pglstat64(const char *name, struct stat *buf) +{ + /* + * Our open wrapper will report STATUS_DELETE_PENDING as ENOENT. We + * request FILE_FLAG_BACKUP_SEMANTICS so that we can open directories too, + * for limited purposes. We use the private handle-based version, so we + * don't risk running out of fds. + */ + HANDLE hFile; + int ret; + + hFile = pgwin32_open_handle(name, O_RDONLY, true); + if (hFile == INVALID_HANDLE_VALUE) + { + if (errno == ENOENT) + { + /* + * If it's a junction point pointing to a non-existent path, we'll + * have ENOENT here (because pgwin32_open_handle does not use + * FILE_FLAG_OPEN_REPARSE_POINT). In that case, we'll try again + * with readlink() below, which will distinguish true ENOENT from + * pseudo-symlink. + */ + memset(buf, 0, sizeof(*buf)); + ret = 0; + } + else + return -1; + } + else + ret = fileinfo_to_stat(hFile, buf); + + /* + * Junction points appear as directories to fileinfo_to_stat(), so we'll + * need to do a bit more work to distinguish them. + */ + if ((ret == 0 && S_ISDIR(buf->st_mode)) || hFile == INVALID_HANDLE_VALUE) + { + char next[MAXPGPATH]; + ssize_t size; + + /* + * POSIX says we need to put the length of the target path into + * st_size. Use readlink() to get it, or learn that this is not a + * junction point. + */ + size = readlink(name, next, sizeof(next)); + if (size < 0) + { + if (errno == EACCES && + pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING) + { + /* Unlinked underneath us. */ + errno = ENOENT; + ret = -1; + } + else if (errno == EINVAL) + { + /* It's not a junction point, nothing to do. */ + } + else + { + /* Some other failure. */ + ret = -1; + } + } + else + { + /* It's a junction point, so report it as a symlink. */ + buf->st_mode &= ~S_IFDIR; + buf->st_mode |= S_IFLNK; + buf->st_size = size; + ret = 0; + } + } + + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + return ret; +} + +/* + * Windows implementation of stat(). + */ +int +_pgstat64(const char *name, struct stat *buf) +{ + int loops = 0; + int ret; + char curr[MAXPGPATH]; + + ret = _pglstat64(name, buf); + + strlcpy(curr, name, MAXPGPATH); + + /* Do we need to follow a symlink (junction point)? */ + while (ret == 0 && S_ISLNK(buf->st_mode)) + { + char next[MAXPGPATH]; + ssize_t size; + + if (++loops > 8) + { + errno = ELOOP; + return -1; + } + + /* + * _pglstat64() already called readlink() once to be able to fill in + * st_size, and now we need to do it again to get the path to follow. + * That could be optimized, but stat() on symlinks is probably rare + * and this way is simple. + */ + size = readlink(curr, next, sizeof(next)); + if (size < 0) + { + if (errno == EACCES && + pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING) + { + /* Unlinked underneath us. */ + errno = ENOENT; + } + return -1; + } + if (size >= sizeof(next)) + { + errno = ENAMETOOLONG; + return -1; + } + next[size] = 0; + + ret = _pglstat64(next, buf); + strcpy(curr, next); + } + + return ret; +} + +/* + * Windows implementation of fstat(). + */ +int +_pgfstat64(int fileno, struct stat *buf) +{ + HANDLE hFile = (HANDLE) _get_osfhandle(fileno); + DWORD fileType = FILE_TYPE_UNKNOWN; + unsigned short st_mode; + + if (buf == NULL) + { + errno = EINVAL; + return -1; + } + + fileType = pgwin32_get_file_type(hFile); + if (errno != 0) + return -1; + + switch (fileType) + { + /* The specified file is a disk file */ + case FILE_TYPE_DISK: + return fileinfo_to_stat(hFile, buf); + + /* + * The specified file is a socket, a named pipe, or an anonymous + * pipe. + */ + case FILE_TYPE_PIPE: + st_mode = _S_IFIFO; + break; + /* The specified file is a character file */ + case FILE_TYPE_CHAR: + st_mode = _S_IFCHR; + break; + /* Unused flag and unknown file type */ + case FILE_TYPE_REMOTE: + case FILE_TYPE_UNKNOWN: + default: + errno = EINVAL; + return -1; + } + + memset(buf, 0, sizeof(*buf)); + buf->st_mode = st_mode; + buf->st_dev = fileno; + buf->st_rdev = fileno; + buf->st_nlink = 1; + return 0; +} + +#endif /* WIN32 */ diff --git a/contrib/libs/libpq/ya.make b/contrib/libs/libpq/ya.make new file mode 100644 index 0000000000..d7acd293f3 --- /dev/null +++ b/contrib/libs/libpq/ya.make @@ -0,0 +1,155 @@ +# Generated by devtools/yamaker from nixpkgs 22.11. + +LIBRARY() + +LICENSE( + Apache-2.0 AND + BSD-3-Clause AND + BSL-1.0 AND + ISC AND + PostgreSQL AND + Public-Domain +) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +VERSION(16.1) + +ORIGINAL_SOURCE(https://github.com/postgres/postgres/archive/REL_16_1.tar.gz) + +PEERDIR( + contrib/libs/libc_compat + contrib/libs/openssl + contrib/libs/zlib +) + +ADDINCL( + contrib/libs/libpq/src/backend + GLOBAL contrib/libs/libpq/src/include + contrib/libs/libpq/src/common + contrib/libs/libpq/src/interfaces/libpq + contrib/libs/libpq/src/port +) + +NO_COMPILER_WARNINGS() + +NO_RUNTIME() + +CFLAGS( + -DFRONTEND + -DUNSAFE_STAT_OK + -D_POSIX_PTHREAD_SEMANTICS + -D_REENTRANT + -D_THREAD_SAFE +) + +SRCS( + src/common/archive.c + src/common/base64.c + src/common/checksum_helper.c + src/common/compression.c + src/common/config_info.c + src/common/controldata_utils.c + src/common/cryptohash_openssl.c + src/common/d2s.c + src/common/encnames.c + src/common/exec.c + src/common/f2s.c + src/common/fe_memutils.c + src/common/file_perm.c + src/common/file_utils.c + src/common/hashfn.c + src/common/hmac_openssl.c + src/common/ip.c + src/common/jsonapi.c + src/common/keywords.c + src/common/kwlookup.c + src/common/link-canary.c + src/common/logging.c + src/common/md5_common.c + src/common/percentrepl.c + src/common/pg_get_line.c + src/common/pg_lzcompress.c + src/common/pg_prng.c + src/common/pgfnames.c + src/common/protocol_openssl.c + src/common/psprintf.c + src/common/relpath.c + src/common/restricted_token.c + src/common/rmtree.c + src/common/saslprep.c + src/common/scram-common.c + src/common/sprompt.c + src/common/string.c + src/common/stringinfo.c + src/common/unicode_norm.c + src/common/username.c + src/common/wait_error.c + src/common/wchar.c + src/interfaces/libpq/fe-auth-scram.c + src/interfaces/libpq/fe-auth.c + src/interfaces/libpq/fe-connect.c + src/interfaces/libpq/fe-exec.c + src/interfaces/libpq/fe-lobj.c + src/interfaces/libpq/fe-misc.c + src/interfaces/libpq/fe-print.c + src/interfaces/libpq/fe-protocol3.c + src/interfaces/libpq/fe-secure-common.c + src/interfaces/libpq/fe-secure-openssl.c + src/interfaces/libpq/fe-secure.c + src/interfaces/libpq/fe-trace.c + src/interfaces/libpq/libpq-events.c + src/interfaces/libpq/pqexpbuffer.c + src/port/bsearch_arg.c + src/port/chklocale.c + src/port/getpeereid.c + src/port/inet_net_ntop.c + src/port/noblock.c + src/port/path.c + src/port/pg_bitutils.c + src/port/pg_crc32c_sb8.c + src/port/pg_strong_random.c + src/port/pgcheckdir.c + src/port/pgmkdirp.c + src/port/pgsleep.c + src/port/pgstrcasecmp.c + src/port/pgstrsignal.c + src/port/pqsignal.c + src/port/qsort.c + src/port/qsort_arg.c + src/port/quotes.c + src/port/snprintf.c + src/port/strerror.c + src/port/tar.c + src/port/thread.c +) + +IF (ARCH_X86_64) + SRCS( + src/port/pg_crc32c_sse42.c + src/port/pg_crc32c_sse42_choose.c + ) +ENDIF() + +IF (OS_WINDOWS) + ADDINCL( + contrib/libs/libpq/src/include/port + contrib/libs/libpq/src/include/port/win32 + contrib/libs/libpq/src/include/port/win32_msvc + ) + SRCS( + src/interfaces/libpq/pthread-win32.c + src/interfaces/libpq/win32.c + src/port/dirmod.c + src/port/inet_aton.c + src/port/open.c + src/port/win32common.c + src/port/win32error.c + src/port/win32gettimeofday.c + src/port/win32ntdll.c + src/port/win32setlocale.c + src/port/win32stat.c + ) +ENDIF() + +END() |